Skip to content

fix(providers): keep a third-party agent's own User-Agent on OpenCode Go - #15453

Merged
diegosouzapw merged 2 commits into
diegosouzapw:release/v3.8.52from
yourspraveen:fix/15311-opencode-go-user-agent
Oct 6, 2026
Merged

diegosouzapw merged 2 commits into
diegosouzapw:release/v3.8.52from
yourspraveen:fix/15311-opencode-go-user-agent

Conversation

@yourspraveen

Copy link
Copy Markdown
Contributor

⚠️ base-red inherited: #15306

Closes #15311

Problem

OpencodeExecutor.buildHeaders feeds the CLI defaults into forwardOpencodeClientHeaders. Its applyCliDefaults replaces every User-Agent that isn't a versioned OpenCode CLI. That rewrite exists for the Zen free tier (#5997, Cloudflare refusing generic UAs from datacenter IPs), but it also ran on the authenticated OpenCode Go path. As a result, a third-party agent sending my-coding-agent/1.0 reached Go as opencode/<version> unless CLI synthesis was switched off globally.

OpenCode Go's client requirements (opencode.ai/docs/go, "Where can I use it?") ask the opposite: a client should

Identify itself with its own user agent, such as my-coding-agent/1.0, rather than a generic SDK or HTTP-library name.

and send a stable x-opencode-session.

Fix

  • forwardOpencodeClientHeaders gains a keepAgentUserAgent option. When it is set, a client User-Agent that names the agent itself is kept.
  • The new isGenericClientUserAgent matches anchored, bounded SDK / HTTP-library defaults: curl, python-requests/httpx, OpenAI/Anthropic SDKs, axios, node-fetch, undici, Go-http-client, okhttp, Bun and others. Those UAs are still replaced, and a missing UA is still filled.
  • buildHeaders enables the option only on the Go surface (identified by registry baseUrl, so aliases don't matter) and outside the free-tier gate. The Zen free-tier policy is unchanged.

Tests

tests/unit/opencode-go-client-user-agent-15311.test.ts covers:

  • R1: Go keeps the agent's UA with synthesis unset and with synthesis on
  • R2: the session is unchanged across turns
  • R3: generic SDK / library UAs are replaced, and a missing UA is filled
  • R4: a genuine opencode/1.18.31 UA is kept
  • R5: the Zen free tier still rewrites a non-CLI UA
  • R6: with synthesis off, the UA and session are forwarded as before

R1 and R2 failed before the fix. All OpenCode tests pass after it (850/850), and so do the existing #5997 synthesis tests.

Related

Local quality gates

I ran the quality.yml fast-gate set locally against release/v3.8.52:

  • Passing (34), including file-size and complexity-ratchets. The User-Agent decision is in its own keepsClientUserAgent, so applyCliDefaults gains no complexity and opencode.ts stays under its frozen size.
  • Failing (3), none caused by this change:
    • cycles and agent-skills-sync fail identically on the untouched base.
    • workflows needs actionlint and zizmor, which aren't installed locally.

OpencodeExecutor.buildHeaders fed the CLI defaults into
forwardOpencodeClientHeaders, whose applyCliDefaults replaces every
User-Agent that is not a versioned OpenCode CLI. That rewrite exists for the
Zen free tier (diegosouzapw#5997), but it ran on the authenticated Go path too, so an
agent sending `my-coding-agent/1.0` reached Go as `opencode/<version>`
unless synthesis was switched off globally.

OpenCode Go's client requirements ask third-party agents to identify
themselves with their own user agent, not a generic SDK or HTTP-library
name, and to send a stable x-opencode-session. On the Go surface (by
registry baseUrl) and outside the free-tier gate, an agent's own UA is now
kept; a generic SDK / HTTP-library UA is still replaced and a missing one
is still filled. The Zen free-tier policy is unchanged.

Closes diegosouzapw#15311
Moves the User-Agent keep/replace decision out of applyCliDefaults into
keepsClientUserAgent (no new complexity-ratchet violation) and trims the
executor call-site comment so open-sse/executors/opencode.ts stays under
its frozen file-size baseline. Behaviour unchanged; covered by the diegosouzapw#15311
and diegosouzapw#5997 header tests.
@yourspraveen

Copy link
Copy Markdown
Contributor Author

CI note for reviewers:

The red checks on this PR are inherited from release/v3.8.52 (#15306) or from CI infrastructure. None of them involves the files this PR changes:

Check Cause Why it is not this PR
Fast Quality Gates only check:cycles fails (14 SCCs) fails identically on the untouched base; this PR adds no import edges in those cycles
Docs Sync (Strict) [i18n-check] drift detected i18n mirrors drifted on the base; this PR touches no translated file
Merge integrity check:agent-skills-sync regenerates omni-providers same dry-run diff on the base; no skill or provider-catalog change here
Lint stops at npm run audit:deps: 44 advisories (incl. next, node-forge) new advisories against the base lockfile; this PR changes no dependency
Build The runner has received a shutdown signal runner infrastructure, cancelled mid-job
Unit Tests fast-path (2/4) 11582 pass, 1 fail: transientBackendRetry: default sleep respects AbortSignal without custom sleep a timing test in open-sse/services/transientBackendRetry, which this PR doesn't touch; it passes 3/3 locally on this branch and on the base, so it looks like a flake on a loaded runner

The checks that exercise this change pass: API Route Typecheck, the other unit-test shards and Vitest. Before pushing I ran the quality.yml fast-gate set locally (34 passing, including file-size and complexity-ratchets) and all OpenCode tests (850/850).

@diegosouzapw
diegosouzapw merged commit e8a18fc into diegosouzapw:release/v3.8.52 Oct 6, 2026
43 of 51 checks passed
diegosouzapw added a commit that referenced this pull request Oct 6, 2026
Follow-up da onda 6. Nenhum código de produto.

Tetos medidos no tip depois dos squashes:

- `open-sse/executors/opencode.ts` 1518 → 1519 (#15453)
- `tests/unit/combo/quota-weighted-strategy.test.ts` novo, congelado em 1217 (#15480)

O adopt de i18n grava o hash atual de `README.md` (#15541, #15467) e `docs/reference/ENVIRONMENT.md` (#15542). Não traduz.

File-size OK (171 congelados, 47 testes congelados). i18n drift PASS (sources=152, targets=10032).

⚠️ base-red inherited: #15306
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(providers): OpenCode Go rewrites third-party User-Agent as OpenCode CLI

2 participants