@codex-infinity/pi-infinity 0.63.3 → 0.64.2
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 +101 -0
- package/README.md +7 -3
- package/dist/core/agent-session-runtime.d.ts +134 -0
- package/dist/core/agent-session-runtime.d.ts.map +1 -0
- package/dist/core/agent-session-runtime.js +262 -0
- package/dist/core/agent-session-runtime.js.map +1 -0
- package/dist/core/agent-session.d.ts +10 -42
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +56 -236
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/export-html/tool-renderer.d.ts +2 -0
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.js +2 -2
- package/dist/core/export-html/tool-renderer.js.map +1 -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.map +1 -1
- package/dist/core/extensions/runner.js +1 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +11 -16
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +5 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +69 -8
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/keybindings.d.ts +10 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +10 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-registry.d.ts +3 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +7 -1
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/sdk.d.ts +5 -2
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +5 -2
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +3 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +13 -6
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +15 -4
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +2 -0
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +42 -10
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +3 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +13 -3
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +1 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +4 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts +4 -2
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +48 -15
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +11 -4
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +112 -89
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +6 -11
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/print-mode.d.ts +2 -2
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +37 -36
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +2 -2
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +72 -49
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/docs/extensions.md +104 -19
- package/docs/json.md +5 -2
- package/docs/keybindings.md +2 -0
- package/docs/rpc.md +21 -7
- package/docs/sdk.md +168 -75
- package/docs/tree.md +6 -3
- package/examples/extensions/README.md +1 -0
- 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/custom-provider-qwen-cli/package.json +1 -1
- package/examples/extensions/hidden-thinking-label.ts +53 -0
- package/examples/extensions/rpc-demo.ts +3 -9
- package/examples/extensions/status-line.ts +0 -8
- package/examples/extensions/todo.ts +0 -2
- package/examples/extensions/tools.ts +0 -5
- package/examples/extensions/widget-placement.ts +4 -12
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/02-custom-model.ts +1 -1
- package/examples/sdk/09-api-keys-and-oauth.ts +3 -3
- package/examples/sdk/12-full-control.ts +1 -1
- package/examples/sdk/13-session-runtime.ts +49 -0
- package/examples/sdk/README.md +5 -4
- package/package.json +4 -4
package/docs/sdk.md
CHANGED
|
@@ -20,7 +20,7 @@ import { AuthStorage, createAgentSession, ModelRegistry, SessionManager } from "
|
|
|
20
20
|
|
|
21
21
|
// Set up credential storage and model registry
|
|
22
22
|
const authStorage = AuthStorage.create();
|
|
23
|
-
const modelRegistry =
|
|
23
|
+
const modelRegistry = ModelRegistry.create(authStorage);
|
|
24
24
|
|
|
25
25
|
const { session } = await createAgentSession({
|
|
26
26
|
sessionManager: SessionManager.inMemory(),
|
|
@@ -49,7 +49,7 @@ The SDK is included in the main package. No separate installation needed.
|
|
|
49
49
|
|
|
50
50
|
### createAgentSession()
|
|
51
51
|
|
|
52
|
-
The main factory function
|
|
52
|
+
The main factory function for a single `AgentSession`.
|
|
53
53
|
|
|
54
54
|
`createAgentSession()` uses a `ResourceLoader` to supply extensions, skills, prompt templates, themes, and context files. If you do not provide one, it uses `DefaultResourceLoader` with standard discovery.
|
|
55
55
|
|
|
@@ -69,61 +69,102 @@ const { session } = await createAgentSession({
|
|
|
69
69
|
|
|
70
70
|
### AgentSession
|
|
71
71
|
|
|
72
|
-
The session manages
|
|
72
|
+
The session manages agent lifecycle, message history, model state, compaction, and event streaming.
|
|
73
73
|
|
|
74
74
|
```typescript
|
|
75
75
|
interface AgentSession {
|
|
76
76
|
// Send a prompt and wait for completion
|
|
77
|
-
// If streaming, requires streamingBehavior option to queue the message
|
|
78
77
|
prompt(text: string, options?: PromptOptions): Promise<void>;
|
|
79
|
-
|
|
78
|
+
|
|
80
79
|
// Queue messages during streaming
|
|
81
|
-
steer(text: string): Promise<void>;
|
|
82
|
-
followUp(text: string): Promise<void>;
|
|
83
|
-
|
|
80
|
+
steer(text: string): Promise<void>;
|
|
81
|
+
followUp(text: string): Promise<void>;
|
|
82
|
+
|
|
84
83
|
// Subscribe to events (returns unsubscribe function)
|
|
85
84
|
subscribe(listener: (event: AgentSessionEvent) => void): () => void;
|
|
86
|
-
|
|
85
|
+
|
|
87
86
|
// Session info
|
|
88
|
-
sessionFile: string | undefined;
|
|
87
|
+
sessionFile: string | undefined;
|
|
89
88
|
sessionId: string;
|
|
90
|
-
|
|
89
|
+
|
|
91
90
|
// Model control
|
|
92
91
|
setModel(model: Model): Promise<void>;
|
|
93
92
|
setThinkingLevel(level: ThinkingLevel): void;
|
|
94
93
|
cycleModel(): Promise<ModelCycleResult | undefined>;
|
|
95
94
|
cycleThinkingLevel(): ThinkingLevel | undefined;
|
|
96
|
-
|
|
95
|
+
|
|
97
96
|
// State access
|
|
98
97
|
agent: Agent;
|
|
99
98
|
model: Model | undefined;
|
|
100
99
|
thinkingLevel: ThinkingLevel;
|
|
101
100
|
messages: AgentMessage[];
|
|
102
101
|
isStreaming: boolean;
|
|
103
|
-
|
|
104
|
-
//
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
// Forking
|
|
109
|
-
fork(entryId: string): Promise<{ selectedText: string; cancelled: boolean }>; // Creates new session file
|
|
110
|
-
navigateTree(targetId: string, options?: { summarize?: boolean; customInstructions?: string; replaceInstructions?: boolean; label?: string }): Promise<{ editorText?: string; cancelled: boolean }>; // In-place navigation
|
|
111
|
-
|
|
112
|
-
// Hook message injection
|
|
113
|
-
sendHookMessage(message: HookMessage, triggerTurn?: boolean): Promise<void>;
|
|
114
|
-
|
|
102
|
+
|
|
103
|
+
// In-place tree navigation within the current session file
|
|
104
|
+
navigateTree(targetId: string, options?: { summarize?: boolean; customInstructions?: string; replaceInstructions?: boolean; label?: string }): Promise<{ editorText?: string; cancelled: boolean }>;
|
|
105
|
+
|
|
115
106
|
// Compaction
|
|
116
107
|
compact(customInstructions?: string): Promise<CompactionResult>;
|
|
117
108
|
abortCompaction(): void;
|
|
118
|
-
|
|
109
|
+
|
|
119
110
|
// Abort current operation
|
|
120
111
|
abort(): Promise<void>;
|
|
121
|
-
|
|
112
|
+
|
|
122
113
|
// Cleanup
|
|
123
114
|
dispose(): void;
|
|
124
115
|
}
|
|
125
116
|
```
|
|
126
117
|
|
|
118
|
+
Session replacement APIs such as new-session, resume, fork, and import live on `AgentSessionRuntimeHost`, not on `AgentSession`.
|
|
119
|
+
|
|
120
|
+
### createAgentSessionRuntime() and AgentSessionRuntimeHost
|
|
121
|
+
|
|
122
|
+
Use the runtime API when you need to replace the active session and rebuild cwd-bound runtime state.
|
|
123
|
+
This is the same layer used by the built-in interactive, print, and RPC modes.
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
import {
|
|
127
|
+
AgentSessionRuntimeHost,
|
|
128
|
+
createAgentSessionRuntime,
|
|
129
|
+
SessionManager,
|
|
130
|
+
} from "@mariozechner/pi-coding-agent";
|
|
131
|
+
|
|
132
|
+
const bootstrap = {
|
|
133
|
+
// Optional: authStorage, model, thinkingLevel, tools, customTools, resourceLoader
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const runtime = await createAgentSessionRuntime(bootstrap, {
|
|
137
|
+
cwd: process.cwd(),
|
|
138
|
+
sessionManager: SessionManager.create(process.cwd()),
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const runtimeHost = new AgentSessionRuntimeHost(bootstrap, runtime);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
`createAgentSessionRuntime()` returns an internal runtime bundle. `AgentSessionRuntimeHost` owns replacement of that bundle across:
|
|
145
|
+
|
|
146
|
+
- `newSession()`
|
|
147
|
+
- `switchSession()`
|
|
148
|
+
- `fork()`
|
|
149
|
+
- `importFromJsonl()`
|
|
150
|
+
|
|
151
|
+
Important behavior:
|
|
152
|
+
|
|
153
|
+
- `runtimeHost.session` changes after those operations
|
|
154
|
+
- event subscriptions are attached to a specific `AgentSession`, so re-subscribe after replacement
|
|
155
|
+
- if you use extensions, call `runtimeHost.session.bindExtensions(...)` again for the new session
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
let session = runtimeHost.session;
|
|
159
|
+
let unsubscribe = session.subscribe(() => {});
|
|
160
|
+
|
|
161
|
+
await runtimeHost.newSession();
|
|
162
|
+
|
|
163
|
+
unsubscribe();
|
|
164
|
+
session = runtimeHost.session;
|
|
165
|
+
unsubscribe = session.subscribe(() => {});
|
|
166
|
+
```
|
|
167
|
+
|
|
127
168
|
### Prompting and Message Queueing
|
|
128
169
|
|
|
129
170
|
The `prompt()` method handles prompt templates, extension commands, and message sending:
|
|
@@ -171,10 +212,15 @@ const state = session.agent.state;
|
|
|
171
212
|
// state.model: Model - current model
|
|
172
213
|
// state.thinkingLevel: ThinkingLevel - current thinking level
|
|
173
214
|
// state.systemPrompt: string - system prompt
|
|
174
|
-
// state.tools:
|
|
215
|
+
// state.tools: AgentTool[] - available tools
|
|
216
|
+
// state.streamingMessage?: AgentMessage - current partial assistant message
|
|
217
|
+
// state.errorMessage?: string - latest assistant error
|
|
175
218
|
|
|
176
|
-
// Replace messages (useful for branching
|
|
177
|
-
session.agent.
|
|
219
|
+
// Replace messages (useful for branching or restoration)
|
|
220
|
+
session.agent.state.messages = messages; // copies the top-level array
|
|
221
|
+
|
|
222
|
+
// Replace tools
|
|
223
|
+
session.agent.state.tools = tools; // copies the top-level array
|
|
178
224
|
|
|
179
225
|
// Wait for agent to finish processing
|
|
180
226
|
await session.agent.waitForIdle();
|
|
@@ -232,9 +278,12 @@ session.subscribe((event) => {
|
|
|
232
278
|
// event.toolResults: tool results from this turn
|
|
233
279
|
break;
|
|
234
280
|
|
|
235
|
-
// Session events (
|
|
236
|
-
case "
|
|
237
|
-
|
|
281
|
+
// Session events (queue, compaction, retry)
|
|
282
|
+
case "queue_update":
|
|
283
|
+
console.log(event.steering, event.followUp);
|
|
284
|
+
break;
|
|
285
|
+
case "compaction_start":
|
|
286
|
+
case "compaction_end":
|
|
238
287
|
case "auto_retry_start":
|
|
239
288
|
case "auto_retry_end":
|
|
240
289
|
break;
|
|
@@ -286,7 +335,7 @@ import { getModel } from "@mariozechner/pi-ai";
|
|
|
286
335
|
import { AuthStorage, ModelRegistry } from "@mariozechner/pi-coding-agent";
|
|
287
336
|
|
|
288
337
|
const authStorage = AuthStorage.create();
|
|
289
|
-
const modelRegistry =
|
|
338
|
+
const modelRegistry = ModelRegistry.create(authStorage);
|
|
290
339
|
|
|
291
340
|
// Find specific built-in model (doesn't check if API key exists)
|
|
292
341
|
const opus = getModel("anthropic", "claude-opus-4-5");
|
|
@@ -334,7 +383,7 @@ import { AuthStorage, ModelRegistry } from "@mariozechner/pi-coding-agent";
|
|
|
334
383
|
|
|
335
384
|
// Default: uses ~/.pi/agent/auth.json and ~/.pi/agent/models.json
|
|
336
385
|
const authStorage = AuthStorage.create();
|
|
337
|
-
const modelRegistry =
|
|
386
|
+
const modelRegistry = ModelRegistry.create(authStorage);
|
|
338
387
|
|
|
339
388
|
const { session } = await createAgentSession({
|
|
340
389
|
sessionManager: SessionManager.inMemory(),
|
|
@@ -347,7 +396,7 @@ authStorage.setRuntimeApiKey("anthropic", "sk-my-temp-key");
|
|
|
347
396
|
|
|
348
397
|
// Custom auth storage location
|
|
349
398
|
const customAuth = AuthStorage.create("/my/app/auth.json");
|
|
350
|
-
const customRegistry =
|
|
399
|
+
const customRegistry = ModelRegistry.create(customAuth, "/my/app/models.json");
|
|
351
400
|
|
|
352
401
|
const { session } = await createAgentSession({
|
|
353
402
|
sessionManager: SessionManager.inMemory(),
|
|
@@ -356,7 +405,7 @@ const { session } = await createAgentSession({
|
|
|
356
405
|
});
|
|
357
406
|
|
|
358
407
|
// No custom models.json (built-in models only)
|
|
359
|
-
const simpleRegistry =
|
|
408
|
+
const simpleRegistry = ModelRegistry.inMemory(authStorage);
|
|
360
409
|
```
|
|
361
410
|
|
|
362
411
|
> See [examples/sdk/09-api-keys-and-oauth.ts](../examples/sdk/09-api-keys-and-oauth.ts)
|
|
@@ -594,7 +643,12 @@ const { session } = await createAgentSession({ resourceLoader: loader });
|
|
|
594
643
|
Sessions use a tree structure with `id`/`parentId` linking, enabling in-place branching.
|
|
595
644
|
|
|
596
645
|
```typescript
|
|
597
|
-
import {
|
|
646
|
+
import {
|
|
647
|
+
AgentSessionRuntimeHost,
|
|
648
|
+
createAgentSession,
|
|
649
|
+
createAgentSessionRuntime,
|
|
650
|
+
SessionManager,
|
|
651
|
+
} from "@mariozechner/pi-coding-agent";
|
|
598
652
|
|
|
599
653
|
// In-memory (no persistence)
|
|
600
654
|
const { session } = await createAgentSession({
|
|
@@ -602,12 +656,12 @@ const { session } = await createAgentSession({
|
|
|
602
656
|
});
|
|
603
657
|
|
|
604
658
|
// New persistent session
|
|
605
|
-
const { session } = await createAgentSession({
|
|
659
|
+
const { session: persisted } = await createAgentSession({
|
|
606
660
|
sessionManager: SessionManager.create(process.cwd()),
|
|
607
661
|
});
|
|
608
662
|
|
|
609
663
|
// Continue most recent
|
|
610
|
-
const { session, modelFallbackMessage } = await createAgentSession({
|
|
664
|
+
const { session: continued, modelFallbackMessage } = await createAgentSession({
|
|
611
665
|
sessionManager: SessionManager.continueRecent(process.cwd()),
|
|
612
666
|
});
|
|
613
667
|
if (modelFallbackMessage) {
|
|
@@ -615,26 +669,30 @@ if (modelFallbackMessage) {
|
|
|
615
669
|
}
|
|
616
670
|
|
|
617
671
|
// Open specific file
|
|
618
|
-
const { session } = await createAgentSession({
|
|
672
|
+
const { session: opened } = await createAgentSession({
|
|
619
673
|
sessionManager: SessionManager.open("/path/to/session.jsonl"),
|
|
620
674
|
});
|
|
621
675
|
|
|
622
|
-
// List
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
console.log(`${info.id}: ${info.firstMessage} (${info.messageCount} messages, cwd: ${info.cwd})`);
|
|
626
|
-
}
|
|
676
|
+
// List sessions
|
|
677
|
+
const currentProjectSessions = await SessionManager.list(process.cwd());
|
|
678
|
+
const allSessions = await SessionManager.listAll(process.cwd());
|
|
627
679
|
|
|
628
|
-
//
|
|
629
|
-
const
|
|
630
|
-
|
|
680
|
+
// Session replacement API for /new, /resume, /fork, and import flows.
|
|
681
|
+
const bootstrap = {};
|
|
682
|
+
const runtime = await createAgentSessionRuntime(bootstrap, {
|
|
683
|
+
cwd: process.cwd(),
|
|
684
|
+
sessionManager: SessionManager.create(process.cwd()),
|
|
631
685
|
});
|
|
686
|
+
const runtimeHost = new AgentSessionRuntimeHost(bootstrap, runtime);
|
|
632
687
|
|
|
633
|
-
//
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
688
|
+
// Replace the active session with a fresh one
|
|
689
|
+
await runtimeHost.newSession();
|
|
690
|
+
|
|
691
|
+
// Replace the active session with another saved session
|
|
692
|
+
await runtimeHost.switchSession("/path/to/session.jsonl");
|
|
693
|
+
|
|
694
|
+
// Replace the active session with a fork from a specific entry
|
|
695
|
+
await runtimeHost.fork("entry-id");
|
|
638
696
|
```
|
|
639
697
|
|
|
640
698
|
**SessionManager tree API:**
|
|
@@ -642,6 +700,10 @@ const { session } = await createAgentSession({
|
|
|
642
700
|
```typescript
|
|
643
701
|
const sm = SessionManager.open("/path/to/session.jsonl");
|
|
644
702
|
|
|
703
|
+
// Session listing
|
|
704
|
+
const currentProjectSessions = await SessionManager.list(process.cwd());
|
|
705
|
+
const allSessions = await SessionManager.listAll(process.cwd());
|
|
706
|
+
|
|
645
707
|
// Tree traversal
|
|
646
708
|
const entries = sm.getEntries(); // All entries (excludes header)
|
|
647
709
|
const tree = sm.getTree(); // Full tree structure
|
|
@@ -785,7 +847,7 @@ if (process.env.MY_KEY) {
|
|
|
785
847
|
}
|
|
786
848
|
|
|
787
849
|
// Model registry (no custom models.json)
|
|
788
|
-
const modelRegistry =
|
|
850
|
+
const modelRegistry = ModelRegistry.create(authStorage);
|
|
789
851
|
|
|
790
852
|
// Inline tool
|
|
791
853
|
const statusTool: ToolDefinition = {
|
|
@@ -851,20 +913,29 @@ The SDK exports run mode utilities for building custom interfaces on top of `cre
|
|
|
851
913
|
Full TUI interactive mode with editor, chat history, and all built-in commands:
|
|
852
914
|
|
|
853
915
|
```typescript
|
|
854
|
-
import {
|
|
855
|
-
|
|
856
|
-
|
|
916
|
+
import {
|
|
917
|
+
AgentSessionRuntimeHost,
|
|
918
|
+
createAgentSessionRuntime,
|
|
919
|
+
InteractiveMode,
|
|
920
|
+
SessionManager,
|
|
921
|
+
} from "@mariozechner/pi-coding-agent";
|
|
857
922
|
|
|
858
|
-
const
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
923
|
+
const bootstrap = {};
|
|
924
|
+
const runtime = await createAgentSessionRuntime(bootstrap, {
|
|
925
|
+
cwd: process.cwd(),
|
|
926
|
+
sessionManager: SessionManager.create(process.cwd()),
|
|
927
|
+
});
|
|
928
|
+
const runtimeHost = new AgentSessionRuntimeHost(bootstrap, runtime);
|
|
929
|
+
|
|
930
|
+
const mode = new InteractiveMode(runtimeHost, {
|
|
931
|
+
migratedProviders: [],
|
|
932
|
+
modelFallbackMessage: undefined,
|
|
933
|
+
initialMessage: "Hello",
|
|
934
|
+
initialImages: [],
|
|
935
|
+
initialMessages: [],
|
|
865
936
|
});
|
|
866
937
|
|
|
867
|
-
await mode.run();
|
|
938
|
+
await mode.run();
|
|
868
939
|
```
|
|
869
940
|
|
|
870
941
|
### runPrintMode
|
|
@@ -872,15 +943,25 @@ await mode.run(); // Blocks until exit
|
|
|
872
943
|
Single-shot mode: send prompts, output result, exit:
|
|
873
944
|
|
|
874
945
|
```typescript
|
|
875
|
-
import {
|
|
946
|
+
import {
|
|
947
|
+
AgentSessionRuntimeHost,
|
|
948
|
+
createAgentSessionRuntime,
|
|
949
|
+
runPrintMode,
|
|
950
|
+
SessionManager,
|
|
951
|
+
} from "@mariozechner/pi-coding-agent";
|
|
876
952
|
|
|
877
|
-
const
|
|
953
|
+
const bootstrap = {};
|
|
954
|
+
const runtime = await createAgentSessionRuntime(bootstrap, {
|
|
955
|
+
cwd: process.cwd(),
|
|
956
|
+
sessionManager: SessionManager.create(process.cwd()),
|
|
957
|
+
});
|
|
958
|
+
const runtimeHost = new AgentSessionRuntimeHost(bootstrap, runtime);
|
|
878
959
|
|
|
879
|
-
await runPrintMode(
|
|
880
|
-
mode: "text",
|
|
881
|
-
initialMessage: "Hello",
|
|
882
|
-
initialImages: [],
|
|
883
|
-
messages: ["Follow up"],
|
|
960
|
+
await runPrintMode(runtimeHost, {
|
|
961
|
+
mode: "text",
|
|
962
|
+
initialMessage: "Hello",
|
|
963
|
+
initialImages: [],
|
|
964
|
+
messages: ["Follow up"],
|
|
884
965
|
});
|
|
885
966
|
```
|
|
886
967
|
|
|
@@ -889,11 +970,21 @@ await runPrintMode(session, {
|
|
|
889
970
|
JSON-RPC mode for subprocess integration:
|
|
890
971
|
|
|
891
972
|
```typescript
|
|
892
|
-
import {
|
|
973
|
+
import {
|
|
974
|
+
AgentSessionRuntimeHost,
|
|
975
|
+
createAgentSessionRuntime,
|
|
976
|
+
runRpcMode,
|
|
977
|
+
SessionManager,
|
|
978
|
+
} from "@mariozechner/pi-coding-agent";
|
|
893
979
|
|
|
894
|
-
const
|
|
980
|
+
const bootstrap = {};
|
|
981
|
+
const runtime = await createAgentSessionRuntime(bootstrap, {
|
|
982
|
+
cwd: process.cwd(),
|
|
983
|
+
sessionManager: SessionManager.create(process.cwd()),
|
|
984
|
+
});
|
|
985
|
+
const runtimeHost = new AgentSessionRuntimeHost(bootstrap, runtime);
|
|
895
986
|
|
|
896
|
-
await runRpcMode(
|
|
987
|
+
await runRpcMode(runtimeHost);
|
|
897
988
|
```
|
|
898
989
|
|
|
899
990
|
See [RPC documentation](rpc.md) for the JSON protocol.
|
|
@@ -926,6 +1017,8 @@ The main entry point exports:
|
|
|
926
1017
|
```typescript
|
|
927
1018
|
// Factory
|
|
928
1019
|
createAgentSession
|
|
1020
|
+
createAgentSessionRuntime
|
|
1021
|
+
AgentSessionRuntimeHost
|
|
929
1022
|
|
|
930
1023
|
// Auth and Models
|
|
931
1024
|
AuthStorage
|
package/docs/tree.md
CHANGED
|
@@ -13,7 +13,7 @@ Sessions are stored as trees where each entry has an `id` and `parentId`. The "l
|
|
|
13
13
|
| View | Flat list of user messages | Full tree structure |
|
|
14
14
|
| Action | Extracts path to **new session file** | Changes leaf in **same session** |
|
|
15
15
|
| Summary | Never | Optional (user prompted) |
|
|
16
|
-
| Events | `session_before_fork` / `
|
|
16
|
+
| Events | `session_before_fork` / `session_start` (`reason: "fork"`) | `session_before_tree` / `session_tree` |
|
|
17
17
|
|
|
18
18
|
## Tree UI
|
|
19
19
|
|
|
@@ -35,6 +35,8 @@ Sessions are stored as trees where each entry has an `id` and `parentId`. The "l
|
|
|
35
35
|
| ↑/↓ | Navigate (depth-first order) |
|
|
36
36
|
| ←/→ | Page up/down |
|
|
37
37
|
| Ctrl+←/Ctrl+→ or Alt+←/Alt+→ | Fold/unfold and jump between branch segments |
|
|
38
|
+
| Shift+L | Set or clear a label on the selected node |
|
|
39
|
+
| Shift+T | Toggle label timestamps |
|
|
38
40
|
| Enter | Select node |
|
|
39
41
|
| Escape/Ctrl+C | Cancel |
|
|
40
42
|
| Ctrl+U | Toggle: user messages only |
|
|
@@ -49,11 +51,12 @@ Sessions are stored as trees where each entry has an `id` and `parentId`. The "l
|
|
|
49
51
|
- Height: half terminal height
|
|
50
52
|
- Current leaf marked with `← active`
|
|
51
53
|
- Labels shown inline: `[label-name]`
|
|
54
|
+
- `Shift+T` shows the latest label-change timestamp next to labeled nodes
|
|
52
55
|
- Foldable branch starts show `⊟` in the connector. Folded branches show `⊞`
|
|
53
56
|
- Active path marker `•` appears after the fold indicator when applicable
|
|
54
57
|
- Search and filter changes reset all folds
|
|
55
58
|
- Default filter hides `label` and `custom` entries (shown in Ctrl+O mode)
|
|
56
|
-
-
|
|
59
|
+
- At each branch point, the active subtree is shown first; other sibling branches are sorted by timestamp (oldest first)
|
|
57
60
|
|
|
58
61
|
## Selection Behavior
|
|
59
62
|
|
|
@@ -141,7 +144,7 @@ Flow:
|
|
|
141
144
|
4. Fire `session_before_tree` event (hook can cancel or provide summary)
|
|
142
145
|
5. Run default summarizer if needed
|
|
143
146
|
6. Switch leaf via `branch()` or `branchWithSummary()`
|
|
144
|
-
7. Update agent: `agent.
|
|
147
|
+
7. Update agent: `agent.state.messages = sessionManager.buildSessionContext().messages`
|
|
145
148
|
8. Fire `session_tree` event
|
|
146
149
|
9. Notify custom tools via session event
|
|
147
150
|
10. Return result with `editorText` if user message was selected
|
|
@@ -52,6 +52,7 @@ cp permission-gate.ts ~/.pi/agent/extensions/
|
|
|
52
52
|
| `qna.ts` | Extracts questions from last response into editor via `ctx.ui.setEditorText()` |
|
|
53
53
|
| `status-line.ts` | Shows turn progress in footer via `ctx.ui.setStatus()` with themed colors |
|
|
54
54
|
| `widget-placement.ts` | Shows widgets above and below the editor via `ctx.ui.setWidget()` placement |
|
|
55
|
+
| `hidden-thinking-label.ts` | Customizes the collapsed thinking label via `ctx.ui.setHiddenThinkingLabel()` |
|
|
55
56
|
| `model-status.ts` | Shows model changes in status bar via `model_select` hook |
|
|
56
57
|
| `snake.ts` | Snake game with custom UI, keyboard handling, and session persistence |
|
|
57
58
|
| `send-user-message.ts` | Demonstrates `pi.sendUserMessage()` for sending user messages from extensions |
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extension-custom-provider",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pi-extension-custom-provider",
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.15.1",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@anthropic-ai/sdk": "^0.52.0"
|
|
12
12
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hidden Thinking Label Extension
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates `ctx.ui.setHiddenThinkingLabel()` for customizing the label shown
|
|
5
|
+
* when thinking blocks are hidden.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* pi --extension examples/extensions/hidden-thinking-label.ts
|
|
9
|
+
*
|
|
10
|
+
* Test:
|
|
11
|
+
* 1. Load this extension
|
|
12
|
+
* 2. Hide thinking blocks with Ctrl+T
|
|
13
|
+
* 3. Ask for something that produces reasoning output
|
|
14
|
+
* 4. The collapsed thinking block label will show the custom text
|
|
15
|
+
*
|
|
16
|
+
* Commands:
|
|
17
|
+
* /thinking-label <text> Set a custom hidden thinking label
|
|
18
|
+
* /thinking-label Reset to the default label
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
22
|
+
|
|
23
|
+
const DEFAULT_LABEL = "Pondering...";
|
|
24
|
+
|
|
25
|
+
export default function (pi: ExtensionAPI) {
|
|
26
|
+
let label = DEFAULT_LABEL;
|
|
27
|
+
|
|
28
|
+
const applyLabel = (ctx: ExtensionContext) => {
|
|
29
|
+
ctx.ui.setHiddenThinkingLabel(label);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
33
|
+
applyLabel(ctx);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
pi.registerCommand("thinking-label", {
|
|
37
|
+
description: "Set the hidden thinking label. Use without args to reset.",
|
|
38
|
+
handler: async (args, ctx) => {
|
|
39
|
+
const nextLabel = args.trim();
|
|
40
|
+
|
|
41
|
+
if (!nextLabel) {
|
|
42
|
+
label = DEFAULT_LABEL;
|
|
43
|
+
ctx.ui.setHiddenThinkingLabel();
|
|
44
|
+
ctx.ui.notify(`Hidden thinking label reset to: ${DEFAULT_LABEL}`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
label = nextLabel;
|
|
49
|
+
ctx.ui.setHiddenThinkingLabel(label);
|
|
50
|
+
ctx.ui.notify(`Hidden thinking label set to: ${label}`);
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* - notify() - after each dialog completes
|
|
14
14
|
* - setStatus() - on turn_start/turn_end
|
|
15
15
|
* - setWidget() - on session_start
|
|
16
|
-
* - setTitle() - on session_start
|
|
16
|
+
* - setTitle() - on session_start
|
|
17
17
|
* - setEditorText() - via /rpc-prefill command
|
|
18
18
|
*/
|
|
19
19
|
|
|
@@ -24,18 +24,12 @@ export default function (pi: ExtensionAPI) {
|
|
|
24
24
|
|
|
25
25
|
// -- setTitle, setWidget, setStatus on session lifecycle --
|
|
26
26
|
|
|
27
|
-
pi.on("session_start", async (
|
|
28
|
-
ctx.ui.setTitle("pi RPC Demo");
|
|
27
|
+
pi.on("session_start", async (event, ctx) => {
|
|
28
|
+
ctx.ui.setTitle(event.reason === "new" ? "pi RPC Demo (new session)" : "pi RPC Demo");
|
|
29
29
|
ctx.ui.setWidget("rpc-demo", ["--- RPC Extension UI Demo ---", "Loaded and ready."]);
|
|
30
30
|
ctx.ui.setStatus("rpc-demo", `Turns: ${turnCount}`);
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
-
pi.on("session_switch", async (_event, ctx) => {
|
|
34
|
-
turnCount = 0;
|
|
35
|
-
ctx.ui.setTitle("pi RPC Demo (new session)");
|
|
36
|
-
ctx.ui.setStatus("rpc-demo", `Turns: ${turnCount}`);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
33
|
// -- setStatus on turn lifecycle --
|
|
40
34
|
|
|
41
35
|
pi.on("turn_start", async (_event, ctx) => {
|
|
@@ -29,12 +29,4 @@ export default function (pi: ExtensionAPI) {
|
|
|
29
29
|
const text = theme.fg("dim", ` Turn ${turnCount} complete`);
|
|
30
30
|
ctx.ui.setStatus("status-demo", check + text);
|
|
31
31
|
});
|
|
32
|
-
|
|
33
|
-
pi.on("session_switch", async (event, ctx) => {
|
|
34
|
-
if (event.reason === "new") {
|
|
35
|
-
turnCount = 0;
|
|
36
|
-
const theme = ctx.ui.theme;
|
|
37
|
-
ctx.ui.setStatus("status-demo", theme.fg("dim", "Ready"));
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
32
|
}
|
|
@@ -130,8 +130,6 @@ export default function (pi: ExtensionAPI) {
|
|
|
130
130
|
|
|
131
131
|
// Reconstruct state on session events
|
|
132
132
|
pi.on("session_start", async (_event, ctx) => reconstructState(ctx));
|
|
133
|
-
pi.on("session_switch", async (_event, ctx) => reconstructState(ctx));
|
|
134
|
-
pi.on("session_fork", async (_event, ctx) => reconstructState(ctx));
|
|
135
133
|
pi.on("session_tree", async (_event, ctx) => reconstructState(ctx));
|
|
136
134
|
|
|
137
135
|
// Register the todo tool for the LLM
|
|
@@ -138,9 +138,4 @@ export default function toolsExtension(pi: ExtensionAPI) {
|
|
|
138
138
|
pi.on("session_tree", async (_event, ctx) => {
|
|
139
139
|
restoreFromBranch(ctx);
|
|
140
140
|
});
|
|
141
|
-
|
|
142
|
-
// Restore state after forking
|
|
143
|
-
pi.on("session_fork", async (_event, ctx) => {
|
|
144
|
-
restoreFromBranch(ctx);
|
|
145
|
-
});
|
|
146
141
|
}
|
|
@@ -1,17 +1,9 @@
|
|
|
1
|
-
import type { ExtensionAPI
|
|
2
|
-
|
|
3
|
-
const applyWidgets = (ctx: ExtensionContext) => {
|
|
4
|
-
if (!ctx.hasUI) return;
|
|
5
|
-
ctx.ui.setWidget("widget-above", ["Above editor widget"]);
|
|
6
|
-
ctx.ui.setWidget("widget-below", ["Below editor widget"], { placement: "belowEditor" });
|
|
7
|
-
};
|
|
1
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
8
2
|
|
|
9
3
|
export default function widgetPlacementExtension(pi: ExtensionAPI) {
|
|
10
4
|
pi.on("session_start", (_event, ctx) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
pi.on("session_switch", (_event, ctx) => {
|
|
15
|
-
applyWidgets(ctx);
|
|
5
|
+
if (!ctx.hasUI) return;
|
|
6
|
+
ctx.ui.setWidget("widget-above", ["Above editor widget"]);
|
|
7
|
+
ctx.ui.setWidget("widget-below", ["Below editor widget"], { placement: "belowEditor" });
|
|
16
8
|
});
|
|
17
9
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extension-with-deps",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.28.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pi-extension-with-deps",
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.28.1",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"ms": "^2.1.3"
|
|
12
12
|
},
|