@yceachan/pi-vision-helper
v0.1.1
Published
pi extension + skill: visual understanding via a configurable vision model (pi-registry reuse or custom responses API; default gpt-5.6-luna) when the main model cannot see images — pure TypeScript, single runtime
Maintainers
Readme
pi-vision-helper(中文文档)
English docs: README.md
主模型没有视觉能力时,pi 的视觉理解委托包:把图片识别/描述/分析路由到一个可配置的视觉模型(OpenAI Responses API)。核心为纯 TypeScript(lib/),单一 runtime、无 python 依赖。
- 零配置可用:默认搜索 pi-registry——
~/.pi/agent/models-store.json中第一个input含image的luna模型(当前为gpt-5.6-luna/opencode-go),API key 取自~/.pi/agent/auth.json。 - 配置驱动:
vision.models[]可混合pi-registry条目(模糊匹配 Provider/Model,走 pi 鉴权)与responses条目(自定义 baseUrl +$ENV_VAR/字面量 apiKey);vision.active指定激活模型;enabled/forceVisionBridge/maxTokens/timeoutMs/systemPrompt调节行为。
包结构:
pi-vision-helper/
├── package.json # pi manifest:extensions + skills
├── lib/ # 核心(工具与 CLI 共用):config、registry、vision
│ ├── config.ts # 配置解析 + schema 归一化
│ ├── registry.ts # models-store / auth.json 访问 + 模糊匹配
│ └── vision.ts # 目标解析 + Responses API 请求往返
├── extensions/
│ └── pi-vision-helper.ts # 注册 `pi-vision-helper` 工具(进程内直调)
├── skills/
│ └── pi-vision-helper/
│ ├── SKILL.md # 触发条件、配置 schema、排查表
│ └── scripts/
│ └── vision.ts # 手动排查 CLI(bun 直跑),共用 lib/
├── README.md # 英文文档
└── README.zh.md # 本文档安装
pi install npm:@yceachan/pi-vision-helper或作为本地路径加入 ~/.pi/agent/settings.json:
"~/work/pi-agent-harness/extensions/mono/packages/pi-vision-helper"改完 /reload(或重启 pi)热加载。
用法
优先使用 pi-vision-helper 工具(schema 强制 images 与 prompt):
pi-vision-helper images=[路径1, 路径2] prompt="详细描述这张图" effort=high max_tokens=4096images:图片路径,支持 Windows(C:\...)与 WSL(/mnt/...)路径;至少一张 (工具 schema 拒绝空数组——纯文本请求也会真实扣费)prompt:必填,必须按用户具体意图显式构造(描述/转录/对比等),禁止省略effort:思考深度(默认取配置defaultEffort,未配置时high;medium易幻觉;xhigh/max需把max_tokens提到 8000+;off/minimal省略 reasoning 字段—— zen 网关直传会 HTTP 400)max_tokens:输出预算含 reasoning(默认取配置maxTokens,未配置 4096;强制范围 256–32768——配置与 CLI 值都会校验)
手动 CLI(同一核心,排查用):
bun packages/pi-vision-helper/skills/pi-vision-helper/scripts/vision.ts img.png \
--prompt "描述这张图" --model luna-customer --effort high --max-tokens 4096配置
配置文件按优先级取第一个存在的:
| 优先级 | 路径 | 作用域 |
| --- | --- | --- |
| 1 | --config <path>(CLI 参数) | 显式指定;文件缺失 = 直接报错 |
| 2 | $PI_VISION_HELPER_CONFIG | 环境变量显式指定;文件缺失 = 直接报错 |
| 3 | $CWD/.pi/vision-helper.json | 项目级(可入仓库,按项目共享) |
| 4 | ~/.pi/agent/pi-vision-helper.json | 用户级(全局默认) |
完全无配置文件 = 默认行为:搜索 pi-registry,使用最先找到的 provider 里第一个匹配到的 luna 模型(input 含 image)。
完整配置示例
{
// ── 全局开关 ──────────────────────────────────────────────────────────
"enabled": true, // 总开关;false = 工具/CLI 拒绝运行
"forceVisionBridge": false, // true = 主模型即使是 VLM 也允许委托
// (默认仅限无视觉主模型)
"defaultEffort": "high", // 默认思考深度;工具/CLI 的 effort 参数可覆写
"maxTokens": 4096, // 默认最大输出 token(含 reasoning);
// 工具/CLI 参数可覆写
"timeoutMs": 60000, // 默认单次视觉调用超时(毫秒);
// pi 工具未配置时回退 300000
"systemPrompt": "", // 自定义系统提示词;
// 空 = 内置默认(要求逐字转录等)
// ── 模型与 API ────────────────────────────────────────────────────────
"vision": {
"active": "luna", // 激活的模型名;缺省 = models[] 第一条;
// models[] 为空 = 旧版扁平字段 / 默认 luna 搜索
"models": [
{
// ① pi-registry 条目 —— 复用 pi 模型目录与 pi 鉴权
"name": "luna", // 唯一名称(vision.active / CLI --model 用)
"type": "pi-registry", // "pi-registry" | "responses"
"Provider": "opencode-go", // 模糊匹配 models-store.json 里的 provider
// (大小写不敏感;无匹配 = 报错并列出可用 providers)
"Model": "gpt-5.6-luna", // 模糊匹配该 provider 下的模型,优先 input 含
// image 的;缺省 = 首个 vision-capable(luna 优先)
// 可选覆盖(pi-registry):
// "cost": { "input": 0.1, "output": 0.6,
// "cacheRead": 0.01, "cacheWrite": 0.125 }, // 美元/每 M token;
// // 缺省 = store 条目成本
// "headers": { "X-Foo": "bar" } // 附加请求头
},
{
// ② responses 条目 —— 任意兼容 OpenAI Responses API 的端点
"name": "luna-customer",
"type": "responses",
"baseUrl": "https://opencode.ai/zen/go/v1",
// 必填:端点根(自动拼 /responses)
"apiKey": "$VISION_API_KEY",// 必填:$ENV_VAR 引用或字面量 key
"model": "gpt-5.6-luna", // 必填:字面模型 id(不做 registry 匹配)
// 可选(responses):
// "cost": { "input": 0.1, "output": 0.6 }, // 缺省 = 0(不计成本)
// "headers": { "X-Foo": "bar" } // 附加请求头
}
]
}
}字段参考
顶层
| 字段 | 类型 | 默认 | 含义 |
| --- | --- | --- | --- |
| enabled | bool | true | 总开关。false = 工具返回"已禁用"文本、CLI 报错退出 |
| forceVisionBridge | bool | false | 仅工具生效的门控:主模型是 VLM 也允许委托。不设时,当前主模型 input 含 "image" 则工具拒绝运行(CLI 无主模型概念,始终可委托) |
| defaultEffort | string | high | 工具/CLI 未传 effort 时的默认思考深度。必须是 off/low/medium/high/xhigh/max 之一(非法值 = 配置报错) |
| maxTokens | number | 4096 | 工具/CLI 未传时的默认 max_output_tokens(含 reasoning)。强制范围 256–32768(越界 = 配置报错) |
| timeoutMs | number | 60000 | 默认单次调用 HTTP 超时(毫秒;pi 工具未配置时用 300000) |
| systemPrompt | string | "" | 替换内置视觉助手指令;"" 保持默认 |
| vision | object | — | 模型选择块(见下);缺省 = 旧版扁平字段 / 默认 luna 搜索 |
vision
| 字段 | 类型 | 默认 | 含义 |
| --- | --- | --- | --- |
| active | string | 首条 | 激活模型条目名;未知名 = 报错并列可用名(绝不静默回退) |
| models | array | [] | 模型条目(按优先级排列);空 = 旧版扁平字段 / 默认 luna 搜索 |
模型条目
字段随 type 而定:
| 字段 | pi-registry | responses | 含义 |
| --- | --- | --- | --- |
| name | ✓ | ✓ | 条目唯一名(active / CLI --model 用);缺省 = <Provider>/<Model> 或 <model> |
| type | ✓ | ✓ | "pi-registry" = 复用 pi 目录与鉴权;"responses" = 自定义端点 |
| Provider | ✓ | — | 模糊匹配 models-store.json 里的 provider(大小写不敏感,provider 亦接受);无匹配 = 报错并列出可用 providers |
| Model | ✓ | — | 模糊匹配该 provider 下的模型(model 亦接受),优先 vision-capable;缺省 = 首个 vision-capable(luna 优先) |
| baseUrl | — | ✓ | 端点根,自动拼 /responses |
| apiKey | — | ✓ | $ENV_VAR 引用(调用时展开,环境未设置 = 报错)或字面量 key |
| model | — | ✓ | 字面模型 id,不做 registry 查找 |
| cost | ✓ | ✓ | 美元/每 M token {input, output, cacheRead, cacheWrite}。pi-registry:覆盖 store 条目成本(缺省 = store 成本);responses:缺省 = 0(不计成本) |
| headers | ✓ | ✓ | 并入请求的附加 HTTP 头(缺省 {}) |
模糊匹配
确定性顺序:精确(忽略大小写)> 候选包含查询串 > 查询串包含候选 > 无匹配 = 报错。 绝不静默选第一个候选——那会把未知 provider 路由到错误后端并真实扣费。
旧版扁平字段(仍兼容)
没有 vision 块时,旧的单模型字段照常工作:
{
"provider": "opencode-go", // registry provider(缺省:第一个 provider)
"model": "gpt-5.6-luna", // registry 模型 id(模糊;缺省:luna 搜索)
"modelMatch": "exact", // "exact" | "substring"
"baseUrl": "https://...", // 覆盖 / 自定义端点
"apiKey": "$VISION_API_KEY", // key 覆盖($ENV_VAR 或字面量)
"apiKeyEnv": "VISION_API_KEY", // 另一种形式:存 key 的环境变量名
"cost": { "input": 0.1, "output": 0.6 },
"headers": { "X-Foo": "bar" },
"defaults": { "effort": "high", "maxTokens": 4096 }
}生效优先级
工具/CLI 参数 > 配置文件 > pi-registry(models-store.json + auth.json)> 内置默认
(luna / high / 4096)。effort 具体链:工具/CLI effort > defaultEffort >
旧版 defaults.effort > high。key 专用优先级:条目 apiKey > 条目环境变量 >
auth.json[provider].key。
工作原理
- 请求:OpenAI Responses API——
POST {baseUrl}/responses,input_text(提示词)+ 每图一个input_image(data:<mime>;base64,...)。MIME 由扩展名推导 (png/jpg/jpeg/jfif/gif/webp/bmp/heic/avif);未知扩展名响亮报错而不是标错。 base64 字节只存在于内存与那次 HTTPS 请求中——不进主模型上下文、不落 session 历史。 models-store.json 里模型条目的api字段仅作参考:zen 网关对声明为 openai-completions 的模型同样服务/responses(kimi-k2.7-code 实测可用)。 - effort:
off/minimal直接省略reasoning字段(zen 网关映射为 null,直传会 HTTP 400invalid_prompt)。 - 用量与成本:工具通过 pi 的 Usage 上报 token 与美元成本——registry 条目成本为默认,
可逐条目
cost覆盖,未知时记 0。 - 报错:配置/registry 问题一律响亮失败并给出可操作信息(列出可用 providers/models、 环境变量名、所读配置文件路径)——无静默降级。
