An OpenCode plugin that judges each new human prompt with Qwen and routes the entire agent turn to the least capable configured model tier. Tool-loop continuations remain on the selected model without another judge request.
The defaults are:
model-router/autoas the trigger modeleasy→sonarllm-dogfooding/Qwen3.6-Sonarcomplex→portkey/gpt-5.6-sol, varianthigh- judge errors, timeouts, and invalid responses →
complex
Reference the plugin from opencode.json and define its three providers. The
Portkey provider intentionally uses @ai-sdk/openai and an environment-backed
credential.
{
"plugin": [
["file:///absolute/path/to/opencode-model-router/src/index.ts", {
"diagnostics": { "echo": true }
}]
],
"provider": {
"model-router": {
"npm": "@ai-sdk/openai-compatible",
"options": { "baseURL": "http://127.0.0.1:1/v1", "apiKey": "unused" },
"models": { "auto": { "name": "Automatic tier" } }
},
"sonarllm-dogfooding": {
"npm": "@ai-sdk/openai-compatible",
"name": "SonarLLM Dogfooding",
"options": {
"baseURL": "https://sonarllm-dogfooding.aws-dev.sonarsource.com/v1"
},
"models": {
"Qwen3.6-Sonar": {
"name": "Qwen3.6-Sonar",
"limit": { "context": 260000, "output": 8192 }
}
}
},
"portkey": {
"npm": "@ai-sdk/openai",
"options": {
"baseURL": "https://api.portkey.ai/v1",
"apiKey": "{env:PORTKEY_OPENAI_API_KEY}"
},
"models": {
"gpt-5.6-sol": {
"name": "gpt-5.6-sol",
"reasoning": true,
"variants": { "high": { "reasoningEffort": "high" } }
}
}
}
}
}Select model-router/auto to route a turn. Selecting any other model manually
bypasses the plugin.
Each routed turn writes judge request, judge response, and either the
selected tier or fallback error to OpenCode's log under the
opencode-model-router service. Request logs contain the user's bounded prompt
text, but never request headers or environment-backed credentials.
The default template sets diagnostics.echo to true for concise judge request
and response summaries. The selected model or fallback notification is always
shown. Interactive OpenCode displays native toasts; opencode run prints
one-line messages to stderr. Full requests and raw responses remain in the log.
The selected tier handles the current turn, while subsequent prompts remain on
model-router/auto and receive a fresh routing decision.
Plugin options accept a custom judge, trigger, tier list, and fallback:
bun install
bun run typecheck
bun testThe opt-in live test needs internal-network access, OpenCode 1.18.16 or newer,
and PORTKEY_OPENAI_API_KEY. It creates isolated XDG config/data directories,
uses the read-only plan agent, and retains sanitized diagnostics under
artifacts/.
RUN_LIVE_E2E=1 bun run e2ePhase 1 deliberately does not retry Qwen worker failures or recover silent worker hangs beyond the nine-second judge timeout.