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
Assistant turn that ends with reasoning only (no text, no tool call, finish "stop") is settled silently and the agent stops #55378
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.
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:
The model makes a shell tool call and gets its output back.
The next step returns a single chunk with 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 empty stop is recorded as a normal completion.
// Repro for #55378: after a tool result, the model ends a step with no text and no// tool call (finish_reason "stop", only reasoning usage). OpenCode settles it silently.import{Effect}from"effect"import{Llm,OpenCodeDriver}from"opencode-drive"exportdefaultOpenCodeDriver.use({
...(process.env.OC_DEV ? {opencode: {dev: process.env.OC_DEV}} : {}),project: {git: true,files: {"README.md": "hello\n"}},tools: ["shell"],tui: {recording: true},},({ ui, llm, tools })=>Effect.gen(function*(){constshells=yield*tools.control("shell")// Step 1: a normal tool call.yield*llm.queue(Llm.toolCall({index: 0,id: "call_ls",name: "shell",input: {command: "ls"}}),Llm.finish("tool-calls"),)// Step 2: the provider returns no content and no tool call, only reasoning usage, then "stop".yield*llm.queue(Llm.raw({id: "chatcmpl-empty",object: "chat.completion.chunk",created: 0,model: "gemini-3.5-flash-lite",choices: [{index: 0,delta: {role: "assistant",content: null},finish_reason: "stop"}],usage: {prompt_tokens: 100,completion_tokens: 24,total_tokens: 124,completion_tokens_details: {reasoning_tokens: 24},},}),)yield*ui.submit("List the files, then tell me what you found")constshell=yield*shells.take("call_ls")yield*shell.succeed({output: "README.md\n",exit: 0})yield*Effect.sleep(4000)yield*ui.screenshot("after-empty-stop")}),)
Run it with opencode-drive: opencode-drive run ./drive.ts. It drives opencode from your PATH; set OC_DEV to the path of an OpenCode checkout to run that from source instead.
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.
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 normal finish_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.
Also seen on 2.0.32 with callstack/Apex (OpenAI-compatible, served by vLLM through LiteLLM). On the gateway the stopping requests are logged as success with a normal stop. Two examples, from about 13.5k agentic steps:
Reasoning only: 13,020 reasoning tokens, 3 output tokens, no text, no tool call. The session went idle and the task was reported complete.
706 reasoning tokens plus 53 non-reasoning output tokens, yet no text part and no tool part were stored. Whatever those 53 tokens were never reached the session. That may point to a dropped tool call rather than a model that simply stopped.
We see a close variant more often: the step ends with text that announces an action ("…Rewriting:", "Let me run the test…"), then stop with no tool call. It's harder to detect, but the same "retry or surface it" handling would help there too.
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.