Skip to content

Auto-compaction infinite loop when assistant ended its turn (finish !== tool-calls) #15533

Closed as not planned

Description

@Lee-SiHyeon

Bug Description

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

  1. Start a long conversation that approaches the context window limit
  2. Have the assistant end its turn naturally (ask a question, or finish responding)
  3. Auto-compaction triggers due to context overflow
  4. Synthetic "Continue if you have next steps..." message is injected
  5. 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:

assistant responds → context overflow → auto-compaction → synthetic "Continue..." →
agent responds → overflow → compaction → synthetic "Continue..." → …

Root Cause

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)
  • Model: Claude Sonnet 4

Related

Activity

  1. added
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on Mar 1, 2026
  2. github-actions commented on Mar 1, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of or closely related to existing issues. Please check:

    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.

  3. Lee-SiHyeon commented on Mar 1, 2026

    @Lee-SiHyeon
    Author

    I did local build and It is fixed when I use my local binary.

  4. aeciolevy commented on Mar 25, 2026

    @aeciolevy

    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.

  5. uriva commented on Mar 25, 2026

    @uriva

    how is this not fixed yet? I can't use opus for a few days now

  6. zachpony commented on Mar 26, 2026

    @zachpony

    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?

  7. uriva commented on Mar 30, 2026

    @uriva

    For me it was posthog mcp, disabling it solves the issue, but this shouldn't be so fragile.

  8. eugenio commented on Apr 2, 2026

    @eugenio

    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 version: latest (pre-rename, opencode.json config)
    • OS: Windows 11 Pro
    • Provider: NadirClaw Router (OpenAI-compatible proxy at http://127.0.0.1:4000/v1)
    • Models: 3-tier routing — Qwen3 30B / Mistral Large 3 / Kimi K2
    • Config:
    {
      "$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

    1. Ask agent to analyze a moderately complex repo (Python/AWS CDK project with submodules)
    2. Agent completes analysis, naturally ends its turn with a summary
    3. Auto-compaction triggers (context near limit from repo exploration)
    4. Compacted summary contains structured sections: "Goal / Instructions / Discoveries / Accomplished / Left to do"
    5. Synthetic "Continue..." is injected
    6. Agent interprets compacted summary + continue prompt as a new task → produces another summary
    7. Loop: Build → Compaction → Build → Compaction → ...

    Transcript excerpt

    ▣ Build · big-pickle · 20.7s
    ▣ Compaction · big-pickle · 7.3s
    ▣ Build · big-pickle · interrupted
    ▣ Compaction · big-pickle · 19.2s
    ▣ Build · big-pickle · 17.6s
    ▣ Compaction · big-pickle · 14.8s
    ▣ Build · big-pickle · 12.7s
    ▣ Compaction · big-pickle · 15.8s
    ... (continued indefinitely)
    

    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

    Related

  9. eugenio commented on Apr 2, 2026

    @eugenio

    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.

  10. eugenio commented on Apr 2, 2026

    @eugenio

    For reference, the working NadirClaw Router setup (opencode.json config) can be found here: https://github.com/eugenio/AWSModelRunner

  11. ForbiddenEra commented on Apr 2, 2026

    @ForbiddenEra

    wow this is happening to me non-stop (gh/opus4.6)

  12. josh-burton commented on Apr 9, 2026

    @josh-burton

    Just started using github copilot with Opus and yep, seeing the same loop

  13. xajik commented on Apr 11, 2026

    @xajik

    Same here with omlx and opencode --model 'gemma-4-26b-a4b-it-8bit'.
    Compaction runs in loops

    Image
  14. 7 remaining items

  15. CJVdeG commented on Apr 26, 2026

    @CJVdeG

    This keeps happening to me with Opus 4.7 set for Sisyphus as default. It keeps looping into compaction.

  16. DressPD commented on Apr 29, 2026

    @DressPD

    still valid issue

  17. removed
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on May 3, 2026
  18. asiek7777777 commented on May 9, 2026

    @asiek7777777

    same

  19. noxware commented on May 14, 2026

    @noxware

    Experiencing this right now with OpenAI provideer, GPT 5.5 model.

  20. b1tflyyyy commented on May 15, 2026

    @b1tflyyyy

    Experiencing this right now with OpenAI provideer, GPT 5.5 model.

    The same issue.

  21. brunomsg commented on May 17, 2026

    @brunomsg

    same here while using my local llama.cpp as provider

  22. Fame510 commented on Jul 4, 2026

    @Fame510

    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

  23. MrGold-Rumple commented on Sep 2, 2026

    @MrGold-Rumple

    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:

    1. The user asked only for an evaluation and a proposed plan.
    2. The normal assistant response completed with finish: "stop" and explicitly stated that no files had been modified.
    3. Immediately afterward, OpenCode created an automatic compaction part (type: "compaction", auto: true, overflow: false).
    4. 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
    5. 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.

    Related risk report: #32634.

  24. wesleysimplicio commented on Oct 6, 2026

    @wesleysimplicio

    Still happening on 1.18.32.

    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.

  25. thdxr commented on Oct 11, 2026

    @thdxr
    Member

    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 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions