@rthadani/pi-failover
A pi provider extension that fails over across an ordered list of compatible models (grouped into capability classes) when a provider runs out of credits or errors, so agent runs never stop when one wallet empties.
Package details
Install @rthadani/pi-failover from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@rthadani/pi-failover- Package
@rthadani/pi-failover- Version
1.2.1- Published
- Oct 31, 2026
- Downloads
- 512/mo · 167/wk
- Author
- rthadani
- License
- MIT
- Types
- extension
- Size
- 42.8 KB
- Dependencies
- 0 dependencies · 2 peers
Pi manifest JSON
{
"extensions": [
"./extensions/failover.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-failover
A pi provider extension that keeps agent runs alive when a model provider runs out of credits or errors. It registers a set of models under the failover provider, grouped into compatibility classes. When the model in use fails, the request is retried on the next model in the same class, wrapping around, so the run never stops when one wallet empties.
The serving backend is always shown in the status bar: failover: strong-model (example-provider) when the requested model is serving, or auto → strong-model (example-provider) when it differs (including auto, which resolves to the first backend of the first set). The line updates on every attempt, so a mid-request failover is visible too.
How it works
- Models are grouped into
sets(capability classes: e.g.opus,sonnet,coding,flash). - Each model is selectable as
failover/<name>, plus a conveniencefailover/auto(first model of the first set). - On a request that fails before any content streams (quota, credits, 403, auth, connection, 5xx), the extension retries the next model in the same set, circularly, up to
maxAttempts. - Context-overflow errors are not retried — they pass through so pi can compact the conversation instead.
- Aborted requests (you pressed ESC) are not retried either — they are forwarded as-is.
- Failover never crosses sets: a model only falls back to peers in its own class.
Install
pi install npm:pi-failover # after publishing
pi install git:github.com/rthadani/pi-failover@v1
pi install ./pi-failover # local directory
Then pick a model in /model: Auto (failover) or any Failover · <name>.
Configure
Create ~/.pi/agent/failover.json (or point FAILOVER_CONFIG at another path). The file is the source of truth; the built-in default is only a placeholder.
{
"contextWindow": 200000,
"maxTokens": 65536,
"maxAttempts": 6,
"sets": [
{
"name": "opus",
"models": [
{
"name": "strong-model",
"provider": "example-provider",
"api": "openai-completions",
"baseUrl": "https://api.example.com/v1",
"apiKey": "$YOUR_API_KEY",
"model": "strong-model",
"reasoning": true,
"contextWindow": 1000000,
"maxTokens": 65536,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
"compat": { "supportsUsageInStreaming": false, "maxTokensField": "max_tokens" }
}
]
}
]
}
Backend fields
| Field | Meaning |
|---|---|
name |
Unique id; the model is exposed as failover/<name>. |
provider |
Display/origin provider (informational). |
api |
One of openai-completions, openai-responses, anthropic-messages, or claude-bridge. The first three match the provider's real HTTP API. claude-bridge is currently the only delegated value: it hands the turn to the pi provider whose id equals that api string (the pi-claude-bridge extension). Delegation is not generic, because pi only exposes another extension's stream functions under its own provider id. If that provider is not registered in any live session, the backend fails fast and rotation continues. |
input |
Accepted modalities; absent means ["text"], and image routing is driven by this field (text-only backends are skipped when a turn carries images), so a delegated backend that serves images needs "input": ["text","image"]. |
baseUrl |
Endpoint for the provider. Ignored by delegated (claude-bridge) backends, where any placeholder works. |
apiKey |
$ENV_VAR / ${ENV_VAR} reference, or a literal value. Must be non-empty even for delegated backends (use a placeholder like not-used). |
model |
The actual model id sent to the provider. |
contextWindow / maxTokens |
Caps used for compaction and output limits. |
cost |
Per-1M-token rates (display/telemetry only). |
compat / thinkingLevelMap |
Optional per-provider compatibility/thinking overrides. |
Environment
FAILOVER_CONFIG— override the config path (default~/.pi/agent/failover.json).- Provider keys referenced by
apiKeyentries (e.g.YOUR_API_KEY).
Select a model at runtime (subagent API)
The subagent API accepts a model argument per spawn, so you can pick a failover class at runtime and override the session default for that one run. Pass failover/<name> (provider/id form, not a bare id), where <name> is any model name from your failover.json:
// run the implementation agent in the coding class
subagent({ agent: "worker", model: "failover/code-model", task: "..." })
// design/reasoning in the opus class
subagent({ agent: "oracle", model: "failover/strong-model", task: "..." })
// fast, cheap recon in the flash class
subagent({ agent: "scout", model: "failover/fast-model", task: "..." })
The model you pass starts that run in its own set, and failover stays circular within that set. The entry point for a class is whichever backend that class lists first, so the mapping lives in your own failover.json rather than in this document.
Omit model to inherit the session model. This is a normal per-spawn override — no extra permission or config needed.
Notes
- If you previously installed a personal copy of
failover.tsunder~/.pi/agent/extensions/, remove it after installing this package to avoid registering thefailoverprovider twice. - A backend whose
apiKeyresolves to empty is skipped automatically. - Mid-stream failures (after content has started) cannot be retracted; those surface as errors and the next request fails over.
Publishing
Releases go to npm via trusted publishing (OpenID Connect). No npm token is stored in the repo: GitHub Actions requests a short-lived OIDC token and npm verifies it against the registered publisher.
- First release only: npm cannot create a new package over OIDC, so publish
1.0.0once from your machine (npm publish --access public). - Then register the trusted publisher on npmjs.com under Settings → Trusted Publishing → GitHub Actions: owner
rthadani, repositorypi-failover, workflowpublish.yml, environment empty. The workflow filename is part of that binding, so do not rename.github/workflows/publish.yml. - Tag a release with
git tag v1.0.0 && git push origin v1.0.0to publish for real. The tag must match theversioninpackage.json. - Manual dispatch (
workflow_dispatch) defaults to a dry run; uncheckdry_runto actually publish. - Requirements: npm CLI
11.5.1or newer, and the repository must be public.