@kingingwang/pi-windows-x64 0.84.4 → 0.86.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 (72) hide show
  1. package/bin/CHANGELOG.md +185 -5
  2. package/bin/README.md +4 -2
  3. package/bin/docs/compaction.md +39 -13
  4. package/bin/docs/containerization.md +45 -0
  5. package/bin/docs/custom-provider.md +22 -13
  6. package/bin/docs/development.md +23 -4
  7. package/bin/docs/docs.json +4 -0
  8. package/bin/docs/environment-variables.md +3 -0
  9. package/bin/docs/extensions.md +62 -45
  10. package/bin/docs/json.md +4 -4
  11. package/bin/docs/keybindings.md +5 -2
  12. package/bin/docs/models.md +37 -3
  13. package/bin/docs/providers.md +10 -2
  14. package/bin/docs/rpc.md +1 -1
  15. package/bin/docs/sdk.md +9 -2
  16. package/bin/docs/security.md +1 -1
  17. package/bin/docs/session-format.md +82 -40
  18. package/bin/docs/sessions.md +27 -0
  19. package/bin/docs/settings.md +60 -5
  20. package/bin/docs/skills.md +1 -1
  21. package/bin/docs/terminal-setup.md +15 -0
  22. package/bin/docs/termux.md +0 -1
  23. package/bin/docs/themes.md +8 -6
  24. package/bin/docs/tui.md +21 -2
  25. package/bin/docs/usage.md +1 -0
  26. package/bin/examples/README.md +3 -0
  27. package/bin/examples/extensions/README.md +0 -1
  28. package/bin/examples/extensions/custom-provider-anthropic/index.ts +18 -12
  29. package/bin/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  30. package/bin/examples/extensions/custom-provider-anthropic/package.json +1 -1
  31. package/bin/examples/extensions/custom-provider-gitlab-duo/index.ts +2 -2
  32. package/bin/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  33. package/bin/examples/extensions/dynamic-resources/dynamic.json +2 -0
  34. package/bin/examples/extensions/gondolin/package-lock.json +2 -2
  35. package/bin/examples/extensions/gondolin/package.json +1 -1
  36. package/bin/examples/extensions/prompt-customizer.ts +19 -67
  37. package/bin/examples/extensions/sandbox/package-lock.json +2 -2
  38. package/bin/examples/extensions/sandbox/package.json +1 -1
  39. package/bin/examples/extensions/with-deps/package-lock.json +2 -2
  40. package/bin/examples/extensions/with-deps/package.json +1 -1
  41. package/bin/examples/plugins/pi-example-plugin/README.md +38 -0
  42. package/bin/examples/plugins/pi-example-plugin/package.json +10 -0
  43. package/bin/examples/plugins/pi-example-plugin/src/contract.ts +13 -0
  44. package/bin/examples/plugins/pi-example-plugin/src/session.ts +23 -0
  45. package/bin/examples/plugins/pi-example-plugin/src/tui.ts +31 -0
  46. package/bin/native/win32/prebuilds/win32-x64/win32-platform.node +0 -0
  47. package/bin/package.json +24 -23
  48. package/bin/pi.exe +2 -2
  49. package/bin/theme/dark.json +2 -1
  50. package/bin/theme/light.json +2 -1
  51. package/bin/theme/theme-schema.json +6 -2
  52. package/package.json +1 -1
  53. package/bin/examples/extensions/kimi-deferred-tools.ts +0 -61
  54. package/bin/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  55. package/bin/node_modules/@mariozechner/clipboard/.yarnrc.yml +0 -1
  56. package/bin/node_modules/@mariozechner/clipboard/Cargo.toml +0 -45
  57. package/bin/node_modules/@mariozechner/clipboard/README.md +0 -60
  58. package/bin/node_modules/@mariozechner/clipboard/build.rs +0 -5
  59. package/bin/node_modules/@mariozechner/clipboard/clipboard.win32-x64-msvc.node +0 -0
  60. package/bin/node_modules/@mariozechner/clipboard/exp.ts +0 -12
  61. package/bin/node_modules/@mariozechner/clipboard/index.d.ts +0 -37
  62. package/bin/node_modules/@mariozechner/clipboard/index.js +0 -606
  63. package/bin/node_modules/@mariozechner/clipboard/package.json +0 -56
  64. package/bin/node_modules/@mariozechner/clipboard/src/clipboard_rs/common.rs +0 -307
  65. package/bin/node_modules/@mariozechner/clipboard/src/clipboard_rs/mod.rs +0 -93
  66. package/bin/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/ios.rs +0 -313
  67. package/bin/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/macos.rs +0 -471
  68. package/bin/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/mod.rs +0 -252
  69. package/bin/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/wayland.rs +0 -431
  70. package/bin/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/win.rs +0 -712
  71. package/bin/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/x11.rs +0 -916
  72. package/bin/node_modules/@mariozechner/clipboard/src/lib.rs +0 -194
