Skip to content

fix(coding-agent): wait for extension continuations in print mode - #15

Merged
junior-ricon merged 8 commits into
mainfrom
junior/print-mode-extension-continuation
Jul 18, 2026
Merged

fix(coding-agent): wait for extension continuations in print mode#15
junior-ricon merged 8 commits into
mainfrom
junior/print-mode-extension-continuation

Conversation

@junior-ricon

@junior-ricon junior-ricon commented Jul 18, 2026

Copy link
Copy Markdown

Summary

Prevent finite print and JSON hosts from disposing while an extension-originated message action is still starting or running.

  • Track fire-and-forget sendMessage() and sendUserMessage() actions as part of AgentSession idleness.
  • Wait for true session idle after extension binding and after each explicit print-mode prompt.
  • Cover session_start and agent_settled continuations in text and JSON modes with deterministic delayed-input regressions.

Root cause

An extension handler can call sendUserMessage() from session_start or agent_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

AgentSession now increments a private pending-action count synchronously around extension message actions. isIdle() and waitForIdle() include that count, while isStreaming and public pendingMessageCount retain 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

  • Refreshed onto KKL main after upstream v0.80.10 sync PR Sync upstream v0.80.10 into KKL fork #18.
  • Focused candidate tests: 37/37 passed, including startup and settled continuations, print-mode shutdown, prompt, and queue coverage.
  • npm run check: passed.
  • Real local JSON/print proof using released ricon-pi v0.3.1: passed a complete label → bounded read → exact tree navigation → landing label → rewind receipt → autonomous continuation loop on openai-codex/gpt-5.6-sol.
    • final marker: LOCAL_PRINT_REWIND_OK
    • credential-pattern counts across output, stderr, and session JSONL: zero
    • Junior home remained clean and unchanged
  • Full non-e2e validation is delegated to PR CI per maintainer direction. A local full-suite attempt exceeded 15 minutes while coding-agent Vitest remained active and is not counted as evidence; the timeout was contained with no surviving test processes.

Non-goals

No changes to ricon-pi, Sessions, Shimmer, project trust, package pins, releases, or interactive UI behavior.

@brownie-ricon brownie-ricon left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change requests

  1. packages/coding-agent/src/modes/print-mode.ts:123-131 waits only after explicit prompts. A session_start handler runs during rebindSession() and can call the same fire-and-forget pi.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.

  2. packages/coding-agent/test/suite/print-mode-agent-settled-continuation.test.ts:68-70 checks ctx.isIdle() before checking that the continuation survived disposal. On exact base, both cases stop at expected [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 check passed.
  • 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_start fire-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.

@brownie-ricon brownie-ricon left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved as a validation re-review at exact head af852905fa30711b6f8f4bcccee932e4dffc757a against ad81157508620e158e069bc44c296f1e2764712b.

I confirmed both original findings are resolved:

  • The pre-prompt waitForIdle() after bindExtensions() covers session_start fire-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_settled regression 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.

@junior-ricon
junior-ricon merged commit 736d14f into main Jul 18, 2026
1 check passed
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.

2 participants