Skip to content

feat(models): add OpenCode Zen and OpenCode Go provider presets - #4764

Open
Ajax-1 wants to merge 1 commit into
Tencent:mainfrom
Ajax-1:feat/opencode-providers
Open

Ajax-1 wants to merge 1 commit into
Tencent:mainfrom
Ajax-1:feat/opencode-providers

Conversation

@Ajax-1

@Ajax-1 Ajax-1 commented Oct 26, 2026

Copy link
Copy Markdown

Description

Adds two built-in model provider presets, OpenCode Zen (opencode_zen, pay-as-you-go) and OpenCode Go (opencode_go, subscription), as proposed in #4703. Until now, operators had to pick the generic provider and hand-fill the base URLs.

Presets (internal/models/providers/opencode.go)

  • ModelTypes: KnowledgeQA only. Neither gateway documents an embedding, rerank, VLM or ASR endpoint.
  • Auth: Authorization: Bearer <OpenCode Console API key>, required.
  • Default base URLs: https://opencode.ai/inference/openai/v1 (Zen) and https://opencode.ai/inference/go/openai/v1 (Go).
  • Order 43/44, placed after the other gateways (OpenRouter, LiteLLM, Requesty). Both share one opencode.svg icon.

Protocol per model
OpenCode documents every model on exactly one route (Zen endpoints, Go endpoints). GPT, Grok and Muse models are served on /responses, so their entries in overrides.json set "api": "openai-responses". All other models stay on Chat Completions, which is also the fallback for ids not in the catalog. No new protocol code is needed.

Catalog (seed.json → models.generated.json)

  • Zen has 39 entries and Go has 22, taken from the endpoint tables. The tables only provide ids and routes. Context window, max output, reasoning and input modalities come from models.dev (opencode / opencode-go), which are now mapped in scripts/model-catalog/sources.json.
  • Excluded on purpose:
    • models that are only served on the Anthropic Messages, Google GenAI or SystemOne routes (Claude, Gemini, Qwen3.8 Flash, Qwen3.6 Plus and Qwen3.5 Plus on Zen, MiniMax M3 and the Qwen models on Go, Jev);
    • Zen's free tier (Big Pickle and the *-free ids), because the docs say "Free-tier chat models require OpenCode; use paid models or Go from other clients";
    • the models listed under "Deprecated models", plus Go's limited-time beam-free.

URL detection
Both presets live on opencode.ai. Zen matches opencode.ai. Go matches the longer opencode.ai/inference/go/, so the longest-pattern rule picks Go for its own path and Zen for everything else. The trailing slash matters: without it, Zen's /inference/google/v1beta route would be detected as Go. A test pins this case.

Design notes

  • Output cap: neither docs page names the field for the Chat Completions route, but the endpoint tables pair every /chat/completions model with @ai-sdk/openai-compatible, which sends max_tokens. Both presets therefore set max_tokens. This matches what these models already receive through the generic provider and what the deepseek / nvidia presets send, so switching a row from generic to a preset does not change the wire field. /responses models are unaffected (max_output_tokens).
  • No thinking switch is documented for the Chat Completions route, so no thinking fields are sent. Per-model thinking_levels like the ones OpenRouter/NVIDIA carry could follow once the gateway behaviour is confirmed.
  • The ids use underscores (opencode_zen / opencode_go) to match azure_openai and huggingface_tei. Happy to switch to the hyphenated ids suggested in the issue if you prefer.

Docs: the built-in vendor table and count in website-docs/03-features/06-models.md (30 → 32) now include both presets, with a short "OpenCode Zen / OpenCode Go" section. The count in 06-development/03-extension-points.md is updated too.

Type of Change

  • 🐛 Bug fix
  • ✨ New feature
  • 💥 Breaking change
  • 📚 Documentation update
  • 🎨 Refactor
  • ⚡ Performance improvement
  • 🧪 Test
  • 🔧 Configuration / Build / CI

Related Issue

Closes #4703

Testing

