pi-cliproxyapi-autoconnect 1.2.1 → 1.2.3

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 (3) hide show
  1. package/README.md +165 -149
  2. package/index.ts +43 -4
  3. package/package.json +4 -2
package/README.md CHANGED
@@ -1,170 +1,174 @@
1
1
  # pi-cliproxyapi-autoconnect
2
2
 
3
- 给 [pi](https://github.com/earendil-works/pi) 用的 **CLIProxyAPI 反代插件**。
3
+ A **CLIProxyAPI provider for [pi](https://github.com/earendil-works/pi)**.
4
4
 
5
- 安装后,pi 的 `/login` 里会多出一个 **CLIProxy** 选项(位于 “Sign in with an API key” 下)。选中后:
5
+ After installation, `/login` shows a **CLIProxy** entry under **“Sign in with an API key”**. Select it and:
6
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。
7
+ 1. Enter the CLIProxy **bound domain** (for example `proxy.example.com`);
8
+ 2. Enter the **API key**;
9
+ 3. The plugin derives every compatible endpoint and tries them automatically in this order: **OpenAI → Gemini → Anthropic** (OpenAI first);
10
+ 4. Every discovered model is registered with pi and becomes available in `/model`;
11
+ 5. Only when every endpoint fails are you asked to pick an endpoint manually (or enter a custom one) and type model IDs.
12
12
 
13
- API Key 由 pi 自己保存在 `~/.pi/agent/auth.json`;插件自己的配置文件只保存域名、地址和模型缓存,**不保存 Key**。
13
+ The API key is stored by pi in `~/.pi/agent/auth.json`. The plugin's own config file only stores the domain, endpoint and model cache; it **never stores the key**.
14
14
 
15
- > 已在 pi `1.2.0` 与 `1.3.0` 上验证:Provider 注册、`/model` 列表、模型发现与回退、实际对话请求(OpenAI 兼容流式)均可用。
15
+ > Verified on pi `1.2.0` and `1.3.0`: provider registration, `/model` listing, model discovery and fallback, and real streaming chat requests over the OpenAI-compatible API.
16
16
 
17
17
  ---
18
18
 
19
- ## 安装
19
+ ## Install
20
20
 
21
- ### 方式 A:从 npm 安装(推荐给其他用户)
21
+ ### Option A: install from npm (recommended)
22
22
 
23
23
  ```powershell
24
24
  pi install npm:pi-cliproxyapi-autoconnect
25
25
  ```
26
26
 
27
- 然后重启 pi(或在 pi 里执行 `/reload`)。
27
+ Then restart pi (or run `/reload` inside pi).
28
28
 
29
- npm 包只包含 `index.ts`、`README.md`、`LICENSE`,由 pi 的 npm 安装器负责下载;下面两个方式只适用于本地目录版。
29
+ The npm package contains only `index.ts`, `README.md` and `LICENSE`; pi's npm installer downloads it. The next two options are only for local development.
30
30
 
31
- ### 方式 B:从本地目录安装(开发/自用)
31
+ ### Option B: install from a local directory
32
32
 
33
- 插件目录:`F:\Desktop\pi-cliproxyapi-autoconnect`。
33
+ Plugin directory: `F:\Desktop\pi-cliproxyapi-autoconnect`.
34
34
 
35
35
  ```powershell
36
36
  pi install F:\Desktop\pi-cliproxyapi-autoconnect
37
37
  ```
38
38
 
39
- 然后重启 pi(或在 pi 里执行 `/reload`)。
39
+ Then restart pi (or run `/reload` inside pi).
40
40
 
41
- ### 方式 C:复制到扩展目录
41
+ ### Option C: copy into the extensions directory
42
42
 
43
43
  ```powershell
44
44
  powershell -ExecutionPolicy Bypass -File F:\Desktop\pi-cliproxyapi-autoconnect\install.ps1
45
45
  ```
46
46
 
47
- 脚本会把插件复制到:
47
+ The script copies the plugin to:
48
48
 
49
49
  ```text
50
50
  %USERPROFILE%\.pi\agent\extensions\pi-cliproxyapi-autoconnect\
51
51
  ```
52
52
 
53
- 如果设置了 `PI_CODING_AGENT_DIR`,则复制到该目录下的 `extensions\pi-cliproxyapi-autoconnect\`。
53
+ If `PI_CODING_AGENT_DIR` is set, it copies to `extensions\pi-cliproxyapi-autoconnect\` under that directory instead.
54
54
 
55
- 也可以手动把整个 `pi-cliproxyapi-autoconnect` 文件夹复制到 `%USERPROFILE%\.pi\agent\extensions\` 下,确保入口是:
55
+ You can also copy the whole `pi-cliproxyapi-autoconnect` folder into `%USERPROFILE%\.pi\agent\extensions\`; make sure the entry point is:
56
56
 
57
57
  ```text
58
58
  %USERPROFILE%\.pi\agent\extensions\pi-cliproxyapi-autoconnect\index.ts
59
59
  ```
60
60
 
61
- pi 会自动加载 `extensions` 目录下的子文件夹(入口为 `index.ts`)。
61
+ pi automatically loads subfolders under `extensions` whose entry point is `index.ts`.
62
62
 
63
- 安装后可以用下面的命令确认插件能被加载、模型能出现:
63
+ After installation, verify that the plugin loads and models are available:
64
64
 
65
65
  ```powershell
66
66
  pi --list-models
67
67
  ```
68
68
 
69
- ### 从旧包 `pi-cliproxy` 迁移
69
+ ### Migrating from the old `pi-cliproxy` package
70
70
 
71
- 包名已改为 `pi-cliproxyapi-autoconnect`,provider ID 仍然是 `cliproxy`,`cliproxy.json` 和 `auth.json` 里的凭据都可以继续使用。
71
+ The package was renamed to `pi-cliproxyapi-autoconnect`. The provider ID is still `cliproxy`, and the existing `cliproxy.json` and `auth.json` credentials remain valid.
72
72
 
73
73
  ```powershell
74
74
  pi remove npm:pi-cliproxy
75
75
  pi install npm:pi-cliproxyapi-autoconnect
76
76
  ```
77
77
 
78
- 然后重启 pi。`/model` 里仍然是 `cliproxy/<模型ID>`,原有配置和模型缓存不需要重建。
78
+ Then restart pi. Models are still listed as `cliproxy/<model-id>`; no config or cache rebuild is required.
79
79
 
80
80
  ---
81
81
 
82
- ## 使用
82
+ ## Usage
83
83
 
84
- 1. 重启 pi,执行 `/login`。
85
- 2. 选择 **“Sign in with an API key”**(不是 “Sign in with an account”)。
86
- 3. 在列表中选择 **CLIProxy**。
87
- 4. 输入绑定域名,例如:
84
+ 1. Restart pi and run `/login`.
85
+ 2. Choose **“Sign in with an API key”** (not “Sign in with an account”).
86
+ 3. Select **CLIProxy** from the list.
87
+ 4. Enter the bound domain, for example:
88
88
  - `proxy.example.com`
89
89
  - `https://proxy.example.com`
90
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** 的顺序自动尝试所有兼容地址:
91
+ - a complete URL such as `https://proxy.example.com/v1` also works
92
+ 5. Enter the CLIProxy API key (the value in CLIProxy's `access.api-keys`).
93
+ 6. The plugin tries every compatible endpoint in this order:
94
94
 
95
95
  ```text
96
- https://<域名>/v1/models OpenAI(最高优先级)
97
- https://<域名>/v1beta/models Gemini
98
- https://<域名>/v1/models Anthropic(带 x-api-key,尽力尝试)
96
+ https://<domain>/v1/models OpenAI (highest priority)
97
+ https://<domain>/v1beta/models Gemini
98
+ https://<domain>/v1/models Anthropic (x-api-key, best effort)
99
99
  ```
100
100
 
101
- 第一个返回非空模型列表的地址会被采用并保存。成功后 `/model` 中立即可见。
102
- 如果输入的是没有写协议的裸域名,上述每个地址还会额外尝试另一种协议(https/http),因此最多 6 次探测。
103
- 7. 执行 `/model`,选择 `cliproxy/<模型ID>` 即可使用。
101
+ The first endpoint that returns a non-empty model list is selected and saved. The models are immediately visible in `/model`.
102
+ If you entered a bare domain without a scheme, every endpoint is also tried with the alternate scheme (https/http), for at most 6 probes.
103
+ 7. Run `/model` and select `cliproxy/<model-id>`.
104
104
 
105
- ### 地址格式化规则
105
+ ### Address formatting
106
106
 
107
- 输入域名后会先归一化成根地址(去掉末尾 `/`、`/v1`、`/v1beta`、`/v1/models` 等后缀,保留路径前缀),再推导:
107
+ The input is first normalized to a root URL: trailing `/`, `/v1`, `/v1beta`, `/v1/models` and similar suffixes are removed, while any path prefix is preserved. The plugin then derives:
108
108
 
109
- | 用途 | 推导出的地址 |
109
+ | Purpose | Derived endpoint |
110
110
  | --- | --- |
111
- | OpenAI 兼容(最高优先级) | `https://<域名>/v1`,模型发现走 `/v1/models` |
112
- | Gemini 兼容 | `https://<域名>/v1beta`,模型发现走 `/v1beta/models` |
113
- | Anthropic 兼容 | `https://<域名>`(SDK 自动追加 `/v1/messages`;模型列表尽力尝试 `/v1/models`) |
111
+ | OpenAI compatible (highest priority) | `https://<domain>/v1`; model discovery uses `/v1/models` |
112
+ | Gemini compatible | `https://<domain>/v1beta`; model discovery uses `/v1beta/models` |
113
+ | Anthropic compatible | `https://<domain>` (the SDK appends `/v1/messages`; model discovery tries `/v1/models` as a best effort) |
114
114
 
115
- 如果输入的是本地/内网地址(`localhost`、`127.0.0.1`、`10.*`、`192.168.*`、`172.16-31.*`、`.local`、`.lan`),默认用 `http://`;否则用 `https://`。没有写协议时,每个兼容地址都会额外尝试另一种协议(https/http)。
115
+ Local and private addresses (`localhost`, `127.0.0.1`, `10.*`, `192.168.*`, `172.16-31.*`, `.local`, `.lan`) default to `http://`; everything else defaults to `https://`. Without an explicit scheme, each compatible endpoint is also tried with the alternate scheme.
116
116
 
117
- ### 拉取失败时的回退
117
+ ### Fallback when discovery fails
118
118
 
119
- 插件会先自动尝试全部兼容地址。之后:
119
+ The plugin first tries every compatible endpoint automatically. After that:
120
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、但模型列表为空,则不再弹地址选择,直接进入手动输入(通常表示上游账号没有可用凭据)。
121
+ 1. If **any** endpoint returned 401/403, the key is the more likely problem:
122
+ - The plugin prompts for the key once more;
123
+ - It retries every endpoint;
124
+ - If authentication still fails, login aborts and **nothing is saved**.
125
+ 2. If there are only other failures (404, timeout, format error, etc.) and no endpoint returned a model list:
126
+ - The plugin reports the failure for each endpoint and probes `/healthz` to check whether the service is CLIProxyAPI;
127
+ - It shows an endpoint picker:
128
+ - Retry OpenAI compatible: `https://<domain>/v1`
129
+ - Anthropic compatible: `https://<domain>`
130
+ - Gemini compatible: `https://<domain>/v1beta`
131
+ - Custom compatible endpoint (enter a full base URL and choose a protocol)
132
+ 3. If the selected endpoint still returns no model list, you can enter model IDs manually (comma or space separated, or leave empty).
133
+ 4. If every endpoint returns HTTP 200 with an empty model list, the picker is skipped and you go straight to manual input (usually because the upstream account has no available credentials).
134
134
 
135
- Anthropic 兼容接口不一定提供模型列表;如果 `/v1/models` 返回 404/405,自动探测会跳过它,选择该地址后请手动输入模型 ID。Gemini 兼容地址会尝试 `/v1beta/models`。
135
+ An Anthropic-compatible endpoint does not always expose a model list. If `/v1/models` returns 404/405, automatic discovery skips it; after selecting that endpoint, enter model IDs manually. Gemini-compatible endpoints are probed at `/v1beta/models`.
136
136
 
137
137
  ---
138
138
 
139
- ## `/cliproxy` 命令
139
+ ## `/cliproxy` command
140
140
 
141
141
  ```text
142
- /cliproxy 查看当前配置、模型数量和最近错误
143
- /cliproxy refresh 立即重新拉取模型列表
142
+ /cliproxy Show the current config, model count and last error
143
+ /cliproxy refresh Refresh the model list immediately
144
+ /cliproxy clear Delete the saved config and its backup
144
145
  ```
145
146
 
146
- 模型列表默认有 **5 分钟缓存**:打开 `/model` 时不会每次都打上游;`/cliproxy refresh` 会强制刷新。
147
+ The model catalog is cached for **5 minutes** by default: opening `/model` does not hit the upstream every time. `/cliproxy refresh` forces a refresh.
147
148
 
148
- 重新配置(换域名或换 Key):直接再执行一次 `/login` → `CLIProxy` 即可。若切换到了完全不同的域名后界面仍有旧缓存,执行 `/reload` 让插件按新配置重建 provider。
149
+ Running `/logout` only removes the credential from pi's `auth.json`; the saved `cliproxy.json` is intentionally kept so a later `/login` can reuse it. While signed out, `/cliproxy` reports that CLIProxy is not signed in instead of showing the old endpoint as active. Use `/cliproxy clear` if you want to remove the saved domain, endpoint and model cache as well.
149
150
 
150
- ### 与 pi 更新命令的关系
151
+ To reconfigure (new domain or key), run `/login` → `CLIProxy` again. If you switched to a completely different domain and the old models are still visible, run `/reload` so the plugin rebuilds the provider from the new config.
151
152
 
152
- - **`pi update --models` 不会刷新本插件的模型列表。**
153
- 该命令只创建一个不加载扩展的临时 ModelRuntime,刷新 pi 内置或 `models.json` 里的模型目录;插件 provider 不在其中。它不会破坏插件,只是不更新 `cliproxy/*`。
154
- - 刷新插件模型请用:`/cliproxy refresh`、打开一次 `/model`、或重启 pi(交互模式启动时会刷新动态 provider)。
155
- - **`pi update --extensions`** 用于更新 npm 包本身(插件代码);更新后重启 pi 即可。
153
+ ### Relationship to pi update commands
154
+
155
+ - **`pi update --models` does not refresh this plugin's model list.**
156
+ It creates a temporary ModelRuntime without extensions and refreshes pi's built-in or `models.json` catalog; plugin providers are not included. It does not break the plugin, but `cliproxy/*` models are not updated.
157
+ - To refresh plugin models, use `/cliproxy refresh`, open `/model`, or restart pi (interactive startup refreshes dynamic providers).
158
+ - **`pi update --extensions`** updates the npm package itself (the plugin code); restart pi after updating.
159
+ - To update only this plugin, run `pi update npm:pi-cliproxyapi-autoconnect`.
156
160
 
157
161
  ---
158
162
 
159
- ## 文件与安全
163
+ ## Files and security
160
164
 
161
- | 内容 | 位置 |
165
+ | Content | Location |
162
166
  | --- | --- |
163
- | API Key | `~/.pi/agent/auth.json`(由 pi 登录流程写入) |
164
- | 域名、兼容地址、模型缓存 | `~/.pi/agent/cliproxy.json` |
165
- | 模型目录缓存(pi 维护) | `~/.pi/agent/models-store.json` |
167
+ | API key | `~/.pi/agent/auth.json` (written by pi's login flow) |
168
+ | Domain, endpoint, model cache | `~/.pi/agent/cliproxy.json` |
169
+ | pi model catalog cache (maintained by pi) | `~/.pi/agent/models-store.json` |
166
170
 
167
- `cliproxy.json` 示例:
171
+ Example `cliproxy.json`:
168
172
 
169
173
  ```json
170
174
  {
@@ -190,51 +194,51 @@ Anthropic 兼容接口不一定提供模型列表;如果 `/v1/models` 返回 4
190
194
  }
191
195
  ```
192
196
 
193
- 说明:
194
-
195
- - 从 1.1.0 起,完整模型元数据(`reasoning` / `input` / `cost` / `contextWindow` / `maxTokens`)会直接写进 `cliproxy.json`,不再只存 ID。
196
- - 每次写入前会把上一版保存为 `cliproxy.json.bak`,方便手动恢复。
197
+ Notes:
197
198
 
198
- - 插件不会把 Key 写进 `cliproxy.json`,也不会打印到日志。
199
- - 登录框里的 Key 输入在 pi 当前 TUI 中**不会显示为掩码**(pi 的登录对话框对 `secret` 和普通文本同样渲染),注意周围环境。
200
- - 删除插件不会删除 `auth.json` 里的凭据;如需清理,可在 pi 里 `/logout` 选择 CLIProxy,或手动编辑 `auth.json`。
199
+ - Since 1.1.0, complete model metadata (`reasoning` / `input` / `cost` / `contextWindow` / `maxTokens`) is written directly to `cliproxy.json`, not just model IDs.
200
+ - The previous version is saved as `cliproxy.json.bak` before each write, for manual recovery.
201
+ - The plugin never writes the key to `cliproxy.json` and never prints it to logs.
202
+ - `/logout` removes the credential from `auth.json` but keeps `cliproxy.json`, so the saved endpoint and model cache can be reused after signing in again. While signed out, `/cliproxy` reports that CLIProxy is not signed in; run `/cliproxy clear` to delete the saved config.
203
+ - The key prompt is **not masked** in pi's current TUI (pi renders `secret` and normal text prompts the same way). Be aware of your surroundings.
204
+ - Removing the plugin does not remove credentials from `auth.json`. To clean up, run `/logout` in pi and select CLIProxy, or edit `auth.json` manually.
201
205
 
202
206
  ---
203
207
 
204
- ## 模型能力说明
208
+ ## Model capabilities
205
209
 
206
- `/v1/models` 只返回模型 ID(可能带 `owned_by`),不返回上下文长度、是否支持图片、是否推理模型等信息。
210
+ `/v1/models` only returns model IDs (and possibly `owned_by`). It does not include context length, image support or reasoning support.
207
211
 
208
- 插件按以下优先级获取能力字段(`name`、`reasoning`、`input`、`cost`、`contextWindow`、`maxTokens`):
212
+ The plugin resolves capability fields (`name`, `reasoning`, `input`, `cost`, `contextWindow`, `maxTokens`) in this order:
209
213
 
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. 按模型名做保守推测。
214
+ 1. A model with the same ID in `~/.pi/agent/models.json` (explicit user config, highest priority);
215
+ 2. Metadata already stored in `cliproxy.json`;
216
+ 3. A model with the same ID cached by pi in `~/.pi/agent/models-store.json` (preserves information when upgrading from an older version);
217
+ 4. pi's built-in model catalog (after stripping prefixes such as `cn:`, `global:` and `models/`);
218
+ 5. Conservative guesses based on the model name.
215
219
 
216
- 也就是说,如果你之前已经手写过指向同一个 CLIProxyAPI 的 provider,新建的 `cliproxy` 会继承这些更准确的元数据;从 1.0.x 升级时也不会丢。
220
+ In other words, if you previously hand-wrote a provider pointing at the same CLIProxyAPI instance, the new `cliproxy` provider inherits the more accurate metadata; upgrading from 1.0.x does not lose it either.
217
221
 
218
- 没有可复用的元数据时,按模型名做保守推测:
222
+ When no metadata is available, the plugin uses conservative guesses:
219
223
 
220
- - `claude*` / Anthropic 协议:上下文 200K,最大输出 64K;
221
- - `gemini*` / Gemini 协议:上下文 1M,最大输出 64K;
222
- - `gpt-5*` / `gpt-6*`:上下文 272K,最大输出 128K;
223
- - 其他:上下文 128K,最大输出 32K;
224
- - 默认只声明文本输入,`reasoning` 关闭,成本为 0。
224
+ - `claude*` / Anthropic protocol: 200K context, 64K max output;
225
+ - `gemini*` / Gemini protocol: 1M context, 64K max output;
226
+ - `gpt-5*` / `gpt-6*`: 272K context, 128K max output;
227
+ - everything else: 128K context, 32K max output;
228
+ - text input only, `reasoning` disabled, cost set to 0.
225
229
 
226
- 如果某个模型的真实能力不同,可以:
230
+ If a model's real capabilities differ:
227
231
 
228
- - 在 `~/.pi/agent/models.json` 里写该模型的元数据(插件会继承);或
229
- - 修改 `index.ts` 里的 `guessLimits()` / `toModel()` 后 `/reload`。
232
+ - Add its metadata to `~/.pi/agent/models.json` (the plugin inherits it); or
233
+ - Edit `guessLimits()` / `toModel()` in `index.ts` and run `/reload`.
230
234
 
231
235
  ---
232
236
 
233
- ## 常见问题
237
+ ## Troubleshooting
234
238
 
235
239
  ### 401 / Invalid API key
236
240
 
237
- CLIProxyAPI 的客户端 Key 在 v8 配置的 `access.api-keys`(旧版是顶层 `api-keys`)中。确认:
241
+ CLIProxyAPI's client key lives in `access.api-keys` in the v8 config (the top-level `api-keys` in older versions). Check:
238
242
 
239
243
  ```yaml
240
244
  access:
@@ -242,96 +246,108 @@ access:
242
246
  - sk-your-real-key
243
247
  ```
244
248
 
245
- `/v1/models` 默认需要鉴权(除非服务端一个 Key 都没配)。
249
+ `/v1/models` requires authentication by default, unless the server has no keys configured at all.
246
250
 
247
- 从 1.2.0 起,登录会先自动尝试全部兼容地址(OpenAI 优先):
251
+ Since 1.2.0, login tries every compatible endpoint first (OpenAI first):
248
252
 
249
- - 如果某个地址成功返回模型,直接采用;
250
- - 如果所有地址都没有返回模型、且其中有 401/403,会提示并**重新要求输入一次 Key**,然后重新尝试全部地址;
251
- - 如果第二次仍然鉴权失败,登录会中止并且不保存配置。
253
+ - If an endpoint returns models, it is used immediately;
254
+ - If no endpoint returns models and at least one returned 401/403, the plugin prompts for the key again and retries every endpoint;
255
+ - If authentication still fails, login aborts and does not save the config.
252
256
 
253
257
  ### 403 `unsafe_example_api_key`
254
258
 
255
- CLIProxyAPI 检测到还在使用示例 Key(`your-api-key-1` 等)。把 `access.api-keys` 换成真实 Key 后重启 CLIProxyAPI。
259
+ CLIProxyAPI detected that the example key (`your-api-key-1`, etc.) is still in use. Replace `access.api-keys` with a real key and restart CLIProxyAPI.
256
260
 
257
- ### `/v1/models` 返回空列表
261
+ ### `/v1/models` returns an empty list
258
262
 
259
- 这是合法结果,表示当前没有可用的上游凭据(或都在冷却)。先在 CLIProxyAPI 里登录/配置上游账号,再 `/cliproxy refresh`。
263
+ This is a valid result: there are currently no available upstream credentials, or all of them are cooling down. Sign in to or configure the upstream accounts in CLIProxyAPI, then run `/cliproxy refresh`.
260
264
 
261
- ### 只有 `/healthz` 能通,`/v1/models` 404
265
+ ### Only `/healthz` works; `/v1/models` returns 404
262
266
 
263
- CLIProxyAPI 本身不支持路径前缀;如果前面套了 nginx/Caddy 且路径有前缀,需要让反代把前缀去掉,例如:
267
+ CLIProxyAPI itself does not support a path prefix. If nginx/Caddy is in front and adds a prefix, make the reverse proxy remove it, for example:
264
268
 
265
269
  ```nginx
266
270
  location /cliproxy/ {
267
- proxy_pass http://127.0.0.1:8317/; # 末尾斜杠 = 去掉 /cliproxy 前缀
271
+ proxy_pass http://127.0.0.1:8317/; # trailing slash removes the /cliproxy prefix
268
272
  }
269
273
  ```
270
274
 
271
- 或者在插件里选择“自定义兼容地址”,填入反代实际暴露的完整 base URL。
275
+ Alternatively, choose “Custom compatible endpoint” in the plugin and enter the full base URL exposed by the reverse proxy.
272
276
 
273
- ### 流式响应中途断 / 长回答超时
277
+ ### Streaming disconnects mid-response / long answers time out
274
278
 
275
- CLIProxyAPI 官方建议调大 nginx 的 `proxy_read_timeout`,Cloudflare 免费版 100 秒超时也可能截断长流式响应。
279
+ CLIProxyAPI recommends increasing nginx's `proxy_read_timeout`. Cloudflare's free-plan 100-second timeout can also truncate long streaming responses.
276
280
 
277
- ### `/model` 里看不到模型
281
+ ### No models visible in `/model`
278
282
 
279
- - `/model` 只列出“已配置认证的 provider”的模型;先完成 `/login`。
280
- - 执行 `/cliproxy` 看模型数量和最近错误。
281
- - 执行 `/cliproxy refresh` 重试。
282
- - 确认 `pi --list-models` 能看到 `cliproxy/*`。
283
+ - `/model` only lists models from providers with configured authentication; complete `/login` first.
284
+ - Run `/cliproxy` to check the model count and last error.
285
+ - Run `/cliproxy refresh` to retry.
286
+ - Confirm that `pi --list-models` shows `cliproxy/*`.
283
287
 
284
- ### 换域名后模型不对
288
+ ### Models look wrong after changing the domain
285
289
 
286
- 执行 `/reload`,或在插件目录改完后重启 pi。模型列表会在每次打开 `/model` 时自动刷新。
290
+ Run `/reload`, or restart pi after editing the plugin. The model list refreshes whenever `/model` is opened.
287
291
 
288
292
  ---
289
293
 
290
- ## 更新日志
294
+ ## Changelog
295
+
296
+ ### 1.2.3
297
+
298
+ - `/cliproxy` now checks whether CLIProxy is actually signed in. After `/logout` it reports “not signed in” instead of displaying the previous endpoint and model count as if they were active.
299
+ - Added `/cliproxy clear` to delete `cliproxy.json` and its backup when the saved config should not be reused.
300
+ - `/cliproxy refresh` refuses to run while signed out.
301
+
302
+ ### 1.2.2
303
+
304
+ - Rewrote this README in English for the npm package page and the pi package gallery.
305
+ - Translated the npm package description to English.
306
+ - The pi TUI remains fully English.
291
307
 
292
308
  ### 1.2.1
293
309
 
294
- - pi TUI 内的登录提示、地址选择、错误信息和 `/cliproxy` 输出全部改为英文。
295
- - provider 显示名仍为 `CLIProxy`,`/login` 入口、`/cliproxy` 命令和模型前缀 `cliproxy/` 不变。
310
+ - All pi TUI strings are now English: login prompts, endpoint picker, errors and `/cliproxy` output.
311
+ - The provider display name remains `CLIProxy`; the `/login` entry, `/cliproxy` command and `cliproxy/` model prefix are unchanged.
296
312
 
297
313
  ### 1.2.0
298
314
 
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 模式且模型列表端点不可用时静默保留缓存,不写入错误。
315
+ - Renamed the package from `pi-cliproxy` to `pi-cliproxyapi-autoconnect`; the provider ID, `cliproxy.json`, `/cliproxy` command and `cliproxy/` model prefix are unchanged.
316
+ - Login now tries every compatible endpoint automatically: **OpenAI → Gemini → Anthropic**, OpenAI first; the first non-empty model list wins.
317
+ - A bare domain also tries both https and http for every protocol, for up to 6 candidates.
318
+ - Best-effort discovery of Anthropic's `/v1/models`; if the endpoint is missing (404/405), fall back to manual model IDs instead of skipping Anthropic entirely.
319
+ - When every endpoint fails and at least one returned 401/403, the plugin asks for the key again. When every endpoint returns an empty list, it skips the endpoint picker and goes straight to manual input.
320
+ - `/cliproxy refresh` silently keeps the cache when the Anthropic endpoint has no model list; it does not persist a refresh error in that case.
305
321
 
306
322
  ### 1.1.0
307
323
 
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` 重启后仍能看到最近错误。
324
+ - On 401/403 during login, prompt for the key again instead of incorrectly entering the endpoint picker; if the second attempt fails, abort without saving the config.
325
+ - `cliproxy.json` now stores complete model metadata (reasoning / input / cost / contextWindow / maxTokens) and keeps a `.bak` backup.
326
+ - Model refresh now has a 5-minute TTL; `/cliproxy refresh` still forces a refresh.
327
+ - Capability metadata now also comes from `models-store.json` and pi's built-in catalog, so upgrading from an older config does not lose information.
328
+ - Refresh failures persist `lastError` to the config, so `/cliproxy` can show the last error after a restart.
313
329
 
314
330
  ---
315
331
 
316
- ## 开发与调试
332
+ ## Development and debugging
317
333
 
318
334
  ```powershell
319
- # 用本地文件临时加载(不写入 settings)
335
+ # Load a local file temporarily (does not write settings)
320
336
  pi --extension F:\Desktop\pi-cliproxyapi-autoconnect\index.ts
321
337
 
322
- # 只看模型
338
+ # List models only
323
339
  pi --list-models
324
340
  ```
325
341
 
326
- 插件只依赖 pi 自带的 peer 包,没有第三方运行时依赖:
342
+ The plugin only depends on pi's host-provided peer packages and has no third-party runtime dependencies:
327
343
 
328
344
  - `@earendil-works/pi-ai`
329
345
  - `@earendil-works/pi-coding-agent`
330
346
 
331
- 核心实现都在 `index.ts`:
347
+ The core implementation is in `index.ts`:
332
348
 
333
- - `runLogin()`:域名 + Key + 模型发现 + 失败回退;
334
- - `refreshProviderModels()`:启动/`/model`/`/cliproxy refresh` 时的动态刷新;
335
- - `buildProvider()`:注册原生 pi-ai Provider(`apiKey.login` 让它出现在 `/login`)。
349
+ - `runLogin()`: domain + key + model discovery + fallback;
350
+ - `refreshProviderModels()`: dynamic refresh on startup, `/model` and `/cliproxy refresh`;
351
+ - `buildProvider()`: registers the native pi-ai provider (`apiKey.login` makes it appear in `/login`).
336
352
 
337
- CLIProxyAPI 参考:<https://github.com/router-for-me/CLIProxyAPI>
353
+ CLIProxyAPI reference: <https://github.com/router-for-me/CLIProxyAPI>
package/index.ts CHANGED
@@ -638,7 +638,7 @@ async function fetchOpenAIModels(baseUrl: string, apiKey: string, signal: AbortS
638
638
  headers: {
639
639
  Accept: "application/json",
640
640
  Authorization: `Bearer ${apiKey}`,
641
- "User-Agent": "pi-cliproxyapi-autoconnect/1.2.1",
641
+ "User-Agent": "pi-cliproxyapi-autoconnect/1.2.3",
642
642
  },
643
643
  signal: requestSignal,
644
644
  });
@@ -662,7 +662,7 @@ async function fetchGeminiModels(baseUrl: string, apiKey: string, signal: AbortS
662
662
  const { signal: requestSignal, cleanup } = abortSignalWithTimeout(signal, REQUEST_TIMEOUT_MS);
663
663
  try {
664
664
  const response = await fetch(url, {
665
- headers: { Accept: "application/json", "User-Agent": "pi-cliproxyapi-autoconnect/1.2.1" },
665
+ headers: { Accept: "application/json", "User-Agent": "pi-cliproxyapi-autoconnect/1.2.3" },
666
666
  signal: requestSignal,
667
667
  });
668
668
  if (!response.ok) {
@@ -703,7 +703,7 @@ async function fetchAnthropicModels(baseUrl: string, apiKey: string, signal: Abo
703
703
  // Anthropic's x-api-key header; sending both is harmless upstream.
704
704
  Authorization: `Bearer ${apiKey}`,
705
705
  "anthropic-version": "2023-06-01",
706
- "User-Agent": "pi-cliproxyapi-autoconnect/1.2.1",
706
+ "User-Agent": "pi-cliproxyapi-autoconnect/1.2.3",
707
707
  },
708
708
  signal: requestSignal,
709
709
  });
@@ -1254,10 +1254,49 @@ export default function (pi: ExtensionAPI): void {
1254
1254
  pi.registerProvider(buildProvider(readConfig()));
1255
1255
 
1256
1256
  pi.registerCommand("cliproxy", {
1257
- description: "Show CLIProxy config, or run /cliproxy refresh to refresh models",
1257
+ description: "Show CLIProxy config, refresh models, or clear the saved config",
1258
1258
  handler: async (args, ctx) => {
1259
1259
  const subcommand = args.trim().toLowerCase();
1260
1260
  const config = readConfig();
1261
+ const signedIn = ctx.modelRegistry.getProviderAuthStatus(PROVIDER_ID).configured;
1262
+
1263
+ if (subcommand === "clear" || subcommand === "reset") {
1264
+ const backupPath = `${configPath()}.bak`;
1265
+ if (!config && !existsSync(backupPath)) {
1266
+ ctx.ui.notify("No saved CLIProxy config to clear.", "info");
1267
+ return;
1268
+ }
1269
+ const confirmed = await ctx.ui.confirm(
1270
+ "Delete saved CLIProxy config?",
1271
+ `This removes ${configPath()} and its backup. You will need to sign in again.`,
1272
+ );
1273
+ if (!confirmed) return;
1274
+ try {
1275
+ for (const path of [configPath(), backupPath]) {
1276
+ if (existsSync(path)) unlinkSync(path);
1277
+ }
1278
+ } catch (error) {
1279
+ ctx.ui.notify(
1280
+ `Failed to clear CLIProxy config: ${error instanceof Error ? error.message : String(error)}`,
1281
+ "error",
1282
+ );
1283
+ return;
1284
+ }
1285
+ lastRefreshError = undefined;
1286
+ ctx.ui.notify("CLIProxy config cleared. Run /login to configure it again.", "info");
1287
+ return;
1288
+ }
1289
+
1290
+ if (!signedIn) {
1291
+ const saved = config
1292
+ ? `\nA saved config remains at ${configPath()} and will be reused after you sign in.\nRemove it with /cliproxy clear.`
1293
+ : "";
1294
+ ctx.ui.notify(
1295
+ `CLIProxy is not signed in.\nRun /login -> "Sign in with an API key" -> CLIProxy.${saved}`,
1296
+ "warning",
1297
+ );
1298
+ return;
1299
+ }
1261
1300
 
1262
1301
  if (subcommand === "refresh") {
1263
1302
  if (!config) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-cliproxyapi-autoconnect",
3
- "version": "1.2.1",
4
- "description": "CLIProxyAPI 自动连接插件 for pi:/login 输入绑定域名 + API Key,自动探测 OpenAI/Gemini/Anthropic 兼容地址并注册模型。",
3
+ "version": "1.2.3",
4
+ "description": "CLIProxyAPI auto-connect provider for pi: sign in with a bound domain and API key, automatically discover OpenAI/Gemini/Anthropic-compatible endpoints, and register models in /model.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "engines": {
@@ -14,6 +14,8 @@
14
14
  "cliproxyapi",
15
15
  "autoconnect",
16
16
  "autodiscover",
17
+ "model-discovery",
18
+ "provider",
17
19
  "openai-compatible"
18
20
  ],
19
21
  "pi": {