omp packages

@blueocean223/pi-provider0.2.3

/provider command for pi: add, edit and test custom providers (relays, proxies, local servers) in models.json

blueocean223 Published 5 days ago MIT ~321 downloads/mo

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.

Did it work for you?

Result

One report per person. A new report replaces your old one.

Reports 0

No reports yet.

Readme

pi-provider

English | 简体中文

Pi(@earendil-works/pi-coding-agent)扩展:提供 /provider 命令,管理 ~/.pi/agent/models.json 里的自定义供应商——中转站、代理、本地 OpenAI 兼容服务。添加供应商、选模型、测试、切换模型,都不用手写 JSON。

界面展示

供应商列表(/provider)——每个供应商一行,带最近一次测试结果;回车进入,t 测试:

 Providers
 ~/.pi/agent/models.json

 → claude-relay  claude.example-relay.com · anthropic-messages · 2 models  ✓ 2/2 · 1.2s · 5m ago
   google        proxy → gemini.example-relay.com
   ollama        localhost:11434/v1 · openai-completions · 1 model  ✓ 1/1 · 310ms · 1h ago
   relay-one     api.relay-one.com/v1 · openai-completions · 3 models

   + Add provider
   + Add local server (Ollama · LM Studio · vLLM)
   + Route a built-in provider through a relay
   Edit models.json

 ↑↓ navigate  enter open  t test  escape/ctrl+c close

测试面板——chat 测试走 pi 自己的请求路径;中转站的报错如果对应某个 compat 标记,会直接给出修复方法(按 c),在通过的模型上回车即切换:

 Test provider: relay-one
 api.relay-one.com/v1 · openai-completions · 3 models

   ✓ Catalog probe — listed 3 model(s) · 205ms
       https://api.relay-one.com/v1/models · HTTP 200
 → ✓ Chat test (gpt-4.1) — replied · 821ms
   ✗ Chat test (o3-mini) — HTTP 400: Invalid value: 'developer' is not a supported role
       ↳ relay rejects the "developer" role — press c to set supportsDeveloperRole=false
   ✓ Chat test (deepseek-chat) — replied · 1.1s

 ✗ 1 of 4 check(s) failed
 ↑↓ choose  enter use model  c apply compat fix  x remove 1 failing  s choose models  r run again
 escape/ctrl+c close

供应商页面(/provider relay-one)——每项设置一行,就地编辑:

 relay-one

 → Base URL      https://api.relay-one.com/v1
   Protocol      OpenAI Chat Completions
   API key       stored in models.json · sk-…9c2e
   Display name  (none — shows the id)
   Compat        none

   Models        3 configured
   Add model ids manually
   Sync metadata from pi's catalog

   Test connection
   View JSON
   Delete provider

 ↑↓ navigate  enter edit / open  escape/ctrl+c back

特性

  • 以供应商为主界面:/provider 打开供应商列表,回车进入某个供应商的页面,每项设置都是一行、就地编辑(base URL、协议、API key、显示名、compat、模型);在列表上按 t 直接测试
  • 五步新增流程:base URL → API key → 协议 → 模型 → 汇总页。按 Esc 回退时已填的值都保留;汇总页可以直接改任意字段,改个拼写错误不用从头走一遍
  • API 协议手动四选一,不做猜测:OpenAI Chat Completions、Anthropic Messages、OpenAI Responses、Google Generative AI
  • API key 只有一个输入框:粘贴 key 即明文保存,输入 $NAME 引用环境变量,留空则之后用 /login。明文 key 不会再显示出来(显示为 sk-…abcd)
  • 自动请求中转站 GET /v1/models,打开模型清单,每行带上下文长度 / 是否 thinking(输入即搜索,Space 切换,Ctrl+A 切换当前可见的全部行)
  • 自动对齐 pi 官方模型目录,为选中模型补全 contextWindow、maxTokens、reasoning、thinkingLevelMap、cost 等元数据;匹配不到则回退默认值(128k 上下文)
  • 转发 Anthropic 模型级 compat 标记(如 Claude Opus/Sonnet 4.6 的 forceAdaptiveThinking),让中转副本与官方端点以相同方式协商 thinking
  • 保存即测试:保存后直接打开测试面板;在通过的模型上按回车即把当前会话切到该模型
  • 测试走 pi 自己的请求路径(modelRegistry.streamSimple):凭据(含 /login 与供应商 headers)、URL 拼接、compat 标记、请求结构都与真实会话一致——reasoning 模型的系统提示以 developer role 发送,并带 reasoning_effort
  • compat 按实际报错设置,不靠猜:中转站拒绝某个请求字段(developer role、reasoning_effort、max_tokens 与 max_completion_tokens、stream_options、store)时,面板会指出是哪个字段,按 c 写入对应 compat 标记并重测失败的模型
  • 测试面板显示每个模型的延迟,x 移除失败的模型,s 选择要测哪些模型;供应商列表显示本次会话里每个供应商最近一次测试结果
  • 每个供应商一张模型清单:已配置的模型默认勾选,中转站有但尚未添加的标 new,已配置但中转站不再列出的会标出来;勾选变化生成 +/- 差异,确认后一次写入
  • 本地服务预设:Ollama、LM Studio、vLLM
  • 支持只改内置供应商的 baseUrl,让它走中转站,不动它的模型列表
  • 可将已配置模型与 pi 官方目录重新对齐——同步上游修复(如新增 compat 标记),不影响 id、自定义名称和手动修改的字段
  • 写入 models.json 采用原子写入(临时文件 + rename),并尽量收紧权限到 0600;每次写入前重新读取文件,保留期间其他地方做的修改
  • 无生产依赖:@earendil-works/pi-coding-agent、@earendil-works/pi-tui 由 pi 运行时提供,装好 pi 即可用

