Skip to content

feat: add OpenCode Go and OpenCode Zen provider support#3211

Open
jopsis wants to merge 3 commits into
docker:mainfrom
jopsis:feat/opencode-providers
Open

feat: add OpenCode Go and OpenCode Zen provider support#3211
jopsis wants to merge 3 commits into
docker:mainfrom
jopsis:feat/opencode-providers

Conversation

@jopsis

@jopsis jopsis commented Jun 23, 2026

Copy link
Copy Markdown

Summary

Add built-in alias support and full documentation for OpenCode Go and OpenCode Zen — the two subscription plans offered by OpenCode.

OpenCode Go (opencode-go)

  • Low-cost subscription ($10/mo) for open-source coding models
  • OpenAI-compatible endpoint at https://opencode.ai/zen/go/v1
  • Covers models: DeepSeek, GLM, Kimi, MiMo, HY3, MiniMax, Qwen
  • Anthropic-compatible models (MiniMax, Qwen) via custom provider config

OpenCode Zen (opencode-zen)

  • Pay-per-use curated gateway for premium + open-source models
  • OpenAI-compatible endpoint at https://opencode.ai/zen/v1
  • Covers models: GPT-5.x, Claude, Gemini, DeepSeek, GLM, Kimi, Grok, MiniMax, Qwen
  • Includes 7 free models (deepseek-v4-flash-free, mimo-v2.5-free, etc.)
  • Anthropic and Google models via custom provider config

Both share the OPENCODE_API_KEY environment variable — the same API key works for both services.

Technical Changes

File Change
pkg/model/provider/aliases.go Register opencode-go and opencode-zen aliases
pkg/config/auto.go Add default models for both providers
cmd/root/models.go Add live API fetch from provider /v1/models endpoint when models.dev has no entry
pkg/config/examples_test.go Skip opencode-zen in models.dev validation
docs/providers/opencode-go/index.md Full documentation page for Go
docs/providers/opencode-zen/index.md Full documentation page for Zen
docs/providers/overview/index.md Add both to built-in aliases table
docs/_data/nav.yml Add both to navigation sidebar
examples/opencode-go.yaml Basic Go usage example
examples/opencode-go-practical.yaml Practical Go example with commands
examples/opencode-zen.yaml Zen example with free model
.gitignore Add graphify-out/

Usage

export OPENCODE_API_KEY="your-api-key"
docker agent run examples/opencode-go.yaml
docker agent run examples/opencode-zen.yaml

Add built-in alias and documentation for both OpenCode subscription plans:

OpenCode Go (opencode-go):
- Low-cost subscription for open-source coding models
- OpenAI-compatible endpoint at https://opencode.ai/zen/go/v1
- Anthropic-compatible models via custom provider config

OpenCode Zen (opencode-zen):
- Pay-per-use curated gateway for premium + open-source models
- OpenAI-compatible endpoint at https://opencode.ai/zen/v1
- Covers GPT-5.x, Claude, Gemini, DeepSeek, GLM, Kimi, Grok
- Includes 7 free models
- Anthropic and Google models via custom provider config

Both share the OPENCODE_API_KEY environment variable.

Technical changes:
- pkg/model/provider/aliases.go: register opencode-go and opencode-zen
- pkg/config/auto.go: add default models for both providers
- cmd/root/models.go: add live fetch from provider /v1/models endpoint
  when models.dev has no entry
- pkg/config/examples_test.go: skip opencode-zen in models.dev validation
- docs/: full provider docs pages, nav entry, overview update
- examples/: usage examples for both providers
- .gitignore: add graphify-out/
@jopsis jopsis requested a review from a team as a code owner June 23, 2026 10:59
@aheritier aheritier added area/docs Documentation changes area/providers For features/issues/fixes related to LLM providers (Bedrock, LiteLLM, Qwen, custom, etc.) kind/feat PR adds a new feature (maps to feat:). Use on PRs only. labels Jun 23, 2026
@dgageot

dgageot commented Jun 25, 2026

Copy link
Copy Markdown
Member

Review summary — requesting changes

The provider aliases look good, but the new live model-fetching in models needs work.