@@ -538,10 +538,13 @@ pi.on("before_agent_start", async (event, ctx) => {
538
538
  // event.systemPrompt - current chained system prompt for this handler
539
539
  // (includes changes from earlier before_agent_start handlers)
540
540
  // event.systemPromptOptions - structured options used to build the system prompt
541
- // .customPrompt - any custom system prompt (from --system-prompt, SYSTEM.md, or custom templates)
541
+ // .customPrompt - exact prompt prefix from --system-prompt, SYSTEM.md, or custom templates
542
+ // .forceSystemPrompt - optional exact replacement for the complete prompt
542
543
  // .selectedTools - tools currently active in the prompt
543
544
  // .toolSnippets - one-line descriptions for each tool
544
- // .promptGuidelines - custom guideline bullets
545
+ // .toolGuidelines - guideline bullets keyed by tool name
546
+ // .promptGuidelines - additional custom guideline bullets
547
+ // .sections - custom XML-wrapped sections keyed by tag name
545
548
  // .appendSystemPrompt - text from --append-system-prompt flags
546
549
  // .cwd - working directory
547
550
  // .contextFiles - AGENTS.md files and other loaded context files
@@ -560,7 +563,7 @@ pi.on("before_agent_start", async (event, ctx) => {
560
563
  });
561
564
  ```
562
565
 
563
- The `systemPromptOptions` field gives extensions access to the same structured data Pi uses to build the system prompt. This lets you inspect what Pi has loaded — custom prompts, guidelines, tool snippets, context files, skills — without re-discovering resources or re-parsing flags. Use it when your extension needs to make deep, informed changes to the system prompt while respecting user-provided configuration.
566
+ The `systemPromptOptions` field gives extensions access to the same structured data Pi uses to build the system prompt. Collections are mutable. Prefer changing `sections`, `selectedTools`, or `promptGuidelines`: Pi diffs the resulting prompt sections against what the model already has and appends one system message patching only the changed sections. Returning `systemPrompt`, or setting `forceSystemPrompt`, replaces the whole prompt for the run: every provider receives the forced text as its leading system prompt (a cache miss when it changes), and the session transcript keeps recording the structured sections. Tool selection changes update both the prompt contributions and executable provider tools; calling `pi.setActiveTools()` inside the handler has the same effect as editing `selectedTools`. Models that accept system messages mid-conversation receive the patch in place and keep their cached prefix; other models get the replayed prompt as their system prompt, which is a cache miss once per change.
564
567
 
565
568
  Inside `before_agent_start`, `event.systemPrompt` and `ctx.getSystemPrompt()` both reflect the chained system prompt as of the current handler. Later `before_agent_start` handlers can still modify it again.
566
569
 
@@ -735,6 +738,25 @@ pi.on("after_provider_response", (event, ctx) => {
735
738
 
736
739
  Header availability depends on provider and transport. Providers that abstract HTTP responses may not expose headers.
737
740
 
741
+ #### cache_warming_decision
742
+
743
+ Fired before each prompt-cache refresh with pi's decision filled in. The event carries only pi's cost estimates; use `ctx.model`, `ctx.isIdle()`, and `ctx.getContextUsage()` for everything else.
744
+
745
+ ```typescript
746
+ pi.on("cache_warming_decision", (event, ctx) => {
747
+ // event.warmCost: price of this refresh
748
+ // event.missCost: extra price of the next request if the entry is lost
749
+ // event.continuationProbability: pi's estimate that a request arrives in time
750
+ // event.action: "warm" | "stop", pi's decision
751
+
752
+ if (ctx.model?.provider === "my-provider") {
753
+ return { action: "stop" };
754
+ }
755
+ });
756
+ ```
757
+
758
+ Return `{ action: "warm" }` or `{ action: "stop" }` to override; the last handler that returns an action wins. `"stop"` ends warming until the next real request.
759
+
738
760
  ### Model Events
739
761
 
740
762
  #### model_select
@@ -906,6 +928,8 @@ pi.on("user_bash", (event, ctx) => {
906
928
  });
907
929
  ```
908
930
 
931
+ Returning `undefined` continues to the next handler, then local execution if none handles the event. A valid result stops propagation: `operations` executes the command through the supplied backend, while `result` records the completed command without executing it.
932
+
909
933
  ### Input Events
910
934
 
911
935
  #### input
@@ -1016,6 +1040,12 @@ Access to models, providers, and resolved authentication. `ctx.modelRegistry.get
1016
1040
 
1017
1041
  `ctx.scopedModels` is the read-only list of models scoped to the current session — the same set the `/scoped-models` command shows. It is resolved at session start from the `--models` CLI flag and the `enabledModels` setting (matched against the available catalogue with minimatch on `provider/modelId` or a bare `modelId`). It is empty when no scoping is configured, meaning every available model is usable. Each entry is `{ model, thinkingLevel? }`, where `thinkingLevel` is set only when a pattern pinned it (e.g. `anthropic/*:high`). Use it to populate a model picker that mirrors the built-in one instead of enumerating the whole catalogue via `ctx.modelRegistry.getAvailable()`.
1018
1042
 
1043
+ #### Streaming model calls
1044
+
1045
+ Use `ctx.modelRegistry.streamSimple(model, context, options)` for provider-neutral options such as `reasoning`, or `stream()` for API-specific options. Both use configured providers and resolve authentication, including for providers registered with `pi.registerProvider()`. Use these instead of `pi-ai/compat` streaming functions, which cannot see extension provider registrations.
1046
+
1047
+ Both return an `AssistantMessageEventStream`. Iterate it for response events and await `.result()` for the final message. Setup failures produce error events and error results.
1048
+
1019
1049
  ### ctx.signal
1020
1050
 
1021
1051
  The current agent abort signal, or `undefined` when no agent turn is active.
@@ -1119,7 +1149,7 @@ const options = ctx.getSystemPromptOptions();
1119
1149
  const contextPaths = options.contextFiles?.map((file) => file.path) ?? [];
1120
1150
  ```
1121
1151
 
1122
- This has the same shape and mutability as `before_agent_start` `event.systemPromptOptions`: custom prompt, active tools, tool snippets, prompt guidelines, appended system prompt text, cwd, loaded context files, and loaded skills. It may include full context file contents, so treat it as sensitive extension-local data and avoid exposing it through command lists, logs, or autocomplete metadata.
1152
+ This has the same shape and mutability as `before_agent_start` `event.systemPromptOptions`: custom or forced prompt, active tools, tool snippets, per-tool and custom rules, custom sections, appended prompt text, cwd, loaded context files, and loaded skills. It may include full context file contents, so treat it as sensitive extension-local data and avoid exposing it through command lists, logs, or autocomplete metadata.
1123
1153
 
1124
1154
  This reports the current base prompt inputs. It does not include per-turn `before_agent_start` chained system-prompt changes, later `context` event message mutations, or `before_provider_request` payload rewrites.
1125
1155
 
@@ -1197,7 +1227,7 @@ Options:
1197
1227
 
1198
1228
  ### ctx.navigateTree(targetId, options?)
1199
1229
 
1200
- Navigate to a different point in the session tree:
1230
+ Navigate to a different point in the session tree. Rejects while an agent response, manual or automatic compaction, or another tree navigation is active, even with `summarize: false`. These conflicts leave the active branch unchanged and reject the promise rather than returning `{ cancelled: true }`. Wait for the active operation to finish (for example, with `await ctx.waitForIdle()` in a command handler) and retry:
1201
1231
 
1202
1232
  ```typescript
1203
1233
  const result = await ctx.navigateTree("entry-id-456", {
@@ -1360,7 +1390,16 @@ export default function (pi: ExtensionAPI) {
1360
1390
 
1361
1391
  ### pi.on(event, handler)
1362
1392
 
1363
- Subscribe to events. See [Events](#events) for event types and return values.
1393
+ Subscribe to events. Returns an unsubscribe function that removes only that registration. See [Events](#events) for event types and return values.
1394
+
1395
+ ```typescript
1396
+ const unsubscribe = pi.on("agent_end", async (event) => {
1397
+ unsubscribe();
1398
+ await updateIntegration(event.messages);
1399
+ });
1400
+ ```
1401
+
1402
+ Handlers run in extension load order, then registration order within each extension. Adding or removing a handler does not affect a dispatch already in progress.
1364
1403
 
1365
1404
  ### pi.registerTool(definition)
1366
1405
 
@@ -1703,7 +1742,7 @@ Typical `sourceInfo.source` values:
1703
1742
 
1704
1743
  ### pi.setModel(model)
1705
1744
 
1706
- Set the current model. Returns `false` if no API key is available for the model. See [models.md](models.md) for configuring custom models.
1745
+ Set the model for the current session. The change is recorded in session history and restored when that session is resumed, but it does not change the configured `defaultProvider` or `defaultModel` used by new sessions. Returns `false` if authentication is not configured for the model's provider. See [models.md](models.md) for configuring custom models.
1707
1746
 
1708
1747
  ```typescript
1709
1748
  const model = ctx.modelRegistry.find("anthropic", "claude-sonnet-4-5");
@@ -1717,7 +1756,9 @@ if (model) {
1717
1756
 
1718
1757
  ### pi.getThinkingLevel() / pi.setThinkingLevel(level)
1719
1758
 
1720
- Get or set the thinking level. Level is clamped to model capabilities (non-reasoning models always use "off"). Changes emit `thinking_level_select`.
1759
+ Get the current thinking level. Level is clamped to model capabilities (non-reasoning models always use "off"). Changes emit `thinking_level_select`.
1760
+
1761
+ `pi.setThinkingLevel()` changes the thinking level for the current session. The change is recorded in session history and restored when that session is resumed, but it does not change the configured default used by new sessions.
1721
1762
 
1722
1763
  ```typescript
1723
1764
  const current = pi.getThinkingLevel(); // "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"
@@ -2099,14 +2140,14 @@ See [examples/extensions/tool-override.ts](../examples/extensions/tool-override.
2099
2140
  **Your implementation must match the exact result shape**, including the `details` type. The UI and session logic depend on these shapes for rendering and state tracking.
2100
2141
 
2101
2142
  Built-in tool implementations:
2102
- - [read.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/tools/read.ts) - `ReadToolDetails`
2103
- - [bash.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/tools/bash.ts) - `BashToolDetails`
2104
- - [powershell.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/tools/powershell.ts) - `PowerShellToolDetails`
2105
- - [edit.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/tools/edit.ts)
2106
- - [write.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/tools/write.ts)
2107
- - [grep.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/tools/grep.ts) - `GrepToolDetails`
2108
- - [find.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/tools/find.ts) - `FindToolDetails`
2109
- - [ls.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/tools/ls.ts) - `LsToolDetails`
2143
+ - [read.ts](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/tools/read.ts) - `ReadToolDetails`
2144
+ - [bash.ts](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/tools/bash.ts) - `BashToolDetails`
2145
+ - [powershell.ts](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/tools/powershell.ts) - `PowerShellToolDetails`
2146
+ - [edit.ts](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/tools/edit.ts)
2147
+ - [write.ts](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/tools/write.ts)
2148
+ - [grep.ts](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/tools/grep.ts) - `GrepToolDetails`
2149
+ - [find.ts](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/tools/find.ts) - `FindToolDetails`
2150
+ - [ls.ts](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/tools/ls.ts) - `LsToolDetails`
2110
2151
 
2111
2152
  ### Remote Execution
2112
2153
 
@@ -2237,7 +2278,7 @@ export default function (pi: ExtensionAPI) {
2237
2278
 
2238
2279
  ### Custom Rendering
2239
2280
 
2240
- Tools can provide `renderCall` and `renderResult` for custom TUI display. See [tui.md](tui.md) for the full component API and [tool-execution.ts](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/modes/interactive/components/tool-execution.ts) for how tool rows are composed.
2281
+ Tools can provide `renderCall` and `renderResult` for custom TUI display. See [tui.md](tui.md) for the full component API and [tool-execution.ts](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/modes/interactive/components/tool-execution.ts) for how tool rows are composed.
2241
2282
 
2242
2283
  By default, tool output is wrapped in a `Box` that handles padding and background. A defined `renderCall` or `renderResult` must return a `Component`. If a slot renderer is not defined, `tool-execution.ts` uses fallback rendering for that slot.
2243
2284
 
@@ -2362,38 +2403,13 @@ If a slot renderer is not defined or throws:
2362
2403
 
2363
2404
  ### Dynamic Tool Loading
2364
2405
 
2365
- Extensions can register many tools while keeping only a small initial set active. A tool can then add more tools with `pi.setActiveTools()` during execution. Pi detects purely additive changes, records the newly available tool names on that tool result, and applies the updated active set before the next model request.
2366
-
2367
- This works with every model. Models with native deferred-loading support preserve the stable prompt prefix and load the new definitions at the tool-result position. Other models use the fallback described below.
2406
+ Extensions can register many tools while keeping only a small initial set active. A tool can then change the active set with `pi.setActiveTools()` during execution. Pi stores the initial prompt and tool loadout in the transcript's first system message, then appends tool and prompt deltas before the next model request. Providers that cannot represent a transition receive a complete transcript checkpoint, which may invalidate the cached prefix.
2368
2407
 
2369
2408
  The lifecycle is:
2370
2409
 
2371
2410
  1. Register every tool with `pi.registerTool()` so it appears in `pi.getAllTools()`.
2372
2411
  2. Keep loader tools, such as `search_tools`, active and leave searchable tools inactive.
2373
- 3. During loader execution, call `pi.setActiveTools([...currentTools, ...matchingTools])`. The change must be additive: do not remove currently active tools in the same call.
2374
- 4. Pi records which tools were added on the loader's tool result.
2375
- 5. Before the next model response, Pi exposes the added definitions using native deferred loading when supported, or the normal active tool list otherwise.
2376
-
2377
- You do not need to return provider-specific tool references or mark the loader as a special search tool. The active-tool change is the signal. Names passed to `pi.setActiveTools()` must already be registered; unknown names are ignored.
2378
-
2379
- #### Models with native deferred loading
2380
-
2381
- - **Anthropic**
2382
- - **Models:** Sonnet, Opus, Fable version 4.5 or newer (without Haiku)
2383
- - **Native representation:** Deferred definitions use `defer_loading`; the load point uses `tool_reference` content.
2384
- - **OpenAI**
2385
- - **Models:** `gpt-5.4` and newer family
2386
- - **Native representation:** Pi adds completed client `tool_search_call` and `tool_search_output` items at the load point.
2387
-
2388
- For a verified custom model or proxy, native handling can be enabled with `compat.supportsToolReferences: true` for `anthropic-messages`, or `compat.supportsToolSearch: true` for `openai-responses` and `openai-codex-responses`. Leave these disabled unless the endpoint and model accept the corresponding native protocol.
2389
-
2390
- #### Fallback behavior
2391
-
2392
- For all other models and providers, dynamic activation still works: Pi sends the complete current active tool list normally on the next request. The model can call the newly activated tools, but adding their definitions may invalidate the provider's cached prompt prefix.
2393
-
2394
- Pi also uses this safe fallback when the active set is not purely additive, such as replacing one group of tools with another. Tool removals therefore work, but they do not use deferred loading.
2395
-
2396
- For the best cache behavior, keep the loader tool active for the whole session and add tools instead of replacing the active set. Also note that activating a tool with `promptSnippet` or `promptGuidelines` rebuilds the system prompt; that system-prompt change can invalidate the prefix even when the provider supports deferred schemas. Lazily loaded tools should usually rely on their tool `description` and omit active-only prompt metadata.
2412
+ 3. During loader execution, call `pi.setActiveTools()` with the desired active tool names. Names must already be registered; unknown names are ignored.
2397
2413
 
2398
2414
  #### Search tool example
2399
2415
 
@@ -2495,7 +2511,7 @@ export default function (pi: ExtensionAPI) {
2495
2511
  }
2496
2512
  ```
2497
2513
 
2498
- When `search_tools` adds a match, the model receives that definition on the immediately following request. On a native-capable model the definition is anchored after the search result without changing the initial tool-schema prefix. On other models it appears in the normal tool list on that same following request.
2514
+ When `search_tools` adds a match, the model receives the complete updated tool list on the immediately following request.
2499
2515
 
2500
2516
  ## Custom UI
2501
2517
 
@@ -2827,6 +2843,7 @@ export default function (pi: ExtensionAPI) {
2827
2843
  **Key points:**
2828
2844
  - Extend `CustomEditor` (not base `Editor`) to get app keybindings (escape to abort, ctrl+d, model switching)
2829
2845
  - Call `super.handleInput(data)` for keys you don't handle
2846
+ - Custom editors keep the standalone working row by default. Pass `{ embedWorkingStatus: true }` as the fourth `CustomEditor` constructor argument to use the built-in editor-border spinner instead.
2830
2847
  - Factory receives `tui`, `theme`, and `keybindings` from the app
2831
2848
  - Use `ctx.ui.getEditorComponent()` before `setEditorComponent()` to wrap the previously configured custom editor
2832
2849
  - Pass `undefined` to restore default: `ctx.ui.setEditorComponent(undefined)`
package/bin/docs/json.md CHANGED
@@ -9,7 +9,7 @@ Outputs all session events as JSON lines to stdout. Useful for integrating pi in
9
9
  ## Event Types
10
10
 
11
11
  Wire events use `JsonAgentSessionEvent`. It matches
12
- [`AgentSessionEvent`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/agent-session.ts)
12
+ [`AgentSessionEvent`](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/agent-session.ts)
13
13
  except that streaming message updates omit cumulative snapshots:
14
14
 
15
15
  ```typescript
@@ -31,7 +31,7 @@ type JsonAgentSessionEvent =
31
31
  `queue_update` emits the full pending steering and follow-up queues whenever they change. `compaction_start` and `compaction_end` cover both manual and automatic compaction.
32
32
 
33
33
  Other base events come from
34
- [`AgentEvent`](https://github.com/earendil-works/pi-mono/blob/main/packages/agent/src/types.ts):
34
+ [`AgentEvent`](https://github.com/earendil-works/pi/blob/main/packages/agent/src/types.ts):
35
35
 
36
36
  ```typescript
37
37
  type AgentEvent =
@@ -53,12 +53,12 @@ type AgentEvent =
53
53
 
54
54
  ## Message Types
55
55
 
56
- Base messages from [`packages/ai/src/types.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/ai/src/types.ts#L134):
56
+ Base messages from [`packages/ai/src/types.ts`](https://github.com/earendil-works/pi/blob/main/packages/ai/src/types.ts#L134):
57
57
  - `UserMessage` (line 134)
58
58
  - `AssistantMessage` (line 140)
59
59
  - `ToolResultMessage` (line 152)
60
60
 
61
- Extended messages from [`packages/coding-agent/src/core/messages.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/messages.ts#L29):
61
+ Extended messages from [`packages/coding-agent/src/core/messages.ts`](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/messages.ts#L29):
62
62
  - `BashExecutionMessage` (line 29)
63
63
  - `CustomMessage` (line 46)
64
64
  - `BranchSummaryMessage` (line 55)
@@ -86,10 +86,12 @@ The dedicated history actions always change history entries, regardless of the c
86
86
 
87
87
  ### TUI Fullscreen Viewport
88
88
 
89
- These actions apply when interactive mode uses `--tui-mode fullscreen` and target the primary transcript scroll region. Two-finger trackpad and mouse-wheel input scroll the region under the pointer, falling back to the transcript over the fixed editor/status/footer dock. Clicking an OSC 8 hyperlink opens it in the default handler. Dragging with the primary mouse button selects text and copies it to the clipboard; holding at the transcript's top or bottom edge auto-scrolls into off-screen content. See [Terminal setup](terminal-setup.md) for terminal-specific mouse and trackpad behavior.
89
+ These actions apply when interactive mode uses `--tui-mode fullscreen` and target the primary transcript scroll region. Two-finger trackpad and mouse-wheel input scroll the region under the pointer, falling back to the transcript over the fixed editor/status/footer dock. Clicking an OSC 8 hyperlink opens it in the default handler. Dragging with the primary mouse button selects text and copies it to the clipboard; holding at the transcript's top or bottom edge auto-scrolls into off-screen content. While the transcript is scrolled up, a clickable "Jump to latest message" label on its bottom row shows the `tui.altScreen.bottom` shortcut. See [Terminal setup](terminal-setup.md) for terminal-specific mouse and trackpad behavior.
90
90
 
91
91
  Fullscreen transcript bindings take precedence over editor bindings. The default unmodified navigation keys therefore control the transcript in fullscreen mode, while their `ctrl` variants continue to control the editor. Outside fullscreen mode, both variants control the editor.
92
92
 
93
+ The transcript search panel shows the configured previous/next shortcuts and clickable arrow controls. Press `tui.altScreen.search` again, or use `tui.altScreen.searchClose`, to close it.
94
+
93
95
  | Key | Default mode | Fullscreen mode |
94
96
  |-----|--------------|-----------------|
95
97
  | `home`, `end` | Editor | Transcript |
@@ -149,7 +151,9 @@ This routing remains configurable through the ordinary action bindings. For exam
149
151
  | `app.model.select` | `ctrl+l` | Open model selector |
150
152
  | `app.model.cycleForward` | `ctrl+p` | Cycle to next model |
151
153
  | `app.model.cycleBackward` | `shift+ctrl+p` (`alt+p` on Windows and WSL) | Cycle to previous model |
154
+ | `app.models.save` | `ctrl+s` | Save the selected default model or scoped model configuration to settings |
152
155
  | `app.thinking.cycle` | `shift+tab` | Cycle thinking level |
156
+ | `app.thinking.save` | `ctrl+s` | Save current thinking level to settings |
153
157
  | `app.thinking.toggle` | `ctrl+t` | Collapse or expand thinking blocks |
154
158
 
155
159
  ### Display and Message Queue
@@ -183,7 +187,6 @@ Used inside the scoped models selector (opened via `/scoped-models`).
183
187
 
184
188
  | Keybinding id | Default | Description |
185
189
  |--------|---------|-------------|
186
- | `app.models.save` | `ctrl+s` | Save current model selection to settings |
187
190
  | `app.models.enableAll` | `ctrl+a` | Enable all models (or all matching the current search) |
188
191
  | `app.models.clearAll` | `ctrl+x` | Clear all models (or all matching the current search) |
189
192
  | `app.models.toggleProvider` | `ctrl+p` | Toggle all models for the current provider |
@@ -9,6 +9,7 @@ Add custom providers and models (Ollama, vLLM, LM Studio, proxies) via `~/.pi/ag
9
9
  - [Supported APIs](#supported-apis)
10
10
  - [Provider Configuration](#provider-configuration)
11
11
  - [Model Configuration](#model-configuration)
12
+ - [Prompt Cache Lifetimes](#prompt-cache-lifetimes)
12
13
  - [Overriding Built-in Providers](#overriding-built-in-providers)
13
14
  - [Per-model Overrides](#per-model-overrides)
14
15
  - [Anthropic Messages Compatibility](#anthropic-messages-compatibility)
@@ -208,6 +209,7 @@ If your command is slow, expensive, rate-limited, or should keep using a previou
208
209
  | `maxTokens` | No | `16384` | Maximum output tokens |
209
210
  | `samplingParams` | No | omitted | Sampling parameters merged verbatim into every request body (see below) |
210
211
  | `cost` | No | all zeros | Per-million-token rates with optional request-wide input pricing tiers |
212
+ | `promptCache` | No | omitted | Best-effort prompt cache lifetime in seconds per retention tier (see below) |
211
213
  | `compat` | No | provider `compat` | Provider compatibility overrides. Merged with provider-level `compat` when both are set. |
212
214
 
213
215
  A cost tier supplies a complete alternate rate set and applies to the full request when total input usage (`input + cacheRead + cacheWrite`) exceeds `inputTokensAbove`. When multiple tiers match, the highest threshold wins.
@@ -236,6 +238,19 @@ Current behavior:
236
238
  - `/model`, `--list-models`, and the interactive footer display entries by model `id`.
237
239
  - The configured `name` is used for model matching and secondary model detail text. It does not replace the footer/status-bar model id.
238
240
 
241
+ ### Prompt Cache Lifetimes
242
+
243
+ `promptCache` states how long the provider keeps a prompt cache entry alive for each retention tier pi can request (`short` is the default tier; `long` is used when `PI_CACHE_RETENTION=long`). Values are seconds and are estimates: providers publish ranges, so pick the conservative end.
244
+
245
+ ```json
246
+ {
247
+ "id": "claude-sonnet-5",
248
+ "promptCache": { "short": 300, "long": 3600 }
249
+ }
250
+ ```
251
+
252
+ The built-in catalog fills this in for direct Anthropic (5 min / 1 h). Other providers, including direct OpenAI, have no built-in lifetime until their cache-expiry and replay behavior has been validated for warming. A model without a value for the tier a request used is never warmed; custom models and provider overrides can opt in when the backing cache behavior is known. See [Cache Warming](settings.md#cache-warming).
253
+
239
254
  ### Sampling Parameters
240
255
 
241
256
  `samplingParams` is a free-form object merged verbatim into every request body for the model, after the fields pi sets itself, so its keys win. Use it to send sampling parameters pi does not model — including server-specific ones like llama.cpp's `min_p` or vLLM's `top_k`:
@@ -359,7 +374,23 @@ Use `modelOverrides` to customize built-in models and matching extension-registe
359
374
  }
360
375
  ```
361
376
 
362
- `modelOverrides` supports these fields per model: `name`, `reasoning`, `thinkingLevelMap`, `input`, `cost` (partial), `contextWindow`, `maxTokens`, `samplingParams` (merged per key), `headers`, `compat`.
377
+ `modelOverrides` supports these fields per model: `name`, `reasoning`, `thinkingLevelMap`, `input`, `cost` (partial), `promptCache` (merged per tier), `contextWindow`, `maxTokens`, `samplingParams` (merged per key), `headers`, `compat`.
378
+
379
+ Use a `promptCache` override to enable cache warming through a proxy whose backing cache you know, for example OpenRouter routed to Anthropic:
380
+
381
+ ```json
382
+ {
383
+ "providers": {
384
+ "openrouter": {
385
+ "modelOverrides": {
386
+ "anthropic/claude-sonnet-4": {
387
+ "promptCache": { "short": 300 }
388
+ }
389
+ }
390
+ }
391
+ }
392
+ }
393
+ ```
363
394
 
364
395
  Direct OpenAI GPT-5.6 Sol, Terra, and Luna default to a `272000` context window so requests remain within OpenAI's short-context pricing tier. To opt into OpenAI's 1.05M context window, increase it for each model you use:
365
396
 
@@ -394,6 +425,8 @@ By default pi sends per-tool `eager_input_streaming: true`. If a proxy or Anthro
394
425
 
395
426
  Some Anthropic models require adaptive thinking (`thinking.type: "adaptive"` plus `output_config.effort`) instead of the legacy budget-based thinking payload. Built-in models set this automatically. For custom providers or aliases that route to those models, set `forceAdaptiveThinking` to `true`.
396
427
 
428
+ Claude models with per-turn effort support use `supportsMidConvoEffort`. Pi then persists each response's provider effort, reconstructs effort-only system messages on later requests, and sends thinking binding controls with `prefix_mismatch_behavior: "drop_block"` to avoid stale signed-thinking prefixes causing persistent 400 responses. Set this only for the exact supported Claude model on a faithful Anthropic Messages transport; do not enable it for APIs that merely imitate the Messages shape.
429
+
397
430
  Some Anthropic-compatible providers emit thinking blocks with empty signatures and still expect them on replay. Set `allowEmptySignature` to `true` only for those providers; real Anthropic rejects empty thinking signatures.
398
431
 
399
432
  Built-in Anthropic models enable `supportsStrictTools` in their model metadata. Custom Anthropic-compatible models must set it to `true` when their endpoint accepts strict JSON-schema tool definitions.
@@ -430,8 +463,10 @@ Built-in Anthropic models enable `supportsStrictTools` in their model metadata.
430
463
  | `sendSessionAffinityHeaders` | Whether to send `x-session-affinity` from the session id when caching is enabled. Default: auto-detected for known providers. |
431
464
  | `supportsCacheControlOnTools` | Whether the provider accepts Anthropic-style `cache_control` markers on tool definitions. Default: `true`. |
432
465
  | `forceAdaptiveThinking` | Whether to send adaptive thinking (`thinking.type: "adaptive"` plus `output_config.effort`) for this model. Built-in adaptive models set this automatically. Default: `false`. |
466
+ | `supportsMidConvoEffort` | Whether the exact Claude model transport supports per-turn effort system messages and thinking binding controls. Pi persists native effort levels and always sends `drop_block` when enabled. Default: `false`. |
433
467
  | `allowEmptySignature` | Whether to replay empty thinking signatures as `signature: ""` instead of converting thinking to text. Default: `false`. |
434
468
  | `supportsStrictTools` | Whether the provider accepts strict JSON-schema tool definitions. Default: `false`; built-in Anthropic models enable it in generated metadata. |
469
+ | `allowedFallbackModels` | Up to three server-side fallback models, each with `provider`, `model`, and complete `cost` metadata. An empty array disables fallback. |
435
470
 
436
471
  ## OpenAI Compatibility
437
472
 
@@ -478,8 +513,7 @@ For providers with partial OpenAI compatibility, use the `compat` field.
478
513
  | `sessionAffinityFormat` | For `openai-completions` and `openai-responses`, the session-affinity header format: `openai` sends `session_id`/`x-client-request-id` (completions also `x-session-affinity`), `openai-nosession` omits the underscore-containing `session_id` header, `openrouter` sends `x-session-id`. Does not affect the `prompt_cache_key` body param. Default: auto-detected. |
479
514
  | `supportsStrictMode` | Whether the provider accepts strict JSON-schema function tool definitions. Defaults depend on the API; built-in OpenAI models carry explicit capability metadata. |
480
515
  | `supportsOpenAIGrammarTools` | Whether OpenAI-compatible APIs emit custom Lark/regex grammar tools. When `false`, grammar-constrained tools fall back to normal function tools. Default: `false`; the built-in model catalog enables it for GPT-5+ models on OpenAI, OpenAI Codex, Azure OpenAI, GitHub Copilot, opencode, and Cloudflare AI Gateway. |
481
- | `deferredToolsMode` | Use provider-specific deferred tool serialization. Currently only `"kimi"` is supported for Kimi's OpenAI-compatible Chat Completions format. |
482
- | `supportsLongCacheRetention` | Whether the provider accepts long cache retention when cache retention is `long`: `prompt_cache_retention: "24h"` for OpenAI prompt caching, or `cache_control.ttl: "1h"` when `cacheControlFormat` is `anthropic`. Default: `true`. |
516
+ | `supportsLongCacheRetention` | Whether the provider accepts long cache retention when cache retention is `long`: `prompt_cache_options.ttl: "30m"` for GPT-5.6+ Responses models, `prompt_cache_retention: "24h"` for earlier OpenAI models, or `cache_control.ttl: "1h"` when `cacheControlFormat` is `anthropic`. Default: `true`. |
483
517
  | `openRouterRouting` | OpenRouter provider routing preferences. This object is sent as-is in the `provider` field of the [OpenRouter API request](https://openrouter.ai/docs/guides/routing/provider-selection). |
484
518
  | `vercelGatewayRouting` | Vercel AI Gateway routing config for provider selection (`only`, `order`) |
485
519
 
@@ -20,6 +20,7 @@ Use `/login` in interactive mode, then select a provider:
20
20
  - Claude Pro/Max
21
21
  - GitHub Copilot
22
22
  - xAI (Grok/X subscription)
23
+ - Meta (Muse subscription)
23
24
  - OpenRouter (OAuth-minted API key billed from OpenRouter credits)
24
25
  - Radius
25
26
 
@@ -44,6 +45,12 @@ Anthropic subscription auth is active for Claude Pro/Max accounts. Third-party h
44
45
  - Run `/login xai`, then select **Use a subscription**
45
46
  - `XAI_API_KEY` remains available through **Use an API key**
46
47
 
48
+ ### Meta (Muse subscription)
49
+
50
+ - Run `/login meta`, then select **Sign in with Meta** to open the device authorization flow
51
+ - The login mints a Model API key that is re-minted automatically about once a day
52
+ - `META_API_KEY` remains available through **Use an API key**
53
+
47
54
  ### OpenRouter
48
55
 
49
56
  - Run `/login openrouter`, then select **Sign in with OpenRouter** to open the OpenRouter PKCE authorization flow
@@ -53,7 +60,7 @@ Anthropic subscription auth is active for Claude Pro/Max accounts. Third-party h
53
60
 
54
61
  ### Radius
55
62
 
56
- Radius is a dynamic `pi-messages` gateway. `/login radius` stores OAuth tokens in `auth.json`; the gateway catalog is refreshed independently and cached in `models-store.json`. Custom Radius gateways can be declared in `models.json` with `"oauth": "radius"` and a gateway `baseUrl`.
63
+ Radius is a `pi-messages` gateway. Pi ships the public Radius model catalog for immediate and offline model lookup, then overlays it with the effective gateway catalog after authentication. `/login radius` stores OAuth tokens in `auth.json`; refreshed catalogs are cached in `models-store.json`. Custom Radius gateways can be declared in `models.json` with `"oauth": "radius"` and a gateway `baseUrl`; they do not inherit the public `radius.pi.dev` catalog.
57
64
 
58
65
  ## API Keys
59
66
 
@@ -94,6 +101,7 @@ pi
94
101
  | Together AI | `TOGETHER_API_KEY` | `together` |
95
102
  | Baseten | `BASETEN_API_KEY` | `baseten` |
96
103
  | Kimi For Coding | `KIMI_API_KEY` | `kimi-coding` |
104
+ | Meta | `META_API_KEY` | `meta` |
97
105
  | MiniMax | `MINIMAX_API_KEY` | `minimax` |
98
106
  | MiniMax (China) | `MINIMAX_CN_API_KEY` | `minimax-cn` |
99
107
  | Qwen Token Plan (existing catalog) | `QWEN_TOKEN_PLAN_API_KEY` | `qwen-token-plan` |
@@ -104,7 +112,7 @@ pi
104
112
  | Xiaomi MiMo Token Plan (Amsterdam) | `XIAOMI_TOKEN_PLAN_AMS_API_KEY` | `xiaomi-token-plan-ams` |
105
113
  | Xiaomi MiMo Token Plan (Singapore) | `XIAOMI_TOKEN_PLAN_SGP_API_KEY` | `xiaomi-token-plan-sgp` |
106
114
 
107
- Reference for environment variables and `auth.json` keys: [`const envMap`](https://github.com/earendil-works/pi-mono/blob/main/packages/ai/src/env-api-keys.ts) in [`packages/ai/src/env-api-keys.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/ai/src/env-api-keys.ts).
115
+ Reference for environment variables and `auth.json` keys: [`const envMap`](https://github.com/earendil-works/pi/blob/main/packages/ai/src/env-api-keys.ts) in [`packages/ai/src/env-api-keys.ts`](https://github.com/earendil-works/pi/blob/main/packages/ai/src/env-api-keys.ts).
108
116
 
109
117
  #### Auth File
110
118
 
package/bin/docs/rpc.md CHANGED
@@ -123,7 +123,7 @@ See [set_follow_up_mode](#set_follow_up_mode) for controlling how follow-up mess
123
123
 
124
124
  #### abort
125
125
 
126
- Abort the current agent operation.
126
+ Abort the current operation and wait for the session to become idle before responding.
127
127
 
128
128
  ```json
129
129
  {"type": "abort"}
package/bin/docs/sdk.md CHANGED
@@ -111,6 +111,8 @@ interface AgentSession {
111
111
  }
112
112
  ```
113
113
 
114
+ `session.navigateTree()` rejects while an agent response, manual or automatic compaction, or another tree navigation is active, even with `summarize: false`. It does not queue navigation or return `{ cancelled: true }` for these conflicts. Wait for the active operation to finish (for example, with `await session.waitForIdle()`) and retry. Rejection leaves the active branch unchanged.
115
+
114
116
  Session replacement APIs such as new-session, resume, fork, and import live on `AgentSessionRuntime`, not on `AgentSession`.
115
117
 
116
118
  ### createAgentSessionRuntime() and AgentSessionRuntime
@@ -244,8 +246,8 @@ const state = session.agent.state;
244
246
  // state.messages: AgentMessage[] - conversation history
245
247
  // state.model: Model - current model
246
248
  // state.thinkingLevel: ThinkingLevel - current thinking level
247
- // state.systemPrompt: string - system prompt
248
- // state.tools: AgentTool[] - available tools
249
+ // state.systemPrompt: string - read-only, replayed from the transcript's system messages
250
+ // state.tools: AgentTool[] - executable tools; changes are declared to the model before the next request
249
251
  // state.streamingMessage?: AgentMessage - current partial assistant message
250
252
  // state.errorMessage?: string - latest assistant error
251
253
 
@@ -788,6 +790,11 @@ const { session: opened } = await createAgentSession({
788
790
  sessionManager: SessionManager.open("/path/to/session.jsonl"),
789
791
  });
790
792
 
793
+ // Resume a session kept outside the filesystem, e.g. in a database
794
+ const { session: restored } = await createAgentSession({
795
+ sessionManager: SessionManager.inMemory(process.cwd(), { id: sessionId }, entries),
796
+ });
797
+
791
798
  // List sessions
792
799
  const currentProjectSessions = await SessionManager.list(process.cwd());
793
800
  const allSessions = await SessionManager.listAll(process.cwd());
@@ -54,6 +54,6 @@ If you bind-mount a host workspace read/write, writes from inside the container
54
54
 
55
55
  ## Reporting Security Issues
56
56
 
57
- To report a security issue, follow the repository [Security Policy](https://github.com/earendil-works/pi-mono/blob/main/SECURITY.md). Do not open a public issue for security-sensitive reports.
57
+ To report a security issue, follow the repository [Security Policy](https://github.com/earendil-works/pi/blob/main/SECURITY.md). Do not open a public issue for security-sensitive reports.
58
58
 
59
59
  Expected local-agent behavior, lack of a built-in sandbox, prompt injection from untrusted content, and behavior of user-installed extensions or skills are generally outside the security boundary unless the report demonstrates a real privilege-boundary bypass or shows how pi grants access that the local user did not already have.