Skip to content

fix(server): stop OpenCode child sessions - #9005

Merged
t3dotgg merged 2 commits into
mainfrom
t3code/fix-opencode-subagent-stop
Sep 1, 2026
Merged

fix(server): stop OpenCode child sessions#9005
t3dotgg merged 2 commits into
mainfrom
t3code/fix-opencode-subagent-stop

Conversation

@t3dotgg

@t3dotgg t3dotgg commented Sep 1, 2026

Copy link
Copy Markdown
Member

OpenCode runs each subagent in a separate child session. T3 Code only stopped the parent session, so child model requests could continue after Stop.

This change walks the parent session's full child tree and stops each descendant. It keeps Stop pending until child cleanup ends, so a parent abort event cannot release the next prompt early. Provider session teardown uses the same cleanup as a best-effort step.

Tests cover nested and late child sessions, unrelated-session isolation, repeated Stop requests, child failures, prompt gating, configured-server teardown, and the global SDK request limit.

Verified with:

  • 83 OpenCode adapter tests
  • 4 shared interrupt tests
  • Server typecheck
  • Targeted lint and format checks

Closes #7769

Made with GPT-5.6 Sol in Codex.


Note

Medium Risk
Changes interrupt completion ordering and timing (waits on full child tree, up to 10s timeouts), which affects prompt gating and race behavior around session.error during stop.

Overview
Stop and session teardown now walk the full OpenCode child session tree (via session.children) and abort every descendant, not only the parent—so subagent work cannot keep running after the user stops a turn.

interruptTurn aborts the parent first, races provider abort acknowledgment against turn completion, then runs descendant cleanup before it finishes. Prompts stay blocked until that cleanup completes (including sessions that appear while the parent is aborting). Unrelated sessions are not touched. A failed child list/abort fails the interrupt with ProviderAdapterRequestError. Concurrency for list/abort SDK calls is capped at 8.

Cancellation handling adds an acknowledgment deferred so a parent MessageAbortedError does not complete the interrupt before child sessions are stopped; real provider errors can still settle the turn while cleanup is in flight.

Teardown aborts the parent, then best-effort descendant abort (failures ignored). User docs describe stop semantics and error vs best-effort teardown.

Reviewed by Cursor Bugbot for commit c463930. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Stop OpenCode child sessions during interrupt and teardown

  • Adds abortOpenCodeDescendants util that walks the session tree via session.children, issuing session.abort for each descendant with a concurrency cap of 8 and surfacing the first failure
  • Reworks makeOpenCodeAdapter.interruptTurn into two phases: phase 1 aborts the parent and races provider acknowledgment against completion (10s timeout); phase 2 cleans up all descendants (10s timeout). Next prompts are deferred until cleanup completes
  • Extends OpenCodeCancellation with an acknowledgment Deferred and turnSettled flag so the adapter can coordinate on explicit provider acknowledgment before proceeding
  • Updates abortOpenCodeSessionForTeardown to best-effort abort discovered children after the parent (1s timeout each)
  • Behavioral Change: interruptTurn now fails the interrupt if any descendant abort fails (after parent acknowledgment); previously only the parent session was aborted. Reviewers should check the failure-preference logic in interruptTurn and the abortOpenCodeDescendants error collection in OpenCodeAdapter.ts

Macroscope summarized c463930.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Sep 1, 2026
Comment thread apps/server/src/provider/Layers/OpenCodeAdapter.ts
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.3 KiB 13.3 KiB 0 B (0.0%) 15.1 KiB
Codex Thread snapshot wire 6.9 KiB 6.9 KiB 0 B (0.0%) 7.3 KiB
Codex Live turn WebSocket wire 6.4 KiB 6.4 KiB 0 B (0.0%) 7.8 KiB
Codex Live turn WebSocket decoded 55.6 KiB 55.6 KiB 0 B (0.0%) 66.4 KiB
Codex Live turn messages 10 10 0 (0.0%) 21
Claude Total thread wire 13.3 KiB 13.3 KiB +12 B (+0.1%) 15.1 KiB
Claude Thread snapshot wire 6.9 KiB 6.9 KiB +3 B (+0.0%) 7.3 KiB
Claude Live turn WebSocket wire 6.4 KiB 6.4 KiB +9 B (+0.1%) 7.8 KiB
Claude Live turn WebSocket decoded 56.4 KiB 56.4 KiB 0 B (0.0%) 66.4 KiB
Claude Live turn messages 10 10 0 (0.0%) 21

