@fanchaozz/provider-manager
A pi extension that manages custom providers and models in ~/.pi/agent/models.json via a TUI dashboard, /providers slash command, and remote model sync.
Package details
Install @fanchaozz/provider-manager from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@fanchaozz/provider-manager- Package
@fanchaozz/provider-manager- Version
1.1.0- Published
- Sep 11, 2026
- Downloads
- 1,427/mo · 221/wk
- Author
- fanchaozz
- License
- MIT
- Types
- extension
- Size
- 200.3 KB
- Dependencies
- 0 dependencies · 1 peer
Pi manifest JSON
{
"extensions": [
"./"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
provider-manager
一个 pi 扩展,通过 TUI 仪表盘、/providers 斜杠命令和远端同步流程,管理 ~/.pi/agent/models.json 中的自定义 provider 和 model。
范围:只覆盖
models.json—— 本扩展不管理内置 provider、不切换 model、不提供登录 UI。这些请用 pi 内置的/model和 provider 认证流程。
安装
pi install npm:@fanchaozz/provider-manager
依赖:@earendil-works/pi-coding-agent(pi 自带)。jiti 向上找 node_modules,不需要在扩展目录内 npm install。
安装后,首次加载时会自动创建 ~/.pi/agent/provider-manager.json(见 用户配置)。删除该文件即可回退到代码默认。
最近变更
版本变更记录看 CHANGELOG.md。
快速开始
| 想做什么 | 操作 |
|---|---|
| 打开仪表盘 | /providers |
| 列出 provider + 它们的 model | /providers ls(过滤:/providers ls kdapi) |
| 新增 provider | 仪表盘 Providers 面板按 n,或 /providers add [<id>] |
| 新增 / 删除 model | 通过 sync(仪表盘 Models 面板按 y),或 手动新增(按 n,sync 拉不到时使用模板) |
| 编辑 provider / model | 仪表盘选中后按 Enter(表单里 Enter 进入字段 edit、确认) |
| 删除 | 仪表盘按 d(确认对话框) |
| 从 provider 的 API 拉取新 model 列表 | 仪表盘按 y,或 /providers sync [<pid>] |
| 探测 auth + 可达性 + 1-token 测试调用 | 仪表盘 t(当前 model)或 T(provider 内全部),结果在浮窗内展示;或 /providers test <pid>/<mid>、/providers test-all [pid] |
从最近 .bak 恢复 |
/providers reset |
| 打印命令帮助 | /providers help |
| 关闭仪表盘 | q 或 Esc |
sync 命令是给全新 provider 填充 model 列表最快的方式:拉取远端 model 列表,显示 checklist,把选中的写回。sync 不到时(离线上游 / 私有部署 / 不支持 /models)可以手动新增:仪表盘 Model 面板按 n,使用 ~/.pi/agent/provider-manager.json#defaultModel 模板(compat.supportsDeveloperRole:false 也保留不丢)。
仪表盘
/providers 打开一个浮窗(类似 pi-mcp-adapter 的 /mcp):不占用对话窗口,可以随时按 q 关闭。对话窗口会保留上面的输出。
仪表盘采用 3 个固定区域 + footer 的布局,不随数据动态膨胀:
- 顶部左栏 —— Providers(固定 8 行可视;超了滚动,首项 pin +
(top),底部(current/total)) - 顶部右栏 —— Models(同上)
- 底栏 —— Detail(固定 16 行;选中项的完整信息)
- Footer(≤2 行 hint拼接;超了会加
+N more截断,不会撑爆宽度)
数据行多了 (provider / model 数超过可视行) 可以:
↑/↓或j/k— 单行滚动(循环)PgUp/PgDn— 整页滚动g/G— 跳顶 / 跳底
跨 provider 切时 model 面板的滚动位置自动重置(避免传过来)。
按键绑定
| 键 | 行为 |
|---|---|
↑↓ / j k |
在当前面板上下移动(循环) |
g / G |
跳到顶 / 底 |
PgUp / PgDn |
整页滚动 |
← / → |
切换 Providers ↔ Models 面板 |
n |
Providers 面板:新增 provider。Models 面板:手动新增 model(sync 不到时;走 defaultModel 模板) |
Enter |
选中行进入 edit 表单(浮窗式,不占对话窗口) |
d |
删除(带确认对话框) |
y |
同步(拉取选中 provider 的远端 model 列表) |
t / T |
仅 Models 面板:探测当前 model / provider 内全部 model(TestPanel 浮窗展示结果,↑↓ 滚动) |
? |
切换帮助覆盖层(按面板显示特有键) |
q / Esc |
关闭仪表盘 |
底部提示按面板动态调整(provider 面板显示 n、model 面板显示 t / T),不会出现在不该出现的面板里。
同步流程
sync 是批量加 model 的最快方式。它会拉取选中 provider 的远端 model 列表并显示 checklist。sync 拉不到时(离线上游 / 私有部署 / 不支持 /models)可以用 手动新增(仪表盘 Model 面板 n)。
checklist 展示该 provider 的所有 model(existing + remote new 都有):
- 已有 model 标
<id> (existing),默认勾选。取消勾选 = 删除。 - 远端新 model 只标
<id>,默认不勾选。勾选 = 添加。
按 Enter 写入结果,按 Esc 取消。保存时最终 models.json 是 (勾选的 existing) + (勾选的 new) 的并集;远端 new 优先于 local(这样能拉到最新的 reasoning / input / ctx / maxTokens / thinkingLevelMap)。
checklist 对齐 pi 的 /models 列表交互(model 多也能顺畅操作):
- 始终可见的 search 输入框:顶部
>提示词 + 输光标,随时键入过滤(不区分大小写,同时匹配id和label);Backspace 删字。 - 视口滚动:默认 8 行可见。item 多于可见行时上下以
⋮ N more below/⋮ N hidden提示。 - 钉住首项:cursor 滚出首页区后,顶部仍钉住
m000 (top)。无论怎么滚都能看到首项。 - wrap-around 导航:
↑/↓顶部 / 底部循环选择;j/k等价。 - Space 切换选中:filter 状态下也作用于过滤后的当前项,不会误动隐藏项。
- 顶部
selected / total selected状态保持。 - 底部
(current/total)位置指示(filter 非空时是过滤后位置,空时是总长度)。 - search-first 约定:所有可打印字符(a / i / g / G 等)都进 search,不作快捷键。避免与过滤输入冲突。
视口高度可以用 ~/.pi/agent/provider-manager.json 的 syncViewportSize 字段覆盖(5–200,越界走默认 8)。
新加的 model 字段来自 ~/.pi/agent/provider-manager.json 的 defaultModel 段(不是代码内置默认)—— 这是 loadDefaultModelConfig() 的行为。在 sync 前编辑这个文件可以定制 sync 出来的 model 模板。
proxy 字段:provider 编辑表单里可填 proxy(形如 http://127.0.0.1:7890)。sync 时设到 HTTPS_PROXY / HTTP_PROXY 环境变量,请求结束后还原。其他并发 fetch 会临时看到同一 proxy(env 是进程全局的,sync 一次只 1 个 fetch)。
apiKey 字符约束:sync 拒绝 code > 255 的 apiKey(含 •、中文、emoji 等,常见于复制粘贴残留)。错误是 actionable:apiKey contains non-Latin-1 character at position 7 (U+2022). Re-enter the key in the provider form.
检测 noise:默认过滤 embed* / tts / whisper / dall-e / clip / moderation / image-* 等 embedding/tts/image-gen 类 model。
用户配置 — provider-manager.json
~/.pi/agent/provider-manager.json 控制以下场景的默认值:
- 在新增 model 表单回答 "yes" 到 "Use default config?"
- 从远端 API 同步新 model
首次启动自动创建。删掉就回退到代码默认。
Schema
{
"_defaultModel": "自由格式注释,运行时忽略",
"defaultModel": {
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 16384,
"thinkingLevelMap": {
"off": null,
"minimal": null,
"low": null,
"medium": "medium",
"high": null,
"xhigh": null,
"max": null
}
}
}
字段规则
reasoning— boolean。true表示该 model 支持扩展思考,thinkingLevelMap才生效。input— 非空数组,内容是"text"和/或"image"。"text" | "image"表示 model 接受该模态。contextWindow/maxTokens— 正整数(token 数)。thinkingLevelMap— object。7 个 key(off/minimal/low/medium/high/xhigh/max)的任意子集。string值(如"medium")表示该 thinking level 启用,字符串发给 provider;null表示禁用。缺失的 key 当null处理。
如果文件缺失、JSON 损坏或校验失败,扩展会静默 fallback 到上面展示的内置默认。
为什么 medium 是默认勾选的
同步的 model 若 reasoning: true 且 thinkingLevelMap.medium = "medium",pi 的 Shift+Tab 思考级别循环会默认落到 medium。根据你上游实际支持的级别选 — 不支持的填 null 禁用即可。
表单编辑器(新增/编辑 model/provider)
addProviderFlow / editProviderFlow / editModelFlow / deleteProviderFlow / deleteModelFlow 都共用一个 TUI 表单(components.ts:FormEditor)。addModelFlow 已停用——model 只能通过 sync 增删。
字段类型
| 类型 | 行为 |
|---|---|
text |
自由文本输入 |
secret |
同 text,但用 Enter 进入 edit 后显示真实值(不显示 masked ••••Xn),切 field 不写回 masked 覆盖原 key |
number |
自由数字输入,提交时校验 |
select |
选项列表;按 Enter 进 edit,Space 选中,↑↓ / jk 导航,再 Enter 退出 |
multiselect |
类似 select 但可多选;Space 切换每项 |
levelmap |
7 行(off / minimal / low / medium / high / xhigh / max);Space 切换每项;提交时归一化缺失的 key 为 null |
readonly |
仅展示,不可编辑 |
按键绑定(统一 view / edit 两态模型)
| 键 | view 模式 | edit 模式 |
|---|---|---|
↑↓ / j k |
切字段 | non-typeable:选项内 nav;typeable:no-op(j/k 是字符) |
Enter |
进 edit | commit + 退出 edit(留在原字段) |
Esc / q |
取消整个 form | 退出 edit(commit) |
s |
保存整个 form | no-op(typeable 里 s 是字符;non-typeable 忽略) |
Space |
non-typeable 快捷进 edit | non-typeable 切换 / 选中 |
Backspace |
no-op | typeable 删最后一个字符 |
| 字符 | no-op | typeable 追加到 draft |
view 模式不接受任何字符输入(含 s / q / 数字 / 字母)。需要先按 Enter 进 edit 才能改。
typeable 字段的 j / k 在 view 模式是 nav(不当作字符),在 edit 模式是字符。
secret 字段的两种保护(避免保存的 key 被 masked 显示覆盖):
- 进入 edit 时
draft恢复为真实值(不是 masked••••Xn),用户能看见 / 修改真 key - commitDraft 在
draftIsOriginal=true(用户没改)时不写回,保证原 key 完整
addProviderFlow 与 editProviderFlow 结构同形
两个流程都用同一个 FormEditor 模板(含 id / name / baseUrl / apiKey / api / authHeader / proxy 字段)。addProviderFlow 的 id 字段有 validate:字符集 [a-z0-9_-]+ + 不能与已有 provider 重复(json.providers[s] 已存在则报 "provider already exists")。错误留在 FormEditor 自带的 ⚠ ... 行显示,不弹 notify 打断流程。
探测 model(t / T)
t 探测当前 model;T 探测当前 provider 内全部 model。每个 model 三档检查:
| 检查 | 做什么 | 成本 |
|---|---|---|
auth |
在 ~/.pi/agent/auth.json(或环境变量)里查 provider 的 API key |
免费 |
reachable |
GET {baseUrl}/models,10s 超时 |
免费 |
generated |
发 4-token prompt("Reply with the single word: ok")并检查 stopReason ∈ {stop, length} |
~4 token |
硬上限:maxTokens 钳到 16;超时 10s(用 PI_PROVIDER_TEST_TIMEOUT 环境变量覆盖)。结果缓存在进程内,重启 pi 前有效。
文件布局
~/.pi/agent/
├── models.json ← 本扩展编辑的文件
├── models.json.bak ← 每次写前的自动备份
└── extensions/
└── provider-manager/ ← 本扩展(pi install / git clone 安装)
本扩展不触碰 models.json 和 models.json.bak 之外的文件。要回滚,从 .bak 恢复:/providers reset,或手动:
cp ~/.pi/agent/models.json.bak ~/.pi/agent/models.json
故障排查
pi install 报 E404 或 "no such package"。 npm registry 没收到这个包名。先 npm view @fanchaozz/provider-manager 看是否发布成功;如果成功还报,检查 npm config get registry 输出不是 npm.pkg.github.com。
仪表盘打开是空的。 你的 models.json 里没有自定义 provider。本扩展只管 models.json — pi 内置 provider(anthropic / openai / google 等)不显示,用 pi 内置的 /model。
Sync 报 ECONNREFUSED / ENOTFOUND。 选中 provider 的 baseUrl 不通。用仪表盘选中该 provider 后按 Enter 进 edit 表单改。
Sync 报 HTTP 500 / HTTP 401。 baseUrl 错或 apiKey 缺失/错。在 provider 编辑表单里核对。
Sync 报 Cannot convert argument to a ByteString。 apiKey 含非 Latin-1 字符(•、中文、emoji 等,常见于复制粘贴残留)。重新打开 provider 的 edit 表单,把 apiKey 字段清空再贴一次真 key。
Sync 总是 ctx=128000 / max=16384(默认值),看起来没读到 user 配置。 检查 ~/.pi/agent/provider-manager.json 是否存在 + 路径正确(必须正好是这个文件名,不是 providers.json 等)。校验:node -e "JSON.parse(require('fs').readFileSync(process.env.HOME+'/.pi/agent/provider-manager.json','utf8'))"。
Dashboard 显示的 apiKey status 与真状态不一致。 dashboard 不通过 pi runtime 检测 key 是否真有效(避免 OAuth / runtime / env / extension 多路径歧义),只自检 models.json 里 apiKey 字段是否非空。真认证测试用 t / T。
保存 secret 字段后 apiKey 变成了 ••••Xn。 这是 0.1.x 的老 bug(切 field 时 commitDraft 把 masked 字符串写回原 key)。0.2.0 已修:进入 edit 时 draft 恢复真实值,未改时 commitDraft 跳写。0.2.0 起,re-enter edit 表单不会改变 key。如果是老版本升上来:edit 表单里把 apiKey 清空再贴一次真 key。
设的 thinking level 一保存就消失。 pi 可能不支持该 level — 换别的,或者填 null 禁用。
按 n / Enter / d / y 后 Esc 仪表盘消失。 当前版本不应发生 — 仪表盘会自动恢复。如果发生了,请带 ~/.pi/agent/provider-manager.log 反馈。
相关
- pi 内置
/model— 切换当前 model - pi 内置 provider auth(
/login或环境变量)— 设 API key - 备份恢复:
/providers reset或cp ~/.pi/agent/models.json.bak ~/.pi/agent/models.json