Prerequisites
Problem Description
OpenCode can sometimes keep an assistant/model turn alive without producing meaningful progress for a long time. This does not appear to be limited to background sub-agents. It can also happen in a main agent session or a normal conversation.
In my logs, I observed two related patterns:
-
Main agent / normal session silent period
In the main session, OpenCode started a model stream and then produced no message.part.updated event for a long time before the stream eventually resumed.
Example pattern:
service=session.processor session.id=<main-session> ... process
service=llm providerID=openai modelID=gpt-5.5 session.id=<main-session> ... stream
...
service=bus type=message.updated publishing
# long gap
service=bus type=message.part.updated publishing
In one observed case, the gap between message.updated and the next message.part.updated was about 923 seconds. The session eventually resumed, so a short timeout would be too aggressive for main-agent turns.
-
Background sub-agent stale state
In a background sub-agent session, the first assistant step completed normally with tool calls. The child OpenCode session export showed:
- first assistant step finished with
finish: "tool-calls"
- tool parts such as
glob, grep, and glob all had state.status: "completed"
- the step ended with
step-finish
After that, OpenCode created another assistant message, but that message had:
parts: []
- all token counts set to 0
- eventual error:
MessageAbortedError: Aborted
During that period, OMO continued to treat the background task as still running because the child session status remained busy.
Example OMO log pattern:
[background-agent] Session still running, relying on event-based progress:
{"sessionStatus":"busy","toolCalls":9}
The toolCalls count stayed fixed for the stale child task, while another background task continued making progress.
Eventually the stale child session was aborted, and OMO logged mixed lifecycle events such as:
Session error - no retry
Abort detected via session.error
Marked session cancelled
session.error received but session still alive, treating as transient
Task completed via session.idle event
Task cancelled via background_cancel
From a user perspective, this can look like the agent is still working, but there may be no actual progress. For background sub-agents, this is especially harmful because the parent/main workflow may keep waiting for the stale child result. For main-agent or normal conversation sessions, the same kind of silent period can make the UI appear stuck, even if it may eventually resume.
This feature request is not asking OMO to fix the underlying OpenCode/provider behavior that can create zero-part or long-silent assistant turns. Instead, it asks OMO to add a progress-aware watchdog so it can detect and handle agent sessions that are busy but not making meaningful progress.
Proposed Solution
Add a stale-progress watchdog for agent sessions, covering both:
- background sub-agent sessions
- main agent / normal conversation sessions
The watchdog should track last meaningful activity, not just elapsed time or sessionStatus.
Meaningful activity could include:
toolCalls count changed
message.part.updated received
message.part.delta received
message.updated with new parts/tokens
assistant part count changed
token count changed
background output became available
session status changed to a terminal state
If a session remains busy but none of the above progress signals change for a configured interval, OMO should classify the session as potentially stale and take a role-appropriate action.
-
Suggested behavior for background sub-agents:
Background sub-agents can use more aggressive thresholds because they are usually delegated, bounded tasks and can be retried or reported to the parent.
Suggested defaults:
backgroundWarnNoProgressMs = 3 * 60_000
backgroundRetryNoProgressMs = 8 * 60_000
backgroundHardFailNoProgressMs = 15 * 60_000
Suggested actions:
- After
backgroundWarnNoProgressMs, log a clear stale-progress warning with task ID, session ID, agent, model, last tool count, and last activity timestamp.
- After
backgroundRetryNoProgressMs, cancel the stale child and retry through the configured fallback chain if retry is available.
- After
backgroundHardFailNoProgressMs, mark the child task as failed or cancelled and notify the parent session instead of leaving the parent waiting indefinitely.
- Treat zero-part / zero-token post-tool assistant turns as high-confidence stale candidates when they remain unchanged for several minutes.
- Ensure that a background task resolves through one terminal path only: completed, failed, retried, or cancelled. Avoid mixed lifecycle transitions such as idle-complete followed by background_cancel.
-
Suggested behavior for main agent / normal conversation sessions:
Main sessions should use more conservative thresholds because long silent reasoning periods can still resume successfully.
Suggested defaults:
mainWarnNoProgressMs = 10 * 60_000
mainSoftInterruptPromptMs = 20 * 60_000
mainHardNoProgressMs = 30 * 60_000
Suggested actions:
- After
mainWarnNoProgressMs, show/log that the main session has had no visible progress for a long time.
- After
mainSoftInterruptPromptMs, optionally surface a non-destructive warning or allow the user to cancel/retry.
- After
mainHardNoProgressMs, classify the session as stalled only if there are still no activity signals.
- Avoid automatically killing main-agent sessions too early, because long silent main-agent turns can eventually resume.
Alternatives Considered
No response
Doctor Output (Optional)
Additional Context
- The issue was a background-agent lifecycle / stale-progress problem.
- A child session stayed
busy with a fixed toolCalls value.
- The child OpenCode session later showed a zero-part / zero-token assistant message ending with
MessageAbortedError.
oh-my-opencode.log
2026-05-25T112230.log
child_session.json
Feature Type
New Hook
Contribution
Prerequisites
Problem Description
OpenCode can sometimes keep an assistant/model turn alive without producing meaningful progress for a long time. This does not appear to be limited to background sub-agents. It can also happen in a main agent session or a normal conversation.
In my logs, I observed two related patterns:
Main agent / normal session silent period
In the main session, OpenCode started a model stream and then produced no
message.part.updatedevent for a long time before the stream eventually resumed.Example pattern:
In one observed case, the gap between
message.updatedand the nextmessage.part.updatedwas about 923 seconds. The session eventually resumed, so a short timeout would be too aggressive for main-agent turns.Background sub-agent stale state
In a background sub-agent session, the first assistant step completed normally with tool calls. The child OpenCode session export showed:
finish: "tool-calls"glob,grep, andgloball hadstate.status: "completed"step-finishAfter that, OpenCode created another assistant message, but that message had:
parts: []MessageAbortedError: AbortedDuring that period, OMO continued to treat the background task as still running because the child session status remained
busy.Example OMO log pattern:
The
toolCallscount stayed fixed for the stale child task, while another background task continued making progress.Eventually the stale child session was aborted, and OMO logged mixed lifecycle events such as:
From a user perspective, this can look like the agent is still working, but there may be no actual progress. For background sub-agents, this is especially harmful because the parent/main workflow may keep waiting for the stale child result. For main-agent or normal conversation sessions, the same kind of silent period can make the UI appear stuck, even if it may eventually resume.
This feature request is not asking OMO to fix the underlying OpenCode/provider behavior that can create zero-part or long-silent assistant turns. Instead, it asks OMO to add a progress-aware watchdog so it can detect and handle agent sessions that are
busybut not making meaningful progress.Proposed Solution
Add a stale-progress watchdog for agent sessions, covering both:
The watchdog should track last meaningful activity, not just elapsed time or
sessionStatus.Meaningful activity could include:
If a session remains
busybut none of the above progress signals change for a configured interval, OMO should classify the session as potentially stale and take a role-appropriate action.Suggested behavior for background sub-agents:
Background sub-agents can use more aggressive thresholds because they are usually delegated, bounded tasks and can be retried or reported to the parent.
Suggested defaults:
Suggested actions:
backgroundWarnNoProgressMs, log a clear stale-progress warning with task ID, session ID, agent, model, last tool count, and last activity timestamp.backgroundRetryNoProgressMs, cancel the stale child and retry through the configured fallback chain if retry is available.backgroundHardFailNoProgressMs, mark the child task as failed or cancelled and notify the parent session instead of leaving the parent waiting indefinitely.Suggested behavior for main agent / normal conversation sessions:
Main sessions should use more conservative thresholds because long silent reasoning periods can still resume successfully.
Suggested defaults:
Suggested actions:
mainWarnNoProgressMs, show/log that the main session has had no visible progress for a long time.mainSoftInterruptPromptMs, optionally surface a non-destructive warning or allow the user to cancel/retry.mainHardNoProgressMs, classify the session as stalled only if there are still no activity signals.Alternatives Considered
No response
Doctor Output (Optional)
Additional Context
busywith a fixedtoolCallsvalue.MessageAbortedError.oh-my-opencode.log
2026-05-25T112230.log
child_session.json
Feature Type
New Hook
Contribution