Skip to content

feat: add OpenCode Zen as an API-key provider#1864

Merged
guillaumegay13 merged 7 commits into
mnfst:mainfrom
guillaumegay13:codex/opencode-zen-provider
Jun 1, 2026
Merged

feat: add OpenCode Zen as an API-key provider#1864
guillaumegay13 merged 7 commits into
mnfst:mainfrom
guillaumegay13:codex/opencode-zen-provider

Conversation

@guillaumegay13

@guillaumegay13 guillaumegay13 commented May 8, 2026

Copy link
Copy Markdown
Collaborator

✨ What changed

  • Register OpenCode Zen in the shared provider registry (alias opencodezen).
  • Discover models via Zen's /v1/models endpoint (Bearer auth, OpenAI-compatible JSON).
  • Proxy Claude / GPT / Qwen / GLM / Kimi / MiniMax / Big Pickle / Ling / Hy3 / Nemotron through /v1/chat/completions with Bearer auth.
  • Proxy Gemini through /v1/models/{id}:generateContent with x-goog-api-key (workaround, see below).
  • Frontend tile, light/dark icon, API-key signup URL.

💭 Why

OpenCode Zen aggregates 41 curated models behind a single key. Manifest needed first-class routing instead of users falling back to "custom provider".

👤 For users

Connect with an OpenCode Zen API key, get all 41 models discovered automatically, route any of them through Manifest's tier system.

📝 Notes — Gemini routing is a workaround

Zen documents a single-key, multi-protocol surface where Claude/GPT/etc. all work through the unified /v1/chat/completions. Gemini does not. Sending Authorization: Bearer <zen_key> to /v1/chat/completions with a Gemini model gets a 401 from Vertex AI itself: OVERLOADED_CREDENTIALS — API key for authentication is used with other authentication credentials. That error proves Zen's gateway is forwarding the client's Authorization header to Vertex AI on top of its own GCP credentials.

The workaround we ship: route Gemini to the dedicated /v1/models/{id}:generateContent path with Google's native x-goog-api-key header. That keeps the Zen key out of the Authorization slot, so it doesn't get forwarded.

Both code sites carry a TODO(opencode-zen) so we can collapse Gemini back onto the unified route once Zen stops tunneling the header through. Tracking this with the OpenCode team — closely related to closed issue #8228.

Tested end-to-end against a live Zen account: Claude Haiku 4.5, GPT 5.4 Nano, Qwen 3.6 Plus, GLM 5.1, and Gemini 3 Flash all return 200 + valid output through Manifest's /v1/chat/completions.


Summary by cubic

Adds OpenCode Zen as an API-key provider with automatic model discovery and first-class routing. Most models use the unified /v1/chat/completions (Bearer); Gemini uses /v1/models/{id}:generateContent (x-goog-api-key) due to an upstream header-forwarding issue.

  • New Features

    • Register opencode-zen (alias opencodezen) in the shared provider registry and UI.
    • Discover models from https://opencode.ai/zen/v1/models with Bearer auth.
    • Route Claude/GPT/Qwen/GLM/Kimi/MiniMax/etc. via /v1/chat/completions; route Gemini via /v1/models/{id}:generateContent with x-goog-api-key.
    • Add provider tile, light/dark icons, and API key signup link.
  • Bug Fixes

    • Namespace discovered model IDs as opencode-zen/<id> to prevent collisions with directly connected providers; the proxy strips the prefix before forwarding.

Written for commit ba8ed1c. Summary will update on new commits.

Review in cubic

Routes Claude models through Zen's native /v1/messages (x-api-key auth)
and everything else through OpenAI-compatible /v1/chat/completions
(Bearer auth). Models are discovered from the public /v1/models endpoint.
…ions

Live testing showed OpenCode Zen treats /v1/chat/completions as a single
OpenAI-compatible entrypoint that handles Claude, GPT, and the
OpenAI-compatible long tail (Qwen, GLM, Kimi, MiniMax, …) — no per-family
adapter is required. Drop the speculative opencode-zen-anthropic endpoint
and the model-prefix redirect in favor of one Bearer-auth route.

