MixRoute Gateway
Registers MixRoute as three Agent Zero chat providers - Anthropic with thinking effort control, general models, and Smart Routing - each with its own API key slot. Adds a sidebar credit visor showing balance, runway, burn rate, cache hit rate, and cache savings, read from the MixRoute console API.
README
MixRoute Gateway
Registers MixRoute as three first-class Agent Zero chat
providers, so Claude models served through the gateway get real thinking effort
control without per-preset api_base or api_key overrides.
Configuration only - no Python, no UI, no background requests.
What you get
| Provider | Serves | API key slot |
|---|---|---|
| MixRoute (Anthropic) | Claude models with thinking effort control | API_KEY_MIXROUTE_ANTHROPIC |
| MixRoute (General) | All 200+ models, no Smart Routing; effort control on OpenAI models only | API_KEY_MIXROUTE_OPENAI |
| MixRoute (Smart Routing) | Smart Routing (model: auto) |
API_KEY_MIXROUTE_SMART |
Plus a credit visor in the sidebar, on by default, showing balance, runway, burn rate, cache hit rate, and cache savings. See Credit visor.
Install
- Copy this directory to
/a0/usr/plugins/mixroute_gateway/. - Restart Agent Zero.
- Enable MixRoute Gateway in Settings -> Plugins.
- Add your keys (below), then pick a MixRoute provider in your model config.
API keys - three separate credentials
This is the part that most often causes confusion.
MixRoute issues the Smart Routing key separately from the non-Smart-Routing
keys. All three look alike - they share the sk- prefix - but they carry
different entitlements and are not interchangeable. That is why this plugin ships
three providers rather than one: each provider id maps to its own key slot, so you
can also segregate spend per key if you want to.
Add them to /a0/usr/.env:
API_KEY_MIXROUTE_ANTHROPIC=sk-xxxxxxxx-your-anthropic-scoped-key
API_KEY_MIXROUTE_OPENAI=sk-xxxxxxxx-your-general-key
API_KEY_MIXROUTE_SMART=sk-xxxxxxxx-your-smart-routing-key
Or paste them into the Settings API-Keys pane, which writes the same slots.
If you only use one MixRoute capability, fill only that slot. An unfilled slot simply means that provider will fail to authenticate if selected.
Key names are not arbitrary: Agent Zero derives them from the provider id as
API_KEY_{PROVIDER_ID_UPPER}. Renaming a provider id orphans its key.
How to create each key in the MixRoute dashboard
The three keys are not interchangeable, and two of them need deliberate setup. Getting this wrong is the most common cause of confusing failures.
1. Smart Routing key — a separate pane
Smart Routing keys are created on a different pane of the MixRoute dashboard from ordinary keys. A Smart Routing key works only for Smart Routing and will be rejected in either of the other two slots. The reverse is also true: an ordinary key cannot drive Smart Routing.
Both directions are enforced by MixRoute with explicit errors:
| Attempt | MixRoute response |
|---|---|
| Smart Routing key with a named model | Smart routing key can only use smart routing model names (e.g. auto) |
Ordinary key with model: auto |
Model 'auto' requires a smart routing dedicated key |
2. Anthropic key — filter it to Anthropic models
When creating the key for API_KEY_MIXROUTE_ANTHROPIC, use MixRoute's model
filter to restrict it to Anthropic models — one, several, or all of them.
This is strongly recommended rather than strictly required, and the reason is practical. The model picker for a provider shows whatever that key can reach. An unfiltered key surfaces all 200+ MixRoute models under MixRoute (Anthropic), which makes it easy to select a non-Anthropic model and send it thinking-effort parameters it cannot honour. Filtering the key makes the wrong choice impossible rather than merely discouraged.
A filtered key rejects anything outside its filter, which is the intended behaviour:
This token has no access to model gpt-5.2
3. General key — leave it unfiltered
For API_KEY_MIXROUTE_OPENAI, create an ordinary key with no model filter. That
gives access to all 200+ MixRoute models, Anthropic ones included.
Effort control on this route is model-dependent:
| Model family via the general key | reasoning_effort |
|---|---|
OpenAI models (e.g. gpt-5.2) |
Works |
| Anthropic models | Ignored — Claude runs at its default level |
The reason is the handler. This provider uses LiteLLM's OpenAI handler, which
passes reasoning_effort through natively to OpenAI models but has no way to
translate it into Anthropic's own effort mechanism. For thinking effort on
Claude, use the MixRoute (Anthropic) provider instead.
Measured on gpt-5.2 through this route, identical prompt, 2 reps per level:
| Effort | Reasoning tokens | Completion tokens |
|---|---|---|
low |
265, 312 | 1071, 1126 |
high |
556, 835 | 1314, 1573 |
Reasoning tokens roughly double. Useful detail: OpenAI models report
reasoning_tokens in the usage object, so the effect is directly observable.
Anthropic models return 0 there even when reasoning demonstrably occurs, so on
that route you have to infer effort from completion-token counts instead.
Which key for which job
| Goal | Key | Provider |
|---|---|---|
| Claude with thinking effort control | Anthropic-filtered | MixRoute (Anthropic) |
| Any model; effort control on OpenAI models only | Unfiltered ordinary | MixRoute (General) |
| Automatic model selection | Smart Routing | MixRoute (Smart Routing) |
The practical split: reach for the Anthropic key when reasoning depth matters, and the general key for everything else.
The /v1 asymmetry is intentional
In conf/model_providers.yaml the Anthropic entry's api_base has no /v1
suffix, while the other two do:
| Provider | api_base |
LiteLLM appends | Final URL |
|---|---|---|---|
| Anthropic | https://api.mixroute.ai |
/v1/messages |
.../v1/messages |
| OpenAI, Smart | https://api.mixroute.ai/v1 |
/chat/completions |
.../v1/chat/completions |
Making the three consistent breaks one of them. Adding /v1 to the Anthropic
entry yields /v1/v1/messages and a 404 on every Claude call. It looks like a
typo; it is load-bearing.
Effort control in presets
Set effort in the preset's Additional Parameters (kwargs) field:
reasoning_effort="high"
The quoted form is correct and is what the UI itself writes when it renders an
existing preset. Unquoted reasoning_effort=high also works: the field parser
tries JSON.parse on the value and falls back to the raw string when that fails,
so both forms produce the identical stored value. In presets.yaml it lands as
reasoning_effort: high.
This field is parsed before the request reaches any provider, so the syntax is the same for every MixRoute provider. What differs is whether the target model acts on it.
Which preset should set it
| Preset provider | Model | reasoning_effort |
|---|---|---|
| MixRoute (Anthropic) | Claude | Works - this is the reason the provider exists |
| MixRoute (General) | OpenAI models | Works |
| MixRoute (General) | Claude | Silently ignored |
| MixRoute (Smart Routing) | auto |
Effort is the router's decision, not the preset's |
The silent case is the trap: pointing the OpenAI provider at a Claude model and setting effort produces no error and no effect.
Anthropic presets - remove the old overrides
If you are migrating a hand-rolled preset that reached MixRoute by overriding the
stock anthropic provider, it will carry three kwargs. Keep one, delete two:
api_base="https://api.mixroute.ai" <- DELETE, the provider supplies it
api_key="sk-..." <- DELETE, comes from API_KEY_MIXROUTE_ANTHROPIC
reasoning_effort="high" <- KEEP
Also clear the top-level API Base field; empty means "use the provider's".
Leaving a stale api_key behind is the dangerous one. It keeps using whatever
credential was pasted there, which may bypass MixRoute billing entirely while
appearing to work.
Verifying effort actually applied
The method differs by route:
| Route | How to check |
|---|---|
| OpenAI models | reasoning_tokens in the usage object rises with effort |
| Anthropic models | reasoning_tokens is always 0; compare completion-token counts across levels instead |
Measured on claude-opus-5 through the Anthropic provider, identical prompt,
3 reps per level: low averaged 1539 completion tokens, high 6635, and max
exceeded 15000. The levels are clearly distinct.
Do not judge effort by how thoughtful the reply reads, and do not conclude from an
empty reasoning_tokens on the Anthropic route that no reasoning occurred.
Credit visor
A sidebar readout of your MixRoute account. On by default — installing the plugin gives the full visor immediately. Turn it off in the settings pane if you want the three chat providers alone; while off, the visor makes no requests to MixRoute at all, so your UI and your account are left untouched.
It shows five things:
| Row | Shows |
|---|---|
| Credits | Dollars remaining |
| Runway | How long that lasts at the measured burn rate |
| Bar | Balance against your green threshold, coloured by state |
| Burn | Spend per hour, and the period it was measured over |
| Cache hit / Saved est. | Cache read share, and what caching saved over that period |
It needs one extra credential in /a0/usr/.env:
API_KEY_MIXROUTE_SYSTEM=<your System API key>
MIXROUTE_ID=<your numeric account id>
The System API key is not one of the three inference keys above. It is a
console-scoped credential created separately in the MixRoute dashboard. The two scopes do
not overlap: an inference key returns invalid access token here, and the System key
returns 401 on chat calls.
| Indicator | Meaning |
|---|---|
| Green | Comfortable balance, above your green threshold |
| Yellow | Getting low — roughly a few hours of headroom |
| Red | Urgent. Below about $2, large requests fail outright |
| Grey | No reading available; hover for why |
* after the figure |
Reading is older than the last poll attempt |
Thresholds and refresh interval are configurable. Defaults assume a busy session and are based on measured burn, so green means hours of headroom rather than minutes.
Not included yet
Per-model breakdown of cache performance, and pagination past the most recent 100 requests. Neither blocks anything today: every request on this account uses one model, so there is nothing to break down, and 100 rows covers hours of normal use.
One display state has never been seen live. Saved est. turns red and negative when
caching costs more than it saves, which needs a cache hit rate below 52.6%. It is
unit-tested and wired, but no session has yet been inefficient enough to trigger it.
Troubleshooting
| Symptom | Likely cause |
|---|---|
| Providers missing from the dropdown | Plugin not enabled, or Agent Zero not restarted |
| 404 on Claude calls | /v1 was added to the Anthropic api_base |
| 401 on one provider only | That provider's key slot is empty or holds the wrong key type |
| Smart Routing 401s while others work | Smart Routing key is separately issued - check you used the right one |
403 + pre-consume quota failed, user remaining quota: ... |
Account is out of credits. Not a configuration fault - top up at MixRoute. The message names the shortfall, e.g. remaining 0.88 vs required 1.76 |
No available channel for model <name> under group default |
MixRoute has no capacity for the model it selected. Fix this in the MixRoute dashboard, not the plugin - repin the affected tier to a model with an available channel. Most often seen on Smart Routing |
| Visor says "check System API key" | An inference key is in API_KEY_MIXROUTE_SYSTEM. The visor needs the console-scoped System key, created separately in the dashboard |
| Visor says "out of credits" but the console shows a balance | The balance fell below the pre-consume requirement for a large request. Check the console figure against your red threshold |
| Visor shows grey with "MixRoute unreachable" | MixRoute's API is not answering. Confirmed against its public status endpoint, so this is not a credential problem |
Visor shows a figure with * after it |
The last poll failed, so the previous reading is being shown. Hover for its age |
| Visor never appears | It is on by default, so check the toggle was not switched off, then that Agent Zero has been restarted since installing |
| Visor rows are blank after an update | Agent Zero caches plugin helpers in memory. A browser refresh cannot reload them - restart Agent Zero |
Saved est. is red and negative |
Caching is costing more than it saves, below roughly 52.6% hit rate. Check the 1-hour cache TTL is active, then look for prompt-prefix churn invalidating the cache |
Widget shows -- |
No successful reading yet. Hover for the reason |