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.
- package/README.md +165 -149
- package/index.ts +43 -4
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,170 +1,174 @@
|
|
|
1
1
|
# pi-cliproxyapi-autoconnect
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A **CLIProxyAPI provider for [pi](https://github.com/earendil-works/pi)**.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
After installation, `/login` shows a **CLIProxy** entry under **“Sign in with an API key”**. Select it and:
|
|
6
6
|
|
|
7
|
-
1.
|
|
8
|
-
2.
|
|
9
|
-
3.
|
|
10
|
-
4.
|
|
11
|
-
5.
|
|
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
|
|
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
|
-
>
|
|
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
|
-
###
|
|
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
|
-
|
|
27
|
+
Then restart pi (or run `/reload` inside pi).
|
|
28
28
|
|
|
29
|
-
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
|
-
###
|
|
31
|
+
### Option B: install from a local directory
|
|
32
32
|
|
|
33
|
-
|
|
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
|
-
|
|
39
|
+
Then restart pi (or run `/reload` inside pi).
|
|
40
40
|
|
|
41
|
-
###
|
|
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
|
-
|
|
53
|
+
If `PI_CODING_AGENT_DIR` is set, it copies to `extensions\pi-cliproxyapi-autoconnect\` under that directory instead.
|
|
54
54
|
|
|
55
|
-
|
|
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
|
|
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
|
-
###
|
|
69
|
+
### Migrating from the old `pi-cliproxy` package
|
|
70
70
|
|
|
71
|
-
|
|
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
|
-
|
|
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.
|
|
85
|
-
2.
|
|
86
|
-
3.
|
|
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
|
-
-
|
|
92
|
-
5.
|
|
93
|
-
6.
|
|
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
|
|
97
|
-
https
|
|
98
|
-
https
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
7.
|
|
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
|
-
|
|
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
|
|
112
|
-
| Gemini
|
|
113
|
-
| Anthropic
|
|
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
|
-
|
|
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.
|
|
122
|
-
-
|
|
123
|
-
-
|
|
124
|
-
-
|
|
125
|
-
2.
|
|
126
|
-
-
|
|
127
|
-
-
|
|
128
|
-
-
|
|
129
|
-
- Anthropic
|
|
130
|
-
- Gemini
|
|
131
|
-
-
|
|
132
|
-
3.
|
|
133
|
-
4.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
153
|
-
|
|
154
|
-
-
|
|
155
|
-
|
|
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
|
|
164
|
-
|
|
|
165
|
-
|
|
|
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
|
-
-
|
|
199
|
-
-
|
|
200
|
-
-
|
|
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`
|
|
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
|
-
|
|
212
|
+
The plugin resolves capability fields (`name`, `reasoning`, `input`, `cost`, `contextWindow`, `maxTokens`) in this order:
|
|
209
213
|
|
|
210
|
-
1. `~/.pi/agent/models.json`
|
|
211
|
-
2. `cliproxy.json
|
|
212
|
-
3. `~/.pi/agent/models-store.json`
|
|
213
|
-
4. pi
|
|
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
|
-
|
|
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
|
|
221
|
-
- `gemini*` / Gemini
|
|
222
|
-
- `gpt-5*` / `gpt-6
|
|
223
|
-
-
|
|
224
|
-
-
|
|
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
|
-
-
|
|
229
|
-
-
|
|
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
|
|
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`
|
|
249
|
+
`/v1/models` requires authentication by default, unless the server has no keys configured at all.
|
|
246
250
|
|
|
247
|
-
|
|
251
|
+
Since 1.2.0, login tries every compatible endpoint first (OpenAI first):
|
|
248
252
|
|
|
249
|
-
-
|
|
250
|
-
-
|
|
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
|
|
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
|
-
|
|
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
|
-
###
|
|
265
|
+
### Only `/healthz` works; `/v1/models` returns 404
|
|
262
266
|
|
|
263
|
-
CLIProxyAPI
|
|
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/; #
|
|
271
|
+
proxy_pass http://127.0.0.1:8317/; # trailing slash removes the /cliproxy prefix
|
|
268
272
|
}
|
|
269
273
|
```
|
|
270
274
|
|
|
271
|
-
|
|
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
|
|
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`
|
|
280
|
-
-
|
|
281
|
-
-
|
|
282
|
-
-
|
|
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
|
-
|
|
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
|
|
295
|
-
- provider
|
|
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
|
-
-
|
|
300
|
-
-
|
|
301
|
-
-
|
|
302
|
-
-
|
|
303
|
-
-
|
|
304
|
-
- `/cliproxy refresh`
|
|
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
|
-
-
|
|
309
|
-
- `cliproxy.json`
|
|
310
|
-
-
|
|
311
|
-
-
|
|
312
|
-
-
|
|
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
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
347
|
+
The core implementation is in `index.ts`:
|
|
332
348
|
|
|
333
|
-
- `runLogin()
|
|
334
|
-
- `refreshProviderModels()
|
|
335
|
-
- `buildProvider()
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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,
|
|
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.
|
|
4
|
-
"description": "CLIProxyAPI
|
|
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": {
|