Skip to content

Reproduction: model alias mismatch with OpenCode Go (related to #526) #541

Description

@sathwick-p

Summary

This is a concrete reproduction of the issue described in #526 — model ID mismatch when using a custom OpenAI-compatible upstream (OpenCode Go) via OPENROUTER_BASE_URL.

The router sends slash-form model IDs (deepseek/deepseek-v4-flash) in the request body, but OpenCode Go expects bare names (deepseek-v4-flash). There is no env-var mechanism to remap model names at runtime.

Steps to reproduce

1. Start the router

docker compose up -d

2. Point OpenRouter at OpenCode Go

Add to .env (docker compose auto-reads this):

OPENROUTER_API_KEY=sk-your-opencode-go-key
OPENROUTER_BASE_URL=https://opencode.ai/zen/go/v1

Then recreate:

docker compose up -d --force-recreate router-server

3. Create a router API key

Login at http://localhost:8080/ui/login (password: admin), then create a key via Settings → API Keys.

4. Send a test request

curl -s -N "http://localhost:8080/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -H "x-api-key: rk_YOUR_KEY" \
  -d '{"model":"deepseek/deepseek-v4-flash","messages":[{"role":"user","content":"say hello in one word"}]}'

5. Actual result

{"type":"error","error":{"type":"ModelError","message":"Model deepseek/deepseek-v4-pro is not supported"}}

The error format ({"type":"error",...}) confirms the request reached OpenCode Go. It was rejected because the model name sent was the router's public slash-form name instead of OpenCode Go's bare name.

Root cause analysis

The OpenRouter client (openaicompat.Client) sends the body's "model" field verbatim — no modelIDMap rewriting happens for OpenRouter:

Provider Has modelIDMap? Constructor in main.go
OpenRouter No (public slug = upstream ID) NewClient(key, url)
DeepInfra Yes NewClientWithModelIDMap(key, url, upstreamIDsForProvider("deepinfra"))
Fireworks Yes NewClientWithModelIDMap(key, url, upstreamIDsForProvider("fireworks"))
Bedrock Yes NewClientWithModelIDMap(key, url, upstreamIDsForProvider("bedrock"))

The modelIDMap rewrites the body's "model" field at request time in rewriteModelField() (internal/providers/openaicompat/client.go:119). For OpenRouter this is a no-op because the map is nil.

OpenCode Go's /v1/models returns bare names (deepseek-v4-flash, deepseek-v4-pro, kimi-k2.6, etc.) but the router catalog uses slash-form IDs (deepseek/deepseek-v4-flash, moonshotai/kimi-k2.6, z-ai/glm-5.2, etc.).

The existing rewriteModelField infrastructure is correct — it just needs an env-var hook so self-hosters can supply runtime mappings.

Proposed fix direction

An env var (e.g. ROUTER_MODEL_ID_MAP) — comma-separated from=to pairs — parsed at boot and merged into the OpenRouter client's modelIDMap. Example:

ROUTER_MODEL_ID_MAP="deepseek/deepseek-v4-flash=deepseek-v4-flash,deepseek/deepseek-v4-pro=deepseek-v4-pro,moonshotai/kimi-k2.6=kimi-k2.6,xiaomi/mimo-v2.5-pro=mimo-v2.5-pro,z-ai/glm-5.2=glm-5.2"

Environment

  • Router: main branch, docker compose stack
  • Upstream: OpenCode Go (https://opencode.ai/zen/go/v1)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions