fix(openai): send x-opencode-session header to OpenCode Go/Zen - #4191
fix(openai): send x-opencode-session header to OpenCode Go/Zen#4191yunus25jmi1 wants to merge 1 commit into
Conversation
|
👋 Some commits in this PR are not signed and verified by GitHub. Please sign your commits with a GPG or SSH key registered in your GitHub account, then force-push. Commits that are not verified: See GitHub's guide on signing commits for setup instructions. I've added |
|
Work in progress in #4190 |
OpenCode requires an x-opencode-session header carrying one stable ID per conversation and rejects requests without it starting 2026-09-06. docker-agent never sent it: provider headers are static and fixed at client construction, and there is no config templating for a per-conversation value, so the only workaround was one hard-coded ID per deployment. Add a per-request middleware for the opencode-go / opencode-zen aliases and any custom provider pointed at opencode.ai. The header value is a salted UUIDv5 derived from the run-loop session ID already present on the request context, so every request of a conversation shares it (including across multiplexed serve api / serve chat deployments) without leaking the raw session ID to a third party. Requests with no session on the context fall back to a per-client ID, and a user-set provider_opts.http_headers value always wins. Fixes docker#4164
b9b59f1 to
161018a
Compare
|
Thanks @aheritier, and sorry for the overlap with #4190, I hadn't seen it. Commits are now verified ( Happy to close this in favour of #4190, but I want to flag one concrete difference first, because it decides whether the header actually delivers "one stable ID per conversation": #4190 mints the UUID at client construction. That is per conversation in
In those paths every conversation would share a single This PR instead adds an Whichever you prefer: I can rebase this on top of #4190 as a follow-up that swaps the static header for the middleware, or you're welcome to fold the middleware into #4190 and I'll close this one. |
|
Your diagnosis is right, and thanks for flagging it rather than just closing. I checked the paths you named: a2a and mcp both load the team once, so my construction-time UUID collapses to a single ID per deployment there. I had also missed that the session ID is already on the context. Update: I've pushed your changes into #4190 with you as co-author ( Happy to close #4190 if the maintainers would rather just take yours. No hard feelings either way. |
|
Superseded by #4190, which now carries the same middleware-based fix with co-author credit. Closing to keep the review in one place. |
Fixes #4164
Problem
OpenCode Go/Zen require an
x-opencode-sessionheader ("one stable ID per conversation") and announced that requests without it may error starting 2026-09-06. docker-agent (Cagent/v1.126.0) never sends it, for the built-inopencode-go/opencode-zenaliases or for custom providers pointed atopencode.ai.Root cause
Headers in the OpenAI provider are static and fixed at client construction (
buildHeaderMapinpkg/model/provider/openai/headers.go). There is no per-request hook for OpenCode and no config templating forhttp_headers, so the only workaround was one hard-coded ID per deployment, which collapses every conversation into a single cache key inserve api/serve chat.Fix
opencodeSessionMiddleware(pkg/model/provider/openai/opencode.go), registered inNewClientwhen the provider isopencode-go,opencode-zen, or a custom provider whosebase_urlhost isopencode.ai(suffix-matched; lookalike hosts and path matches are rejected).httpclient.ContextWithSessionID), so every request of one conversation shares it, across processes and in multiplexed server deployments, without leaking the raw session ID to a third party (the codebase deliberately keepsX-Cagent-Session-Idgateway-only).chatgptAuthMiddleware.provider_opts.http_headers.x-opencode-sessionalways wins.Tests
pkg/model/provider/openai/opencode_test.gocovers provider detection, stable/opaque ID derivation, one ID per conversation on a shared client, per-client fallback, user override, and no leakage to other providers.Validation
go build ./...go test ./pkg/model/provider/...golangci-lint run(0 issues),go run ./lint .(no offenses)go mod tidy --diffclean