Client or integration
Direct HTTP client
Provider or upstream service
opencode-free (https://opencode.ai/zen/v1)
OpenCodex version
2.10.2
Endpoint or capability
/v1/chat/completions (free models, e.g. mimo-v2.5-free)
Current behaviour
Requests via the opencode-free provider fail on free models. Upstream returns:
{"type":"error","error":{"type":"MissingSessionID","message":"Error from provider (Console): OpenCode's free tier can only be used in OpenCode"}}
The proxy currently only sends x-opencode-client: desktop (see opencode-free entry in src/providers/registry.ts), which is not sufficient for the Zen free-tier gate.
Expected behaviour
Free-model requests through opencode-free should succeed (HTTP 200, usage with cost 0), matching what the real OpenCode client gets when it sends its session headers.
Minimal redacted request or reproduction
# 1. Direct upstream repro (no keys involved, keyless free tier):
# Fails - same error the proxy currently triggers:
curl -s -X POST https://opencode.ai/zen/v1/chat/completions -H 'Content-Type: application/json' -H 'x-opencode-client: desktop' -d '{"model":"mimo-v2.5-free","messages":[{"role":"user","content":"say ok"}],"max_tokens":1}'
# Passes - adding any x-opencode-session value clears the gate:
curl -s -X POST https://opencode.ai/zen/v1/chat/completions -H 'Content-Type: application/json' -H 'x-opencode-client: desktop' -H 'x-opencode-session: ses_test123000000000000000001' -H 'User-Agent: opencode/1.18.30' -d '{"model":"mimo-v2.5-free","messages":[{"role":"user","content":"say ok"}],"max_tokens":1}'
# 2. Through the proxy:
# ocx start (default port 10100), provider opencode-free configured, then:
curl -s -X POST http://127.0.0.1:10100/v1/chat/completions -H 'Content-Type: application/json' -d '{"model":"opencode-free/mimo-v2.5-free","messages":[{"role":"user","content":"say ok"}],"max_tokens":5}'
# Before fix: MissingSessionID error. After adding x-opencode-session to
# providers.opencode-free.headers in config + restart: HTTP 200.
Actual response or error
{"type":"error","error":{"type":"MissingSessionID","message":"Error from provider (Console): OpenCode's free tier can only be used in OpenCode"}}
Probe matrix (all redacted, no credentials):
- bare request -> MissingSessionID
- x-opencode-client only -> MissingSessionID
- User-Agent opencode/1.18.30 only -> MissingSessionID
- x-opencode-session set to any value (even unformatted) -> gate passed (200 or quota error, never MissingSessionID)
So the gate checks presence of x-opencode-session, not User-Agent and not session format.
Upstream documentation
No public specification exists for these headers; they were reverse-engineered from the opencode-ai binary (v1.18.30). For providerID starting with "opencode" it sends: x-opencode-project (optional), x-opencode-session (ses_...), x-opencode-request (msg_...), x-opencode-client, User-Agent opencode/. Zen docs: https://opencode.ai/docs/zen/
Suggested mapping or implementation notes
In the openai-chat adapter (or a Zen-specific wrapper) when baseUrl is https://opencode.ai/zen/v1, generate per request:
- x-opencode-session: ses_ (fresh per request)
- x-opencode-request: msg_ (fresh per request)
- User-Agent: opencode/ (only if caller did not set one)
- keep existing x-opencode-client: desktop
Per-request generation mirrors the real client. A static session ID in config works today but risks future per-session rate-limiting.
Additional context and attachments
Related: free-tier gate appears new (previously x-opencode-client alone was enough). Note on the earlier lock-in error string: it is returned with error type MissingSessionID, which is what pointed at the session header.
Checks
Client or integration
Direct HTTP client
Provider or upstream service
opencode-free (https://opencode.ai/zen/v1)
OpenCodex version
2.10.2
Endpoint or capability
/v1/chat/completions (free models, e.g. mimo-v2.5-free)
Current behaviour
Requests via the opencode-free provider fail on free models. Upstream returns:
{"type":"error","error":{"type":"MissingSessionID","message":"Error from provider (Console): OpenCode's free tier can only be used in OpenCode"}}The proxy currently only sends
x-opencode-client: desktop(see opencode-free entry in src/providers/registry.ts), which is not sufficient for the Zen free-tier gate.Expected behaviour
Free-model requests through opencode-free should succeed (HTTP 200, usage with cost 0), matching what the real OpenCode client gets when it sends its session headers.
Minimal redacted request or reproduction
Actual response or error
{"type":"error","error":{"type":"MissingSessionID","message":"Error from provider (Console): OpenCode's free tier can only be used in OpenCode"}}Probe matrix (all redacted, no credentials):
So the gate checks presence of x-opencode-session, not User-Agent and not session format.
Upstream documentation
No public specification exists for these headers; they were reverse-engineered from the opencode-ai binary (v1.18.30). For providerID starting with "opencode" it sends: x-opencode-project (optional), x-opencode-session (ses_...), x-opencode-request (msg_...), x-opencode-client, User-Agent opencode/. Zen docs: https://opencode.ai/docs/zen/
Suggested mapping or implementation notes
In the openai-chat adapter (or a Zen-specific wrapper) when baseUrl is https://opencode.ai/zen/v1, generate per request:
Per-request generation mirrors the real client. A static session ID in config works today but risks future per-session rate-limiting.
Additional context and attachments
Related: free-tier gate appears new (previously x-opencode-client alone was enough). Note on the earlier lock-in error string: it is returned with error type MissingSessionID, which is what pointed at the session header.
Checks