custom-provider-pi 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +286 -0
- package/custom-provider.ts +2066 -0
- package/package.json +40 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 custom-provider contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
# custom-provider
|
|
2
|
+
|
|
3
|
+
pi 扩展:在 TUI 或 RPC(Telegram 等)环境下统一管理第三方模型 Provider。
|
|
4
|
+
|
|
5
|
+
一个命令入口 `/custom-provider`,九个子命令覆盖添加、删除、刷新、测试、查看/编辑配置、启用/禁用与模型修剪;既支持交互引导,也支持 `--flags` / JSON 参数非交互添加(脚本、Telegram 可用)。同一 Provider 内可混用 OpenAI 与 Anthropic 协议(按模型覆盖)。
|
|
6
|
+
|
|
7
|
+
## 安装
|
|
8
|
+
|
|
9
|
+
### 方式一:直接放扩展目录(已安装本机)
|
|
10
|
+
|
|
11
|
+
把 `custom-provider.ts` 复制到 pi 的全局扩展目录即可热加载:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
cp custom-provider.ts ~/.pi/agent/extensions/
|
|
15
|
+
# 然后在 pi 里 /reload
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### 方式二:作为 pi 包安装(发布到 npm / git)
|
|
19
|
+
|
|
20
|
+
本目录已带 `pi` 清单(`package.json#pi.extensions`),可作为 pi 包分享:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# 从本地目录或 git 仓库安装
|
|
24
|
+
pi install local:E:/custom-provider # 或 git:... / npm:...
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
运行时无任何第三方依赖(只用 Node 内置模块),`@earendil-works/pi-coding-agent` 仅做类型引用,由 pi 运行时捆绑,声明在 `peerDependencies`。
|
|
28
|
+
|
|
29
|
+
## 命令总览
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
/custom-provider add [名称] [flags] 添加(交互引导或参数化添加)
|
|
33
|
+
/custom-provider remove <名称> [--yes] 删除(--yes 跳过确认)
|
|
34
|
+
/custom-provider refresh [名称] 重新拉取模型列表
|
|
35
|
+
/custom-provider list 列出所有 provider(含启用状态)
|
|
36
|
+
/custom-provider test <名称> | --base-url 测试连接(已配置项或临时端点)
|
|
37
|
+
/custom-provider config [edit|path|<名称>] 查看 / 编辑配置
|
|
38
|
+
/custom-provider enable|disable <名称> 启用 / 禁用 provider
|
|
39
|
+
/custom-provider prune <名称> [--keep/--drop 关键词] 修剪模型列表(避免全量保留)
|
|
40
|
+
/custom-provider help 显示帮助
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Tab 键可自动补全子命令与 provider 名(大小写不敏感)。
|
|
44
|
+
|
|
45
|
+
## add 详解
|
|
46
|
+
|
|
47
|
+
### 交互模式
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
/custom-provider add
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
按向导依次输入:名称 → 端点 URL → API Key → 协议类型 → 是否自动拉取模型 → 自定义请求头 → 高级配置 → 模型列表。自动拉取成功后**会询问如何过滤模型**(按关键字保留/排除),避免把渠道全量模型写入配置。
|
|
54
|
+
|
|
55
|
+
### 参数模式(非交互)
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
/custom-provider add deepseek \
|
|
59
|
+
--base-url https://api.deepseek.com/v1 \
|
|
60
|
+
--api-key $DEEPSEEK_API_KEY \
|
|
61
|
+
--models deepseek-chat,deepseek-reasoner
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
| flag | 说明 |
|
|
65
|
+
|---|---|
|
|
66
|
+
| `--name` / 位置参数 | provider 名称(字母/数字/-/_,≤32 字符) |
|
|
67
|
+
| `--base-url` / `--url` | API 端点(自动清理 `/v1/models` 尾巴并补全 `/v1`) |
|
|
68
|
+
| `--api-key` / `--key` | 支持 `$ENV` / `!命令` / 字面量 / `local`(默认) |
|
|
69
|
+
| `--api` | `auto`(默认,按 URL 推断)\| `openai-completions` \| `openai-responses` \| `anthropic-messages` \| `google-generative-ai` |
|
|
70
|
+
| `--models` | 逗号分隔的模型 ID 列表 |
|
|
71
|
+
| `--model` | 单个模型 ID,可多次累加 |
|
|
72
|
+
| `--header "K: V"` | 自定义请求头,可多次 |
|
|
73
|
+
| `--headers '{"k":"v"}'` | 以 JSON 形式设置请求头 |
|
|
74
|
+
| `--auth-header` | 开启 `Authorization: Bearer <key>`(非标准 API 用) |
|
|
75
|
+
| `--compat '{...}'` | 协议兼容选项(如 `supportsDeveloperRole`) |
|
|
76
|
+
| `--overrides '{"模型id":{...}}'` | 按模型覆盖:`reasoning` / `input` / `contextWindow` / `maxTokens` / `cost` / `api` / `baseUrl` |
|
|
77
|
+
| `--model-api "模型id:协议"` | 让单个模型走另一协议,可多次(见下文双协议) |
|
|
78
|
+
| `--model-base-url "模型id:url"` | 让单个模型使用另一端点,可多次 |
|
|
79
|
+
| `--force` / `-f` | 已存在时直接覆盖(不加则交互确认 / 报错) |
|
|
80
|
+
| `--json '{...}'` | 完整配置 JSON(跳过所有 flag) |
|
|
81
|
+
| `--ua <预设\|原始UA>` | 预设 User-Agent(见下),或直接给自定义字符串 |
|
|
82
|
+
| `--profile <模板键>` | 应用完整请求头模板(`claude-code` / `codex` / `opencode` / `browser` 等,含 UA + 客户端典型头集合) |
|
|
83
|
+
| `--proxy <URL>` | HTTP/SOCKS 代理地址(支持 `$ENV`) |
|
|
84
|
+
|
|
85
|
+
### JSON 参数
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
/custom-provider add --json '{
|
|
89
|
+
"name": "gw",
|
|
90
|
+
"baseUrl": "https://gw.example.com/v1",
|
|
91
|
+
"apiKey": "$MY_KEY",
|
|
92
|
+
"api": "openai-completions",
|
|
93
|
+
"enabled": true,
|
|
94
|
+
"authHeader": false,
|
|
95
|
+
"headers": { "X-Custom": "v" },
|
|
96
|
+
"models": ["gpt-4o", { "id": "claude-x", "api": "anthropic-messages" }]
|
|
97
|
+
}'
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## 双协议混用(同一 Provider 内 OpenAI + Anthropic)
|
|
101
|
+
|
|
102
|
+
协议决定优先级:**模型 `api` 字段 > provider 级 `api` > 按 URL 自动推断(默认 `openai-completions`)**;模型 `baseUrl` 同理可覆盖端点。
|
|
103
|
+
|
|
104
|
+
三种配置方式:
|
|
105
|
+
|
|
106
|
+
**① flags:**
|
|
107
|
+
```
|
|
108
|
+
/custom-provider add gw --base-url https://gw.example.com/v1 --api-key $K \
|
|
109
|
+
--models gpt-4o,claude-x \
|
|
110
|
+
--model-api claude-x:anthropic-messages \
|
|
111
|
+
--model-base-url claude-x:https://api.anthropic.com
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**② 高级配置(交互向导 → 高级配置):**
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"authHeader": false,
|
|
118
|
+
"compat": {},
|
|
119
|
+
"modelOverrides": {
|
|
120
|
+
"claude-x": { "api": "anthropic-messages", "baseUrl": "https://api.anthropic.com" }
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**③ JSON 参数:** 见上文 `--json` 示例。
|
|
126
|
+
|
|
127
|
+
### User-Agent 预设
|
|
128
|
+
|
|
129
|
+
部分中转/反代服务会按 UA 指纹拦截非浏览器/SDK 请求。除浏览器默认外,内置以下预设(反代一般只校验前缀关键字,版本号仅供参考,可自行改源码 `UA_PRESETS`):
|
|
130
|
+
|
|
131
|
+
| 预设键 | 行为示例 |
|
|
132
|
+
|---|---|
|
|
133
|
+
| `browser`(默认) | `Mozilla/5.0 ... Chrome/131.0.0.0 Safari/537.36` |
|
|
134
|
+
| `claude-code` | `claude-code/2.1.237` |
|
|
135
|
+
| `codex` | `codex_cli_rs/0.148.0 (cli)` |
|
|
136
|
+
| `opencode` | `opencode/1.18.19` |
|
|
137
|
+
| `cursor` | `Cursor/3.16.0 (Windows; 64bit)` |
|
|
138
|
+
| `windsurf` | `Windsurf/2.0.0 (Windows)` |
|
|
139
|
+
| `openwebui` | `OpenWebUI/0.11.0` |
|
|
140
|
+
| `chatgpt` | `Mozilla/5.0 ... ChatGPT-Desktop/1.2025.0` |
|
|
141
|
+
|
|
142
|
+
使用:
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
/custom-provider add my --base-url https://gw.example.com/v1 --api-key $K \
|
|
146
|
+
--models gpt-4o --ua claude-code # 预设键
|
|
147
|
+
/custom-provider add my --base-url ... --ua "MyApp/1.0" # 直接给原始字符串
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
交互向导在「自定义请求头」后会询问 UA 预设(选「自定义」可自己输入)。若请求头里已显式写入 `User-Agent`,则以你写的为准,不覆盖。
|
|
151
|
+
|
|
152
|
+
### 请求头模板
|
|
153
|
+
|
|
154
|
+
`--ua` 只预设一个 `User-Agent` 头。`--profile` 预设**整组请求头**(UA + 客户端典型头集合),对 Claude Code、Codex 等不同客户端各自携带的头集合不同:
|
|
155
|
+
|
|
156
|
+
| 模板键 | 包含的头 |
|
|
157
|
+
|---|---|
|
|
158
|
+
| `browser`(默认) | 仅 UA(浏览器) |
|
|
159
|
+
| `claude-code` | UA + `anthropic-version` + `x-app` + `content-type` + `anthropic-dangerous-direct-browser-access` |
|
|
160
|
+
| `codex` | UA + `accept` |
|
|
161
|
+
| `opencode` | UA |
|
|
162
|
+
| `cursor` | UA |
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
/custom-provider add my --base-url ... --api anthropic-messages \
|
|
166
|
+
--models claude-sonnet-4 --profile claude-code
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
> 优先级:`--header`/`--headers` 显式头 > `--profile` 模板 > `--ua` > 默认浏览器 UA
|
|
170
|
+
|
|
171
|
+
请求头值支持 `$ENV` / `!cmd` 插值(pi 请求时动态解析),支持 JSON 对象或逐行 `"Key: Value"` 两种格式输入。敏感头(`authorization`、`x-api-key`、`anthropic-beta` 等)允许设置但会给出警告提示。
|
|
172
|
+
|
|
173
|
+
### 代理
|
|
174
|
+
|
|
175
|
+
`--proxy` 支持 HTTP/SOCKS 代理地址,配置后注册时会设置 `HTTPS_PROXY` / `HTTP_PROXY` / `ALL_PROXY` 环境变量:
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
/custom-provider add my --base-url https://api.deepseek.com/v1 \
|
|
179
|
+
--api-key $KEY --models deepseek-chat --proxy http://127.0.0.1:7890
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
> ⚠️ Node.js 的 `fetch` 需要 `NODE_USE_ENV_PROXY=1` 才会读取代理环境变量(Vite/Tauri 等桌面应用的内置 fetch 也类似)。传统 `http.request` / `https.request` 不读取这些变量;如需在 Node 底层走代理,请用 `global-agent` 等库或升级到 Node ≥ 22 并设置该环境变量。
|
|
183
|
+
## prune:模型修剪
|
|
184
|
+
|
|
185
|
+
添加时自动拉取后已提供关键字过滤;对已有 provider 可用 `prune` 事后修剪:
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
/custom-provider prune cpa # 交互:列出并按关键字筛选
|
|
189
|
+
/custom-provider prune cpa --keep "deepseek,glm" # 只保留 ID 含任一关键字的模型
|
|
190
|
+
/custom-provider prune cpa --drop "qwen,mini" # 排除 ID 含任一关键字的模型
|
|
191
|
+
/custom-provider prune cpa --keep "deepseek" --drop "4.1"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
- 大小写不敏感子串匹配;`--keep` / `--drop` 可组合
|
|
195
|
+
- 过滤结果为空或未命中时不修改并提示;保留原有模型的详细配置(contextWindow 等)
|
|
196
|
+
- 支持 Tab 补全 provider 名
|
|
197
|
+
|
|
198
|
+
## enable / disable
|
|
199
|
+
|
|
200
|
+
`disable` 写入 `"enabled": false` 并立即注销(`/model` 中消失,配置保留);`enable` 恢复并重新注册。
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
/custom-provider disable cpa # 对应配置: "enabled": false
|
|
204
|
+
/custom-provider enable cpa
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
启动注册、`refresh`、`test`、`prune` 都会跳过 / 拦截已禁用项;`add` 覆盖已禁用 provider 时会保留其禁用状态。
|
|
208
|
+
|
|
209
|
+
## config / list / test / refresh
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
/custom-provider config # 配置摘要(含文件路径与启用状态)
|
|
213
|
+
/custom-provider config cpa # 单个 provider 的完整 JSON
|
|
214
|
+
/custom-provider config edit # 编辑器修改,保存即校验并全量重注册
|
|
215
|
+
/custom-provider config path # 配置文件路径
|
|
216
|
+
/custom-provider list # 全部 provider:状态 / 协议 / 端点 / 模型预览
|
|
217
|
+
/custom-provider test cpa # 用配置测试连接(拉取 /models 验证端点与 Key)
|
|
218
|
+
/custom-provider test --base-url http://localhost:8080/v1 --api-key local # 测临时端点,不保存
|
|
219
|
+
/custom-provider refresh cpa # 重新拉取模型列表(保留已有模型详细配置)
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## 配置文件
|
|
223
|
+
|
|
224
|
+
默认位置(Windows 示例):
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
C:\Users\<你>\.pi\agent\custom-providers.json
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
```jsonc
|
|
231
|
+
{
|
|
232
|
+
"providers": [
|
|
233
|
+
{
|
|
234
|
+
"name": "cpa", // 名称,唯一
|
|
235
|
+
"baseUrl": "https://cpa.example.com/v1",
|
|
236
|
+
"apiKey": "$CPA_API_KEY", // 见下方取值语法
|
|
237
|
+
"api": "openai-completions", // 可选:协议类型
|
|
238
|
+
"enabled": true, // 可选:false = 禁用(不注册)
|
|
239
|
+
"headers": { "X-Custom": "v" }, // 可选:请求头,值支持 $ENV
|
|
240
|
+
"authHeader": false, // 可选:非标准 API 用
|
|
241
|
+
"compat": {}, // 可选:协议兼容选项
|
|
242
|
+
"models": [
|
|
243
|
+
"gpt-4o", // 字符串 = 走 provider 默认协议
|
|
244
|
+
{ "id": "claude-x", "api": "anthropic-messages" }, // 对象 = 按模型覆盖
|
|
245
|
+
{ "id": "vision-1", "input": ["text", "image"], "reasoning": true,
|
|
246
|
+
"contextWindow": 200000, "maxTokens": 16384,
|
|
247
|
+
"cost": { "input": 0, "output": 0 } }
|
|
248
|
+
]
|
|
249
|
+
}
|
|
250
|
+
]
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
`apiKey` 与 header 值的取值语法(pi 原生支持,请求时动态解析):
|
|
255
|
+
|
|
256
|
+
| 写法 | 含义 |
|
|
257
|
+
|---|---|
|
|
258
|
+
| `sk-xxx` 字面量 | 直接使用 |
|
|
259
|
+
| `$ENV_VAR` / `${ENV_VAR}` | 环境变量插值 |
|
|
260
|
+
| `!command` | 执行命令,以输出作为值(如 `!cat ~/.key`) |
|
|
261
|
+
| `local` | 无认证的本地服务(默认) |
|
|
262
|
+
|
|
263
|
+
模型规格(`contextWindow` / `maxTokens`)未显式配置时,自动按 OpenRouter 公开目录(24h 磁盘缓存)→ 内置已知规格 → 保守默认(128K / 16K)填充。
|
|
264
|
+
|
|
265
|
+
## 安全注意事项
|
|
266
|
+
|
|
267
|
+
- `apiKey` 与 header 值**明文存储**在 `custom-providers.json`,请勿把该文件同步进公开仓库;Linux 下可考虑收紧权限
|
|
268
|
+
- `!command` 特性会执行配置中的命令,仅编辑你信任的配置文件
|
|
269
|
+
- 自定义请求头建议使用 `$ENV` 引用而非字面量,避免密钥落盘
|
|
270
|
+
|
|
271
|
+
## 开发
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
npm install # 安装 devDependencies(typescript / @types/node)
|
|
275
|
+
npm run typecheck # tsc --noEmit 类型检查
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
类型依赖只用于本地检查:运行时零第三方依赖,pi 通过 jiti 直接加载 `.ts`。
|
|
279
|
+
|
|
280
|
+
## 发布为 pi 包
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
npm pack # 打包(files: custom-provider.ts, README.md, LICENSE)
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
或推送到 git 仓库后 `pi install git:...`。包已带 `pi-package` 关键字,便于在 pi 包目录被发现。
|