You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(sdk): custom agent loop parity with chat.agent for continuations, steering, and subtasks
Three fixes for chat.customAgent raw loops and chat.createSession:
Continuation boots replayed already-answered user messages into the
first wait: the .in SSE tail attached (via createStopSignal or any
listener) before a resume cursor existed, so S2 replayed from seq 0.
The custom-agent wrapper and createChatSession's first next() now seed
both manager cursors from the latest turn-complete header before
anything attaches, the same boot logic chat.agent uses. Seeding only
setLastSeqNum after attach (the reverted earlier attempt) does not
work because dispatch is gated on the other cursor.
Steering a hand-rolled loop mid-stream wiped the in-flight assistant
text: pipeChatAndCapture called toUIMessageStream without
generateMessageId, so a prepareStep injection starting a new step
regenerated the assistant id and the frontend replaced the partial
message. It now stamps the server-generated id like chat.agent's pipe.
Task-backed tools (ai.toolExecute) failed from custom agent loops with
"session handle is not initialized" on the child run: the chatId only
threaded from the per-turn context that raw loops never set. It now
falls back to the session handle the customAgent wrapper binds at boot,
so child tasks can stream into the parent's chat with
chat.stream.writer({ target: "root" }).
Three fixes for custom agent loops (`chat.customAgent`, `chat.createSession`, and hand-rolled `MessageAccumulator` loops):
6
+
7
+
- Continuation runs no longer replay already-answered user messages into the first turn. The `.in` resume cursor is now seeded before any listener attaches (the same boot logic `chat.agent` uses), so a chat that continues after a cancel, crash, or upgrade only sees genuinely new messages.
8
+
- Steering a hand-rolled loop mid-stream no longer wipes the in-flight assistant response. `chat.pipeAndCapture` now stamps a server-generated message id on the stream, so a `prepareStep` injection keeps the partial text instead of replacing the message.
9
+
- Task-backed tools (`ai.toolExecute`) now work from custom agent loops: the parent's session is threaded to the child run, so child tasks can stream progress into the chat with `chat.stream.writer({ target: "root" })` instead of failing with "session handle is not initialized".
0 commit comments