@earendil-works/pi-coding-agent 0.86.1 → 0.87.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.
- package/CHANGELOG.md +62 -0
- package/README.md +25 -675
- package/dist/bundle/chunks/{anthropic-messages-MYU5ZMRF.js → anthropic-messages-J5WXPPPC.js} +1 -1
- package/dist/bundle/chunks/chunk-65HAU2C5.js +2 -0
- package/dist/bundle/chunks/{chunk-CMRUVXTE.js → chunk-OJP47DM6.js} +48 -42
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/{openai-completions-CYGM3XXP.js → openai-completions-OBX42CLD.js} +2 -2
- package/dist/bundle/chunks/{virtual-modules-MGTKWDID.js → virtual-modules-VHMJYYWQ.js} +1 -1
- package/dist/bundle/cli-runtime.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +14 -4
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/file-processor.d.ts +1 -1
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +1 -1
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session.d.ts +27 -3
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +389 -119
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/cache-warmer.d.ts +1 -0
- package/dist/core/cache-warmer.d.ts.map +1 -1
- package/dist/core/cache-warmer.js +15 -1
- package/dist/core/cache-warmer.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +3 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +155 -57
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/crash-log.d.ts +5 -0
- package/dist/core/crash-log.d.ts.map +1 -1
- package/dist/core/crash-log.js +68 -0
- package/dist/core/crash-log.js.map +1 -1
- package/dist/core/export-html/template.js +6 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +16 -3
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +110 -5
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +77 -6
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/model-config.d.ts +52 -0
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +16 -0
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +1 -1
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/prompt-templates.d.ts +6 -1
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +61 -35
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/provider-composer.d.ts +1 -0
- package/dist/core/provider-composer.d.ts.map +1 -1
- package/dist/core/provider-composer.js +19 -0
- package/dist/core/provider-composer.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +6 -2
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +3 -4
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +36 -9
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +97 -7
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/tools/read.d.ts +4 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +5 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +4 -3
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/bug-report.d.ts.map +1 -1
- package/dist/modes/interactive/bug-report.js +4 -0
- package/dist/modes/interactive/bug-report.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +7 -0
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +3 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +64 -2
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/mime.d.ts.map +1 -1
- package/dist/utils/mime.js +1 -1
- package/dist/utils/mime.js.map +1 -1
- package/dist/utils/tool-result-images.d.ts +3 -1
- package/dist/utils/tool-result-images.d.ts.map +1 -1
- package/dist/utils/tool-result-images.js +4 -1
- package/dist/utils/tool-result-images.js.map +1 -1
- package/docs/cli-integration.md +106 -0
- package/docs/cli.md +268 -0
- package/docs/compaction.md +45 -26
- package/docs/configuration.md +45 -0
- package/docs/containerization.md +109 -82
- package/docs/custom-provider.md +132 -784
- package/docs/docs.json +139 -99
- package/docs/environment-variables.md +3 -5
- package/docs/extensions.md +134 -2956
- package/docs/how-pi-works.md +49 -0
- package/docs/images/interactive-mode.png +0 -0
- package/docs/index.md +24 -69
- package/docs/json.md +193 -65
- package/docs/keybindings.md +57 -102
- package/docs/llama-cpp.md +3 -3
- package/docs/message-types.md +261 -0
- package/docs/models.md +64 -546
- package/docs/packages.md +66 -167
- package/docs/prompt-templates.md +31 -68
- package/docs/providers.md +102 -240
- package/docs/quickstart.md +61 -106
- package/docs/rpc-commands.md +854 -0
- package/docs/rpc-extension-ui.md +200 -0
- package/docs/rpc.md +129 -1556
- package/docs/sdk.md +76 -1160
- package/docs/security.md +70 -32
- package/docs/session-format.md +25 -216
- package/docs/sessions.md +35 -141
- package/docs/settings.md +109 -387
- package/docs/shell-aliases.md +85 -5
- package/docs/skills.md +51 -190
- package/docs/slash-commands.md +60 -0
- package/docs/terminal-setup.md +105 -78
- package/docs/termux.md +74 -83
- package/docs/themes.md +68 -280
- package/docs/tmux.md +31 -39
- package/docs/tui.md +69 -923
- package/docs/usage.md +54 -272
- package/docs/windows.md +43 -17
- package/examples/README.md +13 -2
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/plugins/pi-example-plugin/src/session.ts +3 -2
- package/examples/rpc-client.ts +35 -0
- package/examples/rpc-extension-ui.ts +25 -5
- package/examples/sdk/README.md +1 -1
- package/npm-shrinkwrap.json +20 -20
- package/package.json +8 -8
- package/dist/bundle/chunks/chunk-HTEQD2HM.js +0 -2
- package/docs/development.md +0 -90
package/docs/security.md
CHANGED
|
@@ -1,59 +1,97 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Run Pi safely
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Treat model-generated commands and code as untrusted. Pi can read, change, and execute files with the permissions of the account that started it, and it does not ask for approval before every tool call. Extensions, package installers, language servers, and other child processes run with those same permissions unless an operating-system or virtualization boundary restricts them.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Files, comments, instructions, command output, and model responses can steer the model through prompt injection. Project trust controls which project resources load at startup, but it does not make that content or the resulting actions safe.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Safety comes from limiting the files, credentials, processes, and network services Pi can access and affect if a generated action is wrong or hostile. Watching the transcript, using project trust, and reviewing changes do not create a security boundary.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Choose how to run Pi
|
|
10
|
+
|
|
11
|
+
Different ways of running Pi place different limits on what generated commands can access:
|
|
12
|
+
|
|
13
|
+
| How Pi runs | What remains protected |
|
|
14
|
+
|---|---|
|
|
15
|
+
| Directly, with the permissions of its operating-system user | Anything that user cannot access. A dedicated user account can narrow those permissions, but Pi still shares the operating system and network with other users. |
|
|
16
|
+
| Entirely inside a container, virtual machine, or sandbox | Host files and processes that you do not expose to the environment. Credentials and network services remain accessible if you make them available inside it. This is usually the strongest practical option. |
|
|
17
|
+
| Outside the isolated environment, with only its built-in tools running inside | Host resources are protected from actions performed through those tools. Pi itself and other extensions remain outside the boundary, so this is a narrower form of isolation. |
|
|
18
|
+
|
|
19
|
+
The working folder controls resource discovery and the default location for tools, but it does not prevent commands from accessing other paths available to the Pi process.
|
|
20
|
+
|
|
21
|
+
Whichever option you choose, only provide the files and services required for the task. Keep credentials outside the environment where possible, or use narrowly scoped, short-lived credentials. Restrict network access when commands do not need it.
|
|
22
|
+
|
|
23
|
+
For setup instructions and the limitations of each isolation method, see [Run Pi in an isolated environment](containerization.md).
|
|
24
|
+
|
|
25
|
+
<a id="project-trust"></a>
|
|
26
|
+
|
|
27
|
+
## Understand project trust
|
|
28
|
+
|
|
29
|
+
Project trust controls whether Pi loads most settings and resources supplied by a working folder. It prevents a folder from silently loading executable extensions before you approve it.
|
|
30
|
+
|
|
31
|
+
Project trust is not a complete startup boundary. Pi reads the project `sessionDir` setting while selecting or creating a session, before it resolves project trust. Declining trust prevents the remaining project settings and protected resources from loading, but it cannot undo that initial session-directory lookup.
|
|
32
|
+
|
|
33
|
+
Project trust does not limit what tool calls can access or affect. After Pi starts, enabled tools still use the operating-system permissions of the Pi process. Instructions and other content in the folder can also influence the model.
|
|
34
|
+
|
|
35
|
+
### Resources protected by project trust
|
|
36
|
+
|
|
37
|
+
Pi requires a project-trust decision when it finds any of these resources from the current working directory:
|
|
10
38
|
|
|
11
39
|
- `.pi/settings.json`
|
|
12
40
|
- `.pi/extensions`, `.pi/skills`, `.pi/prompts`, or `.pi/themes`
|
|
13
41
|
- `.pi/SYSTEM.md` or `.pi/APPEND_SYSTEM.md`
|
|
14
42
|
- project `.agents/skills` in the current directory or an ancestor directory
|
|
15
43
|
|
|
16
|
-
A bare `.pi` directory does not
|
|
44
|
+
A bare `.pi` directory does not require project trust.
|
|
17
45
|
|
|
18
|
-
|
|
46
|
+
Granting project trust allows Pi to load:
|
|
19
47
|
|
|
20
|
-
|
|
48
|
+
- project settings
|
|
49
|
+
- extensions, skills, prompt templates, themes, and system-prompt files under `.pi`
|
|
50
|
+
- missing packages configured through project settings
|
|
51
|
+
- project-local and project-package extensions
|
|
21
52
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
53
|
+
Declining project trust skips those protected resources, except for the initial `sessionDir` lookup described above.
|
|
54
|
+
|
|
55
|
+
Context files such as `AGENTS.override.md`, `AGENTS.md`, and `CLAUDE.md` load regardless of project trust unless you disable context loading. Treat instructions in a folder as untrusted input even when you decline project trust.
|
|
56
|
+
|
|
57
|
+
### How Pi chooses a trust decision
|
|
58
|
+
|
|
59
|
+
A command-line `--approve` or `--no-approve` override applies first. When protected resources exist and there is no command-line override:
|
|
26
60
|
|
|
27
|
-
|
|
61
|
+
1. User-level and command-line extensions can handle the `project_trust` event. The first extension that returns yes or no owns the decision.
|
|
62
|
+
2. If no extension decides, Pi looks for a saved decision for the current directory or one of its parents. The closest decision applies.
|
|
63
|
+
3. If no saved decision applies, Pi follows the global `defaultProjectTrust` setting, whose default is `"ask"`.
|
|
28
64
|
|
|
29
|
-
|
|
65
|
+
Saved decisions use canonical directory paths and live in:
|
|
30
66
|
|
|
31
|
-
|
|
67
|
+
```text
|
|
68
|
+
~/.pi/agent/trust.json
|
|
69
|
+
```
|
|
32
70
|
|
|
33
|
-
|
|
71
|
+
Use `/trust` to save a decision for future Pi processes.
|
|
34
72
|
|
|
35
|
-
|
|
73
|
+
### Project trust without an interactive prompt
|
|
36
74
|
|
|
37
|
-
|
|
75
|
+
Print, JSON, and RPC modes cannot show the built-in trust prompt. If no command-line override, extension, or saved decision applies:
|
|
38
76
|
|
|
39
|
-
|
|
77
|
+
- `defaultProjectTrust: "always"` loads protected project resources.
|
|
78
|
+
- `defaultProjectTrust: "ask"` or `"never"` skips them.
|
|
40
79
|
|
|
41
|
-
|
|
80
|
+
Use `--approve` or `--no-approve` when an automated run needs an explicit one-time decision.
|
|
42
81
|
|
|
43
|
-
|
|
82
|
+
## Reduce impact and improve recovery
|
|
44
83
|
|
|
45
|
-
|
|
46
|
-
- run host pi while routing built-in tool execution into a Gondolin micro-VM
|
|
47
|
-
- mount only the workspace paths the agent should access
|
|
48
|
-
- avoid mounting host `~/.pi/agent` unless the container should access host sessions, settings, and credentials
|
|
49
|
-
- pass the minimum required API keys or use short-lived credentials
|
|
50
|
-
- restrict network access when the task does not need it
|
|
51
|
-
- review diffs and outputs before copying results back to trusted systems
|
|
84
|
+
These practices do not replace isolation, but they reduce exposure or make recovery easier:
|
|
52
85
|
|
|
53
|
-
|
|
86
|
+
- Give Pi access only to files and services required for the task.
|
|
87
|
+
- Use snapshots, backups, or version control before substantial changes.
|
|
88
|
+
- Review extensions and packages before loading them. Extensions execute inside the Pi process.
|
|
89
|
+
- Prefer narrowly scoped, short-lived credentials.
|
|
90
|
+
- Review diffs and generated output before applying results to another system.
|
|
91
|
+
- Review sessions before exporting or sharing them. They can contain prompts, tool arguments, command output, file contents, and credentials exposed during the conversation.
|
|
54
92
|
|
|
55
|
-
##
|
|
93
|
+
## Report a security issue
|
|
56
94
|
|
|
57
|
-
|
|
95
|
+
Follow the repository [Security Policy](https://github.com/earendil-works/pi/blob/main/SECURITY.md). Do not open a public issue for a security-sensitive report.
|
|
58
96
|
|
|
59
|
-
Expected local-agent behavior, lack of a built-in sandbox,
|
|
97
|
+
Expected local-agent behavior, prompt injection from untrusted content, lack of a built-in sandbox, and behavior from user-installed extensions or skills are generally outside the security boundary unless the report demonstrates a privilege-boundary bypass or access that the local user did not already have.
|
package/docs/session-format.md
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Sessions are stored as JSONL (JSON Lines) files. Each line is a JSON object with a `type` field. Session entries form a tree structure via `id`/`parentId` fields, enabling in-place branching without creating new files.
|
|
4
4
|
|
|
5
|
+
For programmatic creation, persistence, and tree navigation, see the [`SessionManager` API](sdk.md#sessionmanager-api).
|
|
6
|
+
|
|
7
|
+
|
|
5
8
|
## File Location
|
|
6
9
|
|
|
7
10
|
```
|
|
@@ -30,169 +33,18 @@ Existing sessions are automatically migrated to the current version (v3) when lo
|
|
|
30
33
|
|
|
31
34
|
Source on GitHub ([pi](https://github.com/earendil-works/pi)):
|
|
32
35
|
- [`packages/coding-agent/src/core/session-manager.ts`](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/session-manager.ts) - Session entry types and SessionManager
|
|
33
|
-
- [
|
|
34
|
-
- [`packages/
|
|
35
|
-
- [`packages/
|
|
36
|
+
- [Message Types](message-types.md) - Shared message and content-block reference
|
|
37
|
+
- [`packages/coding-agent/src/core/messages.ts`](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/src/core/messages.ts) - Extended message types
|
|
38
|
+
- [`packages/ai/src/types.ts`](https://github.com/earendil-works/pi/blob/main/packages/ai/src/types.ts) - Base message and content-block types
|
|
39
|
+
- [`packages/agent/src/types.ts`](https://github.com/earendil-works/pi/blob/main/packages/agent/src/types.ts) - Extensible `AgentMessage` union
|
|
36
40
|
|
|
37
41
|
For TypeScript definitions in your project, inspect `node_modules/@earendil-works/pi-coding-agent/dist/` and `node_modules/@earendil-works/pi-ai/dist/`.
|
|
38
42
|
|
|
39
|
-
##
|
|
40
|
-
|
|
41
|
-
Session entries contain `AgentMessage` objects. Understanding these types is essential for parsing sessions and writing extensions.
|
|
42
|
-
|
|
43
|
-
### Content Blocks
|
|
44
|
-
|
|
45
|
-
Messages contain arrays of typed content blocks:
|
|
46
|
-
|
|
47
|
-
```typescript
|
|
48
|
-
interface TextContent {
|
|
49
|
-
type: "text";
|
|
50
|
-
text: string;
|
|
51
|
-
textSignature?: string;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
interface ImageContent {
|
|
55
|
-
type: "image";
|
|
56
|
-
data: string; // base64 encoded
|
|
57
|
-
mimeType: string; // e.g., "image/jpeg", "image/png"
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
interface ThinkingContent {
|
|
61
|
-
type: "thinking";
|
|
62
|
-
thinking: string;
|
|
63
|
-
thinkingSignature?: string;
|
|
64
|
-
redacted?: boolean;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
interface ToolCall {
|
|
68
|
-
type: "toolCall";
|
|
69
|
-
id: string;
|
|
70
|
-
name: string;
|
|
71
|
-
arguments: Record<string, any>;
|
|
72
|
-
thoughtSignature?: string;
|
|
73
|
-
namespace?: string;
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### Base Message Types (from pi-ai)
|
|
78
|
-
|
|
79
|
-
```typescript
|
|
80
|
-
interface SystemMessage {
|
|
81
|
-
role: "system";
|
|
82
|
-
content: string | TextContent[];
|
|
83
|
-
toolsAdded?: Tool[];
|
|
84
|
-
toolsRemoved?: Array<{ name: string }>;
|
|
85
|
-
timestamp: number; // Unix ms
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
interface UserMessage {
|
|
89
|
-
role: "user";
|
|
90
|
-
content: string | (TextContent | ImageContent)[];
|
|
91
|
-
timestamp: number; // Unix ms
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
interface AssistantMessage {
|
|
95
|
-
role: "assistant";
|
|
96
|
-
content: (TextContent | ThinkingContent | ToolCall)[];
|
|
97
|
-
api: string;
|
|
98
|
-
provider: string;
|
|
99
|
-
model: string;
|
|
100
|
-
responseModel?: string;
|
|
101
|
-
responseId?: string;
|
|
102
|
-
providerThinkingLevel?: string;
|
|
103
|
-
diagnostics?: AssistantMessageDiagnostic[];
|
|
104
|
-
usage: Usage;
|
|
105
|
-
stopReason: "pending" | "stop" | "length" | "toolUse" | "error" | "aborted" | "deferred";
|
|
106
|
-
deferred?: DeferredHandle;
|
|
107
|
-
errorMessage?: string;
|
|
108
|
-
rawStopReason?: string;
|
|
109
|
-
endTurn?: boolean;
|
|
110
|
-
timestamp: number;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
interface ToolResultMessage {
|
|
114
|
-
role: "toolResult";
|
|
115
|
-
toolCallId: string;
|
|
116
|
-
toolName: string;
|
|
117
|
-
content: (TextContent | ImageContent)[];
|
|
118
|
-
details?: any; // Tool-specific metadata
|
|
119
|
-
usage?: Usage; // Nested LLM work performed by the tool
|
|
120
|
-
isError: boolean;
|
|
121
|
-
timestamp: number;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
interface Usage {
|
|
125
|
-
input: number;
|
|
126
|
-
output: number;
|
|
127
|
-
cacheRead: number;
|
|
128
|
-
cacheWrite: number;
|
|
129
|
-
cacheWrite1h?: number;
|
|
130
|
-
reasoning?: number;
|
|
131
|
-
totalTokens: number;
|
|
132
|
-
cost: {
|
|
133
|
-
input: number;
|
|
134
|
-
output: number;
|
|
135
|
-
cacheRead: number;
|
|
136
|
-
cacheWrite: number;
|
|
137
|
-
total: number;
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
`"pending"` is reserved for partial messages in streaming events. Terminal events replace it with a completion reason before Pi persists the assistant message, so `"pending"` should never appear in session JSONL. `"deferred"` is a terminal reason for a provider response that will complete later; its `deferred` handle contains the provider data needed to retrieve that response.
|
|
43
|
+
## Messages
|
|
143
44
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
```typescript
|
|
147
|
-
interface BashExecutionMessage {
|
|
148
|
-
role: "bashExecution";
|
|
149
|
-
command: string;
|
|
150
|
-
output: string;
|
|
151
|
-
exitCode: number | undefined;
|
|
152
|
-
cancelled: boolean;
|
|
153
|
-
truncated: boolean;
|
|
154
|
-
fullOutputPath?: string;
|
|
155
|
-
excludeFromContext?: boolean; // true for !! prefix commands
|
|
156
|
-
timestamp: number;
|
|
157
|
-
}
|
|
45
|
+
A `message` entry stores an [`AgentMessage`](message-types.md). Message content blocks, roles, usage, and message timestamps are defined in [Message Types](message-types.md).
|
|
158
46
|
|
|
159
|
-
|
|
160
|
-
role: "custom";
|
|
161
|
-
customType: string; // Extension identifier
|
|
162
|
-
content: string | (TextContent | ImageContent)[];
|
|
163
|
-
display: boolean; // Show in TUI
|
|
164
|
-
details?: any; // Extension-specific metadata
|
|
165
|
-
timestamp: number;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
interface BranchSummaryMessage {
|
|
169
|
-
role: "branchSummary";
|
|
170
|
-
summary: string;
|
|
171
|
-
fromId: string | null; // Previous leaf whose abandoned path was summarized
|
|
172
|
-
timestamp: number;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
interface CompactionSummaryMessage {
|
|
176
|
-
role: "compactionSummary";
|
|
177
|
-
summary: string;
|
|
178
|
-
tokensBefore: number;
|
|
179
|
-
timestamp: number;
|
|
180
|
-
}
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
### AgentMessage Union
|
|
184
|
-
|
|
185
|
-
```typescript
|
|
186
|
-
type AgentMessage =
|
|
187
|
-
| SystemMessage
|
|
188
|
-
| UserMessage
|
|
189
|
-
| AssistantMessage
|
|
190
|
-
| ToolResultMessage
|
|
191
|
-
| BashExecutionMessage
|
|
192
|
-
| CustomMessage
|
|
193
|
-
| BranchSummaryMessage
|
|
194
|
-
| CompactionSummaryMessage;
|
|
195
|
-
```
|
|
47
|
+
Session entry timestamps are ISO 8601 strings. The nested message timestamp is a Unix timestamp in milliseconds.
|
|
196
48
|
|
|
197
49
|
## Entry Base
|
|
198
50
|
|
|
@@ -274,7 +126,7 @@ Created when context is compacted. Stores a summary of earlier messages and a co
|
|
|
274
126
|
{"type":"compaction","id":"f6g7h8i9","parentId":"e5f6g7h8","timestamp":"2024-12-03T14:10:00.000Z","summary":"User discussed X, Y, Z...","firstKeptEntryId":"c3d4e5f6","tokensBefore":50000,"systemMessage":{"role":"system","content":"You are a coding assistant.","toolsAdded":[],"timestamp":1733235000000}}
|
|
275
127
|
```
|
|
276
128
|
|
|
277
|
-
`firstKeptEntryId` is required. It identifies the first entry retained from before the compaction entry. When rebuilding context, Pi replaces older summarized entries with the compaction summary and keeps the range beginning at this entry.
|
|
129
|
+
`firstKeptEntryId` is required. It identifies the first entry retained from before the compaction entry. When rebuilding context, Pi replaces older summarized entries with the compaction summary and keeps the range beginning at this entry. A retain-none compaction stores its own ID in this field, so no preceding entries are retained.
|
|
278
130
|
|
|
279
131
|
Optional fields:
|
|
280
132
|
- `systemMessage`: The replayed prompt sections and tool declarations at the compaction boundary; it becomes the leading system message of the compacted context, and system messages among the kept entries are dropped in its favor. It is absent on older session entries.
|
|
@@ -282,6 +134,16 @@ Optional fields:
|
|
|
282
134
|
- `details`: Implementation-specific data (e.g., `{ readFiles: string[], modifiedFiles: string[] }` for default, or custom data for extensions)
|
|
283
135
|
- `fromHook`: `true` if generated by an extension, `false`/`undefined` if pi-generated (legacy field name)
|
|
284
136
|
|
|
137
|
+
### ContextEditEntry
|
|
138
|
+
|
|
139
|
+
Append-only edit of one earlier context-producing entry. It changes only future model context; the target entry and its metadata remain unchanged in raw history, UI, exports, and session accounting.
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{"type":"context_edit","id":"g6h7i8j9","parentId":"f6g7h8i9","timestamp":"2024-12-03T14:11:00.000Z","targetId":"c3d4e5f6","replacement":null}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Targets may be user, assistant, tool-result, or custom-message entries. `replacement: null` omits the target from model context. A non-null `replacement` replaces only the target message content. String replacements for assistant and tool-result entries are normalized to one text block because those roles require content arrays. If several edits target the same entry, the latest edit on the active branch wins. Edits are branch-relative: navigating to a point before the edit reveals the target's original contribution again.
|
|
146
|
+
|
|
285
147
|
### BranchSummaryEntry
|
|
286
148
|
|
|
287
149
|
Created when switching branches via `/tree` with an LLM generated summary of the left branch up to the common ancestor. Captures context from the abandoned path.
|
|
@@ -366,7 +228,9 @@ Entries normally form one tree, but navigation APIs can create multiple roots:
|
|
|
366
228
|
- Includes entries after the compaction entry
|
|
367
229
|
3. Preserves non-message entries in the selected range so interactive mode can render them
|
|
368
230
|
|
|
369
|
-
`
|
|
231
|
+
`buildSessionProjection()` then applies the latest `context_edit` for each selected target. It returns the model-visible messages together with their source entries. Omitted targets produce no message; replacements retain the source entry's role and metadata while changing only content. The raw selected entries are not modified.
|
|
232
|
+
|
|
233
|
+
`buildSessionContext()` builds on that projection to produce the message list for the LLM:
|
|
370
234
|
|
|
371
235
|
1. Extracts current model and thinking level settings from the full path
|
|
372
236
|
2. Converts selected entries to messages:
|
|
@@ -374,6 +238,7 @@ Entries normally form one tree, but navigation APIs can create multiple roots:
|
|
|
374
238
|
- `compaction` -> complete system checkpoint followed by `compactionSummary`
|
|
375
239
|
- `branch_summary` -> `branchSummary`
|
|
376
240
|
- `custom_message` -> `CustomMessage`
|
|
241
|
+
- `context_edit` -> no context message of its own
|
|
377
242
|
- `usage` and `custom` -> no context message
|
|
378
243
|
|
|
379
244
|
The compaction summary replaces entries before `firstKeptEntryId`. Pre-compaction system messages are folded into the complete checkpoint rather than replayed from the retained range. Retained non-system entries and all entries after the compaction remain available to the LLM.
|
|
@@ -422,59 +287,3 @@ for (const line of lines) {
|
|
|
422
287
|
}
|
|
423
288
|
}
|
|
424
289
|
```
|
|
425
|
-
|
|
426
|
-
## SessionManager API
|
|
427
|
-
|
|
428
|
-
Key methods for working with sessions programmatically.
|
|
429
|
-
|
|
430
|
-
### Static Creation Methods
|
|
431
|
-
- `SessionManager.create(cwd, sessionDir?, options?)` - New session; `options` can set `id` and `parentSession`
|
|
432
|
-
- `SessionManager.open(path, sessionDir?, cwdOverride?)` - Open existing session file
|
|
433
|
-
- `SessionManager.continueRecent(cwd, sessionDir?)` - Continue most recent or create new
|
|
434
|
-
- `SessionManager.inMemory(cwd?, options?, entries?)` - No file persistence, optionally initialized from entries
|
|
435
|
-
- `SessionManager.forkFrom(sourcePath, targetCwd, sessionDir?, options?)` - Fork session from another project
|
|
436
|
-
|
|
437
|
-
### Static Listing Methods
|
|
438
|
-
- `SessionManager.list(cwd, sessionDir?, onProgress?)` - List sessions for a directory
|
|
439
|
-
- `SessionManager.listAll(onProgress?)` - List all sessions across all projects
|
|
440
|
-
- `SessionManager.listAll(sessionDir?, onProgress?)` - List sessions from a custom session root
|
|
441
|
-
|
|
442
|
-
### Instance Methods - Session Management
|
|
443
|
-
- `newSession(options?)` - Start a new session (options: `{ id?: string, parentSession?: string }`)
|
|
444
|
-
- `setSessionFile(path)` - Switch to a different session file
|
|
445
|
-
- `createBranchedSession(leafId)` - Extract branch to new session file
|
|
446
|
-
|
|
447
|
-
### Instance Methods - Appending (all return entry ID)
|
|
448
|
-
- `appendMessage(message)` - Add message
|
|
449
|
-
- `appendThinkingLevelChange(level)` - Record thinking change
|
|
450
|
-
- `appendModelChange(provider, modelId)` - Record model change
|
|
451
|
-
- `appendUsage(kind, provider, model, usage)` - Record model-attributed usage outside the conversation
|
|
452
|
-
- `appendCompaction(summary, firstKeptEntryId, tokensBefore, details?, fromHook?, usage?)` - Add compaction
|
|
453
|
-
- `appendCustomEntry(customType, data?)` - Extension state (not in context)
|
|
454
|
-
- `appendSessionInfo(name)` - Set session display name
|
|
455
|
-
- `appendCustomMessageEntry(customType, content, display, details?)` - Extension message (in context)
|
|
456
|
-
- `appendLabelChange(targetId, label)` - Set/clear label
|
|
457
|
-
|
|
458
|
-
### Instance Methods - Tree Navigation
|
|
459
|
-
- `getLeafId()` - Current position
|
|
460
|
-
- `getLeafEntry()` - Get current leaf entry
|
|
461
|
-
- `getEntry(id)` - Get entry by ID
|
|
462
|
-
- `getBranch(fromId?)` - Walk from entry to root
|
|
463
|
-
- `getTree()` - Get full tree structure
|
|
464
|
-
- `getChildren(parentId)` - Get direct children
|
|
465
|
-
- `getLabel(id)` - Get label for entry
|
|
466
|
-
- `branch(entryId)` - Move leaf to earlier entry
|
|
467
|
-
- `resetLeaf()` - Reset leaf to null (before any entries)
|
|
468
|
-
- `branchWithSummary(entryId, summary, details?, fromHook?, usage?)` - Branch with context summary; `entryId` may be `null` to branch from the root
|
|
469
|
-
|
|
470
|
-
### Instance Methods - Context & Info
|
|
471
|
-
- `buildContextEntries()` - Get active branch entries with compaction applied
|
|
472
|
-
- `buildSessionContext()` - Get messages, thinkingLevel, and model for LLM
|
|
473
|
-
- `getEntries()` - All entries (excluding header)
|
|
474
|
-
- `getHeader()` - Session header metadata
|
|
475
|
-
- `getSessionName()` - Get display name from latest session_info entry
|
|
476
|
-
- `getCwd()` - Working directory
|
|
477
|
-
- `getSessionDir()` - Session storage directory
|
|
478
|
-
- `getSessionId()` - Session UUID
|
|
479
|
-
- `getSessionFile()` - Session file path (undefined for in-memory)
|
|
480
|
-
- `isPersisted()` - Whether session is saved to disk
|
package/docs/sessions.md
CHANGED
|
@@ -1,172 +1,66 @@
|
|
|
1
|
-
# Sessions
|
|
1
|
+
# Sessions and Context
|
|
2
2
|
|
|
3
|
-
Pi saves
|
|
3
|
+
Pi saves a conversation as a session. The active branch of that session supplies conversation history for the next model request. Use session commands to continue work, explore another branch, or reduce the amount of history sent to the model.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Continue or switch sessions
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Pi saves sessions automatically unless you start it with `--no-session`.
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
pi
|
|
11
|
-
pi
|
|
12
|
-
pi --no-session # Ephemeral mode; do not save
|
|
13
|
-
pi --name "my task" # Set session display name at startup
|
|
14
|
-
pi --session <path|id> # Use a specific session file or partial session ID
|
|
15
|
-
pi --fork <path|id> # Fork a session file or partial session ID into a new session
|
|
10
|
+
pi --continue
|
|
11
|
+
pi --resume
|
|
16
12
|
```
|
|
17
13
|
|
|
18
|
-
|
|
14
|
+
`--continue` opens the most recent session for the current working directory. `--resume` opens the session picker. In interactive mode, `/resume` opens the same picker and `/new` starts a new session.
|
|
19
15
|
|
|
20
|
-
|
|
16
|
+
Use `/name` or `--name` to assign a recognizable session name. Run `/session` to verify the current session file, ID, message count, token usage, and cost.
|
|
21
17
|
|
|
22
|
-
|
|
18
|
+
The session picker lets you search, rename, and delete sessions. It can also show paths, change sorting, and limit results to named sessions. See [Keybindings](keybindings.md#sessions) for its shortcuts.
|
|
23
19
|
|
|
24
|
-
|
|
25
|
-
|---------|-------------|
|
|
26
|
-
| `/resume` | Browse and select previous sessions |
|
|
27
|
-
| `/new` | Start a new session |
|
|
28
|
-
| `/name <name>` | Set the current session display name |
|
|
29
|
-
| `/session` | Show session info |
|
|
30
|
-
| `/tree` | Navigate the current session tree |
|
|
31
|
-
| `/fork` | Create a new session from a previous user message |
|
|
32
|
-
| `/clone` | Duplicate the current active branch into a new session |
|
|
33
|
-
| `/compact [prompt]` | Summarize older context; see [Compaction](compaction.md) |
|
|
34
|
-
| `/export [file]` | Export session to HTML |
|
|
35
|
-
| `/share` | Upload as private GitHub gist with shareable HTML link |
|
|
36
|
-
| `/bug [description]` | Report a bug to the Pi developers; see [Reporting Bugs](#reporting-bugs) |
|
|
20
|
+
## Choose how to branch
|
|
37
21
|
|
|
38
|
-
|
|
22
|
+
Pi stores entries as a tree, so returning to an earlier point does not erase the branch you leave.
|
|
39
23
|
|
|
40
|
-
|
|
24
|
+
| Action | Result | Use it when |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| `/tree` | Moves within the current session file | Related alternatives should stay together |
|
|
27
|
+
| `/fork` | Creates a new session from an earlier user message | The alternative should become separate work |
|
|
28
|
+
| `/clone` | Copies the active branch into a new session | You want a separate copy of the current state |
|
|
41
29
|
|
|
42
|
-
In the
|
|
30
|
+
In `/tree`, select a user message to put its text back in the editor. Edit and submit it to create another branch. Selecting an assistant response or another entry continues after that entry with an empty editor.
|
|
43
31
|
|
|
44
|
-
|
|
45
|
-
- toggle path display with Ctrl+P
|
|
46
|
-
- toggle sort mode with Ctrl+S
|
|
47
|
-
- filter to named sessions with Ctrl+N
|
|
48
|
-
- rename with Ctrl+R
|
|
49
|
-
- delete with Ctrl+D, then confirm
|
|
32
|
+
When you leave a branch, Pi can summarize it and attach that summary to the branch you enter. This preserves relevant work from the abandoned path without including every message from it.
|
|
50
33
|
|
|
51
|
-
|
|
34
|
+
For the persisted tree and entry types, see [Session Format](session-format.md).
|
|
52
35
|
|
|
53
|
-
##
|
|
36
|
+
## Manage conversation context
|
|
54
37
|
|
|
55
|
-
|
|
38
|
+
The model receives the active branch, not every branch in the session file. Pi combines that history with the system prompt, discovered context files, available tools, and loaded skill descriptions. [How Pi Works](how-pi-works.md#context) describes how those inputs are assembled.
|
|
56
39
|
|
|
57
|
-
|
|
58
|
-
/name Refactor auth module
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
Set the name at startup with `--name` or `-n`:
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
pi --name "Refactor auth module"
|
|
65
|
-
pi --name "CI audit" -p "Review this build failure"
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
Named sessions are easier to find in `/resume` and `pi -r`.
|
|
69
|
-
|
|
70
|
-
## Branching with `/tree`
|
|
71
|
-
|
|
72
|
-
Sessions are stored as trees. Every entry has an `id` and `parentId`, and the current position is the active leaf. `/tree` lets you jump to any previous point and continue from there without creating a new file.
|
|
73
|
-
|
|
74
|
-
<p align="center"><img src="images/tree-view.png" alt="Tree View" width="600"></p>
|
|
75
|
-
|
|
76
|
-
Example shape:
|
|
77
|
-
|
|
78
|
-
```text
|
|
79
|
-
├─ user: "Hello, can you help..."
|
|
80
|
-
│ └─ assistant: "Of course! I can..."
|
|
81
|
-
│ ├─ user: "Let's try approach A..."
|
|
82
|
-
│ │ └─ assistant: "For approach A..."
|
|
83
|
-
│ │ └─ user: "That worked..." ← active
|
|
84
|
-
│ └─ user: "Actually, approach B..."
|
|
85
|
-
│ └─ assistant: "For approach B..."
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### Tree Controls
|
|
89
|
-
|
|
90
|
-
| Key | Action |
|
|
91
|
-
|-----|--------|
|
|
92
|
-
| ↑/↓ | Navigate visible entries |
|
|
93
|
-
| ←/→ | Page up/down |
|
|
94
|
-
| Ctrl+←/Ctrl+→ or Alt+←/Alt+→ | Fold/unfold or jump between branch segments |
|
|
95
|
-
| Shift+L | Set or clear a label on the selected entry |
|
|
96
|
-
| Shift+T | Toggle label timestamps |
|
|
97
|
-
| Enter | Select entry |
|
|
98
|
-
| Escape/Ctrl+C | Cancel |
|
|
99
|
-
| Ctrl+O | Cycle filter mode |
|
|
100
|
-
|
|
101
|
-
Filter modes are: default, no-tools, user-only, labeled-only, and all. Configure the default with `treeFilterMode` in [Settings](settings.md).
|
|
102
|
-
|
|
103
|
-
### Selection Behavior
|
|
104
|
-
|
|
105
|
-
Selecting a user or custom message:
|
|
106
|
-
|
|
107
|
-
1. Moves the leaf to the selected message's parent.
|
|
108
|
-
2. Places the selected message text in the editor.
|
|
109
|
-
3. Lets you edit and resubmit, creating a new branch.
|
|
110
|
-
|
|
111
|
-
Selecting an assistant, tool, compaction, or other non-user entry:
|
|
112
|
-
|
|
113
|
-
1. Moves the leaf to that entry.
|
|
114
|
-
2. Leaves the editor empty.
|
|
115
|
-
3. Lets you continue from that point.
|
|
116
|
-
|
|
117
|
-
Selecting the root user message resets the leaf to an empty conversation and places the original prompt in the editor.
|
|
118
|
-
|
|
119
|
-
## `/tree`, `/fork`, and `/clone`
|
|
120
|
-
|
|
121
|
-
| Feature | `/tree` | `/fork` | `/clone` |
|
|
122
|
-
|---------|---------|---------|----------|
|
|
123
|
-
| Output | Same session file | New session file | New session file |
|
|
124
|
-
| View | Full tree | User-message selector | Current active branch |
|
|
125
|
-
| Typical use | Explore alternatives in place | Start a new session from an earlier prompt | Duplicate current work before continuing |
|
|
126
|
-
| Summary | Optional branch summary | None | None |
|
|
127
|
-
|
|
128
|
-
Use `/tree` when you want to keep alternatives together. Use `/fork` or `/clone` when you want a separate session file.
|
|
129
|
-
|
|
130
|
-
## Branch Summaries
|
|
131
|
-
|
|
132
|
-
When `/tree` switches away from one branch to another, pi can summarize the abandoned branch and attach that summary at the new position. This preserves important context from the path you left without replaying the whole branch.
|
|
133
|
-
|
|
134
|
-
When prompted, choose one of:
|
|
135
|
-
|
|
136
|
-
1. no summary
|
|
137
|
-
2. summarize with the default prompt
|
|
138
|
-
3. summarize with custom focus instructions
|
|
139
|
-
|
|
140
|
-
See [Compaction](compaction.md) for branch summarization internals and extension hooks.
|
|
40
|
+
The footer shows current context usage. When the active context approaches the model's limit, Pi normally compacts older history automatically. Compaction adds a summary and keeps recent messages. It does not delete the original session entries.
|
|
141
41
|
|
|
142
|
-
|
|
42
|
+
Run `/compact` to compact manually. You can add instructions when the summary should preserve a particular topic or decision. Configure automatic compaction and retained history through [Settings](settings.md#compaction).
|
|
143
43
|
|
|
144
|
-
|
|
44
|
+
Compaction can fail if the provider is unavailable or cannot accept the summarization request. Correct the provider problem and run `/compact` again. Disabling automatic compaction does not disable the manual command.
|
|
145
45
|
|
|
146
|
-
|
|
46
|
+
See [Compaction Reference](compaction.md) for thresholds, retained boundaries, branch-summary behavior, and extension hooks.
|
|
147
47
|
|
|
148
|
-
|
|
149
|
-
- **Export as Zip** writes a zip archive to the current directory. Attach it to an issue or send it to the developers yourself.
|
|
48
|
+
## Control session storage
|
|
150
49
|
|
|
151
|
-
|
|
50
|
+
By default, Pi stores sessions under `~/.pi/agent/sessions/`, grouped by working directory. Use `--session-dir`, `PI_CODING_AGENT_SESSION_DIR`, or the `sessionDir` setting to choose another location. The CLI option has highest precedence.
|
|
152
51
|
|
|
153
|
-
|
|
154
|
-
|------|---------|
|
|
155
|
-
| `report.json` | pi version, runtime, OS, terminal, current model and provider configuration, loaded extensions, and settings. API keys, header values, URL credentials, and the analytics tracking id are never included. |
|
|
156
|
-
| `diagnostics.json` | Provider and runtime error diagnostics attached to assistant messages across the whole session (failed or aborted turns, retries, error messages), plus any recorded crashes. Always included; message content is not. |
|
|
157
|
-
| `session.jsonl` | The current branch of the session, only when you chose to include it. It contains file contents and command output read during the session. |
|
|
158
|
-
| `summary.md` | The model-written summary, only when you chose to generate one. |
|
|
52
|
+
Use `--no-session` for an ephemeral run. An ephemeral session cannot be resumed after Pi exits.
|
|
159
53
|
|
|
160
|
-
|
|
54
|
+
Use `--session` when you already know the session path or ID. Use `--fork` to create a new session from an existing session before interactive mode starts.
|
|
161
55
|
|
|
162
|
-
|
|
56
|
+
## Export or share a session
|
|
163
57
|
|
|
164
|
-
|
|
58
|
+
Use `/export` to write the current session as HTML or JSONL. Use `/share` to upload it and get a viewer link. Pi uses a Radius artifact when Radius authentication is configured; otherwise, it uses a private GitHub gist.
|
|
165
59
|
|
|
166
|
-
|
|
60
|
+
Review exported or shared sessions first. They can contain prompts, model responses, tool arguments, command output, file contents, and extension messages.
|
|
167
61
|
|
|
168
|
-
##
|
|
62
|
+
## Report a bug
|
|
169
63
|
|
|
170
|
-
|
|
64
|
+
Run `/bug [description]` to prepare a private report for the Pi developers. You can include the session transcript, omit it, or ask the current model to summarize the problem. Review any transcript or generated summary because it can contain sensitive conversation data.
|
|
171
65
|
|
|
172
|
-
|
|
66
|
+
The report includes environment and provider configuration without credential values, plus recorded error diagnostics. Upload it through `radius.pi.dev` or export the same report as a zip to inspect and share yourself. Uploads do not require a login; Radius authentication attributes the report to your account so the developers can follow up. If an upload fails, Pi offers to export the zip.
|