- TypeScript 100%
| src | ||
| .gitignore | ||
| LICENSE | ||
| package.json | ||
| README.md | ||
opencode-aor
An opencode plugin for Actually Open Router (aor).
It exposes your aor instance as three providers in opencode — one per client API shape — and populates each provider's model list from the server's GET /v1/models response:
| Provider | npm package | API shape |
|---|---|---|
aor |
@ai-sdk/openai-compatible |
OpenAI |
aor-anthropic |
@ai-sdk/anthropic |
Anthropic |
aor-google |
@ai-sdk/google |
All three point at the same aor base URL and use the same sk-aor-... key. Each model is registered under whichever provider(s) match the api field aor reports for it, so a request is sent in the protocol the serving upstream expects.
Install
Add the plugin to your opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"plugin": [
["git+https://git.trevhost.com/devtrev/opencode-aor.git", { "baseURL": "http://localhost:8000/v1" }]
]
}
baseURL is your aor instance's OpenAI-style root (the part before /chat/completions). Defaults to http://localhost:8000/v1; can also be set via the AOR_BASE_URL env var.
Auth
There are two ways to provide your sk-aor-... key. Use either or both.
/connect (recommended)
aor's GET /v1/models is public, so the plugin discovers models at startup with no key. The three providers (AOR / AOR (Anthropic) / AOR (Google)) then appear in opencode's /connect list. Select one, paste your sk-aor-... key, and that provider is live in the model picker immediately — no restart.
Paste the key once per provider you use. opencode stores credentials per-provider-ID, so the three api shapes are three separate /connect entries — just like openai, anthropic, and google are separate entries. (You don't need to connect a provider whose api shape you won't use.)
AOR_API_KEY env var (set once for all three)
export AOR_API_KEY=sk-aor-...
This covers all three providers' request keys at once, and is also sent on the discovery fetch (harmless for public endpoints; useful if you re-enable auth gating on /v1/models). A /connect-stored key takes precedence over the env var for that provider.
opencode does not load
.envfiles, soAOR_API_KEYmust be set in the real process environment (shell rc, direnv, or a wrapper).
How it works
On startup the plugin's config hook fetches GET ${baseURL}/models (no key needed for the default public endpoint), groups the returned models by their api field (openai / anthropic / google), and injects three providers into opencode's config — each carrying the models that speak its protocol.
A model backed by providers of more than one api type is reported by aor with an array api field and is registered under each matching provider — pick whichever protocol you prefer from the model picker.
Notes / limitations
- Discovery is at startup. If aor isn't running when opencode starts, the providers get no models and won't appear in
/connector the picker. Start aor, then (re)start opencode. - Auth headers are chosen automatically by the AI SDK package per provider (
Authorization: Bearerfor openai-compatible,x-api-keyfor anthropic,x-goog-api-keyfor google). aor accepts thesk-aor-...key in any of these headers. - No protocol translation. aor forwards the client's request shape verbatim to the matching upstream. Sending an OpenAI-shape request to a model only served by an anthropic upstream would not work — which is why each model is only registered under the protocol(s) its upstreams speak.
Cost tracking & context window
The plugin reads cost and limit metadata from aor's GET /v1/models response and injects them into opencode's per-model config. This enables:
$ spentdisplay in opencode's TUI — opencode computes cost client-side from token counts × the pricing we inject.% context useddisplay — opencode computes token usage against the context window limit we inject.
These values come from aor's primary (highest-priority) provider for each model. When limits or pricing vary greatly across providers for the same model, consider splitting into separate catalog models in aor's config so clients get deterministic metadata. See aor's docs/requirements-key-budgets.md for details.
Note: opencode v2's runner currently hardcodes
cost: 0in its step-end events. Cost tracking works on the v1 processor path. This is an opencode gap, not a plugin limitation.
LICENSE
MIT