Skip to content

fix(sdk): add Query.continue() to resume after a failed model turn#82

Open
amish-pratap-singh-lyzr wants to merge 1 commit into
open-gitagent:mainfrom
amish-pratap-singh-lyzr:fix/query-continue-on-model-error
Open

fix(sdk): add Query.continue() to resume after a failed model turn#82
amish-pratap-singh-lyzr wants to merge 1 commit into
open-gitagent:mainfrom
amish-pratap-singh-lyzr:fix/query-continue-on-model-error

Conversation

@amish-pratap-singh-lyzr

@amish-pratap-singh-lyzr amish-pratap-singh-lyzr commented Jul 21, 2026

Copy link
Copy Markdown

Summary

  • query() had no way to recover when the model failed to return output. When a turn ended with stopReason: "error" (or "aborted"), the SDK just emitted a system error message and ended the session — no retry, no continuation.
  • Query.steer() was also a no-op stub (steer(_message) {}), despite the underlying @mariozechner/pi-agent-core Agent already exposing working steer()/followUp()/continue() primitives that were simply never wired up.

This PR wires both up:

  • steer(message) now actually queues a steering message via agent.steer(...) instead of doing nothing. Effective while the agent is still actively running a turn.
  • continue(message?) (new) resumes a session that has gone idle — most importantly after a failed turn:
    • With no argument, it retries the exact turn the model failed to answer: the failed assistant message is dropped so the transcript ends on the user/tool-result message it never responded to, then agent.continue() re-sends it (matches pi-agent-core's documented continue() contract: "Continue from the current transcript. The last message must be a user or tool-result message.").
    • With a message, it queues a follow-up turn via agent.followUp(...) and resumes.
  • The internal message channel gained a reopen() so a query whose async iterator already reached agent_end/done: true can resume streaming once continue() is called.

Test plan

  • npm run build (tsc) — clean, no type errors
  • npm test — all existing 27 tests pass unchanged; added 4 new tests covering the continue()/steer() guard paths (method presence, rejecting before the agent has loaded, matching prior steer() behavior)
  • Manually verified the actual retry mechanics against pi-agent-core's real Agent class with a fake streamFn that fails once then succeeds — confirmed continue() produces a clean transcript (user message + successful assistant reply) rather than leaving the failed message in place

Previously, when the model returned stopReason "error"/"aborted", query()
surfaced a system error message and ended the session with no way to
retry or resume — Query.steer() was also a no-op stub. Both are now wired
into pi-agent-core's Agent instance:

- steer(message) queues a steering message via agent.steer().
- continue(message?) resumes a session that has gone idle. With no
  argument it retries the exact turn the model failed to answer (dropping
  the failed assistant message so the transcript ends on the
  user/tool-result message it never responded to, per pi-agent-core's
  continue() contract). With a message, it queues a follow-up turn.

The internal message channel can now reopen after finishing, since a
completed query's async iterator may be resumed by continue().
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