mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-16 20:02:45 +03:00
The opencode plugin v2 reads its management token from `OMNIROUTE_MANAGEMENT_API_KEY` (the plugin option still wins) and warns once at startup when it has to fall back to the inference key. Eight cases through the real plugin setup, env isolated, asserting the Bearer header on `/api/*`.
Validated first on the combined board of all 38 PRs of this batch (10 merged as-is, 28 after the maintainer rework) on top of release/v3.8.51 c0f92ec: typecheck:core, check:open-sse-typecheck and check:dashboard-typecheck clean; ESLint clean on every changed file; file-size (rebaselined for the combined growth), complexity, cognitive-complexity, changelog-integrity, docs-counts, docs-sync, migration-numbering and i18n new-key gates green; 735 focused node:test cases with the only batch-caused failure (a flag-count assertion) fixed. Then re-validated alone on the fresh release tip right before this merge: ESLint on the changed files, typecheck:core, check:open-sse-typecheck, the file-size/complexity/changelog gates and this PR's own tests.
Thanks @maxmad64bis!
114 lines
7.5 KiB
Markdown
114 lines
7.5 KiB
Markdown
# @omniroute/opencode-plugin-v2
|
|
|
|
OpenCode v2 plugin (`define({ id, setup })`, Promise API) that publishes the live OmniRoute catalog — models from `/v1/models`, combos from `/api/combos` (least-common-denominator join), auto-combos from `/api/combos/auto`, enrichment (names + pricing), and usable-provider filtering — into the v2 `catalog.transform`, with `key` + `env` auth via `integration.transform`.
|
|
|
|
Companion to `@omniroute/opencode-plugin` (OpenCode v1, same repo). The two packages are independent: this one carries its own catalog-mapping logic and the v1 plugin is left untouched.
|
|
|
|
## Install
|
|
|
|
```sh
|
|
npm install @omniroute/opencode-plugin-v2
|
|
```
|
|
|
|
`opencode.json`:
|
|
|
|
```json
|
|
{
|
|
"plugins": [
|
|
{
|
|
"package": "@omniroute/opencode-plugin-v2",
|
|
"options": {
|
|
"providerId": "omniroute",
|
|
"baseURL": "http://localhost:20128"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Credentials
|
|
|
|
The plugin needs a gateway key to read the catalog, and looks for one in this
|
|
order:
|
|
|
|
1. **The credential you connected in OpenCode.** The plugin registers an
|
|
integration, so `opencode auth` (or the Connect action in the model picker)
|
|
can store a key for it. Nothing is written to `opencode.json` — this is the
|
|
recommended route.
|
|
2. **`apiKey` in the plugin options**, when you want a per-project override.
|
|
Remember that this puts the key in a config file you may be committing.
|
|
3. **`OMNIROUTE_API_KEY` in the environment.**
|
|
|
|
If none of the three yields a key, the catalog is empty and the plugin says so
|
|
once at startup rather than leaving you with a silent empty model list.
|
|
|
|
### The management token is a different key
|
|
|
|
Combos, provider health and enrichment (display names, pricing, free-tier
|
|
budgets) come from the gateway's `/api/*` endpoints, which most deployments
|
|
gate behind a **management** token rather than the inference key. Set it
|
|
explicitly:
|
|
|
|
```json
|
|
"options": {
|
|
"baseURL": "http://localhost:20128",
|
|
"managementReadToken": "<management read token>"
|
|
}
|
|
```
|
|
|
|
The token can also come from the `OMNIROUTE_MANAGEMENT_API_KEY` environment
|
|
variable (the option wins when both are set). Resolution order:
|
|
`managementReadToken` option, then `OMNIROUTE_MANAGEMENT_API_KEY`, then the
|
|
`apiKey` fallback.
|
|
|
|
Left unset, `managementReadToken` falls back to `apiKey` for backwards
|
|
compatibility, and the plugin warns once at startup that the fallback is
|
|
active. When a gateway rejects that fallback, the catalog still
|
|
publishes — but with raw model ids instead of display names, no canonical
|
|
alias dedupe, no pricing and no combos. The plugin warns once per endpoint
|
|
when this happens, naming the endpoint and the consequence, so the degraded
|
|
catalog is never a mystery.
|
|
|
|
## Options
|
|
|
|
| Key | Default | Notes |
|
|
| -------------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
| `providerId` | `"omniroute"` | Provider id and integration id; models publish under `<providerId>/…` |
|
|
| `baseURL` | required | OmniRoute gateway root (no `/v1` suffix needed) |
|
|
| `apiKey` | connected credential, then `OMNIROUTE_API_KEY` | Chat key for `/v1/*` — see [Credentials](#credentials) |
|
|
| `managementReadToken` | option, then `OMNIROUTE_MANAGEMENT_API_KEY`, then `apiKey` | Management key for `/api/*` (combos, providers, enrichment) — usually **not** the same key |
|
|
| `displayName` | `"OmniRoute"` | Provider display name |
|
|
| `timeoutMs` | `10000` | Per-endpoint fetch timeout (auto-combos use 5s) |
|
|
| `modelCacheTtlMs` | `300000` | Catalog cache TTL; disk snapshot warms cold starts |
|
|
| `timeouts` | per-endpoint override | `{ models, combos, autoCombos, enrichment }` in ms; falls back to `timeoutMs` |
|
|
| `enrichment` | `true` | Fetch names + pricing (`/api/pricing*`, `/api/free-tier/summary`) |
|
|
| `providerTag` | `true` | Prefix a display name with the upstream provider it routes to |
|
|
| `geminiSanitization` | `true` | Strip `$schema`/`additionalProperties` from tool schemas sent to Gemini models (`$ref` tools are forwarded untouched) |
|
|
| `usableOnly` | `false` | Filter to healthy provisioned providers (`/api/providers`) |
|
|
| `visibleModels` / `hiddenModels` | `[]` | Exact-or-suffix allowlists, deny wins |
|
|
| `apiFormat.allowAnthropic` | `false` | Route allowlisted ids to the Anthropic API block |
|
|
| `apiFormat.anthropicModels` | `[]` | Full model ids routed to Anthropic |
|
|
| `apiFormat.anthropicPrefixes` | v1 defaults | Deprecated, warns once — prefer `anthropicModels` |
|
|
| `logLevel` / `startupDebug` | `warn` / `false` | Logger verbosity |
|
|
|
|
## Tool calling on Gemini models
|
|
|
|
Gemini answers `400 INVALID_ARGUMENT` — for the whole request, not just the
|
|
offending tool — when a tool declaration carries `$schema` or
|
|
`additionalProperties`. Anything that emits standard JSON Schema therefore
|
|
breaks tool calling as soon as the chain routes to Gemini.
|
|
|
|
The plugin strips those keywords from tool schemas bound for a Gemini model of
|
|
this provider, and leaves every other request untouched. A tool carrying a
|
|
`$ref` is forwarded untouched instead of stripped: removing the reference
|
|
would widen the schema to "accept anything". Set
|
|
`"geminiSanitization": false` to turn it off.
|
|
|
|
## Migrating from the v1 plugin
|
|
|
|
The v2 plugin publishes provider id `X` bare. The v1 plugin published `opencode-X` (native-adapter gate). Sessions pinned to `opencode-X/...` must re-select the model under `X/...`.
|
|
|
|
## License
|
|
|
|
MIT
|