Skip to content

Repository files navigation

OpenCode Go Router

npm

Local OpenAI-compatible proxy for OpenCode Go. OpenCode uses one model id — go-router/auto — and this router picks the real upstream model per request (task type, complexity, risk, quota, optional semantic second stage).

Repository: https://github.com/shashankanil/opencode-go-router


How it works

flowchart LR
  OC[OpenCode client] -->|POST /v1/chat/completions model=auto| R[Router :8787]
  R --> C[classify_request]
  C --> D[choose_model / resolve_routing_decision]
  D -->|optional cheap LLM| A[routing agent]
  D --> U[OpenCode Go upstream]
  R --> L[JSONL decision log]
Loading
  1. OpenCode sends chat requests to http://127.0.0.1:8787/v1 with model: "auto" (provider go-router).
  2. Classifier reads the latest user message (and paths in the text): task type (e.g. documentation, debugging, ui_frontend), complexity, risk, token estimate, @overrides.
  3. Deterministic routing maps task → default model from config/router.yaml, then applies policy (repo-wide → strong model, high/dangerous risk → strong model, quota downgrade on unprotected routes).
  4. Optional semantic routing (routing_mode: hybrid | semantic | agent + routing_agent.enabled): a cheap upstream model returns JSON with a suggested model; Python gates it (valid model id, risk floor, quota). Default is deterministicno extra LLM call.
  5. Upstream request is forwarded to OPENCODE_GO_BASE_URL with the chosen literal model id (never auto). Streaming is preserved.
  6. Response headers include x-router-model, x-router-task, x-router-complexity, x-router-risk (and agent skip metadata when relevant).
  7. Decisions append to ROUTER_LOG_PATH (default logs/router-decisions.jsonl or ~/.opencode-go-router/router-decisions.jsonl via npx).

This is not oh-my-openagent / Sisyphus — a small standalone router you run beside OpenCode.


Quick start (npx — recommended)

Requirements: Node 18+, uv (Python 3.11+). The launcher uses uv run --project only — it does not pip install into your user site-packages.

# One-time templates in your project directory
npx opencode-go-router init

# Set upstream key (OpenCode Go)
export OPENCODE_GO_API_KEY="your-key"
export ROUTER_API_KEY="local-router-key"   # optional; must match OpenCode provider apiKey

# Run server (first run may sync deps via uv)
npx opencode-go-router

Config and logs for npx default to ~/.opencode-go-router/ (router.yaml, router-decisions.jsonl). Override with ROUTER_CONFIG_PATH / ROUTER_LOG_PATH.

OpenCode configuration

Copy or merge opencode.example.jsonc into your OpenCode config:

{
  "provider": {
    "go-router": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "OpenCode Go Router",
      "options": {
        "baseURL": "http://127.0.0.1:8787/v1",
        "apiKey": "local-router-key"
      },
      "models": {
        "auto": { "name": "Auto Router" }
      }
    }
  },
  "model": "go-router/auto",
  "small_model": "go-router/auto"
}

Use the same apiKey as ROUTER_API_KEY when the router enforces auth.


Quick start (clone / dev)

git clone https://github.com/shashankanil/opencode-go-router.git
cd opencode-go-router
cp .env.example .env   # set OPENCODE_GO_API_KEY

uv sync --extra dev
export $(grep -v '^#' .env | xargs)
uv run python -m router.main
# or: uv run opencode-go-router

Point OpenCode at http://127.0.0.1:8787/v1 as above.

Console UI

export ROUTER_API_KEY=local-router-key
uv run python -m router.main

Open http://127.0.0.1:8787/console. Rebuild SPA after frontend changes:

cd console && npm install && npm run build

Without console/dist, the server serves console/stub.html.


Endpoints

Method Path Description
GET /health Liveness
GET /v1/models Lists auto
POST /v1/chat/completions OpenAI-compatible chat (streaming supported)
GET /console Admin UI
POST /api/admin/classify Deterministic classify + route (Bearer ROUTER_API_KEY)
POST /api/admin/route-preview Deterministic + agent eligibility / optional agent
GET /api/admin/config Read merged config

Manual overrides

Prefix the latest user message:

Prefix Effect
@glm glm-5.2
@kimi kimi-k2.7-code
@cheap deepseek-v4-flash
@strong glm-5.2
@ui task ui_frontend + glm-5.2
@debug task debugging + kimi-k2.7-code
@auto ignore override routing

Defined in config/router.yamloverrides.


Configuration

Primary file: config/router.yaml (models, routes, classifier rules, quota modes, overrides).

Environment:

Variable Default Purpose
OPENCODE_GO_API_KEY Upstream auth
OPENCODE_GO_BASE_URL https://opencode.ai/zen/go/v1 Upstream base
ROUTER_API_KEY unset Bearer for local /v1 and admin
ROUTER_CONFIG_PATH config/router.yaml Config file
ROUTER_LOG_PATH logs/router-decisions.jsonl Decision log
ROUTER_QUOTA_MODE normal normal / conserve / emergency
ROUTER_ROUTING_MODE from yaml deterministic / semantic / hybrid / agent
ROUTER_HOST 127.0.0.1 Bind host
ROUTER_PORT 8787 Bind port

Quota modes: normal — route defaults; conserve — downgrade unprotected routes; emergency — cheap models on unprotected routes.

Semantic routing (optional): default routing_mode: deterministic adds no extra upstream calls. Example (commented in README only; enable in your local yaml if needed):

# routing_mode: hybrid
# routing_agent:
#   enabled: true
#   model: deepseek-v4-flash

Modes: deterministic, semantic (hybrid eligibility), hybrid, agent. Preview: POST /api/admin/route-preview.


Publishing (maintainers)

  • npm: npm publish from repo root (package opencode-go-router, bin opencode-go-router).
  • Python: pip install / uv pip install from git or PyPI name opencode-go-router (see pyproject.toml).

Tests

uv run python -m pytest tests/ -q

License

MIT — see LICENSE.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages