Repository navigation
Conversation
Ports the fork's stall watchdog: a provider stream that goes silent — no events, no error — never fails on its own and hangs the step until the user stops it. The drain races a silence check over the step's stream clock (90 seconds, polled every 5); silence before the first event is a slow time to first token and silence while a tool call is pending is a long local or hosted execution idling the stream by design, and neither counts. A stall fails the attempt with the incomplete-stream classification so recovery reuses the established paths — pre-output stalls retry, post-output stalls continue — instead of the fork's TransientTurnError, bounded by the step-level retry schedule and its renewed phases.
|
Thanks for your contribution! This PR doesn't have a linked issue. All PRs must reference an existing issue. Please:
See CONTRIBUTING.md for details. |
|
The following comment was made by an LLM, it may be inaccurate: |
|
I built an equivalent runner-level guard for a self-hosted 2.x deployment and read this diff closely. The layer is right — a permission-only check has nothing firing it on the 2.x line, so doing this in 1. Detection requires three adjacent tool parts, which the common real-world loop shape defeatsconst doomLoopDetected = (content, call) => {
const self = content.findIndex((item) => item.type === "tool" && item.id === call.id)
if (self < DOOM_LOOP_THRESHOLD - 1) return false
const input = JSON.stringify(call.input)
return content
.slice(self - (DOOM_LOOP_THRESHOLD - 1), self + 1)
.every((item) => item.type === "tool" && item.state.status !== "streaming" && item.name === call.name && JSON.stringify(item.state.input) === input)
}
This is not hypothetical. @agentgoblin already reported the mechanism in #45442 ("the subagent inserts some thoughts between launches … the system does not consider an identical command repeated five times to be something bad"). I hit the same shape in a plain top-level session, not a subagent: a real 2.0.25 run degenerated into 55 identical cycles over ~2h07m, where every assistant turn contained a short text preamble followed by exactly one Suggested change: count identical 2.
|
|
Automated PR Cleanup Thank you for contributing to opencode. Due to the high volume of PRs from users and AI agents, we periodically close older PRs using automated criteria so maintainers can focus review time on the most active and community-supported contributions. This PR was closed because it matched the following cleanup criteria:
PRs created within the last month are not affected by this cleanup. If you believe this PR was closed incorrectly, or if you are still actively working on it, please leave a comment explaining why it should be reopened. A maintainer can review and reopen it if appropriate. Thanks again for taking the time to contribute. |
Issue for this PR
Closes #45442
Type of change
What does this PR do?
Two protections for runs that never terminate on their own:
How did you verify your code works?
bun test in packages/core: 233 tests pass in the touched files (session-runner, session-step, doom-loop), full suite matches vanilla upstream/v2. bun typecheck passes.
Screenshots / recordings
Not a UI change.
Checklist