pi-ccswitch-auto-switch

Provider-first automatic model failover extension for Pi and CC Switch

Packages

Package details

extension

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.5 and GLM-4.6, for example, are both glm) and avoids the entire family during the current content-policy failover chain. Evidence is session-scoped: it is cleared at session_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.
  • 90-second first-response and 120-second streaming-idle watchdogs.
  • Exponential cooldowns, Retry-After support, 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-run keeps one headless Pi RPC session alive and returns only the final successful answer after automatic model failover.

Requirements

  • Pi 0.84.4 or 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-runrunner.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.mjs0.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 unique provider/model combinations 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/model means 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 模式还会发出协议版本为 1ccswitch-completeccswitch-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 (input event with images), CCSwitch immediately switches to a healthy multimodal candidate (input explicitly includes image) before the request is processed, so the images are preserved;
  • When a tool execution returns images (e.g. the read tool loading an image file, whose result content includes image parts), 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 (input includes image) are considered; models with missing metadata are never assumed to support images;
  • The switch reason is recorded as modality and 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.

License

MIT