Repository navigation
fix(opencode): follow the published endpoint and the client's own headers - #16608
maxmad64bis wants to merge 1 commit into
Conversation
130c9ca to
7712656
Compare
|
If anyone wants to test it, please do. Feedback is welcome! |
|
Live installation validated: the agent→gateway bridge works — sustained 200s with real token throughput Environment: self-hosted OmniRoute on Windows, built from the What works
What still refuses (expected — upstream gate by design)
Field notes for reviewers
|
|
Thanks a lot for the live test and the screenshot — that's the working control this needed. On your points
What changed in this push (rebased on the current release, still one commit)
|
f1086d4 to
e85072e
Compare
e85072e to
05fd368
Compare
05fd368 to
e769f96
Compare
e769f96 to
8aefe8e
Compare
8aefe8e to
45cb935
Compare
c1ba17b to
cd0cb10
Compare
cd0cb10 to
9c94197
Compare
…ders Keyless requests went to the pinned zen/v1 and got 403, and tools added on a retry carried an empty schema the upstream refuses; the endpoint now follows the published catalog, the OpenCode client's requests and headers go out as it sent them, and each new case fails without the change (replaces the earlier head 7712656).
9c94197 to
990c410
Compare
…hout cheaper-inference#16608's endpoint module The cherry-picked surface map was filled by opencodePublishedEndpoint.ts, which belongs to cheaper-inference#16608 (on hold) and is not on the release tip. The catalog module now owns one coalesced in-memory read of models.opencode.ai/api.json (6 h TTL, 30 s attempt floor, 5 s timeout, test-runner guard, no node: imports), and answers only through a gate the executor registers (fail closed when absent or throwing). The mappings for the removed keyless OpenCode Free provider (opencode / oc) are dropped; Zen and Go keep their catalog sections.
…ed catalog declares (#16798) Merged via /merge-batch (2026-10-18, uplift round). Thanks @maxmad64bis for the idea and the original implementation (commit by Dizzle, carried with authorship as 2637fc7)! This PR was stacked on #16608 (on HOLD: the keyless OpenCode Free path it restored was removed in #16310), so the branch was re-cut standalone off release/v3.8.52 with owner approval (force-push with lease): only this PR's own commit was cherry-picked, without #16608's endpoint module. Maintainer rework on top: - refactor(opencode): read the published model surfaces standalone (in-memory, 6 h cache, 30 s attempt floor, 5 s timeout, never throws, no src/ imports) - feat(flags): add OPENCODE_PUBLISHED_CATALOG_ROUTING_ENABLED (default off) - fix(opencode): gate the published-catalog surface lookup on that flag — with it off, getModelTargetFormat returns exactly the tip's answer and the catalog is never fetched Evidence: validated on the combined board of the 34 reworked PRs, then on the current tip: focused tests 85/85 (opencode-model-surface-from-catalog 13/13 + flag registry), typecheck core/open-sse, boundary 774/774, cognitive-complexity within baseline, changelog-integrity, skills-sync Generated 0. Remaining CI reds are the inherited base-red #15306.
|
Thanks @maxmad64bis! Holding this one. We merged the current
If the authenticated Zen and Go paths still need the published base URL or the client header passthrough, a reworked PR would help. It should cover only keyed requests, reuse |
|
Re-homed to |
|
Thank you for the thorough work and the live-test notes on this one. Since you opened it the OpenCode area has changed a lot on release/v3.8.53: the keyless OpenCode Free provider (opencode/oc) was removed in #16310 at the project owner's decision, the keyed free tier now goes to /inference/v1 with non-empty placeholder schemas (#16826), the v2 client fingerprint and tool contracts were ported (#16998), and published-catalog routing for key-based models landed in #16798. As a result this branch is now 253 commits behind and conflicts in opencode.ts, opencodeFreeTierContract.ts, opencodeHeaders.ts and the 12633 test, and the 'Bearer public on keyless requests' part would re-open what #16310 removed, so that needs an owner decision before anything else. If you still see a gap after those changes (published base-URL discovery for opencode-zen, or forwarding the client's own x-opencode-* headers), please open a fresh, narrow PR on the current tip with just that; from the earlier review, please also key the tool-schema memory per provider+session, route the catalog read through the proxy-aware fetch, and paste the 2026-10-14 measurement outputs into the body. I am holding this one rather than closing it so nothing is lost. |
|
Closing without merge, per the maintainer's guidance in the review above. The keyless Thanks for the detailed review and for resolving the conflicts. |

Summary
Default changed:
opencodeandopencode-zentake their base URL from theapifield of the model catalog the OpenCode client reads (nowhttps://opencode.ai/inference/v1, where the pinnedzen/v1answers keyless requests with a 403), and a base URL set on the connection takes effect for them.Requests from the OpenCode client go out with its own
x-opencode-*headers and tool list as written, withBearer publicwhen there's no key, and a tool added on a shape retry carries the parameter schema the client last sent for it, since the upstream refuses a client tool name declared with an empty schema.This restores the OpenCode client → OmniRoute → free model path, confirmed live on two free models with the client's headers; calls that don't carry the client's identity still get the 403.
Related Issues
Target Branch
release/v3.8.xbranch (the highest openrelease/v*), notmainv4-featurelabel for the v4 channelValidation
npm run lintTests Added Or Updated
tests/unit/opencode-published-endpoint.test.ts(29 cases): URL order and fallbacks, rejected catalog values, cold start, a catalog that stays down, header forwarding, auth forms; catalog and upstream stubbed.tests/unit/opencode-client-request-shape.test.ts(8 cases): client requests sent as written, replay and its memory, borrowed schemas, bounded schema table, other clients unchanged; the stub applies the refusals measured on 2026-10-14.x-opencode-requestandBeareron keyed Responses; two placeholder-schema assertions changed.Coverage Notes
open-sse/utils/opencodePublishedEndpoint.ts,open-sse/executors/opencode.ts:opencode-published-endpointandopencode-executor.open-sse/utils/opencodeClient.ts:opencode-client-request-shape,opencode-free-tier-request-contract,opencode-request-shape-retry.open-sse/utils/opencodeHeaders.ts,open-sse/handlers/chatCore/requestFormat.ts:refactor-opencodeHeaders,opencode-native-session-identityand the suites above.Reviewer Notes
FreeTierError), the last value saved underDATA_DIR/cache, then the registry. A cold start waits for one catalog read (5 s at most, once per 30 s when the catalog is down). The replay only follows a refusal and is remembered per prompt, so it doesn't add a round trip to every request. Live check: with this build behind a local gateway, the OpenCode 2.0.29 CLI got 200 fromoc/andopencode-zenfor two free models, with and without an explicit title, from a cold start with no saved URL; no 403 in the call log.opencode.ts, and with fix(providers): remove OpenCode Free while preserving Zen and Go #16310 (on hold), which deletesopencodeFreeTierContract.ts; I'll rebase on whichever lands first.