Skip to content

feat(agent): add AI Agent conversation APIs across all SDK bindings#557

Draft
sunli829 wants to merge 7 commits into
mainfrom
feat/ai-agent-conversations
Draft

feat(agent): add AI Agent conversation APIs across all SDK bindings#557
sunli829 wants to merge 7 commits into
mainfrom
feat/ai-agent-conversations

Conversation

@sunli829

Copy link
Copy Markdown
Collaborator

Summary

Adds full SDK support for the new AI Agent conversation APIs (longbridge/developers#1129) across the Rust core and every language binding (C, C++, Python, Node.js, Java), in both blocking and SSE-streaming response modes.

  • New endpoints: list workspaces, list agents in a workspace, start a conversation, and continue an interrupted conversation.
  • Streaming responses use each binding's most idiomatic shape: a Stream for async Rust, a blocking Iterator for Rust blocking/Python sync, an async for iterator for Python async, callback + Promise for Node.js/C/C++, and a real-backpressure java.util.concurrent.Flow.Publisher for Java.
  • rust/crates/httpclient gained generic SSE support (send_events, built on eventsource-stream) as new shared infrastructure, since no existing HTTP call in the SDK streamed a response before.

Event types

The documented example only shows the success path (chat_startedmessageworkflow_finished). Live testing against the production API surfaced four additional event types the docs don't mention: workflow_started, ping (heartbeat), chat_finished, and chat_title_updated (which can arrive before or after workflow_finished). All four are now modeled as first-class ConversationStreamEvent variants (not just a generic Other catch-all) across every binding.

Bugs found via live testing (not reachable by code review alone)

  • ConversationStreamEvent::Other originally discarded the SSE event-type name, leaving callers unable to tell what kind of unrecognized event they'd received — now carries { event, data }.
  • Java's Flow.Publisher implementation stopped as soon as it saw workflow_finished, but that isn't always the last event in the stream (some runs emit trailing housekeeping events after it) — fixed to drain to the stream's actual end, matching every other binding.
  • The shared request timeout (30s) was too tight for a full conversation round-trip; agent-domain calls now use a longer, dedicated timeout.

Test plan

  • cargo clippy --all --all-features and cargo +nightly fmt --all clean across the workspace
  • Rust core unit tests for SSE envelope/event parsing (cargo test -p longbridge agent)
  • cargo build -p longbridge-c — header regenerates correctly
  • C++ builds against the regenerated C header (CMake/Corrosion)
  • maturin develop — Python extension builds and imports correctly (sync + async)
  • npm run build:debug — Node.js native binary + index.d.ts regenerate correctly
  • mvn compile — Java sources compile against the JNI glue
  • Live-tested every binding (Rust, Python, Node.js, C, C++, Java) against the real production API with a live Agent, covering blocking calls, streaming calls, and the interrupt/continue flow

🤖 Generated with Claude Code

sunli829 added 6 commits July 20, 2026 18:00
Adds workspaces/agents/conversation/continue-conversation endpoints with
both blocking and SSE-streaming response modes, matching each binding's
own idiom: Stream in Rust core, blocking Iterator in Rust `blocking` and
Python sync, async iterator in Python async, callback+Promise in Node.js
and C/C++, and a real backpressured java.util.concurrent.Flow.Publisher
in Java. httpclient gains its first SSE transport support to enable this.
Live testing against the real API surfaced several undocumented SSE event
types (workflow_started, ping, chat_finished, chat_title_updated) that all
correctly fall into the Other catch-all, but it previously discarded the
discriminating `event` field, leaving callers with an unlabeled JSON blob.
Other now carries both the event type name and the data, across all
bindings.
…ping at WorkflowFinished

Live testing showed the server can emit a few more housekeeping events (e.g. a chat_title_updated-shaped Other event, or a trailing ping) after workflow_finished and before actually closing the connection. Java's Flow.Publisher implementation treated WorkflowFinished as a hard stream terminator and silently dropped anything after it; every other binding already drained to the stream's natural end. Removed the early break so Java matches, and corrected the "WorkflowFinished is always the last event" doc claim across all bindings, which this behavior was based on and which real traffic disproves.
…meout

The shared httpclient default (30s) wraps the whole request-response cycle, including waiting for the full body. In blocking mode the server holds the connection silent until the whole LLM turn is done, which can legitimately exceed 30s (observed twice live: a spurious RequestTimeout in both Rust and Python). Added a per-request timeout override to RequestBuilder and applied a 120s budget specifically to the agent domain's calls; every other domain keeps the 30s default.
…ated as typed events

These four SSE event types aren't documented by the API but were consistently observed against the real service during live testing. Modeling them as proper ConversationStreamEvent variants (with typed payloads) instead of leaving them in the Other catch-all makes them discoverable and type-safe for callers. Payloads are marked as reverse-engineered/unverified against future API changes.
….js/Java

Extends the C, C++, Python, Node.js, and Java bindings with the
WorkflowStarted/Ping/ChatFinished/ChatTitleUpdated ConversationStreamEvent
variants added to the Rust core, keeping every binding's event handling in
sync. Also strips disclaimer-style ("not documented by the API",
"reverse-engineered from live traffic") doc comments across all bindings in
favor of plain factual descriptions.
…ents

Extends the AI Agent conversation domain to match longbridge/developers#1176,
which publishes complete SSE event documentation for the first time. Adds 14
new ConversationStreamEvent variants across Rust core and every binding
(C/C++/Python/Node.js/Java): thinking phase (ThinkingStarted/Finished), tool
calls (NodeToolUseStarted/Finished), subagent delegation
(SubagentStarted/Progress/Finished), agent-as-tool delegation
(AgentToolStarted/Progress/Finished), and auxiliary events (QueryMasked,
PlanChanged, ContextCompressStarted/Finished). Also enriches MessagePayload
with type/key/stage fields and WorkflowFinishedPayload with top-level
error/error_code/error_message/error_args/process_data fields, per the docs.

Fixes a real bug uncovered by the new docs: an interrupted run's SSE stream
never emits WorkflowFinished at all (only human_interaction_required, then
chat_finished) — previously every binding's "drive the stream to completion"
helper would error out on any interrupted streaming conversation. Adds
HumanInteractionRequired as a first-class terminal variant (carrying the same
synthesized ConversationResponse WorkflowFinished carries) and fixes
drive_conversation_stream to treat it as terminal alongside WorkflowFinished.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant