Skip to content

fix(cli): wait for detached run terminal state - #2136

Merged
zerob13 merged 4 commits into
devfrom
fix/issue-2113-run-watch-terminal
Aug 11, 2026
Merged

fix(cli): wait for detached run terminal state#2136
zerob13 merged 4 commits into
devfrom
fix/issue-2113-run-watch-terminal

Conversation

@yyhhyyyyyy

@yyhhyyyyyy yyhhyyyyyy commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fix deepchat run watch exiting after a single provider round while the detached Agent run is still active or waiting for user interaction.

  • Treat root Session transitions to idle or error as the authoritative run terminal state.
  • Keep watching after chat.stream.completed and chat.stream.failed.
  • Preserve initial-turn failure termination, cursor recovery, overflow handling, and already-terminal fast paths.
  • Prevent descendant Session terminal events from terminating the root watcher.
  • Expose running | awaiting_interaction | terminal through runs.get and run snapshots.
  • Detect direct permission/question waits, current live-delegation waits, and compatible legacy subagent waits.
  • Derive run phase independently of transcript pagination and cursors.

Root Cause

chat.stream.completed and chat.stream.failed describe a single provider-stream boundary, not the lifecycle of the complete detached run.

A tool loop, permission or question interaction, subagent execution, pending-input handoff, or another provider round may still follow. Treating these events as terminal caused run watch to return success before the owned root Session actually finished.

Compatibility

phase is a required field in the strict public run snapshot schema. The local-control surface version is therefore bumped from 1 to 2 so incompatible clients and servers fail closed.

The local-control protocol remains version 1, and the existing /v1/... transport paths are unchanged.

Test Coverage

Added regression coverage for:

  • provider completion without run termination
  • provider failure without premature termination
  • permission and question pause/resume
  • current live-delegation interaction waits
  • legacy interaction recovery
  • malformed interaction progress
  • cursor replay and catch-up ordering
  • limited transcript pages
  • already-terminal snapshots
  • initial-turn startup failure
  • descendant Session terminal filtering
  • cancellation behavior
  • surface-version compatibility

Validation

  • 29 test files passed
  • 357 tests passed
  • Node and renderer typechecks passed
  • Lint passed with 0 warnings and 0 errors
  • Format check passed
  • i18n validation passed

Fixes #2113

Summary by CodeRabbit

  • New Features

    • Added explicit run phases: running, awaiting interaction, and terminal.
    • Run status now identifies when user input or approval is required.
    • Waiting interactions from delegated tasks are reflected in run status.
  • Improvements

    • run watch continues through provider stream completion and ends when the root run becomes idle or errors.
    • Improved recovery and monitoring for detached runs, including incomplete or malformed progress data.
    • Updated the CLI and local-control protocol to version 2.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 166dffc9-b6d7-46fe-8c98-946e1b28e0ef

📥 Commits

Reviewing files that changed from the base of the PR and between b87426a and e65da8c.

📒 Files selected for processing (2)
  • src/main/session/data/tables/deepchatMessages.ts
  • test/main/session/data/tables/deepchatMessagesTable.test.ts
💤 Files with no reviewable changes (1)
  • src/main/session/data/tables/deepchatMessages.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/main/session/data/tables/deepchatMessagesTable.test.ts

📝 Walkthrough

Walkthrough

The local-control CLI advances to surface version 2. Detached runs expose running, awaiting_interaction, and terminal phases. Run watching continues after provider-round events and ends when the root session reaches idle or error.

Changes

CLI surface version and contracts

