| name | add-provider-models-to-pi |
| disable-model-invocation | true |
| description | 往 pi 的 models.json 新增/适配 provider 模型,含取参、思考三层合成、capture.ts 实测验证与固定。 |
Add Provider Models to Pi
把"往 pi 的 models.json 加模型"这件带判断的操作固化成可复用的执行规程。
对应 provider(leading word):模型实际被托管/调用的 provider,以其 baseUrl/api 为准——不是模型的厂商。例:火山方舟(ark.cn-beijing.volces.com)托管了 MiniMax/Kimi,但 models.dev 里只有 minimax.io/kimi.com 厂商端点。参数必须取自对应 provider,否则 API 格式/窗口会错。
执行协议
1. 确认 Input
- 目标 pi provider:
/home/cnife/.pi/agent/models.json 中已存在的 provider key,或用户要新建并命名。
- 模型清单:一个或多个模型,按 id/名称(如
minimax-m3、kimi-k2.7-code)。
- 完成标准:目标 provider 与模型清单已明确;provider 已存在或新建名已定。
2. 源定位 —— 按对应 provider(托管端点)匹配
- 读目标 pi provider 的
baseUrl + api。
- 用 models-dev-query 技能查 models.dev,找
api/baseUrl 与之相同的 provider:命中则取参;未命中(如方舟)则回退抓该对应 provider的官方 API 文档(web)。
- 注意:models.dev 的厂商端点(minimax.io)与托管端点(方舟)是不同 provider,模型名相同也不能混用参数。
- 完成标准:每个目标模型的参数源已确定(models.dev 命中 / 官方文档回退),并记下依据。
3. 适配 —— 翻译成 pi 的 model 条目
按目标 provider 的 api 类型查 api-adapters.md 对应节,确认该 api 的 compat 字段集、思考参数机制、off 语义、maxTokens 字段名、缓存与 tool 格式(per-api 事实依据)。
id:用用户给的 id;与源确认是端点实际接受的模型名(方舟支持全小写,也接受控制台原名)。
name:显示名。
reasoning:来自源。
thinkingLevelMap:见第 4 步三层合成。
input:pi schema 仅接受 text/image;源的 video 等丢弃。
contextWindow / maxTokens:以对应 provider官方文档为准;与 models.dev 冲突时取官方文档(如方舟 M3 为 512k 而非目录 1M)。
cost:源有按 token 计价填;订阅/套餐制(如 Coding Plan)省略(pi 默认 0)。
- 完成标准:每个模型已生成符合 pi schema 的 JSON 块,input 已去 video,context/maxTokens 取自对应 provider 官方文档。
4. 思考三层合成(核心难点)
- Layer1 Provider 机制:端点怎么收思考参数--按
api 类型查 api-adapters.md 对应节的「思考参数机制」「off 语义」(pi 如何把 thinkingLevelMap/compat 翻译成实际请求参数);源码指针亦在该文件。
- Layer2 模型能力:模型自身支持什么——来自源(
reasoning 否?toggle?分级?常开?)。
- Layer3 pi 处理:pi 把统一 level(off/minimal/low/medium/high/xhigh/max)翻译成该 provider API 的规则(靠
thinkingLevelMap):null 表示该档位不支持(pi 不展示、不可选),非 null 字符串表示支持且 pi 实际发送该端点值。off 行为因 api 而异(completions 多数 thinkingFormat 发显式关闭信号、responses 发 explicit effort、anthropic 不发参数)--具体见 api-adapters.md 的「off 语义」,勿假设"off=不发"。
- 合成:
off 映射非 null(如 "none")= 支持关闭(pi 可选 off 档,具体发送行为见 api-adapters.md);off->null = 不支持关闭。其余档位按模型实际支持情况映射成端点接受的 effort/toggle 字符串,不支持者置 null。同 provider 已有模型仅作交叉校验,不盲抄。
- 完成标准:每个推理模型已列出全部 7 个档位
off/minimal/low/medium/high/xhigh/max 的映射值;null=不支持,非 null 字符串=支持且为端点接受值;Layer1 已查 api-adapters.md 对应节(不可凭记忆跳过),off 语义已确认(支持关闭->非 null,不支持关闭->null)。
5. Checkpoint
跑完取参+适配,产出 brief 再让用户确认一次,确认后才写入:
- 将要插入的模型块(diff/表格)。
- 关键判断:参数源(models.dev 命中 / 官方文档回退)、三层思考结论(机制/能力/最终 map)、context/maxTokens 取值(与 models.dev 不同会标明)、cost 省略或填了。
- 来源链接。
- 完成标准:brief 已呈现并经用户确认;
models.json 写入且 jq empty 校验通过。
验证阶段(步骤 6–9):测试-抓取-循环-固定--写入配置后立即验证,用 capture.ts 扩展抓取 pi 实际发送的请求和响应,通过 ≤3 轮测试-改进循环收敛到正确配置,最终固定。
前提:步骤 5 已写入 models.json 且 jq empty 通过;capture.ts 位于技能 scripts/capture.ts。
6. 运行 agentic 测试
用 pi --extension 临时加载 capture.ts,执行一个 agentic 任务(多轮工具调用),
一次性覆盖四个调试维度:
PI_CAPTURE_LOG=/tmp/pi-verify-<provider>.jsonl \
pi --extension <skill-dir>/scripts/capture.ts \
--print --model <provider>/<model> \
'用 bash 工具列出 /tmp 目录下的前 5 个文件名,然后告诉我一共多少个'
<skill-dir> 替换为本技能实际路径(fd add-provider-models-to-pi 定位)。
- 注意用
--print(非交互模式),事件自动触发。
- 日志写入
PI_CAPTURE_LOG 指定路径(默认 /tmp/pi-capture.jsonl),格式为 JSONL(一行一个聚合 CALL 块)。
- 完成标准:pi 正常完成请求、日志文件已生成非空。
7. 抓取调试
读取 JSONL 日志,用 jq 按 CALL 块分析四维度(每行一个聚合块:assistant 含 request.payload/responses/message,user/toolResult 为精简块 callIndex=null):
| 维度 | jq 证据(JSONL 字段) |
|---|
| 基础链路 | .responses[].status=200;.message.stopReason 非 error |
| 思考参数 | .request.payload 含 reasoning/thinking/reasoning_effort;.message.content.thinkingBlocks>0 |
| tool 格式 | .request.payload.tools 非空;.message.stopReason=toolUse + .message.content.toolCalls 非空 |
| 缓存 | assistant 块第 2+ 个 .message.usage.cacheRead>0 |
L=/tmp/pi-verify-<provider>.jsonl
jq -c 'select(.role=="assistant") | {callIndex, status: .responses[0].status, stopReason: .message.stopReason, errorMessage: .message.errorMessage}' "$L"
jq -c 'select(.role=="assistant") | {callIndex, reasoning: .request.payload.reasoning, thinking: .request.payload.thinking, reasoningEffort: .request.payload.reasoning_effort, thinkingBlocks: .message.content.thinkingBlocks}' "$L"
jq -c 'select(.role=="assistant") | {callIndex, toolCount: (.request.payload.tools // [] | length), stopReason: .message.stopReason, toolCalls: .message.content.toolCalls}' "$L"
jq -c 'select(.role=="assistant") | {callIndex, cacheRead: .message.usage.cacheRead, cacheWrite: .message.usage.cacheWrite}' "$L"
注意事项:
before_provider_headers 事件拿不到 Authorization--pi 在事件返回后才注入 auth。调试 API key 靠"跑通与否"判断。
- user / toolResult 块
callIndex=null(无 provider 请求),分析时用 select(.role=="assistant") 过滤。
- 日志不脱敏(含 payload 里的 system prompt 全文、messages),调试结束删除。
- 完成标准:四维度均已检查,确认有无问题或明确问题所在。
8. 循环改进
如果步骤 7 发现配置问题,进入改进循环:
- 回退:配置问题需恢复时,用步骤 5 的备份或
git diff models.json 还原。
- 调整:根据步骤 7 的发现修正
models.json 配置:
thinkingLevelMap 档位映射错 → 调整第 4 步得出的映射。
compat 推断不对 → 显式设置 compat 字段覆盖自动推断。
- 其他字段错 → 按第 3 步重新适配。
- 重测:重复步骤 6--用
PI_CAPTURE_LOG 覆盖旧日志,确认问题已解决。
- 上限:≤3 轮。超过 3 轮仍未通过,暂停并向用户报告:
- 当前抓取发现(哪些维度通过、哪些失败)。
- 已尝试的调整及其效果。
- 待排查的配置问题。
- 回滚:从备份或 git 恢复步骤 5 前的
models.json。
一轮定义:一次 pi --extension capture.ts --print 运行 + 日志分析。
同轮内多次运行(修复后重测)仍算同一轮。
- 完成标准:配置问题已解决 或 超限暂停向用户报告。
9. 固定
配置验证通过后固定最终结果:
- 清除扩展:调试完成后,确认
models.json 未引用 capture.ts(无 --extension 依赖)。
- 校验:
jq empty /home/cnife/.pi/agent/models.json 确保 JSON 有效。
- 确认:
pi --list-models 2>&1 | grep <provider> 确认新模型可见。
- 清理:删除临时日志文件:
rm -f /tmp/pi-verify-<provider>.jsonl。
- 简报:告知用户:已添加的模型列表、已通过的测试维度、capture.ts 保留位置(后续排查可复用)。
- 完成标准:models.json 有效、模型在 pi 中可见、日志已清理、用户已被告知结果。