Gemini models on Zen still fail with GCP OVERLOADED_CREDENTIALS because
the Zen gateway forwards our Authorization header to Vertex AI on top of
its own credentials; that is a Zen-side bug with no client workaround
and is documented in the endpoint comment.
…dpoint

Live testing confirms Zen's Gemini path requires the upstream-native
combo: `/v1/models/{id}:generateContent` with `x-goog-api-key` auth.
Routing Gemini through the unified /v1/chat/completions hits a Zen
gateway bug that forwards the client's Authorization header to Vertex
AI, triggering GCP OVERLOADED_CREDENTIALS.

All 41 OpenCode Zen models now route end-to-end: Claude, GPT, Qwen,
GLM, Kimi, MiniMax, Big Pickle, etc. via /v1/chat/completions and
Gemini via /v1/models/{id}:generateContent.
Once OpenCode Zen stops tunneling the client Authorization header through
to Vertex AI, the dedicated Gemini route can be collapsed back into the
unified /v1/chat/completions path.
@codecov

codecov Bot commented May 8, 2026

Copy link
Copy Markdown

Bundle Report

Changes will increase total bundle size by 1.19kB (0.1%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
manifest-frontend-esm 1.16MB 1.19kB (0.1%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: manifest-frontend-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/index-*.css 115 bytes 203.62kB 0.06%
assets/ProviderSelectModal-*.js 42 bytes 132.46kB 0.03%
assets/index-*.js 207 bytes 59.51kB 0.35%
assets/routing-*.js 714 bytes 40.13kB 1.81%
assets/providers-*.js 114 bytes 6.97kB 1.66%

Files in assets/ProviderSelectModal-*.js:

  • ./src/services/provider-api-key-urls.ts → Total Size: 1.44kB

Files in assets/routing-*.js:

  • ./src/components/ProviderIcon.tsx → Total Size: 40.3kB

Files in assets/providers-*.js:

  • ./src/services/providers.ts → Total Size: 9.05kB

@codecov

codecov Bot commented May 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.48%. Comparing base (60db5bd) to head (ba8ed1c).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #1864   +/-   ##
=======================================
  Coverage   99.48%   99.48%           
=======================================
  Files         189      189           
  Lines       18121    18132   +11     
  Branches     7177     7180    +3     
=======================================
+ Hits        18028    18039   +11     
  Misses         91       91           
  Partials        2        2           
Flag Coverage Δ
frontend 99.52% <100.00%> (+<0.01%) ⬆️
shared 97.92% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@cubic-dev-ai cubic-dev-ai Bot 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.

No issues found across 17 files

Codex review caught that `parseOpenAI` returned bare IDs from Zen's
catalog (`gemini-3-flash`, `qwen3.6-plus`, `claude-opus-4-7`, …) but
`getModelsForAgent` deduplicates by `id + authType`. A user with both
OpenCode Zen and a directly-connected Google/Qwen/Anthropic provider
would silently lose one provider's model.

Mirrors the existing pattern from `parseCopilot` and the OpenCode Go
catalog: every Zen-discovered model is now prefixed `opencode-zen/`. The
proxy already strips vendor prefixes via `stripVendorPrefix` before
forwarding upstream, so the bare model id reaches Zen unchanged.
@guillaumegay13

Copy link
Copy Markdown
Collaborator Author

@brunobuddy tested locally, ready to be merged!

@guillaumegay13 guillaumegay13 requested a review from brunobuddy May 8, 2026 10:23
…provider

# Conflicts:
#	packages/backend/src/common/constants/providers.spec.ts
#	packages/backend/src/routing/proxy/__tests__/provider-endpoints.spec.ts
#	packages/backend/src/routing/proxy/provider-client.ts
#	packages/backend/src/routing/proxy/provider-endpoints.ts
#	packages/frontend/tests/services/providers.test.ts
#	packages/shared/src/provider-inference.ts
@guillaumegay13 guillaumegay13 merged commit 0dab16d into mnfst:main Jun 1, 2026
17 checks passed
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.

OpenCode Zen Gemini Integration - 500 Internal Server Error

1 participant