Skip to content

[AISAGE-734] fix(gateway): exclude OpenCode Go models served only over the Gemini API - #7787

Merged
chrarnoldus merged 2 commits into
mainfrom
fix/opencode-go-exclude-gemini
Oct 16, 2026
Merged

chrarnoldus merged 2 commits into
mainfrom
fix/opencode-go-exclude-gemini

Conversation

@chrarnoldus

@chrarnoldus chrarnoldus commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Summary

OpenCode Go serves its Gemini models only over Google's native Gemini API. The gateway can only proxy chat_completions, messages and responses (GatewayChatApiKind), so we listed opencode-go/gemini-4-argon-contributor in the catalog even though every request to it failed.

The models.dev sync for direct BYOK providers now drops any model whose per-model provider.npm is a native Gemini API SDK (@ai-sdk/google or @ai-sdk/google-vertex). All other models are kept.

Evidence

models.dev (https://models.dev/api.json, provider opencode-go, fetched 2026-10-16):

  • Provider default: npm: "@ai-sdk/openai-compatible", api: "https://opencode.ai/inference/go/openai/v1".
  • gemini-4-argon-contributor: provider: { npm: "@ai-sdk/google", api: "https://opencode.ai/inference/go/google/v1beta" }.
  • Every other per-model override uses @ai-sdk/anthropic (minimax, qwen) or @ai-sdk/openai (gpt, grok, muse), or overrides only api.
  • https://opencode.ai/zen/go/v1/models lists gemini-4-argon-contributor, so the available-models check doesn't filter it out. The SDK field is the only thing in the data that marks it as unusable.

Production: the Axiom vercel dataset shows ModelProtocolUnsupported ("Model does not support this protocol.") errors from OpenCode Go for opencode-go/gemini-4-argon-contributor on /api/v1/chat/completions.

Why a Gemini SDK denylist, not a model-ID filter or an SDK allowlist

  • Not a model-ID filter: the SDK field describes the real constraint, a protocol we can't proxy. It covers future Gemini models whatever their name. It also keeps a Gemini model that is later served over an OpenAI-compatible endpoint.
  • Not an allowlist: the first version of this PR kept only @ai-sdk/openai-compatible, @ai-sdk/openai and @ai-sdk/anthropic. That would wrongly hide working models, because several SDK names still speak Chat Completions. Per-model overrides found across all of models.dev:
    • opencode (OpenCode Zen) has a model with npm: "@ai-sdk/mistral" on https://opencode.ai/inference/openai/v1, its OpenAI-compatible endpoint.
    • standardcompute has a model with npm: "@openrouter/ai-sdk-provider".
    • Provider defaults include more Chat Completions-compatible SDKs, such as @ai-sdk/xai, @ai-sdk/groq, @ai-sdk/deepinfra, @ai-sdk/togetherai and @ai-sdk/cerebras.
  • Failure mode: an unknown native SDK still gets listed, which is how things work today. A Chat Completions-compatible model is never silently hidden.
  • Scope: the filter applies to every models.dev-backed provider, which is safe. None of nvidia, alibaba-token-plan, edenai, zai-coding-plan, ollama-cloud, xiaomi-token-plan-ams or xiaomi-token-plan-sgp has per-model provider overrides. In the current catalog the filter removes exactly one model: opencode-go/gemini-4-argon-contributor.
  • Malformed data: the schema field uses .catch(undefined). If the field is malformed, the model is kept.

Already-synced data

No schema change is needed. syncDirectByokModels runs from /api/cron/sync-providers every 5 minutes, and each successful sync fully replaces the provider's direct_byok_model_lists row with onConflictDoUpdate. The first sync after deploy removes the stale Gemini entry. After that, gateway instances stop serving it once their 10-minute cachedEnhancedDirectByokModelList cache expires. A new DB test seeds a stale opencode-go row that contains the Gemini model and checks that a re-sync removes it.

Request behaviour after the change

getDirectByokModel no longer resolves opencode-go/gemini-4-argon-contributor, so the gateway doesn't send it to OpenCode Go. A user with credits gets the gateway's own 404 model_not_found ("The requested model '…' does not exist…") with no upstream call. A personal account or organization with a zero balance hits the credits check before that 404. This is existing behaviour for any model that drops out of a direct BYOK list, and this PR doesn't change it.

Verification

  • jest src/lib/providers/direct-byok/sync-direct-byok.test.ts ../../packages/web-shared/src/lib/ai-gateway/providers/direct-byok (from apps/web, NODE_ENV=test): 8 suites, 87 tests passed.
  • Against main's sync-direct-byok.ts, the 2 new tests fail. Against the earlier allowlist version, the parse test fails because the @ai-sdk/mistral and @openrouter/ai-sdk-provider models are dropped. With this change, both tests pass.
  • pnpm --filter web typecheck: passed.
  • pnpm --filter @kilocode/web-shared typecheck: passed. The package isn't changed; this was run as a sanity check.
  • pnpm exec oxlint --config .oxlintrc.json on both changed files: 0 warnings, 0 errors.
  • pnpm exec oxfmt on both changed files, then git diff --check: clean.

@chrarnoldus chrarnoldus self-assigned this Oct 16, 2026
@kilo-code-bot

kilo-code-bot Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental change replaces the SDK allowlist in parseModelsDevProviderModels with a native-Gemini denylist (@ai-sdk/google, @ai-sdk/google-vertex); the updated filter, the .catch(undefined) schema hardening, and the revised test assertions are correct and consistent with the changed code, and I found no new issues.

Overview

Incremental review at commit 57ec27850f9f319ba4f19de772bb5de6ea8fdc1e (since e270c5ff). The denylist keeps Chat Completions-compatible SDKs such as @ai-sdk/mistral and @openrouter/ai-sdk-provider (verified by the updated test) while excluding the per-model Gemini overrides that the gateway cannot proxy. The new test inputs cover both a model that must be excluded (vertex-gemini) and aliases that must be kept.

Notes (non-blocking, not inline findings):

  • Switching from an allowlist to a denylist means native SDKs other than Gemini (e.g. @ai-sdk/amazon-bedrock) are no longer excluded. No current modelsDevFetcher provider has such a per-model override in the models.dev catalog, so this does not affect live behavior today; a future non-Gemini native-API provider would need a matching entry in GEMINI_API_MODELS_DEV_SDKS.
  • The filter inspects only the per-model provider.npm override, not the provider-level default. This matches the current FETCHERS set and is documented in the PR.
Files Reviewed (2 files)
  • apps/web/src/lib/providers/direct-byok/sync-direct-byok.ts
  • apps/web/src/lib/providers/direct-byok/sync-direct-byok.test.ts
Previous Review Summary (commit e270c5f)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit e270c5f)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The change adds a provider.npm SDK filter to parseModelsDevProviderModels, excluding models the gateway cannot proxy (e.g. OpenCode Go's Gemini); the logic, schema hardening via .catch(undefined), and added tests are correct and I found no issues in the changed code.

Files Reviewed (2 files)
  • apps/web/src/lib/providers/direct-byok/sync-direct-byok.ts
  • apps/web/src/lib/providers/direct-byok/sync-direct-byok.test.ts

Notes (non-blocking, not inline findings):

  • The new filter only inspects the per-model provider.npm override, not the provider-level default. This is safe for the current FETCHERS set as documented in the PR, but any future modelsDevFetcher whose provider default is a non-proxyable SDK (e.g. @ai-sdk/google, @ai-sdk/amazon-bedrock) would keep its models. Consider a provider-level default check if such a provider is added.
  • Allowed set (@ai-sdk/openai-compatible, @ai-sdk/openai, @ai-sdk/anthropic) matches the gateway's GatewayChatApiKind protocols and opencode-go's declared supported_chat_apis; @ai-sdk/amazon-bedrock is correctly excluded.

Reviewed by deepseek-v4.1-flash · Input: 36.8K · Output: 5.4K · Cached: 276.5K

Review guidance: REVIEW.md from base branch main

@joshburt
joshburt self-requested a review October 16, 2026 19:15
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.

2 participants