pi-model-config0.4.5
Add a Pi model endpoint from a URL and a key, then keep it in sync: context window, output limit, reasoning, vision and thinking levels are inferred from the endpoint itself, then models.dev, then the model name — then re-added, pruned or repaired on dema
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
pi-model-config
一个 URL 加一个 Key。模型的参数是推断出来的,不是手填的。
一个 Pi 扩展:把第三方 / 自建 / 中转模型端点加进 models.json,并让这条配置持续跟端点保持一致
—— 端点上新出现的加进来、消失的删掉、参数跑偏的修回来,依据是端点自身和
models.dev。
pi install npm:pi-model-config
安装后请新开一个会话(或 /reload):会话进行中安装的包,要等 Pi 重新读取包列表才会加载。
/model-config 菜单
/model-config add 添加或替换一个供应商(五个问题)
/model-config add <url> <key> 只给 URL 和 Key,不问问题
/model-config edit 修改一个供应商的 URL / Key / api / id
/model-config sync 补齐新模型 / 删掉失效模型 / 修参数
/model-config check [--fix] 只对账参数(--fix 不询问直接修复)
/model-config list [--ping] 列出已配置的供应商(--ping 附带端点状态与延迟)
/model-config default [pid/模型] 查看/设置默认供应商、模型与思考等级
/model-config remove 删除一个供应商
/model-config models <pid> 删除不要的模型
/model-config 是唯一的命令名(旧的 /model-setup 写法已在 0.4.0 移除)。
长什么样
$ /model-config add https://my-gateway.example.com/v1 sk-... --all
已配置 my-gateway-example-com:3 个模型,api=openai-completions,key=sk-…sed
- deepseek-v4.1-flash ctx=1048576 (models.dev) max=393216 (models.dev) reasoning (models.dev) [low/high/max] +image (models.dev)
- glm-5.3-flash ctx=131072 (endpoint) max=8192 (endpoint) reasoning (endpoint) [low/medium/high/xhigh/max]
- whisper-1 ctx=128000 (guess) max=16384 (guess)
参数推断来源:端点元数据 > models.dev > 模型名。随时可以手动编辑 models.json,或用 /model-config check 重新对账。原文件已备份。
每个字段都标注了来源(endpoint / models.dev / guess),check 和 sync 的
计划输出也是同样的形式。不加 --all / --only 或不在交互里确认就一个字节
都不写,每次写入前都有备份。
两个新命令的重点就是这行免交互形式:把 URL 和 Key 给它,contextWindow、maxTokens、
推理 / 视觉能力、思考强度全部从端点自己的元数据推断,不用手填;cost 用
models.dev 的官方牌价保底(走网关时的实际计价与牌价不同——这是记账下限,
不是账单承诺;手改的价格永远不被覆盖,详见下文「models.dev 的几个坑」)。
# 先看会加什么、参数是多少 —— 一个字节都不写
/model-config add https://gw.example.com/v1 sk-...
# 真的从这个端点加三个模型
/model-config add https://gw.example.com/v1 sk-... --only gpt-4o,deepseek-v4-pro
# 端点变了:补齐新模型、删掉已下线的
/model-config sync --all
add 和 sync 默认只打印计划、不写盘,必须给 --all 或 --only 才落地。
不存在「敲错一个 flag 就把文件重写一遍」的模式:--onlyy 直接报错,不会当成没写。
--dry-run 即使带了写入 flag 也只预览;--key / $PI_MODEL_CONFIG_API_KEY
可以避免把 Key 写进 shell 历史。
它解决什么
想让 Pi 用上一个 OpenAI 兼容网关,手写得写这么一坨:
{
"providers": {
"my-gateway": {
"baseUrl": "https://gw.example.com/v1",
"api": "openai-completions",
"apiKey": "sk-...",
"models": [
{
"id": "claude-opus-4-6",
"contextWindow": 1000000,
"maxTokens": 32000,
"reasoning": true,
"input": ["text", "image"],
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
"compat": { "supportsReasoningEffort": true },
"thinkingLevelMap": { "minimal": null, "low": "low", "medium": "medium", "high": "high", "xhigh": null, "max": null }
}
]
}
}
}
这些字段填错时全都不会报错:
contextWindow偏大 —— Pi 压缩得太晚,请求直接溢出。contextWindow偏小 —— Pi 压缩得太早,花钱买来的上下文被白白丢掉。cost缺失 —— pi-ai 的calculateCost要读model.cost.tiers,缺了抛TypeError,整轮回复判失败,而且看不出原因。supportsReasoningEffort缺失 ——openai-completions端点下,Pi 靠 URL 猜这个值; 自定义网关猜不出来,于是永远不发reasoning_effort。推理模型就这么不推理地跑着。thinkingLevelMap缺失或写错 —— 端点不支持的档位留在选择器里,支持的档位反而看不到。
没有任何东西校验这些。/model-config add 只问 URL、协议类型、API Key、模型、供应商 ID,
剩下全部推断。
参数从哪来
每个字段按顺序查三个来源:
| 来源 | 怎么取 |
|---|---|
| 端点元数据 | GET {baseUrl}/models,读 context_length、max_completion_tokens、supported_parameters、architecture.input_modalities、inputTokenLimit、supportedGenerationMethods、reasoning_options、reasoning_supported_efforts 等 |
| models.dev | https://models.dev/api.json,只提取「短名 → 能力」映射并本地缓存 |
| 模型名 | id 里的 128k / 1m 标记,加上少量家族默认值 |
add 流程会逐条打印每个字段来自哪个来源,推断结果可核对,而不是玄学。
推测值绝不覆盖已有值。 只有端点元数据和 models.dev 能改掉 models.json 里已有的值;
按名字猜出来的值只能填缺失的字段。端点连不上、models.dev 又没收录时,手调过的配置原样保留。
models.dev 的几个坑
- 聚合商(poe、azure、openrouter……)也收录别家的模型,而 providers 按字母序遍历 ——
所以「先到先得」拿到的是聚合商的错数据。原厂 provider 按模型名前缀匹配
(
claude*→ anthropic、gpt*/o*→ openai、glm*→ zai……),优先于任何聚合商。 - 拉取成功缓存 6 小时;拉取失败缓存 15 分钟。没有这个负缓存,离线机器每次 add / check / 启动都要空等 15 秒超时。失败时保留上一次成功的数据 —— 掉线是降级到旧数据,不是降级到没有。
- 缓存位置:
~/.pi/agent/model-config-modelsdev-cache.json。
/model-config edit
改一个供应商的连接字段,不动其他任何东西。与 add 的区别:add 是整表替换(重新探测、重写模型列表),
edit 只改你给出的字段,模型列表原样保留。
# 交互式:选供应商,逐项问要改什么(回车跳过)
/model-config edit
# 脚本化:先看计划,确认再加 --all
/model-config edit gw --url https://new-gw.example.com/v1 --key sk-new
/model-config edit gw --url https://new-gw.example.com/v1 --all
# 重命名(同步处理 enabledModels 里的旧条目)
/model-config edit gw --id new-name --all
# 开关该端点的自动刷新(见「不探测的端点」)
/model-config edit gw --no-probe --all
/model-config edit gw --probe --all
规则:
- 改 baseUrl / api 会先探测新端点:探测失败就不写入 —— 换错地址不会把能用配置改成不能用的;
- 改 key 不探测(端点对 key 的校验在下次 sync/check 时自然发生);
- 脚本化形式遇到非本机
http://端点拒绝执行(与 add 同一闸门); - baseUrl / apiKey 的修改无需重启:另一个扩展(如 sub-models)每次刷新都会重读 models.json。
/model-config sync
让 models 列表与端点当前的实际情况一致:
- 新增 端点列出了、配置里还没有的模型;
- 删除 端点已不再列出的模型(有 UI 时先确认,且一定先备份);
- 修复 跑偏的参数,规则与
check相同; - 补全 完全没有模型列表的供应商(
"models": []或压根没这个键)—— 手写一个{ baseUrl, api, apiKey }就是这个样子; - 其余一律保留,包括它不认识的字段。
端点把同一个 id 列两次时,只会写一个条目,不会变两条。
两条规则让它可以放心对着一个不稳定的网关跑:
- 删除必须以探测成功为前提。 端点读不到就整个跳过这个供应商 —— 不删,也不用猜测值去修。 网关挂一分钟,绝不可能把你的配置清空。
- 由其他扩展管理的供应商一律跳过。 它们的模型列表是那个扩展在刷新时生成的,
models.json里存的静态兜底本来就该与实时数据不同。
--no-prune 保留端点已下线的模型,但仍会新增和修复。--only <ids> 只限制新增哪些模型,
不限制删除 —— 否则一次局部同步就会留下过期条目。
/model-config models
手动管理某个供应商的模型列表:挑出不要的模型、确认、完成。删除的模型会记入
model-config.json 的 hiddenModels 忽略名单,之后 sync 不会再把它们补回来
——手动删除是一个决定,不该被对账撤销。
# 交互式:选供应商,再逐个挑要删的模型
/model-config models
# 脚本化:直接删这些,不弹对话框
/model-config models my-gateway --only old-model,another-model
想恢复某个被删的模型:跑 sync --only <id>(会同时把它从忽略名单移除),
或从 model-config.json 的 hiddenModels 里删掉对应 id 再跑 sync --all。
菜单路径的 sync 发现忽略名单里的模型端点仍在提供时,也会先问要不要恢复。
/model-config check
把 models.json 里的静态 models 与端点、models.dev 对账,并询问是否写回修正。
- 端点已不再提供的模型只报告,绝不删除 —— 删配置不是对账该做的决定。
- 修复只动有可信来源的字段,所以手写的
name、自定义compat键、本扩展不认识的字段都会保留。 --fix是书面同意:修复全部端点发现的偏差,不再逐个询问(脚本 /pi -p用)。- 对账是幂等的:第二次跑什么都不报。
- 文件解析失败会直接中止,一个字节都不写。
同一套对账会在会话启动时静默跑一次:没发现就完全不出声,/reload 不重跑。
它无权修复的偏差(如下线模型)每次会话报一次——这不是重复报问题的 bug,而是它刻意不替你做删除决定。
它是尽力而为、不阻塞启动的:启动永远不会为了等一次网络探测而卡住;而立刻结束的会话
(比如 pi -p "...")可能在审计跑完前就退出了。被中断的审计不会留下半截状态 ——
每次写入都是原子的、要么全成要么全不成 —— 它只是什么都不做,等下一个会话再说。
需要确定性请用 /model-config check。
/model-config list --ping 与 default
list 默认纯读文件、不联网。--ping 给每个端点发一次探测,标出可访问性与延迟——
回答「hub 是不是又挂了」这类问题不用跑完整的 check:
/model-config list --ping
# - me
# https://… | api=openai-completions | key=sk-8a8…117e | 5 个模型
# ✓ 可访问(214ms,HTTP 200)
default 把手编 settings.json 三个字段变成一条命令:
/model-config default # 看当前默认
/model-config default me/glm-5.3 high --all # 脚本化设置(默认模型 + 思考等级)
规则:脚本化形式不带 --all 只打印计划;选择的模型会先按 enabledModels
和 models.json 校验,选 pi 解析不到的模型会被拒绝而不是把坏状态写进 settings;
修改写入前备份 settings.json,新会话生效。
非交互模式
check、list、sync 以及 add <url> <key> 形式在 RPC / JSON / print 模式下都能用,
没有 UI 时报告写到 stdout。
区别在「谁来同意这次写入」。sync 和 add 的同意来自 flag(--all / --only),
所以自动化运行拿到计划后只执行你明确要求的那部分;sync 只在有 UI 时才额外为删除弹一次确认。
check 的同意是 --fix:没有 UI 时不带 flag 它只报告、不写,并指出要落地请用 sync --all
或 check --fix。remove、菜单、以及不带参数的 add 需要对话框,会明确拒绝而不是做到一半失败。
一个额外的闸门:脚本化 add 遇到非本机的 http:// 端点会直接拒绝(API Key 会明文发送,
脚本模式无人确认)。改用 https、用交互式 add 确认,或明确加 --all 表示接受该风险。
由其他扩展管理的供应商
扩展可以在运行时整体替换某个 provider 的 models 数组,这时 models.json 里只剩静态兜底
和凭据。往那儿写模型参数是无效的,强行「修复」等于跟那个扩展互相覆盖。所以这类 id
只报告、不自动改写,add 时也会先提醒。
声明一次即可:
// ~/.pi/agent/model-config.json
{ "runtimeProviders": ["my-provider"] }
或 PI_MODEL_CONFIG_RUNTIME_PROVIDERS="a,b"。id 大小写不敏感。model-config.json 写坏了
只会降级成「没有配置项」并给出提示 —— 它永远不能把命令弄瘫。
不探测的端点
黑洞端点会让每次对账干等到超时,也有些端点你根本不想让它刷新模型。两种退出方式,可叠加:
// provider 级,写在 models.json —— /model-config edit 开关的就是它:
{ "providers": { "slow-endpoint": { "noProbe": true, ... } } }
// 全局列表,写在 model-config.json(或 PI_MODEL_CONFIG_NO_PROBE="a,b"):
{ "noProbe": ["slow-endpoint"] }
或 PI_MODEL_CONFIG_NO_PROBE="a,b"。id 大小写不敏感。效果:
check(含启动对账和--fix)跳过该 provider 的端点探测,只用 models.dev / 名称推断对账, 报告里注明ℹ noProbe;sync整体跳过该 provider —— sync 的本职就是从端点拉新模型 —— 表格里注明原因;list --ping依然会 ping 它:那是你显式点名的动作。
它会写什么
models.json—— 先备份成models.json.bak-<毫秒时间戳>,再原子写入(临时文件 + rename), 中断不会留下半截文件,重写也不会放宽已有的严格权限(如 0600)。同名的三个文件 (models.json / settings.json / model-config.json)的时间戳备份都只保留最近 5 份; 备份本身失败时会给出警告(写入照常进行,不会因此中断)。写入会重排整个文件, 手写的//注释不会保留。settings.json—— 只碰enabledModels,且只在其非空时:添加供应商会自动追加<id>/*; 删除时会先问。
/model 的快照问题
/model 选择器用的是会话启动时的 enabledModels 快照,而 agent-session.reload()
不会重算它。所以刚加或刚删的供应商只在新会话或重启 pi 之后才出现 / 消失 —— /reload
不够。所有提示都如实这么说。
API Key
Key 从对话框读入、写进 models.json,而 pi 以明文保存该文件。Key 永远不会被打印回来:
短到「前 6 + 后 4」就等于全泄露的,只报长度。base URL 是 http:// 且非回环地址时,
不加确认不往下走 —— 那样 Key 是明文上路的。
探测也认识 pi 的凭据库:当某个 provider 在 models.json 里没有 apiKey 时,
check、list --ping 和 edit 会回退到 pi 存在 ~/.pi/agent/auth.json 里的
api_key 凭据(也就是运行时优先用的那个 stored credential)。OAuth 型凭据
不参与 —— 它的 bearer 由 pi 的刷新流程签发。本扩展只读 auth.json,
从不写它:那个文件由 pi 持锁管理。
Google Gemini
Gemini 的 REST 用 ?key= 鉴权而不是 bearer,所以探测走查询参数;base URL 没有版本段时
补 /v1beta;读 name / inputTokenLimit / outputTokenLimit;并按
supportedGenerationMethods 过滤掉 embedding 之类的非对话模型。
配置文件一览
| 文件 | 用途 |
|---|---|
~/.pi/agent/models.json |
读写。JSONC:允许注释和尾逗号。 |
~/.pi/agent/settings.json |
只碰 enabledModels。严格 JSON,与 Pi 的 settings-manager 一致。 |
~/.pi/agent/model-config.json |
可选:runtimeProviders、hiddenModels、noProbe。 |
~/.pi/agent/model-config-modelsdev-cache.json |
models.dev 缓存,删了没事。 |
设置 PI_CODING_AGENT_DIR 可以把以上全部指到别处。
开发
npm test # node --test,不联网,零依赖
npm run lint # 全量源文件语法检查
测试会在临时目录里自建 PI_CODING_AGENT_DIR 并注入假 fetch,不碰网络,也不碰你真实的
models.json。
老实说清限制
- 参数质量取决于来源。端点什么都不报、models.dev 又没收录的模型,拿到的是按名字猜的默认值,
报告里会标成
guessed。请核对,然后手改models.json。 - 只写
models.json这一种格式,不修改 Pi 自带的 provider。 - 不推断价格改为官方牌价保底:models.dev 里有该模型的价格就用它(让费用
统计不再是全零),走网关时的实际计费与牌价不同,它只是量级参考;
手改的
cost永远不会被覆盖 —— 把网关的真实价格填进 models.json, 对账会原样保留。 - 已消失的模型永远不会被自动删除。
致谢
为 LINUX DO 社区而写,并首发于社区。
许可证
MIT