Blocking

  1. fetchProviderModels uses http.DefaultClient — no timeout, so docker agent models can hang forever. Use &http.Client{Timeout: 30*time.Second, Transport: remote.NewTransport(ctx)} and build requests with http.NewRequestWithContext(ctx, ...).
  2. models list now does live network I/O — it used to be side-effect-free; --all may now contact unconfigured providers. Make it opt-in (e.g. --fetch-live) or limit to an explicit --provider, and document/timeout it.
  3. OpenCode Zen base_url looks wrong — points at a /v1/models listing endpoint, which yields malformed paths like .../v1/models/chat/completions. Use https://opencode.ai/zen (or /zen/v1); keep /v1/models internal to listing.
  4. Missing tests for fetch/merge — cover success, non-200, malformed JSON, empty body, duplicate IDs, deterministic merge, context cancellation, and provider filters. Inject *http.Client/URL to make it testable.

Non-blocking
5. Example test skip logic is fragile (depends on models.dev contents) — centralize the list of built-in providers expected to be absent.
6. Verify the Responses API auto-detection claim for the aliased URLs.
7. Split the unrelated .gitignore change (/graphify-out/) into its own commit.

Positives: aliases follow existing conventions, default-models fallback is the right behavior, response bodies closed correctly, frozen config versions untouched.

- cmd/root/models.go: use &http.Client{Timeout: 30s, Transport: remote.NewTransport}
  instead of http.DefaultClient in fetchProviderModels. Extract fetchModelsFromURL
  for testability. Only trigger live model fetch when --provider is explicitly set
  (models list --all remains side-effect-free).
- cmd/root/models_test.go: add 10 unit tests for fetchModelsFromURL covering
  success, non-200, malformed JSON, empty body, empty data array, duplicate IDs,
  empty IDs, context cancellation, and embedding models.
- pkg/config/examples_test.go: centralize providers absent from models.dev in
  modelsDevAbsentProviders map instead of hardcoding per-line.
- pkg/model/provider/openai/client.go: add opencode-go and opencode-zen to
  autoSelectsResponsesAPI so GPT models on Zen correctly route to Responses API.
- .gitignore: revert unrelated graphify-out/ change (will land separately).
@jopsis

jopsis commented Jun 25, 2026

Copy link
Copy Markdown
Author

Addressed all review points

Thanks @dgageot for the thorough review! All points addressed:

1. http.DefaultClient&http.Client{Timeout: 30s, Transport: remote.NewTransport(ctx)}

fetchModelsFromURL now uses a properly configured client with 30s timeout and the same transport used by models.dev fetches.

2. Side-effect-free models list

Live model fetching only triggers when the user explicitly specifies --provider:

  • models list --all → no network calls (only models.dev + defaults)
  • models list --all --provider opencode-zen → fetches from /v1/models endpoint

3. Base URL concern ✅

Verified that the SDK's WithBaseURL automatically ensures a trailing / on the path, so URL resolution is correct:

WithBaseURL("https://opencode.ai/zen/v1")
→ internally sets Path: "/zen/v1/"
→ + path "chat/completions"
→ "/zen/v1/chat/completions" ✓

The /v1/models endpoint is fetched separately in fetchProviderModels by appending /models — it does not reuse the base URL as an API endpoint.

4. Tests ✅

10 unit tests added for fetchModelsFromURL covering:

  • Success, non-200 (404, 500), malformed JSON, empty body, empty data array
  • Duplicate IDs, empty IDs, context cancellation, embedding model passthrough

5. Centralized absent providers list ✅

modelsDevAbsentProviders map centralizes which providers are expected to be absent from models.dev, replacing the fragile inline hardcode.

6. Responses API auto-detection ✅

Added opencode-go and opencode-zen to autoSelectsResponsesAPI so GPT models (gpt-5.x) correctly route to the Responses API when using Zen.

7. .gitignore split ✅

Reverted the graphify-out/ change — will land in a separate PR.

@dgageot

dgageot commented Jun 26, 2026

Copy link
Copy Markdown
Member

/review

@github-actions

Copy link
Copy Markdown
Contributor

👋 Heads up: The /review command is deprecated. Please re-request a review from docker-agent in the PR sidebar instead.

@docker-agent docker-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Assessment: 🟡 NEEDS ATTENTION

2 medium-severity findings introduced by this PR — both require attention before merging.

