v1.5.4 stopped stripping reasoning_content, which fixes clients that send
it — but most agent clients (pi included) never store or replay their
reasoning, keeping only the tool call. OpenCode Go validates the field on
any assistant turn that carries tool_calls and rejects the whole request:
400 invalid_request_error: The `reasoning_content` in the thinking mode
must be passed back to the API.
Verified against the live endpoint that an EMPTY string satisfies the
check, so the adapter now fills in "" when a tool-calling assistant turn
has no reasoning_content. Nothing is fabricated: the reasoning shown to
the client is still exactly what the upstream returned for that turn.
Measured: with a tool_call + tool_result history and no reasoning_content,
all 25 configured Go models returned 400 before and all 25 answer
correctly now.
Test: TestOpenCodeGoVsZenReasoning also pins that a plain assistant turn
(no tool calls) must NOT gain the field.
Zen (https://opencode.ai/zen/v1) and Go (https://opencode.ai/zen/go/v1)
are different services with different requirements, and one shared adapter
could not satisfy both.
The decisive difference is reasoning_content:
* OpenCode Go runs thinking models and REQUIRES the assistant turn's
reasoning_content to be echoed back. The shared adapter stripped it
(msg.reasoning_content = nil), so every replay of a thinking turn
failed with:
400 invalid_request_error: The `reasoning_content` in the thinking
mode must be passed back to the API.
Reproduced directly: the same request with reasoning_content -> 200,
without -> 400. That is why the Go tier never worked in an agent loop.
* The Zen free pool must not receive it, so it keeps stripping.
Both adapters keep the earlier fixes they share (never drop an assistant
turn carrying tool_calls; send stream_options only when streaming; role
whitelist; multimodal strip) and the opencode client fingerprint headers —
the Go endpoint additionally REQUIRES x-opencode-session, which the
adapter already sends.
config: localzen -> opencodezen, gozen -> opencodego.
Verified: all 25 gozen models answer correctly through the gateway with a
thinking + tool_call + tool_result history (was 0/25 before), streaming
included; the Zen free models still pass.
Test: TestOpenCodeGoVsZenReasoning pins the Go-keeps / Zen-strips split.