Skip to content

Handle OpenCode subagent resumption#66

Merged
Jay1 merged 3 commits into
mainfrom
jcode/subagent-continuation-handling
Jun 6, 2026
Merged

Handle OpenCode subagent resumption#66
Jay1 merged 3 commits into
mainfrom
jcode/subagent-continuation-handling

Conversation

@Jay1

@Jay1 Jay1 commented Jun 6, 2026

Copy link
Copy Markdown
Owner

Summary

  • keep OpenCode turns alive when premature idle follows background subagent tool-calls
  • resume completion when provider reports busy and later emits a terminal assistant message
  • add regression coverage for premature idle -> provider resumption -> real idle lifecycle

Verification

  • bun run --cwd apps/server typecheck
  • safe-run --profile test -- bun run --cwd apps/server test src/provider/Layers/OpenCodeAdapter.test.ts
  • bunx oxfmt@0.52.0 --check apps/server/src/provider/Layers/OpenCodeAdapter.ts apps/server/src/provider/Layers/OpenCodeAdapter.test.ts

Summary by CodeRabbit

  • Bug Fixes

    • Improved robustness when sessions go idle due to background activity: the UI now emits a clear "waiting for background tasks" warning, defers turn completion while awaiting resumption, and enforces a timeout to avoid indefinite waits.
  • Tests

    • Added runtime lifecycle tests that simulate premature idle/resume scenarios and verify warning emissions, resumption handling, and proper turn completion.
    • Updated a chat composer test to add extra render settling between navigation steps.

@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Wondering what really moved? Review this PR in Change Stack to inspect semantic changes, definitions, and references.

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d23dbcab-f25b-40b5-a383-c7e9cc7f9ba2

📥 Commits

Reviewing files that changed from the base of the PR and between 265d5bc and cc127a5.

📒 Files selected for processing (1)
  • apps/web/src/components/ChatView.browser.tsx

📝 Walkthrough

Walkthrough

OpenCodeAdapter now detects when an OpenCode session becomes idle prematurely after tool calls but before final assistant completion, enters a waiting state, schedules a resumption timeout, and defers turn completion. If the session resumes (busy status), waiting state clears; if the timeout expires, the turn fails. Event filtering is updated to process status events while waiting, and two new tests validate single and repeated idle/resume lifecycles.

Changes

Resumption waiting logic

Layer / File(s) Summary
Data model and state lifecycle
apps/server/src/provider/Layers/OpenCodeAdapter.ts
OpenCodeSessionContext adds activeTurnWaitingForResumption boolean and activeTurnResumptionStartedAt timestamp. Fields are initialized to not-waiting on session start and turn start, and are cleared alongside other active-turn state.
Resumption timeout watchdog
apps/server/src/provider/Layers/OpenCodeAdapter.ts
New timeout watchdog fails the turn if resumption does not occur within the timeout window; marks turn failed, updates provider session error state, emits runtime.warning, and performs best-effort native logging.
Event filtering and status transitions
apps/server/src/provider/Layers/OpenCodeAdapter.ts
shouldHandleSubscribedEvent now returns true for session.status events while waiting for resumption. Busy status clears waiting state and resets activity markers. Idle status (in multiple event paths) conditionally enters waiting mode when tool-calls finished but no final assistant completion activity occurred; schedules the timeout and emits a runtime.warning instead of completing the turn immediately.
Runtime lifecycle tests
apps/server/src/provider/Layers/OpenCodeAdapter.test.ts
Two tests: one simulates tool-calls finished → premature idle → busy status → final assistant message → real idle and asserts a single runtime.warning; the other simulates repeated premature idle/resume cycles, asserts two runtime.warning events, eventual turn.completed, and no runtime.error.
Composer test render settling tweaks
apps/web/src/components/ChatView.browser.tsx
Inserted await nextFrame() between intermediate history navigation assertions to allow the composer UI to settle between sequential Up/Down key events.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 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
Title check ✅ Passed The title directly and clearly describes the main change: handling OpenCode subagent resumption when premature idle occurs after background tool calls.
Description check ✅ Passed The description covers the core changes and includes verification steps, but lacks detailed context in the Why section and does not follow all template sections including UI Changes and Reviewer Notes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@github-actions github-actions Bot added size:L vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Jun 6, 2026

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

🤖 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 `@apps/server/src/provider/Layers/OpenCodeAdapter.test.ts`:
- Around line 3001-3122: Add a second focused regression test (or extend the
existing "waits for provider resumption when background subagents cause
premature idle then completes on real idle") that reproduces a repeated
idle/resume window: use the same createSubscribedEventQueue /
createMockOpenCodeRuntime and OpenCodeAdapter usage, startSession and sendTurn,
then push events in this order — a tool-call finished message, a session.idle to
trigger the first waiting window, a session.status {type: "busy"} to resume,
immediately another session.idle while the adapter is now in the
resumed-but-still-on-turn state to trigger a second waiting window, another
session.status {type: "busy"} to clear it, then a final assistant message with
finish: "end_turn" and a final session.idle to complete the turn — and assert
that the adapter emits the corresponding lifecycle events and emits two distinct
runtime.warning entries (or otherwise records two waiting windows) before
turn.completed; target the OpenCodeAdapter.startSession / sendTurn and
adapter.streamEvents event sequence when implementing the pushes and assertions.

In `@apps/server/src/provider/Layers/OpenCodeAdapter.ts`:
- Around line 2992-3016: The legacy idle watchdog (deferPrematureIdleCompletion)
must not run while a turn is already in resumption waiting state; modify the
idle handling in OpenCodeAdapter so that when
context.activeTurnWaitingForResumption is true you skip calling yield*
deferPrematureIdleCompletion and avoid starting the old 10s failure path—ensure
the existing branch that sets context.activeTurnWaitingForResumption,
context.activeTurnResumptionStartedAt and calls yield* scheduleResumptionTimeout
remains the only path taken in that case; apply the same guard around calls to
deferPrematureIdleCompletion in the other similar blocks (the ones near where
scheduleResumptionTimeout, deferPrematureIdleCompletion, and
context.activeTurnWaitingForResumption are referenced).
- Around line 2219-2230: The watchdog uses context.activeTurnResumptionStartedAt
but never binds to a specific epoch, so a stale timeout can cancel a newer wait;
fix scheduleResumptionTimeout by reading and storing the current
context.activeTurnResumptionStartedAt (or a new local "resumptionEpoch") at the
moment you schedule the Effect, then in the timeout handler verify that the
stored epoch still equals context.activeTurnResumptionStartedAt in addition to
the existing checks (context.stopped, context.activeTurnId,
context.activeTurnWaitingForResumption); do the same epoch-capture/compare
pattern for the other similar watchdogs referenced in this file to ensure each
timeout is tied to the exact waiting window.
🪄 Autofix (Beta)

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: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 71fb5298-e3a0-4601-9c72-0911658ed8be

📥 Commits

Reviewing files that changed from the base of the PR and between aaabad9 and e0a917a.

📒 Files selected for processing (2)
  • apps/server/src/provider/Layers/OpenCodeAdapter.test.ts
  • apps/server/src/provider/Layers/OpenCodeAdapter.ts

Comment thread apps/server/src/provider/Layers/OpenCodeAdapter.test.ts
Comment thread apps/server/src/provider/Layers/OpenCodeAdapter.ts
Comment thread apps/server/src/provider/Layers/OpenCodeAdapter.ts
@Jay1 Jay1 merged commit 24da448 into main Jun 6, 2026
8 checks passed
@Jay1 Jay1 deleted the jcode/subagent-continuation-handling branch June 6, 2026 05:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant