Client or integration
Codex App
Area
Tools / MCP / web search
Summary
A hosted web-search turn aborts with stream disconnected before completion: forced-answer pass produced no usable assistant output when the forced-answer pass ends with a terminal done, no visible assistant text, and no tool call.
#1001 fixed the original silent-success defect by turning that case into a hard LoopError(502, …) at src/web-search/loop.ts:853, and the merged fix (PR #1030) took the second of the two options the report offered — "surface an explicit in-stream error". The first option, "recover with a bounded final-answer retry", was never implemented. As a result one empty final pass ends the entire turn, even though every search result needed to answer is already in the request and nothing about the response is structurally broken.
Expected: when the forced-answer pass produces no usable output and the response is not malformed, re-ask once with the results already gathered; fail the turn only if that retry is also empty. Malformed tool calls should keep failing immediately, because they report an upstream protocol problem.
The upstream model in the observed failure is deepseek-v4.1-flash over the OpenCode Go subscription. An occasionally empty assistant message on a tool-free request is upstream behavior, not a protocol violation, and it is recoverable — the search results are already in context.
Reproduction
ocx start with hosted web search and Codex App connected to the proxy.
- Route a model that intermittently returns an empty assistant message for a tool-free request (observed:
deepseek-v4.1-flash via the OpenCode Go subscription).
- Ask a question that consumes the search budget (default
maxSearches=3), so the loop sends the forced-answer request with the synthetic web_search tool removed.
- The forced pass returns HTTP 200, a terminal
done, no assistant text, and no tool call.
- The stream disconnects before completion with the message above and the gathered results are discarded.
Deterministic reproduction on dev at 7a0513c (2.52.0) with the existing runWithWebSearch harness:
- Pass 1 emits a batched
web_search call, consuming the budget.
- The forced pass emits
done with no text_delta and no tool call.
Current dev replays the empty passthrough and then throws:
throw new LoopError(502, "forced-answer pass produced no usable assistant output");
Version
@bitkyc08/opencodex 2.51.0 installed; the defect is present on dev at 7a0513c (2.52.0).
Operating system
macOS 26.6.2 arm64; client is Codex App.
Provider and model
opencode-go (Console Go) subscription route to deepseek-v4.1-flash, adapter openai-chat. The failing request is the forced-answer pass of the hosted web-search loop.
Logs or error output
stream disconnected before completion: forced-answer pass produced no usable assistant output
Code path: src/web-search/loop.ts:853 (LoopError(502, …) inside the forceAnswer terminal check).
Screenshots and supporting files
A fix with regression coverage is linked below as a pull request.
Checks
Client or integration
Codex App
Area
Tools / MCP / web search
Summary
A hosted web-search turn aborts with
stream disconnected before completion: forced-answer pass produced no usable assistant outputwhen the forced-answer pass ends with a terminaldone, no visible assistant text, and no tool call.#1001 fixed the original silent-success defect by turning that case into a hard
LoopError(502, …)atsrc/web-search/loop.ts:853, and the merged fix (PR #1030) took the second of the two options the report offered — "surface an explicit in-stream error". The first option, "recover with a bounded final-answer retry", was never implemented. As a result one empty final pass ends the entire turn, even though every search result needed to answer is already in the request and nothing about the response is structurally broken.Expected: when the forced-answer pass produces no usable output and the response is not malformed, re-ask once with the results already gathered; fail the turn only if that retry is also empty. Malformed tool calls should keep failing immediately, because they report an upstream protocol problem.
The upstream model in the observed failure is
deepseek-v4.1-flashover the OpenCode Go subscription. An occasionally empty assistant message on a tool-free request is upstream behavior, not a protocol violation, and it is recoverable — the search results are already in context.Reproduction
ocx startwith hosted web search and Codex App connected to the proxy.deepseek-v4.1-flashvia the OpenCode Go subscription).maxSearches=3), so the loop sends the forced-answer request with the syntheticweb_searchtool removed.done, no assistant text, and no tool call.Deterministic reproduction on
devat7a0513c(2.52.0) with the existingrunWithWebSearchharness:web_searchcall, consuming the budget.donewith notext_deltaand no tool call.Current
devreplays the empty passthrough and then throws:Version
@bitkyc08/opencodex2.51.0 installed; the defect is present ondevat7a0513c(2.52.0).Operating system
macOS 26.6.2 arm64; client is Codex App.
Provider and model
opencode-go(Console Go) subscription route todeepseek-v4.1-flash, adapteropenai-chat. The failing request is the forced-answer pass of the hosted web-search loop.Logs or error output
Code path:
src/web-search/loop.ts:853(LoopError(502, …)inside theforceAnswerterminal check).Screenshots and supporting files
A fix with regression coverage is linked below as a pull request.
Checks