pi-cliproxyapi-autoconnect 0.0.0-stage → 1.2.1

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.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +336 -2
  3. package/index.ts +1313 -0
  4. package/package.json +41 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 pi-cliproxyapi-autoconnect 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 CHANGED
@@ -1,3 +1,337 @@
1
- # Temporary Holding Version
1
+ # pi-cliproxyapi-autoconnect
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 给 [pi](https://github.com/earendil-works/pi) 用的 **CLIProxyAPI 反代插件**。
4
+
5
+ 安装后,pi 的 `/login` 里会多出一个 **CLIProxy** 选项(位于 “Sign in with an API key” 下)。选中后:
6
+
7
+ 1. 输入 CLIProxy 的**绑定域名**(例如 `proxy.example.com`);
8
+ 2. 输入 **API Key**;
9
+ 3. 插件按 CLIProxy 的地址规则推导出兼容地址,并**自动依次尝试**:OpenAI → Gemini → Anthropic(OpenAI 优先);
10
+ 4. 把拉到的模型列表注册进 pi,之后在 `/model` 里直接选择使用;
11
+ 5. 只有所有兼容地址都失败时才让你手动选择(或手填地址),并可以手动输入模型 ID。
12
+
13
+ API Key 由 pi 自己保存在 `~/.pi/agent/auth.json`;插件自己的配置文件只保存域名、地址和模型缓存,**不保存 Key**。
14
+
15
+ > 已在 pi `1.2.0` 与 `1.3.0` 上验证:Provider 注册、`/model` 列表、模型发现与回退、实际对话请求(OpenAI 兼容流式)均可用。
16
+
17
+ ---
18
+
19
+ ## 安装
20
+
21
+ ### 方式 A:从 npm 安装(推荐给其他用户)
22
+
23
+ ```powershell
24
+ pi install npm:pi-cliproxyapi-autoconnect
25
+ ```
26
+
27
+ 然后重启 pi(或在 pi 里执行 `/reload`)。
28
+
29
+ npm 包只包含 `index.ts`、`README.md`、`LICENSE`,由 pi 的 npm 安装器负责下载;下面两个方式只适用于本地目录版。
30
+
31
+ ### 方式 B:从本地目录安装(开发/自用)
32
+
33
+ 插件目录:`F:\Desktop\pi-cliproxyapi-autoconnect`。
34
+
35
+ ```powershell
36
+ pi install F:\Desktop\pi-cliproxyapi-autoconnect
37
+ ```
38
+
39
+ 然后重启 pi(或在 pi 里执行 `/reload`)。
40
+
41
+ ### 方式 C:复制到扩展目录
42
+
43
+ ```powershell
44
+ powershell -ExecutionPolicy Bypass -File F:\Desktop\pi-cliproxyapi-autoconnect\install.ps1
45
+ ```
46
+
47
+ 脚本会把插件复制到:
48
+
49
+ ```text
50
+ %USERPROFILE%\.pi\agent\extensions\pi-cliproxyapi-autoconnect\
51
+ ```
52
+
53
+ 如果设置了 `PI_CODING_AGENT_DIR`,则复制到该目录下的 `extensions\pi-cliproxyapi-autoconnect\`。
54
+
55
+ 也可以手动把整个 `pi-cliproxyapi-autoconnect` 文件夹复制到 `%USERPROFILE%\.pi\agent\extensions\` 下,确保入口是:
56
+
57
+ ```text
58
+ %USERPROFILE%\.pi\agent\extensions\pi-cliproxyapi-autoconnect\index.ts
59
+ ```
60
+
61
+ pi 会自动加载 `extensions` 目录下的子文件夹(入口为 `index.ts`)。
62
+
63
+ 安装后可以用下面的命令确认插件能被加载、模型能出现:
64
+
65
+ ```powershell
66
+ pi --list-models
67
+ ```
68
+
69
+ ### 从旧包 `pi-cliproxy` 迁移
70
+
71
+ 包名已改为 `pi-cliproxyapi-autoconnect`,provider ID 仍然是 `cliproxy`,`cliproxy.json` 和 `auth.json` 里的凭据都可以继续使用。
72
+
73
+ ```powershell
74
+ pi remove npm:pi-cliproxy
75
+ pi install npm:pi-cliproxyapi-autoconnect
76
+ ```
77
+
78
+ 然后重启 pi。`/model` 里仍然是 `cliproxy/<模型ID>`,原有配置和模型缓存不需要重建。
79
+
80
+ ---
81
+
82
+ ## 使用
83
+
84
+ 1. 重启 pi,执行 `/login`。
85
+ 2. 选择 **“Sign in with an API key”**(不是 “Sign in with an account”)。
86
+ 3. 在列表中选择 **CLIProxy**。
87
+ 4. 输入绑定域名,例如:
88
+ - `proxy.example.com`
89
+ - `https://proxy.example.com`
90
+ - `http://192.168.1.10:8317`
91
+ - 也可以直接粘贴完整地址,如 `https://proxy.example.com/v1`
92
+ 5. 输入 CLIProxy 的 API Key(即 CLIProxy 配置里 `access.api-keys` 中的值)。
93
+ 6. 插件会按 **OpenAI → Gemini → Anthropic** 的顺序自动尝试所有兼容地址:
94
+
95
+ ```text
96
+ https://<域名>/v1/models OpenAI(最高优先级)
97
+ https://<域名>/v1beta/models Gemini
98
+ https://<域名>/v1/models Anthropic(带 x-api-key,尽力尝试)
99
+ ```
100
+
101
+ 第一个返回非空模型列表的地址会被采用并保存。成功后 `/model` 中立即可见。
102
+ 如果输入的是没有写协议的裸域名,上述每个地址还会额外尝试另一种协议(https/http),因此最多 6 次探测。
103
+ 7. 执行 `/model`,选择 `cliproxy/<模型ID>` 即可使用。
104
+
105
+ ### 地址格式化规则
106
+
107
+ 输入域名后会先归一化成根地址(去掉末尾 `/`、`/v1`、`/v1beta`、`/v1/models` 等后缀,保留路径前缀),再推导:
108
+
109
+ | 用途 | 推导出的地址 |
110
+ | --- | --- |
111
+ | OpenAI 兼容(最高优先级) | `https://<域名>/v1`,模型发现走 `/v1/models` |
112
+ | Gemini 兼容 | `https://<域名>/v1beta`,模型发现走 `/v1beta/models` |
113
+ | Anthropic 兼容 | `https://<域名>`(SDK 自动追加 `/v1/messages`;模型列表尽力尝试 `/v1/models`) |
114
+
115
+ 如果输入的是本地/内网地址(`localhost`、`127.0.0.1`、`10.*`、`192.168.*`、`172.16-31.*`、`.local`、`.lan`),默认用 `http://`;否则用 `https://`。没有写协议时,每个兼容地址都会额外尝试另一种协议(https/http)。
116
+
117
+ ### 拉取失败时的回退
118
+
119
+ 插件会先自动尝试全部兼容地址。之后:
120
+
121
+ 1. 如果**任一**地址返回 401/403,说明更可能是 Key 的问题:
122
+ - 提示并重新输入一次 Key;
123
+ - 重新尝试全部地址;
124
+ - 第二次仍鉴权失败则中止,**不保存配置**。
125
+ 2. 其他失败(404、超时、格式错误等)且所有地址都没有模型列表时:
126
+ - 提示每个地址的失败原因,并尝试用 `/healthz` 判断是不是 CLIProxyAPI;
127
+ - 弹出兼容地址选择:
128
+ - 重试 OpenAI 兼容地址:`https://<域名>/v1`
129
+ - Anthropic 兼容地址:`https://<域名>`
130
+ - Gemini 兼容地址:`https://<域名>/v1beta`
131
+ - 自定义兼容地址(手填完整 base URL,并选择协议)
132
+ 3. 选择后如果仍然拿不到模型列表,会让你手动输入模型 ID(逗号或空格分隔,可留空)。
133
+ 4. 如果所有地址都返回 200、但模型列表为空,则不再弹地址选择,直接进入手动输入(通常表示上游账号没有可用凭据)。
134
+
135
+ Anthropic 兼容接口不一定提供模型列表;如果 `/v1/models` 返回 404/405,自动探测会跳过它,选择该地址后请手动输入模型 ID。Gemini 兼容地址会尝试 `/v1beta/models`。
136
+
137
+ ---
138
+
139
+ ## `/cliproxy` 命令
140
+
141
+ ```text
142
+ /cliproxy 查看当前配置、模型数量和最近错误
143
+ /cliproxy refresh 立即重新拉取模型列表
144
+ ```
145
+
146
+ 模型列表默认有 **5 分钟缓存**:打开 `/model` 时不会每次都打上游;`/cliproxy refresh` 会强制刷新。
147
+
148
+ 重新配置(换域名或换 Key):直接再执行一次 `/login` → `CLIProxy` 即可。若切换到了完全不同的域名后界面仍有旧缓存,执行 `/reload` 让插件按新配置重建 provider。
149
+
150
+ ### 与 pi 更新命令的关系
151
+
152
+ - **`pi update --models` 不会刷新本插件的模型列表。**
153
+ 该命令只创建一个不加载扩展的临时 ModelRuntime,刷新 pi 内置或 `models.json` 里的模型目录;插件 provider 不在其中。它不会破坏插件,只是不更新 `cliproxy/*`。
154
+ - 刷新插件模型请用:`/cliproxy refresh`、打开一次 `/model`、或重启 pi(交互模式启动时会刷新动态 provider)。
155
+ - **`pi update --extensions`** 用于更新 npm 包本身(插件代码);更新后重启 pi 即可。
156
+
157
+ ---
158
+
159
+ ## 文件与安全
160
+
161
+ | 内容 | 位置 |
162
+ | --- | --- |
163
+ | API Key | `~/.pi/agent/auth.json`(由 pi 登录流程写入) |
164
+ | 域名、兼容地址、模型缓存 | `~/.pi/agent/cliproxy.json` |
165
+ | 模型目录缓存(pi 维护) | `~/.pi/agent/models-store.json` |
166
+
167
+ `cliproxy.json` 示例:
168
+
169
+ ```json
170
+ {
171
+ "version": 2,
172
+ "domain": "proxy.example.com",
173
+ "rootUrl": "https://proxy.example.com",
174
+ "baseUrl": "https://proxy.example.com/v1",
175
+ "api": "openai-completions",
176
+ "models": [
177
+ {
178
+ "id": "gemini-2.5-pro",
179
+ "name": "gemini-2.5-pro",
180
+ "ownedBy": "google",
181
+ "reasoning": false,
182
+ "input": ["text"],
183
+ "cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
184
+ "contextWindow": 1000000,
185
+ "maxTokens": 65536
186
+ }
187
+ ],
188
+ "source": "auto",
189
+ "updatedAt": 0
190
+ }
191
+ ```
192
+
193
+ 说明:
194
+
195
+ - 从 1.1.0 起,完整模型元数据(`reasoning` / `input` / `cost` / `contextWindow` / `maxTokens`)会直接写进 `cliproxy.json`,不再只存 ID。
196
+ - 每次写入前会把上一版保存为 `cliproxy.json.bak`,方便手动恢复。
197
+
198
+ - 插件不会把 Key 写进 `cliproxy.json`,也不会打印到日志。
199
+ - 登录框里的 Key 输入在 pi 当前 TUI 中**不会显示为掩码**(pi 的登录对话框对 `secret` 和普通文本同样渲染),注意周围环境。
200
+ - 删除插件不会删除 `auth.json` 里的凭据;如需清理,可在 pi 里 `/logout` 选择 CLIProxy,或手动编辑 `auth.json`。
201
+
202
+ ---
203
+
204
+ ## 模型能力说明
205
+
206
+ `/v1/models` 只返回模型 ID(可能带 `owned_by`),不返回上下文长度、是否支持图片、是否推理模型等信息。
207
+
208
+ 插件按以下优先级获取能力字段(`name`、`reasoning`、`input`、`cost`、`contextWindow`、`maxTokens`):
209
+
210
+ 1. `~/.pi/agent/models.json` 中同 ID 模型(用户显式配置,最高优先级);
211
+ 2. `cliproxy.json` 中已保存的元数据;
212
+ 3. `~/.pi/agent/models-store.json` 中 pi 缓存过的同 ID 模型(用于从旧版本升级时保留信息);
213
+ 4. pi 内置模型目录(会先去掉 `cn:`、`global:`、`models/` 等前缀再匹配);
214
+ 5. 按模型名做保守推测。
215
+
216
+ 也就是说,如果你之前已经手写过指向同一个 CLIProxyAPI 的 provider,新建的 `cliproxy` 会继承这些更准确的元数据;从 1.0.x 升级时也不会丢。
217
+
218
+ 没有可复用的元数据时,按模型名做保守推测:
219
+
220
+ - `claude*` / Anthropic 协议:上下文 200K,最大输出 64K;
221
+ - `gemini*` / Gemini 协议:上下文 1M,最大输出 64K;
222
+ - `gpt-5*` / `gpt-6*`:上下文 272K,最大输出 128K;
223
+ - 其他:上下文 128K,最大输出 32K;
224
+ - 默认只声明文本输入,`reasoning` 关闭,成本为 0。
225
+
226
+ 如果某个模型的真实能力不同,可以:
227
+
228
+ - 在 `~/.pi/agent/models.json` 里写该模型的元数据(插件会继承);或
229
+ - 修改 `index.ts` 里的 `guessLimits()` / `toModel()` 后 `/reload`。
230
+
231
+ ---
232
+
233
+ ## 常见问题
234
+
235
+ ### 401 / Invalid API key
236
+
237
+ CLIProxyAPI 的客户端 Key 在 v8 配置的 `access.api-keys`(旧版是顶层 `api-keys`)中。确认:
238
+
239
+ ```yaml
240
+ access:
241
+ api-keys:
242
+ - sk-your-real-key
243
+ ```
244
+
245
+ `/v1/models` 默认需要鉴权(除非服务端一个 Key 都没配)。
246
+
247
+ 从 1.2.0 起,登录会先自动尝试全部兼容地址(OpenAI 优先):
248
+
249
+ - 如果某个地址成功返回模型,直接采用;
250
+ - 如果所有地址都没有返回模型、且其中有 401/403,会提示并**重新要求输入一次 Key**,然后重新尝试全部地址;
251
+ - 如果第二次仍然鉴权失败,登录会中止并且不保存配置。
252
+
253
+ ### 403 `unsafe_example_api_key`
254
+
255
+ CLIProxyAPI 检测到还在使用示例 Key(`your-api-key-1` 等)。把 `access.api-keys` 换成真实 Key 后重启 CLIProxyAPI。
256
+
257
+ ### `/v1/models` 返回空列表
258
+
259
+ 这是合法结果,表示当前没有可用的上游凭据(或都在冷却)。先在 CLIProxyAPI 里登录/配置上游账号,再 `/cliproxy refresh`。
260
+
261
+ ### 只有 `/healthz` 能通,`/v1/models` 404
262
+
263
+ CLIProxyAPI 本身不支持路径前缀;如果前面套了 nginx/Caddy 且路径有前缀,需要让反代把前缀去掉,例如:
264
+
265
+ ```nginx
266
+ location /cliproxy/ {
267
+ proxy_pass http://127.0.0.1:8317/; # 末尾斜杠 = 去掉 /cliproxy 前缀
268
+ }
269
+ ```
270
+
271
+ 或者在插件里选择“自定义兼容地址”,填入反代实际暴露的完整 base URL。
272
+
273
+ ### 流式响应中途断 / 长回答超时
274
+
275
+ CLIProxyAPI 官方建议调大 nginx 的 `proxy_read_timeout`,Cloudflare 免费版 100 秒超时也可能截断长流式响应。
276
+
277
+ ### `/model` 里看不到模型
278
+
279
+ - `/model` 只列出“已配置认证的 provider”的模型;先完成 `/login`。
280
+ - 执行 `/cliproxy` 看模型数量和最近错误。
281
+ - 执行 `/cliproxy refresh` 重试。
282
+ - 确认 `pi --list-models` 能看到 `cliproxy/*`。
283
+
284
+ ### 换域名后模型不对
285
+
286
+ 执行 `/reload`,或在插件目录改完后重启 pi。模型列表会在每次打开 `/model` 时自动刷新。
287
+
288
+ ---
289
+
290
+ ## 更新日志
291
+
292
+ ### 1.2.1
293
+
294
+ - pi TUI 内的登录提示、地址选择、错误信息和 `/cliproxy` 输出全部改为英文。
295
+ - provider 显示名仍为 `CLIProxy`,`/login` 入口、`/cliproxy` 命令和模型前缀 `cliproxy/` 不变。
296
+
297
+ ### 1.2.0
298
+
299
+ - 包名从 `pi-cliproxy` 改为 `pi-cliproxyapi-autoconnect`;provider ID、`cliproxy.json`、`/cliproxy` 命令和模型前缀 `cliproxy/` 保持不变。
300
+ - 登录时自动依次尝试全部兼容地址:**OpenAI → Gemini → Anthropic**,OpenAI 优先;第一个非空模型列表胜出。
301
+ - 裸域名会为每种协议同时尝试 https/http,最多 6 个候选地址。
302
+ - 支持尽力探测 Anthropic 的 `/v1/models`;若该端点不存在(404/405),回退到手动模型 ID,不再直接跳过。
303
+ - 所有地址都失败且存在 401/403 时才重新输入 Key;所有地址都返回空列表时不再显示地址选择,直接进入手动输入。
304
+ - `/cliproxy refresh` 在 Anthropic 模式且模型列表端点不可用时静默保留缓存,不写入错误。
305
+
306
+ ### 1.1.0
307
+
308
+ - 登录遇到 401/403 时重新输入一次 Key,而不是错误地进入兼容地址选择;第二次仍失败则中止且不保存配置。
309
+ - `cliproxy.json` 保存完整模型元数据(reasoning / input / cost / contextWindow / maxTokens),并保留 `.bak` 备份。
310
+ - 模型刷新增加 5 分钟 TTL;`/cliproxy refresh` 仍会强制刷新。
311
+ - 能力元数据增加 `models-store.json` 与 pi 内置模型目录两个来源,升级旧配置时不会丢失信息。
312
+ - 刷新失败时把 `lastError` 持久化到配置,`/cliproxy` 重启后仍能看到最近错误。
313
+
314
+ ---
315
+
316
+ ## 开发与调试
317
+
318
+ ```powershell
319
+ # 用本地文件临时加载(不写入 settings)
320
+ pi --extension F:\Desktop\pi-cliproxyapi-autoconnect\index.ts
321
+
322
+ # 只看模型
323
+ pi --list-models
324
+ ```
325
+
326
+ 插件只依赖 pi 自带的 peer 包,没有第三方运行时依赖:
327
+
328
+ - `@earendil-works/pi-ai`
329
+ - `@earendil-works/pi-coding-agent`
330
+
331
+ 核心实现都在 `index.ts`:
332
+
333
+ - `runLogin()`:域名 + Key + 模型发现 + 失败回退;
334
+ - `refreshProviderModels()`:启动/`/model`/`/cliproxy refresh` 时的动态刷新;
335
+ - `buildProvider()`:注册原生 pi-ai Provider(`apiKey.login` 让它出现在 `/login`)。
336
+
337
+ CLIProxyAPI 参考:<https://github.com/router-for-me/CLIProxyAPI>