pi-cliproxyapi-native 0.3.5 → 0.3.6

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/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ For releases before 0.3.6, see the [GitHub releases](https://github.com/hawkff/pi-cliproxyapi-native/releases).
4
+
5
+ ## [0.3.6] - 2026-11-10
6
+
7
+ - Pi's background prompt-cache refreshes skip the quota wait. Before, a refresh that hit a quota limit showed a quota countdown while Pi sat idle, then sent the whole request again after the reset.
8
+ - Claude on unprefixed, `oauth/`, `vertex/`, and `antigravity/` routes reports a one-hour cache lifetime, so Pi stops refreshing those caches every five minutes. CLIProxyAPI keeps OAuth Claude caches for an hour. `api/` routes keep Pi's five-minute refreshes.
9
+ - Claude message threads stay off. A proxy route that drops the `thread` field would send only the newest messages.
10
+ - Live Claude quota lookups send the Claude Code version that CLIProxyAPI 8.0.63 uses.
11
+ - The `/cli:model` picker reports Pi as waiting for input in terminals that show program status.
12
+ - The extension targets Pi 1.5.1 and CLIProxyAPI 8.0.63.
package/README.md CHANGED
@@ -21,6 +21,7 @@ Chat uses Pi's native API adapters and model metadata, with availability from yo
21
21
  - [Refresh](#refresh)
22
22
  - [Wait for quota reset](#wait-for-quota-reset)
23
23
  - [Retry failed turns](#retry-failed-turns)
24
+ - [Prompt cache refreshes](#prompt-cache-refreshes)
24
25
  - [Compaction](#compaction)
25
26
  - [Aliases and model limits](#aliases-and-model-limits)
26
27
  - [Backend routes](#backend-routes)
@@ -31,15 +32,15 @@ Chat uses Pi's native API adapters and model metadata, with availability from yo
31
32
 
32
33
  ## Install
33
34
 
34
- The extension targets Pi 1.5.0 and CLIProxyAPI 8.0.57, with Node.js 22.19 or newer. Run CLIProxyAPI with your upstream accounts configured before connecting Pi. The extension uses Pi's host-provided packages, adds no runtime dependencies, and needs no compilation.
35
+ The extension targets Pi 1.5.1 and CLIProxyAPI 8.0.63, with Node.js 22.19 or newer. Run CLIProxyAPI with your upstream accounts configured before connecting Pi. The extension uses Pi's host-provided packages, adds no runtime dependencies, and needs no compilation.
35
36
 
36
37
  If you installed `pi-cliproxy-native`, remove it before installing the renamed package. Both register the same `cliproxyapi` provider.
37
38
 
38
39
  ```sh
39
- pi install npm:pi-cliproxyapi-native@0.3.5
40
+ pi install npm:pi-cliproxyapi-native@0.3.6
40
41
  ```
41
42
 
42
- For Git installation, use `pi install git:github.com/hawkff/pi-cliproxyapi-native@v0.3.5`. For a local checkout, use `pi install /path/to/pi-cliproxyapi-native`.
43
+ For Git installation, use `pi install git:github.com/hawkff/pi-cliproxyapi-native@v0.3.6`. For a local checkout, use `pi install /path/to/pi-cliproxyapi-native`. After an update, Pi shows the new [changelog](CHANGELOG.md) entries under "Extension Updates" on its next launch.
43
44
 
44
45
  The default proxy address is `http://localhost:8317`. For another address, set the [connection](#connection) before logging in. Restart Pi, then run:
45
46
 
@@ -93,7 +94,7 @@ Open `/cli:model` to search the live image/video catalog, or use its subcommands
93
94
 
94
95
  Search by friendly name, exact ID, backend, owner, or image/video purpose. The picker shows known media models, including disabled entries with a reason. It omits chat models and unknown IDs.
95
96
 
96
- The terminal picker is keyboard-only. Type to search, use the selection keys to move, press Enter to select, or Escape to cancel. It respects custom selection keybindings. Mouse clicks and wheel events do not change selection.
97
+ The terminal picker is keyboard-only. Type to search, use the selection keys to move, press Enter to select, or Escape to cancel. It respects custom selection keybindings. Mouse clicks and wheel events do not change selection. Terminals that show program status mark Pi as waiting for input while the picker is open.
97
98
 
98
99
  Starting session or branch navigation discards pending picker commands, even if another extension later cancels navigation. Run the selection again if you stay on the same branch.
99
100
 
@@ -291,6 +292,14 @@ Escape or Ctrl+C cancels a pending retry in the terminal. New input, a model cha
291
292
 
292
293
  Retries preserve the conversation rather than replaying the original prompt. They do not fix credentials or increase quotas, and resumed work can incur provider charges. Use `/auto-retry off` if a persistent error needs manual correction.
293
294
 
295
+ ### Prompt cache refreshes
296
+
297
+ Pi refreshes a Claude prompt cache in the background so it doesn't expire between requests. Pi 1.5.1 does this by default, during runs and for up to 30 minutes after them. Set Pi's `cacheWarming` setting to `"streaming"` to limit refreshes to active runs, or to `"off"` to stop them.
298
+
299
+ CLIProxyAPI keeps OAuth Claude caches for an hour. The extension reports a one-hour cache lifetime for Claude on unprefixed, `oauth/`, `vertex/`, and `antigravity/` routes, so Pi doesn't refresh those caches. `api/` routes keep Anthropic's five-minute lifetime. Pi refreshes them when it estimates that a refresh saves at least $0.05. If your unprefixed Claude IDs reach API keys, select their `api/` IDs, or set `promptCache` for those IDs through `modelOverrides` in Pi's `models.json`.
300
+
301
+ A refresh that hits a quota limit fails without waiting for the reset. Chat and compaction requests keep the quota waits described above.
302
+
294
303
  ### Compaction
295
304
 
296
305
  For automatic compaction and `/compact`, the extension limits medium or higher thinking to low without changing your chat thinking level. It uses Pi's default thinking budgets for these requests. Without an explicit output cap, summaries use the model's output limit. Pi's native adapters reduce the output allowance when needed to fit the remaining context space.
@@ -303,7 +312,7 @@ Authentication failures, exhausted quotas, and inputs that exceed the model's co
303
312
 
304
313
  ### Aliases and model limits
305
314
 
306
- The chat catalog skips unknown IDs rather than guessing their capabilities. Recognized catalog owners resolve duplicate metadata IDs; ambiguous cross-family matches stay out.
315
+ The chat catalog skips unknown IDs rather than guessing their capabilities. Recognized catalog owners resolve duplicate metadata IDs; ambiguous cross-family matches stay out. For example, CLIProxyAPI 8.0.63 lists `gpt-6-chat-thinking` and `gemini-omni-1.2-flash`, which have no metadata in Pi 1.5.1, so `/cliproxyapi-refresh` reports them as not registered until you add an alias. Pi 1.5.1 includes `claude-fable-5-2`, which registers without one.
307
316
 
308
317
  To describe a proxy alias, add a canonical metadata reference to `~/.pi/agent/pi-cliproxyapi.json`:
309
318
 
@@ -385,7 +394,7 @@ Run `/reload` after changing settings and `/cliproxyapi-refresh` before starting
385
394
 
386
395
  ## Protocol notes
387
396
 
388
- Claude uses the legacy fine-grained tool-streaming header in place of eager tool fields.
397
+ Claude uses the legacy fine-grained tool-streaming header in place of eager tool fields. Claude message threads stay off, because a proxy route that drops the `thread` field would send only the newest messages.
389
398
 
390
399
  GPT models keep Pi's OpenAI Responses capabilities when the proxy lists them as owned by OpenAI. These capabilities are strict tools, grammar tools such as codemode, tool declarations added mid-conversation, tool search, and instructions placed mid-conversation. Each passed live checks through CLIProxyAPI 8.0.48 with an OpenAI API key and with a ChatGPT subscription. OpenAI-compatible providers and other model families keep these capabilities off.
391
400
 
@@ -393,11 +402,11 @@ On `api/` routes, Pi can send thinking effort as a `configuration_update` item.
393
402
 
394
403
  When Pi omits strictness in the top-level Responses tool list, the extension sends `strict: null`, so optional arguments remain optional. Tools declared inside the conversation keep Pi's strictness values. Explicit payload hooks retain final control.
395
404
 
396
- OpenAI images POST `model`, `prompt`, `n`, and supplied controls to `/v1/images/generations`, without `response_format`. Editing uses `/v1/images/edits` with JSON `images` and optional `mask` or `markup` data URLs. A nonzero `partial_images` adds `stream: true`, and the extension reads server-sent events. Each `*.partial_image` frame becomes a progress preview, and the `*.completed` frame carries the final image and usage. xAI uses the same route with `response_format: "b64_json"`. Gemini uses `/v1beta/models/{id}:generateContent`. Media generation sends the prompt and generation options without chat history, system instructions, or tools.
405
+ OpenAI images POST `model`, `prompt`, `n`, and supplied controls to `/v1/images/generations`, without `response_format`. Editing uses `/v1/images/edits` with JSON `images` and optional `mask` or `markup` data URLs. A nonzero `partial_images` adds `stream: true`, and the extension reads server-sent events. With `streaming.keepalive-seconds` set, streamed previews need CLIProxyAPI 8.0.60 or newer, because older versions could insert keep-alive comments inside an image event. Each `*.partial_image` frame becomes a progress preview, and the `*.completed` frame carries the final image and usage. xAI uses the same route with `response_format: "b64_json"`. Gemini uses `/v1beta/models/{id}:generateContent`. Media generation sends the prompt and generation options without chat history, system instructions, or tools.
397
406
 
398
407
  OpenAI image POSTs use a dedicated HTTP connection. It follows `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` from the environment, where Pi also places its `httpProxy` setting, on Node 22.21+ and 24.5+. Older Node versions connect directly. The connection disables socket timeouts so the ten-minute deadline controls the request, requests identity encoding, and rejects compressed responses.
399
408
 
400
- The OpenAI image implementation follows CLIProxyAPI v8.0.57's [image handler](https://github.com/router-for-me/CLIProxyAPI/blob/v8.0.57/sdk/api/handlers/openai/openai_images_handlers.go) and [Codex image executor](https://github.com/router-for-me/CLIProxyAPI/blob/v8.0.57/internal/runtime/executor/codex_openai_images.go), plus the OpenAI [generation](https://developers.openai.com/api/reference/resources/images/methods/generate) and [editing](https://developers.openai.com/api/reference/resources/images/methods/edit) references. The xAI and Google routes follow v7.2.158's [video handler](https://github.com/router-for-me/CLIProxyAPI/blob/v7.2.158/sdk/api/handlers/openai/openai_videos_handlers.go), [Gemini handler](https://github.com/router-for-me/CLIProxyAPI/blob/v7.2.158/sdk/api/handlers/gemini/gemini_handlers.go), and [Vertex executor](https://github.com/router-for-me/CLIProxyAPI/blob/v7.2.158/internal/runtime/executor/gemini_vertex_executor.go). See [xAI's video documentation](https://docs.x.ai/developers/model-capabilities/video/generation) for duration and status semantics.
409
+ The OpenAI image implementation follows CLIProxyAPI v8.0.63's [image handler](https://github.com/router-for-me/CLIProxyAPI/blob/v8.0.63/sdk/api/handlers/openai/openai_images_handlers.go) and [Codex image executor](https://github.com/router-for-me/CLIProxyAPI/blob/v8.0.63/internal/runtime/executor/codex_openai_images.go), plus the OpenAI [generation](https://developers.openai.com/api/reference/resources/images/methods/generate) and [editing](https://developers.openai.com/api/reference/resources/images/methods/edit) references. The xAI and Google routes follow v7.2.158's [video handler](https://github.com/router-for-me/CLIProxyAPI/blob/v7.2.158/sdk/api/handlers/openai/openai_videos_handlers.go), [Gemini handler](https://github.com/router-for-me/CLIProxyAPI/blob/v7.2.158/sdk/api/handlers/gemini/gemini_handlers.go), and [Vertex executor](https://github.com/router-for-me/CLIProxyAPI/blob/v7.2.158/internal/runtime/executor/gemini_vertex_executor.go). See [xAI's video documentation](https://docs.x.ai/developers/model-capabilities/video/generation) for duration and status semantics.
401
410
 
402
411
  ## License
403
412
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-cliproxyapi-native",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "description": "CLIProxyAPI chat discovery, image generation and editing, and video generation with Pi's native adapters",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -23,6 +23,7 @@
23
23
  "extensions",
24
24
  "src",
25
25
  "README.md",
26
+ "CHANGELOG.md",
26
27
  "LICENSE"
27
28
  ],
28
29
  "pi": {
@@ -39,9 +40,9 @@
39
40
  },
40
41
  "devDependencies": {
41
42
  "@biomejs/biome": "^2.6.5",
42
- "@earendil-works/pi-ai": "^1.5.0",
43
- "@earendil-works/pi-coding-agent": "^1.5.0",
44
- "@earendil-works/pi-tui": "^1.5.0",
43
+ "@earendil-works/pi-ai": "^1.5.1",
44
+ "@earendil-works/pi-coding-agent": "^1.5.1",
45
+ "@earendil-works/pi-tui": "^1.5.1",
45
46
  "@types/node": "^24.19.2",
46
47
  "typebox": "1.3.27",
47
48
  "typescript": "7.0.2"
package/src/catalog.ts CHANGED
@@ -365,6 +365,10 @@ export function mapCatalog(value: unknown, config: Config, known: readonly Model
365
365
  api,
366
366
  baseUrl: endpoint(config.baseUrl, api),
367
367
  headers: undefined,
368
+ // CLIProxyAPI gives OAuth Claude caches a one-hour TTL. Only api/ routes keep Pi's five-minute refreshes.
369
+ ...(api === "anthropic-messages" && prefix !== "api"
370
+ ? { promptCache: { short: 3600, long: 3600 } }
371
+ : {}),
368
372
  compat:
369
373
  api === "anthropic-messages"
370
374
  ? {
@@ -374,6 +378,8 @@ export function mapCatalog(value: unknown, config: Config, known: readonly Model
374
378
  supportsMidConvoSystemMessages: false,
375
379
  supportsMidConvoToolChanges: false,
376
380
  supportsMidConvoEffort: false,
381
+ // A route that drops the thread field would send only the newest messages.
382
+ supportsMessageThreads: false,
377
383
  allowedFallbackModels: undefined,
378
384
  }
379
385
  : api === "google-generative-ai"
@@ -182,7 +182,8 @@ export async function fetchClaudeQuota(
182
182
  Authorization: "Bearer $TOKEN$",
183
183
  "Content-Type": "application/json",
184
184
  "anthropic-beta": "oauth-2025-04-20",
185
- "User-Agent": "claude-cli/2.1.280 (external, cli)",
185
+ // CLIProxyAPI 8.0.63 presents this Claude Code version for OAuth accounts.
186
+ "User-Agent": "claude-cli/2.1.321 (external, cli)",
186
187
  },
187
188
  });
188
189
  if (!isRecord(response) || typeof response.status_code !== "number")
package/src/picker.ts CHANGED
@@ -295,6 +295,7 @@ export function registerModelPicker(pi: ExtensionAPI, config: Config) {
295
295
  () => tui.requestRender(),
296
296
  done,
297
297
  ),
298
+ { blocked: { kind: "question", message: "Choose a CLIProxyAPI image or video model" } },
298
299
  );
299
300
  } else {
300
301
  const matches = searchPickerItems(items, query);
package/src/provider.ts CHANGED
@@ -161,6 +161,9 @@ function route(
161
161
  options?.env?.CLIPROXYAPI_MANAGEMENT_KEY ?? process.env.CLIPROXYAPI_MANAGEMENT_KEY ?? "";
162
162
  const liveClaude =
163
163
  model.api === "anthropic-messages" && !backend && authType !== "api-key" && managementKey !== "";
164
+ // Pi's cache warmer replays a request with these options. A delayed replay cannot keep a cache warm.
165
+ const warming =
166
+ options?.disableContinuation === true && options.maxTokens === 1 && options.maxRetries === 0;
164
167
  const adapterModel = google ? { ...model, id: metadataId } : model;
165
168
  // Google needs canonical IDs for tool turns. Swap identities to keep bare history cross-route.
166
169
  const adapterContext = google
@@ -231,7 +234,7 @@ function route(
231
234
  let started = false;
232
235
  let retry = false;
233
236
  for await (const event of run()) {
234
- if (event.type === "error" && event.reason === "error" && !started) {
237
+ if (event.type === "error" && event.reason === "error" && !started && !warming) {
235
238
  const resetAt = quotaRetryAt(event.error.errorMessage, response);
236
239
  const failure = quotaError(event.error.errorMessage);
237
240
  const upstream =
@@ -320,7 +323,7 @@ export function createCliproxyProvider(
320
323
  let skipped: string[] = [];
321
324
  const standardAuth = envApiKeyAuth("CLIProxyAPI API key", ["CLIPROXYAPI_API_KEY"]);
322
325
  const scope = createHash("sha256")
323
- .update(JSON.stringify([5, { baseUrl: config.baseUrl, aliases: config.aliases }]))
326
+ .update(JSON.stringify([6, { baseUrl: config.baseUrl, aliases: config.aliases }]))
324
327
  .digest("hex");
325
328
  const provider = createProvider<CpaApi>({
326
329
  id: PROVIDER_ID,