Baseline: ce71c04 · PR result: c463930 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@macroscopeapp

macroscopeapp Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The adapter now performs recursive, concurrent cleanup of OpenCode child sessions and holds cancellation/next-prompt progress until that cleanup completes, with new timeout and failure behavior. This is a substantial change to an existing production request path rather than a small isolated fix.

You can add or adjust custom eligibility rules. Learn more.

@t3dotgg
t3dotgg merged commit 62d39bf into main Sep 1, 2026
26 checks passed
@t3dotgg
t3dotgg deleted the t3code/fix-opencode-subagent-stop branch September 1, 2026 11:05
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Sep 1, 2026
github-actions Bot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 1, 2026
## What's Changed
* perf(server): scan only appended transcript bytes for usage summaries by @StiensWout in pingdotgg/t3code#9024
* perf(server): cut chatty tool-update frames by 90% by @Adamulek123 in pingdotgg/t3code#8368
* fix(server): settle threads server-side by @t3dotgg in pingdotgg/t3code#8600
* fix(clients): dedupe skills in composer menus by @Adamulek123 in pingdotgg/t3code#8043
* fix(server): stop OpenCode child sessions by @t3dotgg in pingdotgg/t3code#9005
* perf(web): defer pull request line stats until visible by @Adamulek123 in pingdotgg/t3code#6471
* perf(server): skip full-message reads while streaming by @t3dotgg in pingdotgg/t3code#9032
* perf(client-runtime): halve server config bootstrap traffic by @Adamulek123 in pingdotgg/t3code#8367


