Assistant turn that ends with reasoning only (no text, no tool call, finish "stop") is settled silently and the agent stops #55378
Description
Description
This is #49673 on OpenCode 2. That issue (DeepSeek V4.1 Flash: "output=0, finish=stop … the chat stops after tool calls with no answer at all") was closed only because it was filed against OpenCode 1; the maintainer asked to reopen it if it was still relevant on 2.0, and that never happened. We reproduced the same symptom on 2.0.29 with Gemini.
When the model ends a step with reasoning tokens only (no text, no tool call, finish_reason: "stop"), OpenCode settles the turn as a normal completion and shows nothing. The agent just stops right after a tool result, with no error.
The streamed response for that step:
{
"choices": [{"index": 0, "finish_reason": "stop",
"message": {"role": "assistant", "content": null, "tool_calls": []}}],
"usage": {"completion_tokens": 24,
"completion_tokens_details": {"text_tokens": 0, "reasoning_tokens": 24}}
}All the output tokens are reasoning, nothing else comes back, and the turn ends.
Expected: a step with no text and no tool call is not settled as a successful turn: retry it, or surface it as an error so the user knows to continue.
Plugins
N/A
OpenCode version
2.0.29
Steps to reproduce
Not deterministic:
- Use a Gemini model (seen with
gemini-3.5-flash-lite) in an agentic session with tool calls. - Occasionally the step right after a tool result streams back only reasoning, then
finish_reason: "stop". - OpenCode ends the turn with no visible output and waits for the user as if it had answered.
Screenshot and/or share link
The tool output is shown, and then nothing: no message, no error.
Operating System
Linux
Terminal
N/A
Activity
opencode-agent commentedon Oct 14, 2026
Thanks for the clear report. I was able to reproduce this on 2.0.29 with a simulated model, and it still happens on the latest
dev(34d8ded0c).What I did:
shelltool call and gets its output back.content: null, no tool calls,finish_reason: "stop"and usage of 24 tokens, all reasoning.The TUI shows the tool output and then nothing: no answer, no error, and the session goes idle as if the turn had ended normally. The token counter still includes that step's usage. The recording and screenshot below show it, and the script below reproduces it.
It looks like the session runner only treats an empty step as a failure when the finish reason is
unknown. An emptystopis recorded as a normal completion.Related issues:
stopcase on v1, with a proposed retry fixlengthfinishrecording.mp4
Reproduction script (drive.ts)
Run it with opencode-drive:
opencode-drive run ./drive.ts. It drivesopencodefrom yourPATH; setOC_DEVto the path of an OpenCode checkout to run that from source instead.zonemeen commentedon Oct 14, 2026
I’d like to take this on. My plan is to detect stop responses with no text or tool calls, retry with a limit, and surface a clear error if retries fail. I’ll also add a regression test for reasoning-only responses after a tool result.
yxlimo commentedon Oct 17, 2026
Reproducing the same symptom on OpenCode 2.0.32 through the free-tier channel (
opencode.ai/inference/...), across three models — so this is not Gemini-specific:mimo-v2.6-flash-free(×18),deepseek-v4.1-flash-free(×1),glm-5.3-flash-free(×1) within ~48h of multi-session agentic usage.What we can add beyond the hypotheses discussed so far is a raw stream capture taken at a passive MITM tap for one occurrence (glm-5.3-flash-free): the upstream sent a complete ~800 B stream —
No tool-call deltas at any point. The session DB recorded exactly what the stream contained (
finish:"stop", no tool parts). 13 consecutive control streams on the same capture were healthy with normalfinish_reason:"tool_calls"endings — so (a) the client settles the turn precisely as received and nothing is dropped client-side, and (b) the tap itself does not perturb the stream.This shape matches the captured stream in this issue exactly (empty/reasoning-only content,
finish_reason:"stop", no text, no tool calls). Note it differs from the two shapes in #44148 (finish_reason:"other"and clean-FIN cutoff, Go plan): so at least three distinct upstream failure shapes currently end in the same silent stop.Related context, also from below: #49673 was never reopened despite still reproducing (the free-tier hits above were on 2.0.x), and PR #40531 (retry empty responses) remains unmerged/conflicted — so the client-side fix path is still open while occurrence continues.
One possibly-relevant lead, with the caveat that causality is unproven: across 17 occurrences we recorded, 7 had a Magic-Context historian sub-session request rejected with HTTP 403 ("free tier can only be used from within OpenCode") 1.0–1.7 s around the hit (enrichment ~150× vs baseline assistant messages). If the upstream throttles bursts of parallel free-tier-authenticated requests, that could correlate with the empty-stop shape. Happy to share sanitized capture scripts and evidence on request.
thymikee commentedon Oct 17, 2026
Also seen on 2.0.32 with
callstack/Apex(OpenAI-compatible, served by vLLM through LiteLLM). On the gateway the stopping requests are logged assuccesswith a normalstop. Two examples, from about 13.5k agentic steps:We see a close variant more often: the step ends with text that announces an action ("…Rewriting:", "Let me run the test…"), then
stopwith no tool call. It's harder to detect, but the same "retry or surface it" handling would help there too.luisboch commentedon Oct 20, 2026
Seeing this on 2.1.1 too, and there it looks like a regression: it happens on almost every step after a tool result, not occasionally.
Environment
.deb, channellatest)github-copilot/gemini-3.8-flash(variantmedium)What happens
The model calls
read, the tool result comes back fine, and the next step ends with nothing in it:{ "content": [], "finish": "stop", "rawFinish": "stop", "tokens": { "input": 6434, "output": 0, "reasoning": 0, "cache": { "read": 15815 } } }