安装

pi install npm:@blueocean223/pi-provider

然后重启 pi,或在会话里执行 /reload。加 -l 则安装到当前项目(.pi/settings.json)而不是全局;卸载用 pi remove npm:@blueocean223/pi-provider。注意带 scope:npm 上不带 scope 的 pi-provider 是另一个项目。

不安装、只在本次运行中试用:

pi -e npm:@blueocean223/pi-provider

从源码安装、参与开发见开发。

用法

在 pi 会话里输入(子命令和供应商 id 都支持 Tab 补全):

命令 作用
/provider 供应商列表——回车进入供应商页面,t 测试;新增和编辑 models.json 在列表底部(别名 list)
/provider <id> 直接进入该供应商的页面
/provider add 新增中转站,或任何兼容 OpenAI / Anthropic / Google 协议的端点
/provider local 新增本地服务(Ollama、LM Studio、vLLM)
/provider models [id] 为供应商添加或移除模型(别名 add-models)
/provider proxy 让内置供应商走中转站(只覆盖 baseUrl)
/provider test [id] 测试连通性,并对每个模型做 chat 测试(别名 probe)
/provider remove [id] 删除供应商(别名 rm)
/provider path 直接编辑 models.json(别名 edit)

在各个界面里,操作结果(已保存、已删除、已切换到 …)显示为下一个界面顶部的一行提示。直接回到聊天的子命令只用一条通知报告结果。

供应商列表与供应商页面

列表每个供应商一行——id host · 协议 · N models,再加本次会话里最近一次测试结果(✓ 3/3 · 820ms · 2m ago)。只改了 baseUrl 的内置供应商显示为 proxy → host。

供应商页面列出各项设置;在某行上回车即编辑,改动立即写入(编辑时按 Esc 不做任何修改):

  • Base URL、Protocol、Display name
  • API key——回车替换(留空保留已存的 key);x 删除 key(明文 key 会先确认)
  • Compat(OpenAI 系协议)——预设,或以 JSON 编辑
  • Models——合并后的模型清单(见下文);Add model ids manually 手动添加;Sync metadata from pi's catalog 同步元数据
  • Test connection、View JSON、Delete provider

/provider add

  1. Base URL——中转站 API 根地址,自动去掉结尾斜杠
  2. API key——粘贴 key(保存在 models.json,文件权限 0600);输入 $MY_RELAY_API_KEY 引用环境变量;留空则之后用 /login / --api-key
  3. API protocol——手动选择(不自动推断):OpenAI Chat Completions(openai-completions,绝大多数中转站)、Anthropic Messages、OpenAI Responses、Google Generative AI
  4. Models——自动拉取模型目录(OpenAI 风格 { data: [{ id }] },与聊天协议无关;按 baseUrl 是否已含 /v1 决定 {baseUrl}/v1/models、{baseUrl}/models、{baseUrl}/api/v1/models 的尝试顺序),至少选一个。中转站列不出模型时,会打开编辑器并写明原因,可以手动输入 model id
  5. 汇总页——所有字段在一页上,provider id 按域名自动建议(api.relay-one.com → relay-one)。建议的 id 不会与 models.json 里已有的 id、pi 已有的供应商(deepseek、openai 等)或子命令名重复,重复时依次加 -2、-3。手动填了内置供应商的 id 会显示警告:pi 会把这条配置并入它自己的供应商,该供应商的内置模型也会改发到这个 base URL。在某行上回车即编辑,Models 回到模型清单。Save and test 写入并打开测试面板

每个选中的 model id 都会匹配 pi 官方模型目录(直接取自 pi 运行中的模型注册表,因此各种安装方式都能用,且包含 pi 的远程目录刷新结果):匹配到则复制官方的 contextWindow / maxTokens / reasoning / thinkingLevelMap / cost 等字段(id 仍然用中转站自己的),匹配不到则用默认值(128k 上下文、非 reasoning、零成本)。对于 Anthropic 协议的模型,描述模型自身请求特性的 compat 标记(如 forceAdaptiveThinking、supportsStrictTools)也会一并复制;网关/会话路由类标记则有意不复制。