Comment thread pkg/model/provider/openai/client.go Outdated
func autoSelectsResponsesAPI(provider string) bool {
switch provider {
case "openai", "github-copilot":
case "openai", "github-copilot", "opencode-go", "opencode-zen":

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[MEDIUM] opencode providers added to autoSelectsResponsesAPI but likely don't support the OpenAI Responses API

autoSelectsResponsesAPI now returns true for opencode-go and opencode-zen. This means that if a user configures one of these providers with a model whose name matches modelinfo.SupportsResponsesAPI (e.g. gpt-5, o3, gpt-4.1-mini), the client will route the request to the OpenAI Responses API endpoint (/responses) instead of /chat/completions.

OpenCode is a third-party proxy, not a direct OpenAI service. The Responses API (/v1/responses) is an OpenAI-specific surface that third-party proxies almost never implement. Sending a request there would result in a confusing 404 or 501 error with no fallback.

The comment above autoSelectsResponsesAPI makes this risk explicit: it was added specifically for GitHub Copilot, which requires the Responses API for newer OpenAI models and explicitly rejects them on /chat/completions. OpenCode doesn't have that requirement — the correct path for OpenCode is always /chat/completions.

Suggested fix: Remove opencode-go and opencode-zen from autoSelectsResponsesAPI unless OpenCode has confirmed Responses API support:

case "openai", "github-copilot":
    return true

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

[RESOLVED] opencode-go removed, opencode-zen kept with documentation evidence

Addressed in commit 0b1408d:

  • opencode-go removed — correct observation: Go only has open-source models, none match SupportsResponsesAPI (gpt-4.1+, gpt-5+, codex+, o-series). Always routes to /chat/completions.

  • opencode-zen kept — Zen explicitly documents the /v1/responses endpoint. See:

    Users calling GPT models through Zen without this flag would get a 400 error from Zen's /chat/completions — identical to the GitHub Copilot case the flag was designed for.

Comment thread pkg/config/auto.go
"dmr": "ai/qwen3:latest",
"mistral": "mistral-small-latest",
"amazon-bedrock": "global.anthropic.claude-sonnet-4-5-20250929-v1:0",
"opencode-go": "deepseek-v4-flash",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[MEDIUM] opencode-go and opencode-zen missing from cloudProvidersOPENCODE_API_KEY is never detected

DefaultModels includes entries for these two providers, but neither is listed in cloudProviders. As a result:

  1. AvailableProviders never includes them — even when OPENCODE_API_KEY is set, availableProviders["opencode-go"] and availableProviders["opencode-zen"] are always false.
  2. AutoModelConfig never auto-selects them — a user with only OPENCODE_API_KEY set will get no model auto-selected (falling through to the DMR fallback).
  3. docker agent models never shows them — without --all or --provider opencode-go, the default models from DefaultModels are filtered out because availableProviders[prov] is false.

This means the PR's user-facing workflow (export OPENCODE_API_KEY="…") works only if the user also explicitly sets --model opencode-go/… or uses --all. The key being set but having no effect is a confusing user experience.

Suggested fix: Add both providers to cloudProviders:

{"opencode-go",  []string{"OPENCODE_API_KEY"}, "OPENCODE_API_KEY"},
{"opencode-zen", []string{"OPENCODE_API_KEY"}, "OPENCODE_API_KEY"},

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

[RESOLVED] Both providers added to cloudProviders in commit 0b1408d

  • Added opencode-zen and opencode-go to cloudProviders in pkg/config/auto.go
  • Both use OPENCODE_API_KEY env var (single key for both services)
  • opencode-zen listed first (higher priority) so it auto-selects when only OPENCODE_API_KEY is set
  • Tests updated to verify:
    • DefaultModels includes both providers
    • AvailableProviders returns both when OPENCODE_API_KEY is set
    • opencode-zen wins auto-selection over opencode-go (priority ordering)

…_API_KEY detection

- Remove opencode-go from autoSelectsResponsesAPI (Go has no GPT models)
- Keep opencode-zen in autoSelectsResponsesAPI (Zen documents /v1/responses)
- Add both providers to cloudProviders so OPENCODE_API_KEY is auto-detected
- opencode-zen has higher priority than opencode-go in cloudProviders
- Update tests for DefaultModels, integration, and precedence ordering
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/docs Documentation changes area/providers For features/issues/fixes related to LLM providers (Bedrock, LiteLLM, Qwen, custom, etc.) kind/feat PR adds a new feature (maps to feat:). Use on PRs only.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants