pi-ccswitch-auto-switch
Provider-first automatic model failover extension for Pi and CC Switch
Package details
Install pi-ccswitch-auto-switch from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-ccswitch-auto-switch- Package
pi-ccswitch-auto-switch- Version
0.3.10- Published
- Sep 7, 2026
- Downloads
- 528/mo · 528/wk
- Author
- errorje
- License
- MIT
- Types
- extension
- Size
- 97.5 KB
- Dependencies
- 0 dependencies · 0 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
Pi CCSwitch Auto Switch
中文说明:README.zh-CN.md
Resilient model failover for Pi when its providers are managed by CC Switch.
The extension observes real Pi requests, records sanitized health signals, and—only in interactive TUI/RPC sessions—moves a failed request to a healthy model. It treats provider failures as provider failures: an exhausted balance, invalid credentials, or rate limit will not cause a rapid series of retries against sibling models from the same provider.
Features
- Uses Pi's effective model registry; never reads CC Switch databases, Pi auth files, or API keys.
- Provider-first circuit breakers for authentication, quota, billing, and rate-limit failures.
- Endpoint circuit breakers for DNS, connection, server, and streaming failures.
- Endpoint platform isolation: when several models on the same endpoint (same BaseURL/provider) fail within one round, the whole endpoint is isolated so sibling models from the same platform are not tried one by one.
- Model-only isolation for missing models and incompatible parameters.
- Learns model-family content-policy constraints from real failures (
glm-4.5andGLM-4.6, for example, are bothglm) and avoids the entire family during the current content-policy failover chain. Evidence is session-scoped: it is cleared atsession_start, because a new session may handle tasks that are not content-sensitive, so the family becomes eligible again until this session observes its own content-policy rejection. - Applies hard health, failure-domain, policy-family, input-modality, and context filters before ranking candidates by provider diversity, model equivalence, capability compatibility, and historical reliability.
- Independent-provider semantics: a copied vendor (e.g.
my-provider-copy) shares the BaseURL but is a distinct provider with its own endpoint key, so isolating one never blocks the other.
- Independent-provider semantics: a copied vendor (e.g.
- 90-second first-response and 120-second streaming-idle watchdogs.
- Exponential cooldowns,
Retry-Aftersupport, and one persisted half-open probe lease per provider. - Persistent, atomic, cross-process health state with error redaction and bounded logs.
- Compact Pi status bar and interactive health panel.
- Non-interactive
--print/ JSON runs monitor and record failures but do not inject a competing retry. pi-ccswitch-runkeeps one headless Pi RPC session alive and returns only the final successful answer after automatic model failover.
Requirements
- Pi
0.84.4or newer. - CC Switch
3.20+is recommended for its native Pi model configuration support. - Node.js
22.19+only for local development and tests. Pi supplies the runtime for the extension itself.
Configuration
The extension requires no user configuration: it observes Pi's real requests and reads only the model metadata Pi already exposes. It never reads CC Switch databases, Pi auth files, API keys, cookies, or .env files, and it never writes Pi model settings or CC Switch data.
All knobs below are optional and have sensible defaults:
| Setting | Scope | Default | Notes |
|---|---|---|---|
PI_CODING_AGENT_DIR |
Extension state | ~/.pi/agent |
Where health state, logs, and failure reports are stored. Only relevant if you relocated your Pi agent directory; the extension follows Pi's own convention. |
PI_BIN |
Headless runner only | pi on PATH |
Must point to the real pi executable. Legacy self-references to pi-ccswitch-run or ccswitch-run are ignored with a warning and fall back to pi; other invalid commands remain configuration errors. |
Model scope (/model etc.) |
Failover candidates | Full registry | When Pi has an active model scope, failover only considers models inside that scope; otherwise the full registry is used. The status bar shows which source is active. |
baseUrl metadata |
Endpoint isolation | provider key | Endpoint-level platform isolation groups models by baseUrl (provided by CC Switch 3.20+). Without it, isolation degrades to provider-level grouping, which still works. |
Installation
Pi package install (recommended)
pi install git:github.com/JunyWuuuu91/pi-ccswitch-auto-switch
This works on macOS, Linux, and Windows when Git is available. After the npm release, this will also work:
pi install npm:pi-ccswitch-auto-switch
Restart Pi or run /reload after installing or updating. To update the Git installation later, run pi update --extensions.
CC Switch should be configured normally. This extension deliberately does not write Pi model settings or CC Switch data.
Headless / automation use
pi-ccswitch-run(runner.mjs)是独立于 Pi 扩展的 headless 调用入口:它启动一个 pi --mode rpc 会话,把一次请求自动切换到健康模型后只返回最终成功结果。它不在 pi install 的扩展加载路径里自动暴露给下游项目,需要单独安装。
在消费方项目内安装(推荐,保证 require.resolve 可解析)
pi install git:... 只把扩展装进 Pi 全局目录(~/.pi/agent/...),不会把它放进下游项目的 node_modules 解析路径。因此消费方代码里 require.resolve('pi-ccswitch-auto-switch/runner.mjs') 需要把本包安装进自己的项目依赖:
# 在消费方项目目录内执行
npm i github:JunyWuuuu91/pi-ccswitch-auto-switch
# 或从 npm registry 安装最新版
npm i pi-ccswitch-auto-switch@latest
安装后 require.resolve('pi-ccswitch-auto-switch/runner.mjs') 会命中项目自身 node_modules,bin pi-ccswitch-run 也可直接调用。
版本锁定警告(0.x caret 陷阱)
npm 对 ^0.1.6 的 caret 语义只匹配 0.1.x,不会自动升到含 runner.mjs 的 0.3.x。如果机器上 ~/.pi/agent/npm/node_modules/pi-ccswitch-auto-switch 仍停留在 0.1.6(该版本无 runner.mjs、无 pi-ccswitch-run bin),重复执行 pi install 也不会升级。请手动升级 npm 侧版本:
cd ~/.pi/agent/npm && npm install pi-ccswitch-auto-switch@latest
升级后确认 ~/.pi/agent/npm/node_modules/pi-ccswitch-auto-switch/runner.mjs 存在。也可以在扩展内执行 /ccswitch-doctor 检查 runner.mjs 是否可解析。
运行方式
pi-ccswitch-run --no-tools --no-context-files @prompt.md "Summarize the attached text"
The runner starts one pi --mode rpc --no-session --no-extensions --extension <this package>/index.ts process, so only CCSwitch is loaded. PI_BIN may point to the real Pi executable. For migration safety, an old PI_BIN=pi-ccswitch-run or PI_BIN=ccswitch-run value emits a warning and falls back to pi on PATH instead of recursing or terminating every downstream job. Arbitrary commands are still rejected. The default deadline is ten minutes and can be changed with --timeout-ms.
Exit codes are 0 for success, 1 when candidates are exhausted, 2 for invocation/RPC configuration failures, 124 for timeout, and 130/143 for interruption. Text @files are supported in the first release; images and stdin input are intentionally not.
Commands
| Command | What it does |
|---|---|
/ccswitch or /ccswitch status |
Open the health panel. |
/ccswitch help |
Show the command reference in Pi. |
/ccswitch refresh |
Refresh Pi's model registry and the status display. |
/ccswitch reactivate <provider/model|all> |
Clear a breaker and let the next real request verify recovery, while preserving history. |
/ccswitch disable <provider/model> |
Manually exclude a model from failover. |
/ccswitch reset <provider/model|all> |
Delete selected health history after confirmation; all also clears learned content-policy constraints. |
/ccswitch-test |
Inspect candidate discovery without changing models. |
/ccswitch-doctor |
Diagnose whether runner.mjs is present and resolvable. |
Examples:
/ccswitch reactivate all
/ccswitch disable my-provider/my-model-id
/ccswitch reset my-provider/my-model-id
Status bar
CCS v0.3.5 ✓70/131 · ⏳61 · ⛔0 · 🔄3 · provider/model-id
v0.3.5: the installed CCSwitch extension version.✓70/131: 70 healthy models out of 131 uniqueprovider/modelcombinations in Pi's effective scope. Duplicate scoped entries are counted once.⏳61: 61 models are currently affected by automatic model, provider, or endpoint cooldowns. One provider breaker can account for many affected models.⛔0: no manually disabled models.🔄3: 本次 pi session 成功切换的模型次数(衡量扩展有效程度)。/new、/fork、/resume等新 session 开始时归零;但失败记录与冷却状态不重置(它们是物理事实,跨 session 保留)。累计切换数(state.switches)与最近 20 条切换日志会持久化到状态文件,可在/ccswitch面板和/ccswitch-test中查看。provider/model-id: 当前实际生效的模型(provider/id,切换后立即更新,长名自动截断)。- During a switch,
CCS ↻2 provider/modelmeans this is the second switch attempt of the current round. Attempts are only bounded by the round time window, not a fixed count; a round fails only once every candidate has been tried.
四个状态(健康/冷却/禁用/切换)即使为 0 也始终显示,便于确认扩展处于监控中。All-healthy still shows zero counters, e.g. CCS ✓131/131 · ⏳0 · ⛔0 · 🔄0 · provider/model-id. Use /ccswitch or /ccswitch-test to see Pi's raw scope entry count, the deduplicated model count, affected model counts, and the underlying breaker-record count.
切换成功后扩展还会通过 appendEntry 向会话注入一条 ccswitch-switch custom entry(不参与 LLM 上下文),触发 TUI 底栏重绘——这样 Pi 右下角的模型名显示也会同步为切换后的模型。RPC 模式还会发出协议版本为 1 的 ccswitch-complete 或 ccswitch-exhausted 终态 entry;runner 用它们区分中间失败轮和最终结果。
Failover behavior
The state machine waits for Pi's native retry cycle to settle before switching. A user message invalidates any pending switch from an older round, avoiding duplicate dispatches.
| Failure | Scope | Initial cooldown |
|---|---|---|
401, 403, quota, billing |
Provider | 30 minutes |
429 |
Provider | Retry-After when present; otherwise 5 minutes |
DNS, network, 408, 5xx, interrupted stream |
Endpoint | 2 minutes |
404, invalid model, incompatible parameters |
Model | 15 minutes |
| Content-policy or sensitive-content rejection | Current model + learned model-family constraint | 2-minute model cooldown; family evidence is session-scoped (cleared at session_start) |
| Context overflow | Current round only | None |
Cooldowns grow exponentially within bounded limits. Learned policy-constrained families are excluded only after a content-policy rejection; they remain eligible during ordinary rate-limit, network, and model-configuration failovers. Context-overflow retries only consider models with a larger context window, and image requests do not move to a model that explicitly supports text only. Unknown errors are isolated to the current model and still fail over normally. A user cancellation is the only aborted turn that does not trigger failover; watchdog cancellations are recorded as timeouts.
Modality precheck (automatic switch to a multimodal model for images)
When building a provider request, Pi silently handles images according to the current model's input capabilities: if the model does not support images (its input does not include image), Pi replaces the image with a text placeholder (image omitted: model does not support images) — the request does not fail, so the reactive failover path never fires and the model just answers "I can't see the image", which is useless for OCR tasks.
CCSwitch therefore prechecks before the request is sent, instead of waiting for a failure:
- When user input carries images (
inputevent withimages), CCSwitch immediately switches to a healthy multimodal candidate (inputexplicitly includesimage) before the request is processed, so the images are preserved; - When a tool execution returns images (e.g. the
readtool loading an image file, whose result content includesimageparts), CCSwitch also switches to a multimodal model before the next LLM call, so the tool-result images are not stripped; - Only models that explicitly support images (
inputincludesimage) are considered; models with missing metadata are never assumed to support images; - The switch reason is recorded as
modalityand counted in both the session and lifetime switch counters; - If no multimodal candidate is available, CCSwitch notifies the user and keeps the current model (Pi will still strip the image and add its notice).
The modality precheck applies only in interactive TUI/RPC sessions (the same scope as failover); print/json modes only monitor and never switch.
Data and privacy
Health state is stored in Pi's agent directory as ccswitch-auto-switch-state.json. The extension stores counters, timestamps, cooldowns, learned model-family policy constraints, and redacted/truncated error summaries. It does not access credentials, authorization headers, CC Switch's database, or Pi's auth.json.
Development
npm install
npm run typecheck
npm test
Tests use Node's built-in test runner and cover the failure matrix, family-level policy avoidance, provider-first selection, input compatibility, cooldowns, state persistence, and Windows-compatible paths.