New tests:

  • internal/models/providers/opencode_test.go covers:
    • the preset shape: types, default URL, Bearer auth, key required;
    • URL detection for both gateways, including mixed-case hosts, full /chat/completions and /responses URLs, and Zen's /inference/google/ route;
    • the protocol for every catalog entry by rule: gpt- / grok- / muse- on Responses, the rest on Chat Completions with max_tokens. It also checks the exact row counts (Zen 39, Go 22) and that there are no free-tier, deprecated, Anthropic-only or Google-only ids. Removing a single Responses override (e.g. muse-wonder-1.0) or the max_tokens setting makes it fail.
  • internal/models/parity/opencode_test.go makes real HTTP calls against httptest and asserts:
    • the request path (…/openai/v1/chat/completions and …/openai/v1/responses, plus the same under /inference/go/);
    • the Authorization: Bearer header;
    • the output-cap field: max_tokens on Chat Completions and max_output_tokens on Responses, with no other cap field sent;
    • that the response parses without error.
  • TestLegacyProviderDetection gains the two default base URLs.
  • Updated: expectedIDs and the vendor count in providers_test.go, plus parity/testdata/catalog-baseline.json, which only gains entries for the 61 new models and leaves existing entries unchanged. The existing TestEveryChatModelRequestShape and TestEveryCatalogEntryResolves cover all 61 new entries.

Commands (Go 1.26.2, golangci-lint v2.12.2, as in CI):

git diff --check origin/main...HEAD                      # clean
gofmt -l $(git diff --name-only origin/main...HEAD -- '*.go')   # no output
python3 scripts/model-catalog/generate.py --check        # Verified 32 providers and 420 catalog rules
golangci-lint run --new-from-rev=origin/main ./...       # 0 issues
go test -count=1 ./internal/models/...                   # all packages ok
go vet $(go list ./... | grep -v /docreader/)            # ok
go test -tags desktop ./internal/container               # ok
go build ./cmd/server                                    # ok

I also ran the full go test $(go list ./... | grep -v /docreader/) on this branch and on a clean main checkout (22a331a). The same 9 packages (63 tests) fail on both, all of them environment-related: internal/agent/tools, internal/application/service, internal/application/service/file, internal/datasource, internal/datasource/connector/{notion,yuque}, internal/handler, internal/sandbox and internal/utils. The causes are a missing database, no Docker daemon and a 10-minute timeout in agent/tools. This change adds no new failures.

Checklist

  • git diff --check origin/main...HEAD passes
  • Changed source files are formatted
  • Targeted tests for the changed packages/components pass
  • Diff-scoped lint passes where applicable (for Go: golangci-lint run --new-from-rev=origin/main ./...)
  • Full-repository checks were run, or any unrelated/environment-dependent failures are documented above
  • Self-reviewed the code
  • Added/updated tests covering the change
  • Updated related documentation (README, website-docs/, Swagger annotations, etc.)
  • Breaking changes are clearly called out in the description above (none)

Screenshots / Recordings

No frontend change. The provider dropdown is built from GET /api/v1/models/providers, so both presets show up there automatically.

OpenCode Zen (pay-as-you-go) and OpenCode Go (subscription) are
OpenAI-compatible gateways authenticated with an OpenCode Console API
key. Operators could only reach them through the generic provider with
hand-filled base URLs and no protocol hint.

Add two KnowledgeQA-only presets, opencode_zen and opencode_go:

- default base URLs https://opencode.ai/inference/openai/v1 and
  https://opencode.ai/inference/go/openai/v1, Bearer auth, key required;
- catalogs built from the endpoint tables on opencode.ai/docs/zen and
  opencode.ai/docs/go: only models served under the OpenAI-compatible
  base, without Zen's free tier and deprecated ids. Metadata comes from
  models.dev (now mapped in sources.json);
- GPT, Grok and Muse models are documented on /responses, so their
  overrides set api=openai-responses; everything else stays on Chat
  Completions, which is also the default for ids not in the catalog;
- Chat Completions sends the output cap as max_tokens, the field the
  documented @ai-sdk/openai-compatible package sends and what these
  models already got through the generic provider;
- both live on opencode.ai, so URL detection keys Go on its
  "/inference/go/" segment and leaves every other opencode.ai address
  to Zen. The trailing slash keeps Zen's /inference/google/ route from
  matching Go.

Closes Tencent#4703
@Ajax-1
Ajax-1 force-pushed the feat/opencode-providers branch from b953c8e to 8a2937c Compare October 29, 2026 16:26

This branch has not been deployed

No deployments
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.

[Feature]: Add OpenCode Zen and OpenCode Go model provider presets

1 participant