新增流程不再预先询问 compat:pi 文档要求 compat 标记描述已验证的差异,所以改为在中转站确实拒绝某个字段时,由测试面板给出对应的标记。

/provider local

选择 Ollama(localhost:11434/v1)、LM Studio(localhost:1234/v1)或 vLLM(localhost:8000/v1),已安装的模型会列出并默认勾选。本地供应商会写入一个占位 API key,因为 pi 只显示凭据可解析的供应商的模型。端口可在汇总页修改。

/provider models

每个供应商一张清单:已配置的模型默认勾选;中转站列出但尚未配置的模型默认不勾选,标 new;已配置但中转站不再列出的模型标 not listed by relay。取消勾选即移除,勾选即添加,最后确认 +/- 差异。

新增的模型从 pi 官方目录补全元数据;已有条目和手动修改过的元数据原样保留,不取消勾选的模型不会被删除。内置供应商本身已有的模型不会显示为 new。请求目录时使用该供应商已保存的 key 和请求头。仅覆盖 baseUrl 的代理在没有 API 协议时不能添加模型,但已经配置的自定义模型仍然可以移除。

供应商页面上的 Sync metadata from pi's catalog 会将所有已配置模型重新与官方目录匹配,写入前展示字段级 diff(model: field 旧值 → 新值)。只更新目录管理的字段(reasoning、thinkingLevelMap、input、contextWindow、maxTokens、cost、compat);id、自定义 name、api 和未知字段都会保留,匹配不到官方目录的模型原样保留。

/provider test

所有检查在同一个实时面板里进行——spinner 原地变成 ✓/✗,Esc 中断请求,关闭面板后聊天记录中不留痕迹:

  • Catalog 探测——尝试模型目录端点,能列出模型即视为健康;拿不到列表则回退成普通 HTTP 请求按状态码判断
  • Chat 测试(模型 id)——每个模型一行,通过 pi 自己的模型注册表发送:一句要求只回一个词的系统提示加 "hi",最多 16 个输出 token,OpenAI 系协议的 reasoning 模型开启 reasoning。通过的行显示延迟(6 秒起标为警告色);失败的行显示 HTTP 状态码和中转站返回的错误信息。注册表里还找不到的模型,改用相同凭据手工构造的最小请求

同时最多发 4 个 chat 请求(几十个请求一起打过去,中转站只会回 429,看着像真的失败);排队中的行显示为 ○ … queued。检查上方的提示会说明没有解析到 API key 的情况(例如当前 shell 没有设置 $ENV_VAR),或 key 是 !command(catalog 探测不会执行它)。测试结束后:

按键 作用
↑↓ / 回车 把当前会话切换到一个通过的模型
c 写入报错指向的 compat 标记,并重测失败的模型
x 从 models.json 移除失败的模型(先确认)
s 选择要测试的模型
r 重新运行

终端太矮、放不下所有行时,列表会滚动,让结论和按键提示留在屏幕上。运行中显示正在运行的检测项,结束后显示正在选的行或第一个失败项。没有可切换的通过模型时,用 ↑↓ 滚动列表。

仅覆盖 baseUrl 的代理只做 catalog 探测——它们的对话走内置供应商。

/provider proxy

只想让某个内置供应商(anthropic、openai、google、openrouter、deepseek、xai、mistral、groq、minimax、minimax-cn、kimi-coding、zai、zai-coding-cn,或自行输入其他 id)改走中转站时用这个:选择供应商,填中转站 base URL,可选填 key(留空继续用 /login 或环境变量鉴权),在汇总页确认后 Save and test。如果该供应商已有自定义模型,汇总页可以选择保留或删除。

pi 取凭据的顺序是:--api-key、/login 存的凭据(auth.json)、models.json 里的 apiKey、环境变量。所以如果你对该供应商做过 /login,中转站收到的是那个凭据,这里填的 key 不会被使用。汇总页、供应商页面和测试面板都会提示这一点;中转站有自己的 key 时,用 /logout 删除该凭据。

/provider path

在编辑器中打开 models.json。JSON 无效时会带着错误信息和你的修改重新打开编辑器;有效的修改确认后原样保存,注释和格式都保留。

配置文件示例

/provider add 保存后,~/.pi/agent/models.json 大致长这样:

{
  "providers": {
    "my-relay": {
      "baseUrl": "https://api.example.com/v1",
      "api": "openai-completions",
      "apiKey": "$MY_RELAY_API_KEY",
      "models": [
        {
          "id": "claude-sonnet-4-6",
          "name": "Claude Sonnet 4.6",
          "reasoning": true,
          "contextWindow": 200000,
          "maxTokens": 64000,
          "cost": { "input": 3, "output": 15, "cacheRead": 0.3, "cacheWrite": 3.75 }
        }
      ]
    }
  }
}

