You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Auto-compaction infinite loop when assistant ended its turn (finish !== tool-calls) #15533
When auto-compaction triggers after the assistant has naturally ended its turn (e.g., asked a question via the question tool, or simply finished responding with finish === "stop"), SessionCompaction.process() unconditionally injects a synthetic "Continue..." user message, creating an infinite loop.
Steps to Reproduce
Start a long conversation that approaches the context window limit
Have the assistant end its turn naturally (ask a question, or finish responding)
Auto-compaction triggers due to context overflow
Synthetic "Continue if you have next steps..." message is injected
Agent responds to the synthetic continue → context overflows again → compaction → synthetic continue → ...
Expected Behavior
When the assistant had naturally ended its turn (finish === "stop"), the compaction should complete without injecting a synthetic continue message. The session loop should exit and wait for real user input.
The synthetic continue should only be injected when the assistant was in the middle of tool execution (finish === "tool-calls" or "unknown").
Actual Behavior
The synthetic continue is always injected during auto-compaction, regardless of the assistant's state. This causes an unbounded loop:
In packages/opencode/src/session/compaction.ts, the process() function (line ~202) checks result === "continue" && input.auto but does not check the assistant's finish reason before injecting the synthetic continue.
Environment
OpenCode v1.2.15
Observed with oh-my-opencode plugin (Sisyphus/Ultraworker agent)
These issues share the same observable behavior but differ in where the fix should be applied. It may be worth coordinating with the assignees of those issues to ensure the fixes are complementary.
It’s an infinite loop. For me, this mostly happened with Claude Opus through GitHub Copilot.
After digging further, it looked like an MCP handshake with hundreds of definitions was triggering it.
Just reduced the access to the MCPs tool I was using, and it stopped.
I'm experiencing the same issue. Disabling MCP resolves it, but the problem reoccurs as soon as I re-enable MCP. So is there a permanent fix for this rather than just keeping MCP disabled?
Also, I'm curious why this issue seems to only be triggered when using the GitHub Copilot provider. I haven't been able to reproduce it with other providers. Is there something specific about how the Copilot provider handles the MCP handshake/tool definitions that causes this infinite loop?
Additional reproduction case — non-Anthropic models via OpenAI-compatible router
Hitting this exact loop with a local OpenAI-compatible proxy routing to open-weight models. The behavior matches the description perfectly: auto-compaction fires, synthetic "Continue..." is injected, agent re-executes, context overflows, compaction fires again — infinite cycle.
User typing "stop" did not break the cycle — the agent acknowledged "stop", produced another summary, and re-entered the loop.
Notes
These open-weight models are more susceptible than Claude/GPT-4 to treating compacted summaries as actionable instructions
The compaction summary format with "Instructions" and "Left to do" headings reads as an active task, which compounds the problem when paired with the synthetic "Continue..." message
Confirms the root cause identified here: process() should check finish reason before injecting the synthetic continue
Update: Resolved in my case. The root cause was not the compaction mechanism itself.
The loop was caused by the BigPickle agent (the default agent/routing system). Switching to a custom NadirClaw Router (OpenAI-compatible proxy with smart routing: Qwen3 30B for simple tasks, Kimi K2.5 for complex) resolved the infinite compaction loop completely.
The same models, same project, same context — just a different routing/agent layer — and the loop is gone. This suggests the issue may be specific to how certain agent configurations handle the post-compaction synthetic "Continue..." message, rather than a universal compaction bug.
The fix (only inject continue on finish === "tool-calls") is right. As a general guard against synthetic-message loops like this, a runtime breaker that denies an unbounded run of identical synthetic continuations catches the whole class if a new edge case slips through. Small framework-agnostic one here if useful: https://github.com/Fame510/SHACKLE
Confirmed this is still reproducible on OpenCode 1.18.26, and the impact is broader than an infinite compaction loop: it can cross a user decision/authorization boundary.
I inspected the persisted message metadata for a sanitized incident with this sequence:
The user asked only for an evaluation and a proposed plan.
The normal assistant response completed with finish: "stop" and explicitly stated that no files had been modified.
Immediately afterward, OpenCode created an automatic compaction part (type: "compaction", auto: true, overflow: false).
When compaction completed, OpenCode injected a new user-role text part with:
synthetic: true
metadata.compaction_continue: true
the hard-coded Continue if you have next steps... text
With no real user message in between, the agent resumed and subsequently invoked write-capable tools.
The TUI hides the intervening compaction messages, so the synthetic continuation appears directly below the assistant response as an ordinary user bubble. This makes the provenance misleading and obscures that the agent was restarted by OpenCode rather than by the user.
This confirms the root cause described here: post-compaction continuation does not preserve the terminal state of the pre-compaction assistant turn. A completed finish: "stop" turn should return control to the user, even if automatic compaction runs afterward.
Suggested invariant:
Compaction may run after a terminal assistant response, but must not synthesize a continuation in that case.
Synthetic continuation should be allowed only when compaction interrupted a demonstrably in-progress turn, such as a tool-execution loop.
Synthetic messages must not be treated as new authorization for write-capable or externally visible actions.
The TUI should visually distinguish system-generated continuation from actual user input.
User sent oi. The assistant finished stop (31692 input tokens, 21 output). The configured context limit was 28000, so the processor set needsCompaction and returned "compact" even though finish was stop. The part was stored as {auto: true, overflow: false} because that flag is !finish. Compaction then inserted Continue if you have next steps, or stop and ask for clarification if you are unsure how to proceed.
That continue turn never got a real completion and spun until abort. Counts are on #49414.
When the assistant already stopped and there is no pending tool, compaction should not insert that continue message.
Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.
Activity
github-actions commentedon Mar 1, 2026
This issue might be a duplicate of or closely related to existing issues. Please check:
finish=stop), different root cause (string ID comparison in loop termination logic)processor.tsreturning"continue"when it should return"stop"These issues share the same observable behavior but differ in where the fix should be applied. It may be worth coordinating with the assignees of those issues to ensure the fixes are complementary.
Lee-SiHyeon commentedon Mar 1, 2026
I did local build and It is fixed when I use my local binary.
aeciolevy commentedon Mar 25, 2026
I was seeing the same.
It’s an infinite loop. For me, this mostly happened with Claude Opus through GitHub Copilot.
After digging further, it looked like an MCP handshake with hundreds of definitions was triggering it.
Just reduced the access to the MCPs tool I was using, and it stopped.
uriva commentedon Mar 25, 2026
how is this not fixed yet? I can't use opus for a few days now
zachpony commentedon Mar 26, 2026
I'm experiencing the same issue. Disabling MCP resolves it, but the problem reoccurs as soon as I re-enable MCP. So is there a permanent fix for this rather than just keeping MCP disabled?
Also, I'm curious why this issue seems to only be triggered when using the GitHub Copilot provider. I haven't been able to reproduce it with other providers. Is there something specific about how the Copilot provider handles the MCP handshake/tool definitions that causes this infinite loop?
uriva commentedon Mar 30, 2026
For me it was posthog mcp, disabling it solves the issue, but this shouldn't be so fragile.
eugenio commentedon Apr 2, 2026
Additional reproduction case — non-Anthropic models via OpenAI-compatible router
Hitting this exact loop with a local OpenAI-compatible proxy routing to open-weight models. The behavior matches the description perfectly: auto-compaction fires, synthetic "Continue..." is injected, agent re-executes, context overflows, compaction fires again — infinite cycle.
Setup
opencode.jsonconfig)http://127.0.0.1:4000/v1){ "$schema": "https://opencode.ai/config.json", "provider": { "nadirclaw": { "npm": "@ai-sdk/openai-compatible", "name": "NadirClaw Router", "options": { "baseURL": "http://127.0.0.1:4000/v1" }, "models": { "auto": { "name": "Auto (Qwen3 30B / Mistral Large 3 / Kimi K2)" }, "eco": { "name": "Budget (Qwen3 Coder 30B)" }, "premium": { "name": "Premium (Kimi K2 Thinking)" } } } } }Reproduction
Build → Compaction → Build → Compaction → ...Transcript excerpt
User typing "stop" did not break the cycle — the agent acknowledged "stop", produced another summary, and re-entered the loop.
Notes
process()should checkfinishreason before injecting the synthetic continueRelated
eugenio commentedon Apr 2, 2026
Update: Resolved in my case. The root cause was not the compaction mechanism itself.
The loop was caused by the BigPickle agent (the default agent/routing system). Switching to a custom NadirClaw Router (OpenAI-compatible proxy with smart routing: Qwen3 30B for simple tasks, Kimi K2.5 for complex) resolved the infinite compaction loop completely.
The same models, same project, same context — just a different routing/agent layer — and the loop is gone. This suggests the issue may be specific to how certain agent configurations handle the post-compaction synthetic "Continue..." message, rather than a universal compaction bug.
eugenio commentedon Apr 2, 2026
For reference, the working NadirClaw Router setup (opencode.json config) can be found here: https://github.com/eugenio/AWSModelRunner
ForbiddenEra commentedon Apr 2, 2026
wow this is happening to me non-stop (gh/opus4.6)
josh-burton commentedon Apr 9, 2026
Just started using github copilot with Opus and yep, seeing the same loop
xajik commentedon Apr 11, 2026
Same here with omlx and opencode --model 'gemma-4-26b-a4b-it-8bit'.
Compactionruns in loops7 remaining items
CJVdeG commentedon Apr 26, 2026
This keeps happening to me with Opus 4.7 set for Sisyphus as default. It keeps looping into compaction.
DressPD commentedon Apr 29, 2026
still valid issue
asiek7777777 commentedon May 9, 2026
same
noxware commentedon May 14, 2026
Experiencing this right now with OpenAI provideer, GPT 5.5 model.
b1tflyyyy commentedon May 15, 2026
The same issue.
brunomsg commentedon May 17, 2026
same here while using my local llama.cpp as provider
fix(session): cap auto-compaction continue at one turn (anomalyco#15533)
Fame510 commentedon Jul 4, 2026
The fix (only inject continue on
finish === "tool-calls") is right. As a general guard against synthetic-message loops like this, a runtime breaker that denies an unbounded run of identical synthetic continuations catches the whole class if a new edge case slips through. Small framework-agnostic one here if useful: https://github.com/Fame510/SHACKLEMrGold-Rumple commentedon Sep 2, 2026
Confirmed this is still reproducible on OpenCode 1.18.26, and the impact is broader than an infinite compaction loop: it can cross a user decision/authorization boundary.
I inspected the persisted message metadata for a sanitized incident with this sequence:
finish: "stop"and explicitly stated that no files had been modified.type: "compaction",auto: true,overflow: false).synthetic: truemetadata.compaction_continue: trueContinue if you have next steps...textThe TUI hides the intervening compaction messages, so the synthetic continuation appears directly below the assistant response as an ordinary user bubble. This makes the provenance misleading and obscures that the agent was restarted by OpenCode rather than by the user.
This confirms the root cause described here: post-compaction continuation does not preserve the terminal state of the pre-compaction assistant turn. A completed
finish: "stop"turn should return control to the user, even if automatic compaction runs afterward.Suggested invariant:
Related risk report: #32634.
wesleysimplicio commentedon Oct 6, 2026
Still happening on 1.18.32.
User sent
oi. The assistant finishedstop(31692 input tokens, 21 output). The configured context limit was 28000, so the processor setneedsCompactionand returned"compact"even thoughfinishwasstop. The part was stored as{auto: true, overflow: false}because that flag is!finish. Compaction then insertedContinue if you have next steps, or stop and ask for clarification if you are unsure how to proceed.That continue turn never got a real completion and spun until abort. Counts are on #49414.
When the assistant already stopped and there is no pending tool, compaction should not insert that continue message.
thdxr commentedon Oct 11, 2026
Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (
opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.— from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