Skip to content

fix(opencode-zen): align free-tier v2 headers and read/shell fingerprint (#4845) - #4860

Open
ShayNeeo wants to merge 1 commit into
decolua:masterfrom
ShayNeeo:fix/opencode-zen-v2-fingerprint
Open

ShayNeeo wants to merge 1 commit into
decolua:masterfrom
ShayNeeo:fix/opencode-zen-v2-fingerprint

Conversation

@ShayNeeo

Copy link
Copy Markdown
Contributor

Summary

Following #4842 (which updated OpenCodeExecutor in open-sse/executors/opencode.js and open-sse/utils/opencodeFingerprint.js for the OpenCode v2 3-layer free-tier gate), OpenCodeZenExecutor (open-sse/executors/opencode-zen.js, ocz/*) only received the generateSessionId/translateSessionId counter update and still sent:

  1. OPENCODE_UA = "opencode/1.18.31" and v1 hasValidOpencodeVersion (>= 1.17)
  2. x-opencode-client: "desktop" and only x-opencode-session (omitting x-opencode-session-id, x-session-affinity, x-session-id, and x-opencode-project)
  3. Local ensureChatFingerprintTools / ensureResponsesFingerprintTools helpers injecting ["bash", "glob", "grep", "read"] with empty parameters: { type: "object", properties: {} }

Live Upstream Verification

Even when authenticated with a Zen API key on /zen/v1/*, upstream evaluates the free-tier gate on free models (ocz/space-bunny-free, ocz/mimo-v2.6-flash-free, ocz/muse-spark-1.3-contributor-free, ocz/big-pickle, and tests/translator/real/opencode-zen-free-responses.real.test.js) before validating the API key:

  • OpenCodeZenExecutor before this commit (opencode/1.18.31 + properties: {} stubs): HTTP 403 FreeTierError
  • OpenCodeZenExecutor with v2 headers + old properties: {} stubs: HTTP 403 FreeTierError
  • OpenCodeZenExecutor with v2 headers + applyFingerprintTools(out, flat) (read/shell verbatim schemas): passes the 403 FreeTierError gate completely.

Changes

  • open-sse/executors/opencode-zen.js:
    • Align OPENCODE_UA ("opencode/latest/2.0.26/cli"), OPENCODE_CLIENT ("cli"), and hasValidOpencodeVersion (v2 channel/version/client regex) with open-sse/executors/opencode.js.
    • Send mirrored session headers (x-opencode-session, x-opencode-session-id, x-session-affinity, x-session-id) and x-opencode-project in buildHeaders.
    • Replace duplicate ensureChatFingerprintTools / ensureResponsesFingerprintTools stubs with shared applyFingerprintTools(out, false) / applyFingerprintTools(out, true) from ../utils/opencodeFingerprint.js (including caller tool conflict aliasing and placeholder system/instructions note).
  • tests/unit/opencode-session.test.js:
    • Add unit tests verifying OpenCodeZenExecutor v2 headers and read/shell fingerprint application on Chat Completions and Responses requests.

Note: Built atop the #4842 commits (d8d0e04c, ccfb7838) so the top commit (cb825c7) cherry-picks cleanly onto local master.

Refs #4845, #4842, #4837, #4839

Copilot AI balanced review requested due to automatic review settings October 15, 2026 08:12

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Amir83Nasr added a commit to Amir83Nasr/10Router that referenced this pull request Oct 15, 2026
…/inference/v1

Upstream decolua#4860 (3 commits):
- d8d0e04 keep a valid counter in translated session ids to stop 403 FreeTierError
- ccfb783 move free tier to /inference/v1 with the v2 client fingerprint
- cb825c7 align free-tier v2 headers and read/shell fingerprint

Applied to local format: v2 UA opencode/latest/2.0.26/cli, verbatim
read/shell fingerprint via applyFingerprintTools (replaces bash/read
decoys), deterministic session prefix with counter 1, /inference/v1
routing, mirrored session headers without x-opencode-request.
Preserved local free-usage breaker, stable session pool and ocz
isResponsesModel; executor-const-guard adjusted to local retry policy.
@AFG473319

Copy link
Copy Markdown

Thanks for this ??? it fixed OpenCode Zen free-tier 403s for us too. ????

We've backported it into our fork (AFRouter), adapted to our diverged opencode-zen executor:

??? AFG473319/AFRouter#53

Notes from our reproduction, in case they're useful to you:

  • The original shape (opencode/1.18.31 UA, desktop, bash/glob/grep/read, no x-opencode-project, no session mirrors) returned 403 FreeTierError against https://opencode.ai/zen/v1/chat/completions for mimo-v2.6-flash-free ??? both with a keyed Bearer sk-??? and with Bearer public.
  • Adding x-opencode-project + the mirrored session headers to that same old body flipped it to 200 in our live probes, which is exactly the header change you made here.
  • One caveat for anyone re-testing: after a burst of probes the gate started answering 429 FreeUsageLimitError and then a blanket 403 FreeTierError for every shape (including this fix's fingerprint), so the limiter appears per-IP/abuse-based, not purely fingerprint-based.

Full credit to @ShayNeeo in our commit (Co-authored-by) and PR body. Thanks again! ????

AFG473319 added a commit to AFG473319/AFRouter that referenced this pull request Oct 15, 2026
…nce/v1 routing (#53)

Backport of decolua/9router PR #4860 by ShayNeeo, adapted to this fork.

OpenCode's free tier now answers the v1 client shape this fork still sent with
403 FreeTierError. Ports the upstream fix:

- opencodeFingerprint: OPENCODE_FINGERPRINT_TOOLS becomes the verbatim
  `read`/`shell` pair from the OpenCode v2.0.26 CLI; a caller tool that reuses an
  exact fingerprint name with a different definition travels under an alias (the
  response side restores the caller's name), and chat requests no longer default
  tool_choice to "none" (upstream answers that with 403).
- opencode-zen executor: v2 CLI UA (opencode/latest/2.0.26/cli), x-opencode-client
  "cli", x-opencode-project, mirrored session headers; free-tier models route to
  /inference/v1 with `Bearer public` and drop x-opencode-request.
- helpers: add isOpencodeFreeTierModel() (detects the "-free" suffix) instead of
  hardcoding a model list in the executor.
- tests: add the upstream free-tier test and update the fork's opencode tests to
  the read/shell fingerprint (this also repairs the previously failing
  opencode-free-tool-choice suite).

Verification (PR #53):
- Reproduced the 403 FreeTierError with this fork's previous executor; the v2
  header set is the shape the live gate accepted in our probes.
- CI: 0 new failures vs master, 7 fixed (the opencode-free-tool-choice suite).

Credits: original fix and live verification by ShayNeeo
(decolua/9router#4860).

Co-authored-by: ShayNeeo <phamquocthanh357@gmail.com>
andyvandaric added a commit to andyvandaric/9router that referenced this pull request Oct 17, 2026
… strategy in full

Problem: the fork ran an older fingerprint contract than upstream frontier on the keyed lane and lacked both proxy escape hatches from issue decolua#4983. opencode-zen still sent the v1 UA plus a stub bash/glob/grep/read quartet with empty schemas and the v1-only x-opencode-request header, the fingerprint helper could not satisfy the gate when a caller tool reuses read/shell with platform-specific wording, and proxyAwareFetch had no way out of an egress the gate had flagged.

Changes: port upstream PR decolua#4972 (in-place fingerprint normalization with alias fallback), decolua#4883 (UA opencode/latest/2.0.29/cli across both executors, registry and dashboard test; strict v2 channel matcher kept), decolua#4860 fingerprint/strategy for opencode-zen (verbatim read/shell via applyFingerprintTools, cli client, four session mirrors, drop x-opencode-request and x-api-key for free tier; /zen/v1 to /inference/v1 switch NOT taken), decolua#4987 (open-sse/utils/proxyDispatcher.js with opt-in socks5 dns=local, shared by proxyFetch and the dashboard proxy test, fail-closed ERR_PROXY_DNS_MODE) and decolua#4988 (replay a proxied 403 FreeTierError once on the direct egress, strictProxy contract preserved). undici ^7.19.2 to ^7.30.1. Version 0.5.108.

Verification: full suite re-derived on this machine from a git stash -u baseline - failure sets byte-identical (95 = 95, 0 new), passes 3592 to 3617. Targeted opencode/proxy/session groups 214 pass. undici 7.30.1 exposes Socks5ProxyAgent and createSocks5Connection; the local-DNS dispatcher is exercised end to end against a local SOCKS5 plus TLS fixture (11 cases). Root cause of the free-tier 403 is egress-IP load-shedding (decolua#4983), so these ports restore request truth and add escape hatches but cannot make a flagged egress succeed.

@luqman-v1 luqman-v1 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM: aligns OpenCode Zen free-tier v2 headers and read/shell tool fingerprint. Safe and clean.

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.

4 participants