anomalyco / anomalyco/opencode
[Zen/GO Gateway] Short reply via Anthropic-compat endpoint missing stop_reason -> client triggers false retry (duplicate output)
@MrMushrooooom is already working on this.
Since Aug 20, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
Summary
When using the Zen/GO gateway (https://opencode.ai/zen/go/v1) via its Anthropic-compatible endpoint, very short completions cause the client to think the stream was truncated and auto-retry with Continue exactly where you left off, producing garbled duplicate output.
Root cause appears to be OpenAI -> Anthropic streaming translation: the final stop_reason / message_stop event is missing or not forwarded for short replies, so Anthropic clients never receive a clean termination.
Repro
- Gateway:
https://opencode.ai/zen/go/v1(Zen/GO) - Client: Hermes Agent Desktop (Anthropic-compatible client)
- Model:
muse-spark-1.2-contributorviaopencode-go(DeepSeek channel also affected, but repro here is Muse Spark) - Prompt: trivial short prompt, e.g. "测试新模型是否能正常对话,不用过多的回复" / "test if model can talk normally, short reply only"
- Expected:
content_block_stop+message_stopwithstop_reason: "end_turn"and stream ends cleanly. - Actual: content arrives correctly ("正常,能对话" / single short sentence), but stream ends without proper
stop_reason. Client interprets as network truncation.
Observed behavior
Hermes injects system message:
[System: The previous response was cut off by a network error mid-stream. Continue exactly where you left off. Do not restart or repeat prior text. Finish the answer directly.]
Model then emits a duplicate/continuation (e.g. "✓", "正常", then repeated system injections), visible as "乱七八糟东西" to user. Turning off Hermes retry still leaves the stream technically incomplete per Anthropic spec.
Longer replies are less likely to trigger this; short 1-2 token replies reproduce reliably (3/3 in session).
Hypothesis
Zen gateway translates OpenAI streaming (choices[0].finish_reason + data: [DONE]) to Anthropic SSE (message_delta with stop_reason, message_stop). For very short completions the final delta is dropped or stop_reason is null, so message_stop never fires.
Expected fix
Ensure for every OpenAI stream termination (including finish_reason: "stop" on short content), the gateway always emits:
event: message_delta
data: {"delta":{"stop_reason":"end_turn","stop_sequence":null}, ...}
event: message_stop
even when content is 1-2 tokens.
Evidence
- Gateway base_url:
https://opencode.ai/zen/go/v1withUser-Agent: OpenCode/1.0 - Token:
opencode-gosubscription ($10/mo, Zen) - Client logs show Hermes adding the continuation prompt only after GO stream ends without stop signal (not a client network drop).
- Same model via native OpenAI endpoint does not exhibit this (only via Anthropic-compat translation).
Impact
Any Anthropic-compat client (Hermes, Claude Code, OpenCode) using Zen/GO will see occasional duplicate/garbled output on short replies. Looks like "GO bug + Hermes over-eager retry" but primary fix is in gateway translation.
Happy to provide a minimal SSE dump if needed.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.