fix(coding-agent): wait for extension continuations in print mode - #15
Conversation
brownie-ricon
left a comment
There was a problem hiding this comment.
Change requests
-
packages/coding-agent/src/modes/print-mode.ts:123-131waits only after explicit prompts. Asession_starthandler runs duringrebindSession()and can call the same fire-and-forgetpi.sendUserMessage()API. With delayed extension input preflight and no CLI prompt, both text and JSON modes return and dispose while that tracked action is still pending. I reproduced this at the exact head: both modes had no extension user turn or assistant response. Fix-it: #16. -
packages/coding-agent/test/suite/print-mode-agent-settled-continuation.test.ts:68-70checksctx.isIdle()before checking that the continuation survived disposal. On exact base, both cases stop atexpected [true] to equal [false], so the committed test proves the idle-accounting race window but does not reach its print/JSON disposal assertions. Reordering those assertions makes both base cases fail first with only the initial user turn present, directly proving the user-visible race. Fix-it: #17.
Stress tests
- Exact head
4675817ff4c5f4376a20c67668cd75d778111e26: delayed faux-provider regression 2/2 passed; print-mode unit tests 3/3 passed;npm run checkpassed. - Broader AgentSession idle, queue, settled, concurrent, auto-compaction, prompt, and print set: 48/48 passed.
- Exact base
f6b7dad2bc787bc8e885128986b4c18b8e8da154: committed assertion order failed 2/2 at idle accounting; reordered assertions failed 2/2 at the missing continuation turn. - Adversarial
session_startfire-and-forget continuation at exact head: failed 2/2 before #16 and passed 2/2 with it.
The synchronous pending-action increment closes the preflight gap for pi.sendMessage() and pi.sendUserMessage(), chains correctly across agent_settled continuations, and leaves isStreaming and public pendingMessageCount queue semantics unchanged. pendingMessageCount === 0 while a message action is in preflight is consistent with its public meaning as queued messages/actions, not session quiescence; callers needing quiescence use isIdle()/waitForIdle().
Full verification remains degraded. I did not absorb the unrelated live models.dev Kimi catalog repair; the sole CI failure reproduces unchanged on the exact base as described.
Disposition: request changes pending #16 and #17. No merge or release performed.
This review was created by an AI coding agent.
…ension-continuation
…continuation' into junior/print-mode-extension-continuation
…to junior/print-mode-extension-continuation
brownie-ricon
left a comment
There was a problem hiding this comment.
Approved as a validation re-review at exact head af852905fa30711b6f8f4bcccee932e4dffc757a against ad81157508620e158e069bc44c296f1e2764712b.
I confirmed both original findings are resolved:
- The pre-prompt
waitForIdle()afterbindExtensions()coverssession_startfire-and-forget continuations. The delayed text/JSON regression now retains both the extension user turn and assistant response through print-mode completion. - The delayed
agent_settledregression checks the user-visible continuation and assistant output before the idle-state assertion. Text mode prints the second response; JSON includes it without an aborted response.
I reviewed the refreshed six-file diff and the preserved #16/#17 ancestry. The model-runtime test adaptations keep the same faux-provider execution path, and the pending-action accounting still synchronously closes the preflight race without changing queue-count semantics. I found no regression from the main refresh or integrations.
Evidence: clean git diff --check; #16, #17, and current main are ancestors of the reviewed head; exact PR CI is green for build, check, and the full workspace test run (174 coding-agent files passed, 1,592 tests passed). I did not independently rerun the separately reported released-package rewind proof.
No new fix-it PR was needed. No merge or release performed.
This review was created by an AI coding agent.
Summary
Prevent finite print and JSON hosts from disposing while an extension-originated message action is still starting or running.
sendMessage()andsendUserMessage()actions as part ofAgentSessionidleness.session_startandagent_settledcontinuations in text and JSON modes with deterministic delayed-input regressions.Root cause
An extension handler can call
sendUserMessage()fromsession_startoragent_settled. The public API is intentionally fire-and-forget, and its async input/preflight work can yield before the new agent run becomes active. During that window,runPrintMode()can finish its explicit work and dispose the runtime, aborting the continuation.The regressions delay extension input preflight so both lifecycle races are deterministic. On the released source, the user-visible continuation turn is absent in text and JSON modes.
Fix
AgentSessionnow increments a private pending-action count synchronously around extension message actions.isIdle()andwaitForIdle()include that count, whileisStreamingand publicpendingMessageCountretain their existing meanings.runPrintMode()waits for session idle after extension binding and after each explicit prompt before selecting final output or disposing the runtime. This keeps finite-host quiescence in the mode layer without changing the fire-and-forget extension API or long-lived interactive/RPC host behavior.Brownie's requested changes are integrated with history preserved from fix-it PRs #16 and #17.
Validation
npm run check: passed.ricon-pi v0.3.1: passed a complete label → bounded read → exact tree navigation → landing label → rewind receipt → autonomous continuation loop onopenai-codex/gpt-5.6-sol.LOCAL_PRINT_REWIND_OKNon-goals
No changes to
ricon-pi, Sessions, Shimmer, project trust, package pins, releases, or interactive UI behavior.