**Full Changelog**: pingdotgg/t3code@v0.0.38-nightly.20260901.1245...v0.0.38-nightly.20260901.1246

Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.38-nightly.20260901.1246
github-actions Bot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 1, 2026
## What's Changed
* Add mobile composer attachment menu with video support by @juliusmarminge in pingdotgg/t3code#8843
* fix(web): restore unified activity logs and composer banners by @t3dotgg in pingdotgg/t3code#8734
* fix(web): address composer banner review follow-ups by @juliusmarminge in pingdotgg/t3code#8850
* fix(web): widen sync banners and simplify the working timer by @juliusmarminge in pingdotgg/t3code#8855
* fix(preview): improve browser recording quality by @maria-rcks in pingdotgg/t3code#8839
* fix(web): mark pull request links as external by @juliusmarminge in pingdotgg/t3code#8856
* fix(mobile): replace Callstack glass with Expo glass by @juliusmarminge in pingdotgg/t3code#8862
* fix(server): skip IDE detection in Claude probes by @yashranaway in pingdotgg/t3code#8634
* chore(macroscope): review diagnostic overrides by @t3-code[bot] in pingdotgg/t3code#8917
* fix(contracts): accept CLI event origins by @nateEc in pingdotgg/t3code#8905
* fix(web): hide invalid slash skill completions by @nateEc in pingdotgg/t3code#8904
* fix(mobile): defer draft navigation until submission completes by @juliusmarminge in pingdotgg/t3code#8914
* chore: disable CodeRabbit review status by @juliusmarminge in pingdotgg/t3code#8933
* Delete app.json by @juliusmarminge in pingdotgg/t3code#8934
* fix(web): show scrollbar for wide markdown tables by @UtkarshUsername in pingdotgg/t3code#8868
* fix(mobile): shimmer active tool rows by @juliusmarminge in pingdotgg/t3code#8932
* chore(deps): bump Electron to 43.4.1 by @StiensWout in pingdotgg/t3code#8626
* fix(chat): smooth worktree setup status by @juliusmarminge in pingdotgg/t3code#8922
* feat(mobile): add video playback with native iOS controls by @juliusmarminge in pingdotgg/t3code#8919
* fix(web): prevent chat metadata overlap by @MatthewFeroz in pingdotgg/t3code#8851
* fix(server): preserve usage cache outside walked roots by @Lucenx9 in pingdotgg/t3code#8540
* feat(mobile): add native image and PDF previews by @juliusmarminge in pingdotgg/t3code#8959
* fix(server): allow long thread IDs in HTTP routes by @nateEc in pingdotgg/t3code#8898
* fix(shared): preserve Windows shell PATH priority by @UtkarshUsername in pingdotgg/t3code#8748
* fix(web): make WSL settings searchable by @UtkarshUsername in pingdotgg/t3code#8881
* feat(web): add expand/collapse all control to the files surface by @UtkarshUsername in pingdotgg/t3code#8889
* feat(mobile): upload attachments while composing by @juliusmarminge in pingdotgg/t3code#8978
* fix(chat): keep agent activity visible between actions by @maria-rcks in pingdotgg/t3code#8984
* fix(server): isolate remote web session cookies by @Bil0000 in pingdotgg/t3code#8085
* feat(pull-requests): link GitHub references in markdown by @maria-rcks in pingdotgg/t3code#8812
* perf(server): reduce frequency of full tool call output being loaded into memory from db by @t3dotgg in pingdotgg/t3code#8988
* feat(web): add pull request list filters by @maria-rcks in pingdotgg/t3code#8809
* feat(web): search individual settings by detail by @maria-rcks in pingdotgg/t3code#8831
* feat(client): render viewed images in work logs by @maria-rcks in pingdotgg/t3code#8936
* fix(client): use package import for markdown image helpers by @juliusmarminge in pingdotgg/t3code#9010
* test: remove static presentation snapshots by @t3-code[bot] in pingdotgg/t3code#9008
* perf(server): bound snapshot activity payload memory by @t3dotgg in pingdotgg/t3code#9000
* perf(server): cut idle CPU use and stop provider event leaks by @t3dotgg in pingdotgg/t3code#8187
* perf(server): scan only appended transcript bytes for usage summaries by @StiensWout in pingdotgg/t3code#9024
* perf(server): cut chatty tool-update frames by 90% by @Adamulek123 in pingdotgg/t3code#8368
* fix(server): settle threads server-side by @t3dotgg in pingdotgg/t3code#8600
* fix(clients): dedupe skills in composer menus by @Adamulek123 in pingdotgg/t3code#8043
* fix(server): stop OpenCode child sessions by @t3dotgg in pingdotgg/t3code#9005
* perf(web): defer pull request line stats until visible by @Adamulek123 in pingdotgg/t3code#6471
* perf(server): skip full-message reads while streaming by @t3dotgg in pingdotgg/t3code#9032
* perf(client-runtime): halve server config bootstrap traffic by @Adamulek123 in pingdotgg/t3code#8367
* fix(web): align un-settle banner action by @StiensWout in pingdotgg/t3code#9033
* fix(web): block type-to-focus behind open dialogs by @Lucenx9 in pingdotgg/t3code#8139
* feat(shortcuts): copy active thread reference by @maria-rcks in pingdotgg/t3code#8994
* fix(mobile): keep thread scroll bounds current after animations by @juliusmarminge in pingdotgg/t3code#9013
* fix(server): cache project favicon resolution by @willsheldon in pingdotgg/t3code#9080
* feat(claude): add Claude Fable 5.1 model by @q1 in pingdotgg/t3code#9078
* fix(preview): restore recording and macOS rendering after Electron 43 by @StiensWout in pingdotgg/t3code#9001
* feat(desktop): add configurable quit shortcut confirmation by @juliusmarminge in pingdotgg/t3code#9076
* feat(web): open project settings from thread menus by @SunkenInTime in pingdotgg/t3code#8925
* fix(chat): reuse one row for live activity by @maria-rcks in pingdotgg/t3code#9062
* feat(models): discover Claude models from remote manifest by @juliusmarminge in pingdotgg/t3code#9084
* Revert "fix(chat): reuse one row for live activity" by @maria-rcks in pingdotgg/t3code#9096
* fix(web): sync sidebar PR state from open panel by @t3-code[bot] in pingdotgg/t3code#9092
* fix(web): changing projects no longer creates a draft by @extoci in pingdotgg/t3code#9097
* fix(web): keep theme placeholder text dimmer than entered text by @flamboh in pingdotgg/t3code#9104
* fix(web): keep the selected environment when changing projects by @t3dotgg in pingdotgg/t3code#9102

## New Contributors
* @willsheldon made their first contribution in pingdotgg/t3code#9080
* @q1 made their first contribution in pingdotgg/t3code#9078

**Full Changelog**: pingdotgg/t3code@v0.0.37...v0.0.38

Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). 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.

OpenCode Stop can leave sub-agent provider requests running

1 participant