@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.

Packages

Package details

extension

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

English | 简体中文

一个 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
关闭仪表盘 qEsc

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 输入框:顶部 > 提示词 + 输光标,随时键入过滤(不区分大小写,同时匹配 idlabel);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.jsonsyncViewportSize 字段覆盖(5–200,越界走默认 8)。

新加的 model 字段来自 ~/.pi/agent/provider-manager.jsondefaultModel(不是代码内置默认)—— 这是 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: truethinkingLevelMap.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 显示覆盖):

  1. 进入 edit 时 draft 恢复为真实值(不是 masked ••••Xn),用户能看见 / 修改真 key
  2. commitDraft 在 draftIsOriginal=true(用户没改)时不写回,保证原 key 完整

addProviderFloweditProviderFlow 结构同形

两个流程都用同一个 FormEditor 模板(含 id / name / baseUrl / apiKey / api / authHeader / proxy 字段)。addProviderFlowid 字段有 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.jsonmodels.json.bak 之外的文件。要回滚,从 .bak 恢复:/providers reset,或手动:

cp ~/.pi/agent/models.json.bak ~/.pi/agent/models.json

故障排查

pi installE404 或 "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.jsonapiKey 字段是否非空。真认证测试用 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 resetcp ~/.pi/agent/models.json.bak ~/.pi/agent/models.json