Repository navigation
Description
Summary
When a background subagent session triggers compaction/context overflow handling, the background job can be marked cancelled even though the child session continues running and eventually finishes. After this happens, task_status reports state: cancelled while session status events still show the child session as busy.
This looks like a mismatch between BackgroundJob fiber state and the actual child session lifecycle.
Repro
- Start OpenCode with native background subagents enabled.
- Launch a background task that reads enough large files to trigger compaction/context overflow.
- Reuse/resume the same background task/session and continue reading large files.
- Wait for compaction to occur.
- Call
task_statusfor the task id.
Observed task id in my repro: ses_1aa9421abffeuASVxya3Kva4Th.
Expected
If the child session is still busy/running after compaction, task_status should report running or otherwise reflect the live child session state. Compaction should not make the background task look cancelled unless the child session was actually stopped.
Actual
task_status returned:
task_id: ses_1aa9421abffeuASVxya3Kva4Th
state: cancelled
<task_error>
</task_error>
But the child session continued running after that and eventually reached idle/finished.
Sanitized log timeline
OpenCode log:
15:21:30 context_length_exceeded for child session ses_1aa9421abffeuASVxya3Kva4Th
15:21:30 compaction agent started for same session
15:21:32 bus type=session.compacted publishing
15:22:01 task_status result observed as state=cancelled
15:22:07+ repeated session busy events for the same child session after cancelled state
15:22:59 child session eventually emitted idle/finished behavior
Plugin-side lifecycle logs from a local OpenCode plugin also showed the mismatch:
15:22:01 parsed task status output { taskID: ses_1aa9421abffeuASVxya3Kva4Th, state: cancelled }
15:22:01 background job status updated { state: cancelled }
15:22:07 session busy event received { sessionId: ses_1aa9421abffeuASVxya3Kva4Th, backgroundJobState: cancelled }
15:22:08 session busy event received { sessionId: ses_1aa9421abffeuASVxya3Kva4Th, backgroundJobState: cancelled }
...
15:22:59 session status idle received for same child session
Source pointers
From current source, this appears related to:
packages/opencode/src/background/job.tsBackgroundJob.startmarks interrupted job fibers ascancelledviaCause.hasInterruptsOnly(cause) ? "cancelled" : "error".
packages/opencode/src/tool/task.ts- background
taskwraps child session execution inBackgroundJob.start({ id: nextSession.id, run: runTask() ... }).
- background
packages/opencode/src/tool/task_status.tstask_statustrustsBackgroundJob.statusbefore checking live session status / latest assistant state.
packages/opencode/src/session/compaction.tsandpackages/opencode/src/session/prompt.ts- compaction can create synthetic continuation messages and continue the same session after context overflow.
Possible fix direction
Either:
task_statusshould not trustBackgroundJob.status === cancelledif the child session status is currentlybusy/retry; orBackgroundJobshould not mark a background task cancelled until the child session is actually stopped/deleted, not merely because the wrapper fiber was interrupted during compaction/continuation.
This matters for background orchestration because callers will treat cancelled as terminal and may stop tracking or reuse the session incorrectly while it is still doing work.
Activity