@kingingwang/pi-windows-arm64 0.85.1 → 0.87.0
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/bin/CHANGELOG.md +148 -0
- package/bin/README.md +39 -1
- package/bin/docs/compaction.md +62 -17
- package/bin/docs/custom-provider.md +22 -13
- package/bin/docs/development.md +4 -4
- package/bin/docs/docs.json +4 -0
- package/bin/docs/environment-variables.md +1 -0
- package/bin/docs/extensions.md +127 -49
- package/bin/docs/json.md +4 -4
- package/bin/docs/models.md +61 -2
- package/bin/docs/providers.md +10 -2
- package/bin/docs/sdk.md +17 -4
- package/bin/docs/security.md +1 -1
- package/bin/docs/session-format.md +96 -41
- package/bin/docs/sessions.md +27 -0
- package/bin/docs/settings.md +56 -1
- package/bin/docs/termux.md +0 -1
- package/bin/docs/tui.md +2 -2
- package/bin/docs/usage.md +1 -0
- package/bin/examples/extensions/README.md +0 -1
- package/bin/examples/extensions/custom-provider-anthropic/index.ts +18 -12
- package/bin/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/bin/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/bin/examples/extensions/custom-provider-gitlab-duo/index.ts +2 -2
- package/bin/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/bin/examples/extensions/gondolin/package-lock.json +2 -2
- package/bin/examples/extensions/gondolin/package.json +1 -1
- package/bin/examples/extensions/prompt-customizer.ts +19 -67
- package/bin/examples/extensions/sandbox/package-lock.json +2 -2
- package/bin/examples/extensions/sandbox/package.json +1 -1
- package/bin/examples/extensions/with-deps/package-lock.json +2 -2
- package/bin/examples/extensions/with-deps/package.json +1 -1
- package/bin/examples/plugins/pi-example-plugin/src/session.ts +3 -2
- package/bin/export-html/template.js +6 -1
- package/bin/native/win32/prebuilds/win32-arm64/win32-platform.node +0 -0
- package/bin/package.json +17 -23
- package/bin/pi.exe +2 -2
- package/package.json +1 -1
- package/bin/examples/extensions/kimi-deferred-tools.ts +0 -61
- package/bin/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
- package/bin/node_modules/@mariozechner/clipboard/.yarnrc.yml +0 -1
- package/bin/node_modules/@mariozechner/clipboard/Cargo.toml +0 -45
- package/bin/node_modules/@mariozechner/clipboard/README.md +0 -60
- package/bin/node_modules/@mariozechner/clipboard/build.rs +0 -5
- package/bin/node_modules/@mariozechner/clipboard/clipboard.win32-arm64-msvc.node +0 -0
- package/bin/node_modules/@mariozechner/clipboard/exp.ts +0 -12
- package/bin/node_modules/@mariozechner/clipboard/index.d.ts +0 -37
- package/bin/node_modules/@mariozechner/clipboard/index.js +0 -606
- package/bin/node_modules/@mariozechner/clipboard/package.json +0 -56
- package/bin/node_modules/@mariozechner/clipboard/src/clipboard_rs/common.rs +0 -307
- package/bin/node_modules/@mariozechner/clipboard/src/clipboard_rs/mod.rs +0 -93
- package/bin/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/ios.rs +0 -313
- package/bin/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/macos.rs +0 -471
- package/bin/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/mod.rs +0 -252
- package/bin/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/wayland.rs +0 -431
- package/bin/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/win.rs +0 -712
- package/bin/node_modules/@mariozechner/clipboard/src/clipboard_rs/platform/x11.rs +0 -916
- package/bin/node_modules/@mariozechner/clipboard/src/lib.rs +0 -194
package/bin/docs/extensions.md
CHANGED
|
@@ -294,7 +294,8 @@ user sends prompt ────────────────────
|
|
|
294
294
|
│ ┌─── turn (repeats while LLM calls tools) ───┐ │
|
|
295
295
|
│ │ │ │
|
|
296
296
|
│ ├─► turn_start │ │
|
|
297
|
-
│ ├─► context (can modify messages)
|
|
297
|
+
│ ├─► context (can modify conversation messages) │
|
|
298
|
+
│ ├─► context_with_system (can modify the full transcript)
|
|
298
299
|
│ ├─► before_provider_headers (can mutate headers) |
|
|
299
300
|
│ ├─► before_provider_request (can inspect or replace payload)
|
|
300
301
|
│ ├─► after_provider_response (status + headers, before stream consume)
|
|
@@ -307,9 +308,13 @@ user sends prompt ────────────────────
|
|
|
307
308
|
│ │ └─► tool_execution_end │ │
|
|
308
309
|
│ │ │ │
|
|
309
310
|
│ └─► turn_end │ │
|
|
311
|
+
│ └─► threshold compaction before a naturally required next turn
|
|
310
312
|
│ │
|
|
311
313
|
├─► agent_end │
|
|
312
|
-
|
|
314
|
+
├─► retry backoff or final-attempt recovery (when selected)
|
|
315
|
+
│ └─► fresh agent_start on successful recovery │
|
|
316
|
+
├─► agent_before_settle (can append entries and continue)│
|
|
317
|
+
└─► agent_settled (final, notification only) │
|
|
313
318
|
│
|
|
314
319
|
user sends another prompt ◄────────────────────────────────┘
|
|
315
320
|
|
|
@@ -538,10 +543,13 @@ pi.on("before_agent_start", async (event, ctx) => {
|
|
|
538
543
|
// event.systemPrompt - current chained system prompt for this handler
|
|
539
544
|
// (includes changes from earlier before_agent_start handlers)
|
|
540
545
|
// event.systemPromptOptions - structured options used to build the system prompt
|
|
541
|
-
// .customPrompt -
|
|
546
|
+
// .customPrompt - exact prompt prefix from --system-prompt, SYSTEM.md, or custom templates
|
|
547
|
+
// .forceSystemPrompt - optional exact replacement for the complete prompt
|
|
542
548
|
// .selectedTools - tools currently active in the prompt
|
|
543
549
|
// .toolSnippets - one-line descriptions for each tool
|
|
544
|
-
// .
|
|
550
|
+
// .toolGuidelines - guideline bullets keyed by tool name
|
|
551
|
+
// .promptGuidelines - additional custom guideline bullets
|
|
552
|
+
// .sections - custom XML-wrapped sections keyed by tag name
|
|
545
553
|
// .appendSystemPrompt - text from --append-system-prompt flags
|
|
546
554
|
// .cwd - working directory
|
|
547
555
|
// .contextFiles - AGENTS.md files and other loaded context files
|
|
@@ -560,13 +568,13 @@ pi.on("before_agent_start", async (event, ctx) => {
|
|
|
560
568
|
});
|
|
561
569
|
```
|
|
562
570
|
|
|
563
|
-
The `systemPromptOptions` field gives extensions access to the same structured data Pi uses to build the system prompt.
|
|
571
|
+
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
572
|
|
|
565
573
|
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
574
|
|
|
567
|
-
#### agent_start / agent_end / agent_settled
|
|
575
|
+
#### agent_start / agent_end / agent_before_settle / agent_settled
|
|
568
576
|
|
|
569
|
-
`agent_start` fires when a low-level agent run begins. `agent_end` fires when that run ends, but Pi may still auto-retry, auto-compact and retry, or continue with queued follow-up messages.
|
|
577
|
+
`agent_start` fires when a low-level agent run begins. `agent_end` fires when that run ends, but Pi may still auto-retry, auto-compact and retry, or continue with queued follow-up messages. `agent_before_settle` is the final actionable boundary: it can append session entries and request one continuation. `agent_settled` is final and notification-only; use it for status integrations that need to know Pi will not continue running automatically.
|
|
570
578
|
|
|
571
579
|
```typescript
|
|
572
580
|
pi.on("agent_start", async (_event, ctx) => {});
|
|
@@ -575,11 +583,28 @@ pi.on("agent_end", async (event, ctx) => {
|
|
|
575
583
|
// event.messages - messages from this low-level run
|
|
576
584
|
});
|
|
577
585
|
|
|
586
|
+
let addedReviewReminder = false;
|
|
587
|
+
pi.on("agent_before_settle", async (event, ctx) => {
|
|
588
|
+
if (addedReviewReminder) return;
|
|
589
|
+
addedReviewReminder = true;
|
|
590
|
+
return {
|
|
591
|
+
entries: [...event.entries, {
|
|
592
|
+
type: "custom_message",
|
|
593
|
+
customType: "review-reminder",
|
|
594
|
+
content: "Review the final diff before replying.",
|
|
595
|
+
display: false,
|
|
596
|
+
}],
|
|
597
|
+
continue: true,
|
|
598
|
+
};
|
|
599
|
+
});
|
|
600
|
+
|
|
578
601
|
pi.on("agent_settled", async (_event, ctx) => {
|
|
579
|
-
// ctx.isIdle() is true here
|
|
602
|
+
// ctx.isIdle() is true; runs requested here start after all settled handlers finish.
|
|
580
603
|
});
|
|
581
604
|
```
|
|
582
605
|
|
|
606
|
+
If the run is aborted while `agent_before_settle` handlers are running, valid returned entries are still committed, but requested continuation is suppressed. Work requested from `agent_settled` is deferred until every settled handler completes, so notification dispatch is non-reentrant.
|
|
607
|
+
|
|
583
608
|
#### ui_prompt_start / ui_prompt_end
|
|
584
609
|
|
|
585
610
|
Notification-only lifecycle events for blocking user-facing extension UI prompts. They fire around `ctx.ui.select()`, `ctx.ui.confirm()`, `ctx.ui.input()`, `ctx.ui.editor()`, and `ctx.ui.custom()` so host/status integrations can report "waiting for user" instead of just "running".
|
|
@@ -607,11 +632,34 @@ pi.on("turn_start", async (event, ctx) => {
|
|
|
607
632
|
// event.turnIndex, event.timestamp
|
|
608
633
|
});
|
|
609
634
|
|
|
635
|
+
let replacedResponse = false;
|
|
610
636
|
pi.on("turn_end", async (event, ctx) => {
|
|
611
637
|
// event.turnIndex, event.message, event.toolResults
|
|
638
|
+
// event.entries contains the structural entries proposed so far.
|
|
639
|
+
if (replacedResponse || event.outcome !== "completed" || event.toolResults.length > 0) return;
|
|
640
|
+
replacedResponse = true;
|
|
641
|
+
return {
|
|
642
|
+
entries: [
|
|
643
|
+
...event.entries,
|
|
644
|
+
{ type: "context_edit", targetId: event.messageEntryId, replacement: null },
|
|
645
|
+
{
|
|
646
|
+
type: "custom_message",
|
|
647
|
+
customType: "replacement-instruction",
|
|
648
|
+
content: "Answer again using the persisted user request.",
|
|
649
|
+
display: false,
|
|
650
|
+
},
|
|
651
|
+
],
|
|
652
|
+
continue: true,
|
|
653
|
+
};
|
|
612
654
|
});
|
|
613
655
|
```
|
|
614
656
|
|
|
657
|
+
`turn_end` runs after the assistant and tool-result messages have been persisted and before the low-level `turn_end` event. Retry backoff and final-attempt recovery still happen after `agent_end`, preserving their existing lifecycle and queue ordering; `agent_before_settle` sees the repaired projection after that work completes. Boundary handlers run in extension load and registration order. Each handler sees prior proposals in `event.entries` and sees `event.context` rebuilt from them. Returning `entries` or `continue` replaces only that field; omitted fields preserve the current proposal. Allowed draft entry types are `custom`, `custom_message`, `context_edit`, and `compaction`. The complete proposal is validated before it is appended in list order after all handlers finish; a handler error is reported and later handlers still run. Validation prevents partially applied semantic errors, but persistence is not transactional.
|
|
658
|
+
|
|
659
|
+
`continue: true` ensures one next provider request for that boundary invocation. If tool results, steering, or a follow-up already cause that request, they satisfy the decision and no additional request is made; otherwise Pi makes one context-only request. Error and aborted responses remain hard exits. `continue: false` never suppresses natural work. Guard continuation conditions: an unconditional `continue: true` is evaluated again after the next response and can create an endless loop. A `custom_message` draft contributes a user-role model message but is extension-authored: it does not run human input hooks, slash commands, skills, or prompt templates.
|
|
660
|
+
|
|
661
|
+
Host integrations that construct `TurnEndEvent` values must now provide `messageEntryId`, `toolResultEntryIds`, `outcome`, `entries`, `continue`, and `context`. `ExtensionEvent` exhaustive switches must also handle `agent_before_settle`. `ExtensionRunner.emit()` excludes actionable turn boundaries; dispatch `turn_end` and `agent_before_settle` through `emitBoundary(baseEvent, buildContext)` so handlers receive chained previews. Other dedicated runner methods still return results for events such as `session_before_*`.
|
|
662
|
+
|
|
615
663
|
#### message_start / message_update / message_end
|
|
616
664
|
|
|
617
665
|
Fired for message lifecycle updates.
|
|
@@ -678,12 +726,31 @@ Fired before each LLM call. Modify messages non-destructively. See [Session Form
|
|
|
678
726
|
|
|
679
727
|
```typescript
|
|
680
728
|
pi.on("context", async (event, ctx) => {
|
|
681
|
-
// event.messages - deep copy, safe to modify
|
|
729
|
+
// event.messages - deep copy without system messages, safe to modify
|
|
682
730
|
const filtered = event.messages.filter(m => !shouldPrune(m));
|
|
683
731
|
return { messages: filtered };
|
|
684
732
|
});
|
|
685
733
|
```
|
|
686
734
|
|
|
735
|
+
`event.messages` holds the conversation without system messages. The prompt and tool declarations belong to Pi and are not part of this hook: when the handler returns a changed list, Pi replays the current prompt sections and tool declarations into one leading system message ahead of the returned messages. Filtering, windowing, or slicing from a compaction summary therefore cannot drop the prompt or the tools. An unchanged list keeps mid-conversation system messages in place, so models that accept them retain their cached prefix. System messages a handler adds are kept after Pi's head. To change the prompt or the tool set durably, use [`before_agent_start`](#before_agent_start) or `pi.setActiveTools()`; to edit system messages for one request, use [`context_with_system`](#context_with_system).
|
|
736
|
+
|
|
737
|
+
#### context_with_system
|
|
738
|
+
|
|
739
|
+
Fired before each LLM call, after every `context` handler has run and Pi has restored the prompt and tool state. `event.messages` is the full transcript, including the leading system message and any mid-conversation prompt or tool patches (see [Session Format](session-format.md#sessionmessageentry)). The returned messages are sent as they are: this hook owns the prompt and tool declarations for the request.
|
|
740
|
+
|
|
741
|
+
```typescript
|
|
742
|
+
import { getCurrentSystemMessage } from "@earendil-works/pi-ai";
|
|
743
|
+
|
|
744
|
+
pi.on("context_with_system", async (event, ctx) => {
|
|
745
|
+
const cut = findCutIndex(event.messages);
|
|
746
|
+
// Fold the dropped prefix so its prompt and tool state survives as the new head.
|
|
747
|
+
const head = getCurrentSystemMessage(event.messages.slice(0, cut));
|
|
748
|
+
return { messages: head ? [head, ...event.messages.slice(cut)] : event.messages.slice(cut) };
|
|
749
|
+
});
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
Rules: keep a system message at index 0 (providers read the prompt and initial tool declarations there; Pi reports an error if a handler drops it). Removing a system message removes the tool declarations and section patches it carries. Check your output with `getCurrentSystemPrompt()` and `getCurrentTools()` from `@earendil-works/pi-ai`. Handlers run in extension load order; a `systemPrompt` forced from `before_agent_start` is still projected onto the request afterwards.
|
|
753
|
+
|
|
687
754
|
#### before_provider_headers
|
|
688
755
|
|
|
689
756
|
Fired after the outgoing HTTP headers are assembled. Use it to add, override, or remove request headers.
|
|
@@ -735,6 +802,25 @@ pi.on("after_provider_response", (event, ctx) => {
|
|
|
735
802
|
|
|
736
803
|
Header availability depends on provider and transport. Providers that abstract HTTP responses may not expose headers.
|
|
737
804
|
|
|
805
|
+
#### cache_warming_decision
|
|
806
|
+
|
|
807
|
+
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.
|
|
808
|
+
|
|
809
|
+
```typescript
|
|
810
|
+
pi.on("cache_warming_decision", (event, ctx) => {
|
|
811
|
+
// event.warmCost: price of this refresh
|
|
812
|
+
// event.missCost: extra price of the next request if the entry is lost
|
|
813
|
+
// event.continuationProbability: pi's estimate that a request arrives in time
|
|
814
|
+
// event.action: "warm" | "stop", pi's decision
|
|
815
|
+
|
|
816
|
+
if (ctx.model?.provider === "my-provider") {
|
|
817
|
+
return { action: "stop" };
|
|
818
|
+
}
|
|
819
|
+
});
|
|
820
|
+
```
|
|
821
|
+
|
|
822
|
+
Return `{ action: "warm" }` or `{ action: "stop" }` to override; the last handler that returns an action wins. `"stop"` ends warming until the next real request.
|
|
823
|
+
|
|
738
824
|
### Model Events
|
|
739
825
|
|
|
740
826
|
#### model_select
|
|
@@ -906,6 +992,8 @@ pi.on("user_bash", (event, ctx) => {
|
|
|
906
992
|
});
|
|
907
993
|
```
|
|
908
994
|
|
|
995
|
+
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.
|
|
996
|
+
|
|
909
997
|
### Input Events
|
|
910
998
|
|
|
911
999
|
#### input
|
|
@@ -1016,6 +1104,12 @@ Access to models, providers, and resolved authentication. `ctx.modelRegistry.get
|
|
|
1016
1104
|
|
|
1017
1105
|
`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
1106
|
|
|
1107
|
+
#### Streaming model calls
|
|
1108
|
+
|
|
1109
|
+
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.
|
|
1110
|
+
|
|
1111
|
+
Both return an `AssistantMessageEventStream`. Iterate it for response events and await `.result()` for the final message. Setup failures produce error events and error results.
|
|
1112
|
+
|
|
1019
1113
|
### ctx.signal
|
|
1020
1114
|
|
|
1021
1115
|
The current agent abort signal, or `undefined` when no agent turn is active.
|
|
@@ -1119,7 +1213,7 @@ const options = ctx.getSystemPromptOptions();
|
|
|
1119
1213
|
const contextPaths = options.contextFiles?.map((file) => file.path) ?? [];
|
|
1120
1214
|
```
|
|
1121
1215
|
|
|
1122
|
-
This has the same shape and mutability as `before_agent_start` `event.systemPromptOptions`: custom prompt, active tools, tool snippets,
|
|
1216
|
+
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
1217
|
|
|
1124
1218
|
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
1219
|
|
|
@@ -1197,7 +1291,7 @@ Options:
|
|
|
1197
1291
|
|
|
1198
1292
|
### ctx.navigateTree(targetId, options?)
|
|
1199
1293
|
|
|
1200
|
-
Navigate to a different point in the session tree:
|
|
1294
|
+
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
1295
|
|
|
1202
1296
|
```typescript
|
|
1203
1297
|
const result = await ctx.navigateTree("entry-id-456", {
|
|
@@ -1360,7 +1454,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
1360
1454
|
|
|
1361
1455
|
### pi.on(event, handler)
|
|
1362
1456
|
|
|
1363
|
-
Subscribe to events. See [Events](#events) for event types and return values.
|
|
1457
|
+
Subscribe to events. Returns an unsubscribe function that removes only that registration. See [Events](#events) for event types and return values.
|
|
1458
|
+
|
|
1459
|
+
```typescript
|
|
1460
|
+
const unsubscribe = pi.on("agent_end", async (event) => {
|
|
1461
|
+
unsubscribe();
|
|
1462
|
+
await updateIntegration(event.messages);
|
|
1463
|
+
});
|
|
1464
|
+
```
|
|
1465
|
+
|
|
1466
|
+
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
1467
|
|
|
1365
1468
|
### pi.registerTool(definition)
|
|
1366
1469
|
|
|
@@ -2101,14 +2204,14 @@ See [examples/extensions/tool-override.ts](../examples/extensions/tool-override.
|
|
|
2101
2204
|
**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.
|
|
2102
2205
|
|
|
2103
2206
|
Built-in tool implementations:
|
|
2104
|
-
- [read.ts](https://github.com/earendil-works/pi
|
|
2105
|
-
- [bash.ts](https://github.com/earendil-works/pi
|
|
2106
|
-
- [powershell.ts](https://github.com/earendil-works/pi
|
|
2107
|
-
- [edit.ts](https://github.com/earendil-works/pi
|
|
2108
|
-
- [write.ts](https://github.com/earendil-works/pi
|
|
2109
|
-
- [grep.ts](https://github.com/earendil-works/pi
|
|
2110
|
-
- [find.ts](https://github.com/earendil-works/pi
|
|
2111
|
-
- [ls.ts](https://github.com/earendil-works/pi
|
|
2207
|
+
- [read.ts](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/tools/read.ts) - `ReadToolDetails`
|
|
2208
|
+
- [bash.ts](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/tools/bash.ts) - `BashToolDetails`
|
|
2209
|
+
- [powershell.ts](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/tools/powershell.ts) - `PowerShellToolDetails`
|
|
2210
|
+
- [edit.ts](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/tools/edit.ts)
|
|
2211
|
+
- [write.ts](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/tools/write.ts)
|
|
2212
|
+
- [grep.ts](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/tools/grep.ts) - `GrepToolDetails`
|
|
2213
|
+
- [find.ts](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/tools/find.ts) - `FindToolDetails`
|
|
2214
|
+
- [ls.ts](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/tools/ls.ts) - `LsToolDetails`
|
|
2112
2215
|
|
|
2113
2216
|
### Remote Execution
|
|
2114
2217
|
|
|
@@ -2239,7 +2342,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
2239
2342
|
|
|
2240
2343
|
### Custom Rendering
|
|
2241
2344
|
|
|
2242
|
-
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
|
|
2345
|
+
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.
|
|
2243
2346
|
|
|
2244
2347
|
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.
|
|
2245
2348
|
|
|
@@ -2364,38 +2467,13 @@ If a slot renderer is not defined or throws:
|
|
|
2364
2467
|
|
|
2365
2468
|
### Dynamic Tool Loading
|
|
2366
2469
|
|
|
2367
|
-
Extensions can register many tools while keeping only a small initial set active. A tool can then
|
|
2368
|
-
|
|
2369
|
-
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.
|
|
2470
|
+
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.
|
|
2370
2471
|
|
|
2371
2472
|
The lifecycle is:
|
|
2372
2473
|
|
|
2373
2474
|
1. Register every tool with `pi.registerTool()` so it appears in `pi.getAllTools()`.
|
|
2374
2475
|
2. Keep loader tools, such as `search_tools`, active and leave searchable tools inactive.
|
|
2375
|
-
3. During loader execution, call `pi.setActiveTools(
|
|
2376
|
-
4. Pi records which tools were added on the loader's tool result.
|
|
2377
|
-
5. Before the next model response, Pi exposes the added definitions using native deferred loading when supported, or the normal active tool list otherwise.
|
|
2378
|
-
|
|
2379
|
-
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.
|
|
2380
|
-
|
|
2381
|
-
#### Models with native deferred loading
|
|
2382
|
-
|
|
2383
|
-
- **Anthropic**
|
|
2384
|
-
- **Models:** Sonnet, Opus, Fable version 4.5 or newer (without Haiku)
|
|
2385
|
-
- **Native representation:** Deferred definitions use `defer_loading`; the load point uses `tool_reference` content.
|
|
2386
|
-
- **OpenAI**
|
|
2387
|
-
- **Models:** `gpt-5.4` and newer family
|
|
2388
|
-
- **Native representation:** Pi adds completed client `tool_search_call` and `tool_search_output` items at the load point.
|
|
2389
|
-
|
|
2390
|
-
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.
|
|
2391
|
-
|
|
2392
|
-
#### Fallback behavior
|
|
2393
|
-
|
|
2394
|
-
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.
|
|
2395
|
-
|
|
2396
|
-
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.
|
|
2397
|
-
|
|
2398
|
-
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.
|
|
2476
|
+
3. During loader execution, call `pi.setActiveTools()` with the desired active tool names. Names must already be registered; unknown names are ignored.
|
|
2399
2477
|
|
|
2400
2478
|
#### Search tool example
|
|
2401
2479
|
|
|
@@ -2497,7 +2575,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
2497
2575
|
}
|
|
2498
2576
|
```
|
|
2499
2577
|
|
|
2500
|
-
When `search_tools` adds a match, the model receives
|
|
2578
|
+
When `search_tools` adds a match, the model receives the complete updated tool list on the immediately following request.
|
|
2501
2579
|
|
|
2502
2580
|
## Custom UI
|
|
2503
2581
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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)
|
package/bin/docs/models.md
CHANGED
|
@@ -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)
|
|
@@ -204,10 +205,12 @@ If your command is slow, expensive, rate-limited, or should keep using a previou
|
|
|
204
205
|
| `reasoning` | No | `false` | Supports extended thinking |
|
|
205
206
|
| `thinkingLevelMap` | No | omitted | Maps pi thinking levels to provider values and marks unsupported levels (see below) |
|
|
206
207
|
| `input` | No | `["text"]` | Input types: `["text"]` or `["text", "image"]` |
|
|
208
|
+
| `inputLimits` | No | omitted | Request limits and image preprocessing for this model (see below) |
|
|
207
209
|
| `contextWindow` | No | `128000` | Context window size in tokens |
|
|
208
210
|
| `maxTokens` | No | `16384` | Maximum output tokens |
|
|
209
211
|
| `samplingParams` | No | omitted | Sampling parameters merged verbatim into every request body (see below) |
|
|
210
212
|
| `cost` | No | all zeros | Per-million-token rates with optional request-wide input pricing tiers |
|
|
213
|
+
| `promptCache` | No | omitted | Best-effort prompt cache lifetime in seconds per retention tier (see below) |
|
|
211
214
|
| `compat` | No | provider `compat` | Provider compatibility overrides. Merged with provider-level `compat` when both are set. |
|
|
212
215
|
|
|
213
216
|
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 +239,46 @@ Current behavior:
|
|
|
236
239
|
- `/model`, `--list-models`, and the interactive footer display entries by model `id`.
|
|
237
240
|
- The configured `name` is used for model matching and secondary model detail text. It does not replace the footer/status-bar model id.
|
|
238
241
|
|
|
242
|
+
### Image Input Limits
|
|
243
|
+
|
|
244
|
+
Use `inputLimits.images.resize` to configure how new images are encoded before they enter conversation history:
|
|
245
|
+
|
|
246
|
+
```json
|
|
247
|
+
{
|
|
248
|
+
"id": "vision-model",
|
|
249
|
+
"input": ["text", "image"],
|
|
250
|
+
"inputLimits": {
|
|
251
|
+
"images": {
|
|
252
|
+
"resize": {
|
|
253
|
+
"maxWidth": 1568,
|
|
254
|
+
"maxHeight": 1568,
|
|
255
|
+
"maxBytes": 524288,
|
|
256
|
+
"jpegQuality": 75
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
`maxBytes` is the maximum base64-encoded payload size. Omitted resize fields use pi's conservative defaults: 2000×2000, 4.5 MiB encoded, and JPEG quality 80. Built-in vision models carry that profile explicitly so unknown gateways never receive larger images than before.
|
|
264
|
+
|
|
265
|
+
Pi applies the selected model's resize profile to `@file` attachments, the `read` tool, and images returned by tools. Images are encoded once before they enter history; changing models does not rewrite historical images or invalidate the cached conversation prefix. The `images.autoResize` setting can disable resizing globally.
|
|
266
|
+
|
|
267
|
+
The catalog can also record `inputLimits.maxRequestBytes`, `images.maxPerMessage`, and `images.maxPerRequest`. These fields describe hard provider limits; this initial implementation does not yet rewrite or reject conversation history based on them.
|
|
268
|
+
|
|
269
|
+
### Prompt Cache Lifetimes
|
|
270
|
+
|
|
271
|
+
`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.
|
|
272
|
+
|
|
273
|
+
```json
|
|
274
|
+
{
|
|
275
|
+
"id": "claude-sonnet-5",
|
|
276
|
+
"promptCache": { "short": 300, "long": 3600 }
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
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).
|
|
281
|
+
|
|
239
282
|
### Sampling Parameters
|
|
240
283
|
|
|
241
284
|
`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 +402,23 @@ Use `modelOverrides` to customize built-in models and matching extension-registe
|
|
|
359
402
|
}
|
|
360
403
|
```
|
|
361
404
|
|
|
362
|
-
`modelOverrides` supports these fields per model: `name`, `reasoning`, `thinkingLevelMap`, `input`, `cost` (partial), `contextWindow`, `maxTokens`, `samplingParams` (merged per key), `headers`, `compat`.
|
|
405
|
+
`modelOverrides` supports these fields per model: `name`, `reasoning`, `thinkingLevelMap`, `input`, `inputLimits` (deep-merged), `cost` (partial), `promptCache` (merged per tier), `contextWindow`, `maxTokens`, `samplingParams` (merged per key), `headers`, `compat`.
|
|
406
|
+
|
|
407
|
+
Use a `promptCache` override to enable cache warming through a proxy whose backing cache you know, for example OpenRouter routed to Anthropic:
|
|
408
|
+
|
|
409
|
+
```json
|
|
410
|
+
{
|
|
411
|
+
"providers": {
|
|
412
|
+
"openrouter": {
|
|
413
|
+
"modelOverrides": {
|
|
414
|
+
"anthropic/claude-sonnet-4": {
|
|
415
|
+
"promptCache": { "short": 300 }
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
```
|
|
363
422
|
|
|
364
423
|
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
424
|
|
|
@@ -435,6 +494,7 @@ Built-in Anthropic models enable `supportsStrictTools` in their model metadata.
|
|
|
435
494
|
| `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`. |
|
|
436
495
|
| `allowEmptySignature` | Whether to replay empty thinking signatures as `signature: ""` instead of converting thinking to text. Default: `false`. |
|
|
437
496
|
| `supportsStrictTools` | Whether the provider accepts strict JSON-schema tool definitions. Default: `false`; built-in Anthropic models enable it in generated metadata. |
|
|
497
|
+
| `allowedFallbackModels` | Up to three server-side fallback models, each with `provider`, `model`, and complete `cost` metadata. An empty array disables fallback. |
|
|
438
498
|
|
|
439
499
|
## OpenAI Compatibility
|
|
440
500
|
|
|
@@ -481,7 +541,6 @@ For providers with partial OpenAI compatibility, use the `compat` field.
|
|
|
481
541
|
| `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. |
|
|
482
542
|
| `supportsStrictMode` | Whether the provider accepts strict JSON-schema function tool definitions. Defaults depend on the API; built-in OpenAI models carry explicit capability metadata. |
|
|
483
543
|
| `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. |
|
|
484
|
-
| `deferredToolsMode` | Use provider-specific deferred tool serialization. Currently only `"kimi"` is supported for Kimi's OpenAI-compatible Chat Completions format. |
|
|
485
544
|
| `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`. |
|
|
486
545
|
| `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). |
|
|
487
546
|
| `vercelGatewayRouting` | Vercel AI Gateway routing config for provider selection (`only`, `order`) |
|
package/bin/docs/providers.md
CHANGED
|
@@ -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
|
|
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
|
|
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/sdk.md
CHANGED
|
@@ -91,6 +91,8 @@ interface AgentSession {
|
|
|
91
91
|
|
|
92
92
|
// State access
|
|
93
93
|
agent: Agent;
|
|
94
|
+
sessionManager: SessionManager;
|
|
95
|
+
refreshContext(): void;
|
|
94
96
|
model: Model | undefined;
|
|
95
97
|
thinkingLevel: ThinkingLevel;
|
|
96
98
|
messages: AgentMessage[];
|
|
@@ -111,6 +113,8 @@ interface AgentSession {
|
|
|
111
113
|
}
|
|
112
114
|
```
|
|
113
115
|
|
|
116
|
+
`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.
|
|
117
|
+
|
|
114
118
|
Session replacement APIs such as new-session, resume, fork, and import live on `AgentSessionRuntime`, not on `AgentSession`.
|
|
115
119
|
|
|
116
120
|
### createAgentSessionRuntime() and AgentSessionRuntime
|
|
@@ -244,13 +248,13 @@ const state = session.agent.state;
|
|
|
244
248
|
// state.messages: AgentMessage[] - conversation history
|
|
245
249
|
// state.model: Model - current model
|
|
246
250
|
// state.thinkingLevel: ThinkingLevel - current thinking level
|
|
247
|
-
// state.systemPrompt: string - system
|
|
248
|
-
// state.tools: AgentTool[] -
|
|
251
|
+
// state.systemPrompt: string - read-only, replayed from the transcript's system messages
|
|
252
|
+
// state.tools: AgentTool[] - executable tools; changes are declared to the model before the next request
|
|
249
253
|
// state.streamingMessage?: AgentMessage - current partial assistant message
|
|
250
254
|
// state.errorMessage?: string - latest assistant error
|
|
251
255
|
|
|
252
|
-
//
|
|
253
|
-
|
|
256
|
+
// Model-visible messages are projected from session.sessionManager.
|
|
257
|
+
// agent.state.messages is a refreshed inspection cache; do not assign it for restoration.
|
|
254
258
|
|
|
255
259
|
// Replace tools
|
|
256
260
|
session.agent.state.tools = tools; // copies the top-level array
|
|
@@ -259,6 +263,15 @@ session.agent.state.tools = tools; // copies the top-level array
|
|
|
259
263
|
await session.agent.waitForIdle();
|
|
260
264
|
```
|
|
261
265
|
|
|
266
|
+
Provider requests use `session.sessionManager` as the canonical finalized context. Assigning `session.agent.state.messages` does not replace persisted context and may be overwritten at the next request boundary. Restore externally stored history when constructing the session instead:
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
const restoredManager = SessionManager.inMemory(process.cwd(), { id: sessionId }, entries);
|
|
270
|
+
const { session } = await createAgentSession({ sessionManager: restoredManager });
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
For an existing session, use `session.navigateTree(entryId)` to move its active branch. Use `session.sessionManager.appendMessage(...)` plus `session.refreshContext()` only when intentionally appending externally managed entries.
|
|
274
|
+
|
|
262
275
|
### Events
|
|
263
276
|
|
|
264
277
|
Subscribe to events to receive streaming output and lifecycle notifications.
|
package/bin/docs/security.md
CHANGED
|
@@ -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
|
|
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.
|