Layer / File(s) Summary
Surface V2 contract and registry
docs/architecture/local-control-plane/spec.md, docs/guides/cli.md, src/shared/contracts/..., src/main/cli/..., test/main/cli/*
The local-control surface version changes to 2. The CLI registry and related validation use CLI_SURFACE_V2. OCR contracts use shared version constants.
Public run phase contract
src/shared/contracts/routes/runs.routes.ts
Run snapshots require a phase of running, awaiting_interaction, or terminal. The inferred PublicRunPhase type is exported.

Interaction-aware phase projection

Layer / File(s) Summary
Interaction detection and snapshot projection
src/main/agent/deepchat/runtime/sessionUpdates.ts, src/main/app/composition.ts, src/main/cli/runService.ts, src/cli/format.ts
Run snapshots detect direct actions, validated subagent progress, descendant waits, and pending assistant messages. Human-readable output includes the interaction-wait state.
Pending assistant message recovery
src/main/session/data/..., test/main/session/data/...
Session transcript recovery queries pending assistant messages by session, role, and status. Results use deterministic ordering and transcript materialization.
Phase projection validation
test/main/cli/runService.test.ts
Tests cover current and legacy interaction states, descendant waits, malformed progress, and pending messages outside limited transcript pages.

Root-session watcher termination

Layer / File(s) Summary
Root-session watch flow
docs/architecture/local-control-plane/spec.md, docs/guides/cli.md, src/main/cli/runService.ts
Provider stream completion and failure events no longer terminate run watch. Watching ends when the owned root session reaches idle or error.
Watcher recovery and terminal-state tests
test/main/cli/runService.test.ts
Tests cover provider completion and failure, cursor replay and catch-up, startup failure, descendant-session filtering, and terminal snapshot recovery.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI as run watch
  participant CliRunService
  participant SessionTranscript
  participant RootSession
  participant ProviderRound
  CLI->>CliRunService: start watch for run
  CliRunService->>SessionTranscript: retrieve pending assistant messages
  ProviderRound-->>CliRunService: provider-round completion or failure
  CliRunService->>RootSession: inspect root session state
  RootSession-->>CliRunService: idle or error
  CliRunService-->>CLI: emit terminal result
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the primary change: keeping detached run watches active until the run reaches a terminal state.
Linked Issues check ✅ Passed The implementation addresses root-session termination, interaction phases, descendant filtering, recovery paths, and related tests required by issue [#2113].
Out of Scope Changes check ✅ Passed The changes support the linked issue by updating run lifecycle reporting, interaction detection, protocol versioning, documentation, and tests.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-2113-run-watch-terminal

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
test/main/cli/runService.test.ts (1)

248-260: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

One pending-watcher assertion, defined twice and too weak. Both sites assert that the watcher promise has not settled after a single microtask. The watcher awaits emit and the event iterator several times per event, so a regression that terminates one tick later still passes. These are the primary regression tests for continued watching.

  • test/main/cli/runService.test.ts#L248-L260: make expectWatcherPending race the watcher promise against a scheduled timer instead of awaiting one microtask.
  • test/main/cli/runService.test.ts#L612-L622: replace the inline copy with a call to expectWatcherPending.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/main/cli/runService.test.ts` around lines 248 - 260, In
test/main/cli/runService.test.ts:248-260, update expectWatcherPending to race
the watcher promise against a scheduled timer so it verifies the promise remains
pending through the event-processing turns, rather than checking after one
microtask. In test/main/cli/runService.test.ts:612-622, remove the duplicated
inline pending assertion and call expectWatcherPending instead.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/architecture/local-control-plane/spec.md`:
- Line 218: Update the capability-matrix section heading associated with
CLI_SURFACE_V2 from “V1 Capability Matrix” to “V2 Capability Matrix,” leaving
the surrounding content unchanged.

In `@src/main/cli/runService.ts`:
- Around line 478-481: Update the phaseMessages selection in buildSnapshot to
avoid calling getMessages(runId) for the full transcript during generating runs
with pagination. Use an existing bounded projection, such as the latest
assistant message or bounded recent-assistant query, as the source for runPhase
while preserving page.messages for non-generating or non-paginated cases.

---

Nitpick comments:
In `@test/main/cli/runService.test.ts`:
- Around line 248-260: In test/main/cli/runService.test.ts:248-260, update
expectWatcherPending to race the watcher promise against a scheduled timer so it
verifies the promise remains pending through the event-processing turns, rather
than checking after one microtask. In test/main/cli/runService.test.ts:612-622,
remove the duplicated inline pending assertion and call expectWatcherPending
instead.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9331a156-6dbe-465b-b306-71c4c48427c9

📥 Commits

Reviewing files that changed from the base of the PR and between 6e9facf and 1651458.

📒 Files selected for processing (18)
  • docs/architecture/local-control-plane/spec.md
  • docs/guides/cli.md
  • src/cli/format.ts
  • src/main/agent/deepchat/runtime/sessionUpdates.ts
  • src/main/app/composition.ts
  • src/main/cli/index.ts
  • src/main/cli/routes.ts
  • src/main/cli/runService.ts
  • src/main/cli/server.ts
  • src/main/cli/surface.ts
  • src/shared/contracts/localControl.ts
  • src/shared/contracts/routes/ocr.routes.ts
  • src/shared/contracts/routes/runs.routes.ts
  • test/main/cli/client.test.ts
  • test/main/cli/inputCapabilityServices.test.ts
  • test/main/cli/runService.test.ts
  • test/main/cli/server.test.ts
  • test/main/cli/surface.test.ts

Comment thread docs/architecture/local-control-plane/spec.md
Comment thread src/main/cli/runService.ts
@yyhhyyyyyy
yyhhyyyyyy requested a review from zerob13 August 10, 2026 14:32

@zerob13 zerob13 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The lifecycle fix and phase contract are coherent and CI is green. One added optimization expands startup risk without evidence that the existing session index is insufficient; details are inline.

Comment thread src/main/session/data/tables/deepchatMessages.ts Outdated
@zerob13
zerob13 merged commit 37183ca into dev Aug 11, 2026
12 checks passed
@zhangmo8
zhangmo8 deleted the fix/issue-2113-run-watch-terminal branch August 11, 2026 05:38
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.

[bug] Do not terminate run watch on provider stream completion

2 participants