Repository navigation
Description
Summary
The same model (deepseek-v4.1-flash) behaves differently depending on the provider route: via opencode-go (Zen gateway, https://opencode.ai/zen/go/v1) it falls into infinite autoregressive repetition loops before tool calls; via the direct DeepSeek API (deepseek/deepseek-flash) the exact same sessions run clean. We have a clean A/B (same weights, two serving stacks, stable difference across many runs), session transcripts of the loops, and a plausible root cause.
This looks like the gateway mishandling reasoning models' tool-calling transitions (most likely: feeding reasoning_content back into the conversation, and/or missing sampling safeguards).
Environment
- opencode: v1.18.3x (2026-09-27), macOS (darwin/arm64)
- Provider A (degenerates):
opencode-go—https://opencode.ai/zen/go/v1, modeldeepseek-v4.1-flash, requests carryx-opencode-sessionheader - Provider B (clean):
deepseek—https://api.deepseek.com/v1, modeldeepseek-flash - Agent harness: custom subagents with tools (bash/read/edit), temperature 0.2–0.3, up to 100+ tool-call steps per session
Evidence
1. Clean A/B on the same model
- Same session content replayed against both providers:
opencode-go/deepseek-v4.1-flash→ enters repetition attractor loops, repeatedlydeepseek/deepseek-flash(direct) → runs to completion, repeatedly
- The user's manual switch mid-session (gateway → direct) made the 400/loop problems disappear immediately; switching back reproduces them.
2. Loop transcripts (verbatim, from agent=coding and primary orchestrator sessions)
Pattern A — English (the model stalls before emitting a tool call, then loops):
Let me run.
Let me execute.
Let me do it now.
OK.
Let me run.
Let me execute.
…(repeats for 100+ lines)
Pattern B — same class, different vocabulary:
Emit.
OK.
Now.
OK.
Emitting.
OK.
I must emit. Doing it.
Let me grep.
Emit.
OK — emitting.
Recon.
OK.
…(fixed ~12-line cycle, repeats indefinitely)
Russian-localized session, same fixed cycle:
Сгенерируй.
OK — генерирую.
Вызов.
OK.
Сейчас.
OK.
Генерация.
OK.
Я должен выполнить вызов. Занимаюсь этим.
…(repeats)
Notably, the vocabulary of the loops mirrors instruction text from the agent prompts (compliance-narration words like "emit"/"OK"/"call") — consistent with the model regurgitating its own prior assistant text, i.e. the loop is self-feeding through conversation history.
3. What the direct API does differently
- Direct DeepSeek API responses carry reasoning in
reasoning_content, and the model was trained with the contract thatreasoning_contentmust not be fed back as input on subsequent turns. - Hypothesis: the Zen gateway re-includes the assistant's reasoning/hesitation text in subsequent
messages(or otherwise alters the reasoning→tool_call transition), so the model keeps seeing — and then predicting — its own deliberation text instead of transitioning to the tool-call token. - Secondary suspect: the gateway passes through low
temperature(0.2–0.3) without vendor-side anti-repetition safeguards; greedy-ish decoding makes the attractor inescapable once seeded.
4. Related gateway-side quirks observed the same day
stream error … AI_APICallError: Bad Requeston gateway requests whose message history the direct API accepts; the gateway's error body is truncated to{"model":"deepseek-v4.1-flash"}— no diagnostics are recoverable.- After such an error, opencode disposes and recreates the whole instance (feels like a hang).
Expected vs actual
- Expected: the same model behind the Zen gateway behaves like the direct API — reasoning handled per the provider contract (
reasoning_contentnot fed back), tool calls emitted after deliberation, sampling sane for low-temperature agent workloads. - Actual: gateway route reliably degenerates into infinite pre-tool-call narration loops on agentic workloads; direct route is stable.
Reproduction sketch
- Configure two providers:
opencode-go(Zen,x-opencode-sessionheader) and direct DeepSeek, same model tier (deepseek-v4.1-flash/deepseek-flash). - Run an agentic session with ~50+ tool-call steps and a prompt that requires multi-step verification (e.g., "run these tests, then narrow failing ones, then re-run").
- Gateway route: assistant text degenerates into fixed repetition cycles ("Let me run. / Let me execute. / …" or localized equivalents) instead of emitting the tool call.
- Direct route: same session completes.
Happy to provide full session JSONL dumps (DB rows with message/part payloads) for both routes if that helps debugging.
Activity
github-actions commentedon Sep 28, 2026
This issue doesn't fully meet our contributing guidelines.
What needs to be fixed:
Please edit this issue to address the above within 2 hours, or it will be automatically closed.
This issue might be a duplicate of existing issues. Please check:
If you believe this was flagged incorrectly, please let a maintainer know.
github-actions commentedon Sep 28, 2026
This issue has been automatically closed because it was not updated to meet our contributing guidelines within the 2-hour window.
Feel free to open a new issue that follows our issue templates.