以下字段命令本身不会生成,但 models.json 支持,可按需手动补充:authHeader、headers、modelOverrides、oauth。

保存后在测试面板里对通过的模型按回车即可切换,也可以之后用 /model 选择;无需重启 pi。

开发

git clone https://github.com/BlueOcean223/pi-provider.git
cd pi-provider
bun install
pi install "$(pwd)"
bun run test

本地路径会直接写入设置、不复制文件,修改后执行 /reload 即生效。

测试和类型检查会 import pi 在运行时提供的包(@earendil-works/*、typebox)。bun install 不安装它们(见 bunfig.toml),所以它们来自你正在运行的 pi:把它们从 pi 的安装目录链接到本目录或上级目录的 node_modules/ 下。

文件结构:

pi-provider/
├── index.ts                  # 注册 /provider:参数解析、补全、路由
├── flows/
│   ├── home.ts                # 供应商列表、供应商选择器、models.json 编辑器
│   ├── provider.ts            # 供应商页面:就地编辑字段、删除
│   ├── add.ts                 # 新增中转站 / 本地服务:向导 + 汇总页
│   ├── proxy.ts               # 让内置供应商走中转站
│   ├── models.ts              # 合并模型清单、手动添加 id、目录元数据同步
│   ├── test.ts                # 测试面板流程:注册表 chat 测试、compat 修复、移除失败模型、切换模型
│   ├── fields.ts              # 每个供应商字段一个输入界面(新增、汇总页、供应商页面共用)
│   └── shared.ts              # 鉴权解析、注册表刷新、元数据补全、写入助手
├── scripts/verify-pack.mjs    # 检查 `npm publish` 实际要发布的文件
└── lib/
    ├── types.ts               # ProviderApi / ModelEntry / ProviderConfig 等类型与文案
    ├── models-json.ts         # 读写 models.json(兼容 JSONC、原子写入、0600 权限收紧)
    ├── detect-api.ts          # GET /v1/models 探测、连通性测试、备用 chat ping
    ├── official-catalog.ts    # 从 pi 运行中的模型注册表取官方目录,做 id 匹配与元数据补全
    ├── model-management.ts    # 模型 diff/merge/refresh 不变量
    ├── compat-hints.ts        # 把中转站报错映射到能修复它的 compat 标记
    ├── test-history.ts        # 每个供应商最近一次测试结果(仅本次会话)
    ├── row-menu.ts            # 对象页面的行列表:列对齐、按行生效的快捷键、提示行
    ├── loop-ui.ts             # 循环滚动 select/editor、带预填的输入框、向导步骤机、spinner
    ├── checks-panel.ts        # ✓/✗ 实时检查面板,含延迟、选择模型与测试后操作
    ├── checkbox-select.ts     # 基于 pi-tui SettingsList 的 [x]/[ ] checklist 多选
    └── testing/tui-harness.ts # 测试中用脚本按键驱动 ui.custom 界面

运行 bun run test 执行测试,bun run typecheck 执行类型检查。测试覆盖各组件(checklist、行列表、输入框、测试面板)、向导步骤机、模型 diff/merge 不变量、compat 提示,以及 TUI 模式下用脚本按键跑完整流程(新增 → 汇总 → 保存 → 测试 → 切换模型、compat 修复后重测、在供应商页面修改 key)和 RPC 模式下的流程。

npm publish 前会先跑测试、类型检查和 scripts/verify-pack.mjs:它按 import 关系检查 npm 实际要打包的文件(不缺文件,也不带测试和本地笔记)。

注意事项

  • models.json 路径与 pi 本体一致,尊重 PI_CODING_AGENT_DIR 环境变量;默认为 ~/.pi/agent/models.json
  • 与 pi 一致,本扩展接受 models.json 中的 // 注释与尾逗号——但重写文件时它们会被移除(会写入的界面在文件含注释时会提示)
  • 模型元数据直接取自 pi 运行中的模型注册表(ctx.modelRegistry),任何安装方式都能补全;万一注册表为空,所有模型回退默认元数据,不影响正常使用,只是展示的上下文 / 价格不准确
  • 每次写入后会重新加载注册表(不联网),/model 和模型切换立即能看到改动
  • 各子命令需要可弹对话框的 UI(ctx.hasUI:TUI 或 RPC 宿主均可)。RPC 模式下列表退化为 select,模型清单退化为编辑器版 on/off 列表,测试面板以一条通知报告结果,面板按键(切换模型、compat 修复、移除失败模型)不可用。完全非交互环境会直接报错并打印 models.json 路径

License

MIT(见 LICENSE)