fix: send opencode User-Agent on upstream requests to avoid Zen free-tier 429 - #138
Open
cheerc wants to merge 1 commit into
Open
fix: send opencode User-Agent on upstream requests to avoid Zen free-tier 429#138cheerc wants to merge 1 commit into
cheerc wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Upstream HTTP requests from the
opencode-zenandopencode-goproviders now carry aUser-Agent: opencode/routatic-proxyheader. Users can route OpenCode Zen free models (e.g.deepseek-v4-flash-free) through the proxy without hitting429 FreeUsageLimitError→502 all models failed.Why
Closes #137. opencode.ai's Zen free tier rate-limits by client identity: requests whose
User-Agentstarts withopencode/are exempt; anything else (Go's defaultGo-http-client/1.1, curl) getsHTTP 429 {"type":"FreeUsageLimitError","message":"Rate limit exceeded. Please try again later."}. The proxy never set a User-Agent on upstream requests, so all Zen free-model traffic was throttled even though the same account key works fine from the native opencode CLI.CONFIGURATION.md/MODELS.mdadvertise Zen free models as supported fallbacks, so this is a documented-behavior violation, not a usage issue.How
upstreamUserAgent = "opencode/routatic-proxy"ininternal/provider/opencode_zen.go(theopencode/prefix is what the free-tier check keys on).User-Agentalongside the existing headers at all upstream request construction sites: ZendoRequest(chat completions, stream + non-stream),doJSONRequest(Responses/Gemini),executeAnthropic,streamAnthropic; GodoRequest,executeAnthropic,streamAnthropic.httptestupstream servers asserting theopencode/prefix (and existing auth headers) for every wire format / stream variant.Scope
opencode_zen.go/opencode_go.go+ regression tests ininternal/provider/opencode_useragent_test.go.internal/clientpackage (used by the router's Claude/Anthropic and OpenRouter paths) — not implicated in the Zen free-tier bug; the auth-error short-circuit behavior in [bug] Do not fall back when encountering a usage limit #101 and [bug] Auth errors (401/403) should short-circuit the fallback chain #108 is untouched.Verification
go test ./internal/provider/ -run OpencodeUserAgent -count=1→ 9/9 FAIL, all withUser-Agent = "Go-http-client/1.1", want prefix "opencode/".ok9/9 PASS.go test ./... -count=1→ all packages ok.gofmt -l internal/provider/→ clean;go vet ./internal/provider/→ ok.deepseek-v4-flash-freereturns 200; same request was 429/502 before.Current HEAD: 229fec4
Risks
None known. The header is cosmetic to upstream; no behavior change for users who already use paid
opencode-go/ Claude / OpenRouter paths. If the upstream free-tier check ever changes, tests atinternal/provider/opencode_useragent_test.gowill flag it.Lessons
The free-tier limiter keys on the effective
User-Agentof the upstream client, not on the API key alone. Any future proxy client should mirror the first-party client's User-Agent to stay in the same quota bucket.Closes #137