* fix(opencode-go): send OpenClaw User-Agent on native OpenCode Go routes
OpenCode Go's documented client-identification contract requires coding
agents to identify themselves with a specific User-Agent. opencode-go
requests previously carried only the generic OpenAI SDK fallback.
Add a vendor-documented attribution policy for opencode-go that sets
User-Agent: openclaw/<version> only on the verified native OpenCode Go
endpoint; Zen and custom-proxy routes are unchanged. Route the Anthropic
transport through the same central policy via the plugin stream wrapper
so both Go transports identify consistently, with caller headers winning.
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
* fix(opencode-go): send OpenClaw User-Agent on native OpenCode Go routes
Worked on by:
- @VACInc
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
OpenClaw-Publication: 2182e49f-af02-4250-864c-f7777a89eb83
* test(opencode-go): prove User-Agent precedence
Cover configured User-Agent replacement on native OpenCode Go requests across OpenAI-compatible, Anthropic stream, and simple-completion paths. Custom proxy routes retain the configured value.
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
* fix(opencode-go): send OpenClaw User-Agent on native OpenCode Go routes
Worked on by:
- @VACInc
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
OpenClaw-Publication: 41cb2f26-9a12-4b40-b903-2d5b2fc3ccbd
* fix(opencode-go): scope attribution to Go routes
Worked on by:
- @VACInc
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
* fix(ai): merge transport headers case-insensitively
Worked on by:
- @VACInc
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
* fix(opencode-go): send OpenClaw User-Agent on native OpenCode Go routes
Worked on by:
- @VACInc
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
OpenClaw-Publication: e353cea0-b205-4dde-bded-b9bf49b93cec
* test(opencode): keep Zen live replay on free model
Worked on by:
- @VACInc
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
* Publish openclaw/openclaw-openclaw-vacinc-issue-135538
Worked on by:
- @VACInc
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
OpenClaw-Publication: 2d3d8e21-99a1-4cd1-a90e-9ee00e647982
* Publish openclaw/openclaw-openclaw-vacinc-issue-135538
Worked on by:
- @VACInc
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
OpenClaw-Publication: 5bffe897-9d10-4b1b-b7de-550c3b400168
* test(opencode): use replay-capable free Zen model
Worked on by:
- @VACInc
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
* test(opencode): use interleaved free Zen model
Worked on by:
- @VACInc
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
* test(opencode): stabilize free Zen live smoke
Worked on by:
- @VACInc
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
---------
Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
* fix(agents): preserve reasoning_content replay across DeepSeek tier suffixes
OpenCode Zen exposes DeepSeek V4 as `deepseek-v4-flash-free`, which keeps the upstream DeepSeek thinking-mode contract that requires `reasoning_content` to be passed back on follow-up requests. The existing replay allowlist only matched the bare ids (`deepseek-v4-flash`, `kimi-k2-thinking`, ...), so the tier-suffixed id missed every candidate and the sanitizer stripped `reasoning_content` from the assistant turn. DeepSeek then rejected the second API call with HTTP 400 and the session deadlocked.
Strip the well-known tier suffixes (`-free`, `-paid`, `-trial`) when generating allowlist candidates so the base model id matches and the reasoning replay survives. Existing matching for prefixed / colon-suffixed routes is unchanged.
Fixes#87575
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(agents): avoid spread-rebuild when iterating allowlist candidates
oxlint flagged the [...candidates] spread as an unnecessary array copy. Use an explicit baseCount loop bound instead so we still iterate the original entries while pushing tier-stripped variants onto the same array.
Co-authored-by: Cursor <cursoragent@cursor.com>
* test(opencode): add live DeepSeek replay probe
* test(opencode): avoid forced tool choice in live replay
---------
Co-authored-by: Pluviobyte <Pluviobyte@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>