@mariozechner/pi-coding-agent 0.27.9 → 0.28.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/CHANGELOG.md +22 -0
- package/README.md +16 -17
- package/dist/cli/list-models.d.ts +2 -2
- package/dist/cli/list-models.d.ts.map +1 -1
- package/dist/cli/list-models.js +2 -7
- package/dist/cli/list-models.js.map +1 -1
- package/dist/config.d.ts +2 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -3
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +6 -3
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +18 -20
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +104 -0
- package/dist/core/auth-storage.d.ts.map +1 -0
- package/dist/core/auth-storage.js +232 -0
- package/dist/core/auth-storage.js.map +1 -0
- package/dist/core/model-registry.d.ts +50 -0
- package/dist/core/model-registry.d.ts.map +1 -0
- package/dist/core/model-registry.js +268 -0
- package/dist/core/model-registry.js.map +1 -0
- package/dist/core/model-resolver.d.ts +7 -7
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +12 -44
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/sdk.d.ts +13 -26
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +24 -101
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +0 -5
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +0 -19
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +15 -1
- package/dist/core/skills.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -8
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +37 -22
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +3 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +4 -3
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts +3 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +21 -14
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts +3 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +6 -6
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +53 -48
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/sdk.md +86 -61
- package/examples/custom-tools/hello/index.ts +15 -15
- package/examples/custom-tools/question/index.ts +3 -3
- package/examples/custom-tools/subagent/agents.ts +1 -2
- package/examples/custom-tools/subagent/index.ts +332 -125
- package/examples/custom-tools/todo/index.ts +30 -12
- package/examples/hooks/confirm-destructive.ts +5 -7
- package/examples/hooks/custom-compaction.ts +7 -7
- package/examples/hooks/dirty-repo-guard.ts +5 -9
- package/examples/hooks/permission-gate.ts +1 -5
- package/examples/sdk/02-custom-model.ts +20 -7
- package/examples/sdk/04-skills.ts +1 -1
- package/examples/sdk/05-tools.ts +11 -14
- package/examples/sdk/06-hooks.ts +1 -1
- package/examples/sdk/07-context-files.ts +1 -1
- package/examples/sdk/08-slash-commands.ts +3 -3
- package/examples/sdk/09-api-keys-and-oauth.ts +36 -26
- package/examples/sdk/10-settings.ts +2 -2
- package/examples/sdk/12-full-control.ts +19 -20
- package/examples/sdk/README.md +26 -13
- package/package.json +4 -5
- package/dist/core/model-config.d.ts +0 -58
- package/dist/core/model-config.d.ts.map +0 -1
- package/dist/core/model-config.js +0 -384
- package/dist/core/model-config.js.map +0 -1
- package/dist/core/oauth/index.d.ts +0 -41
- package/dist/core/oauth/index.d.ts.map +0 -1
- package/dist/core/oauth/index.js +0 -84
- package/dist/core/oauth/index.js.map +0 -1
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
* The onSession callback reconstructs state by scanning past tool results.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { Type } from "@sinclair/typebox";
|
|
12
11
|
import { StringEnum } from "@mariozechner/pi-ai";
|
|
13
|
-
import { Text } from "@mariozechner/pi-tui";
|
|
14
12
|
import type { CustomAgentTool, CustomToolFactory, ToolSessionEvent } from "@mariozechner/pi-coding-agent";
|
|
13
|
+
import { Text } from "@mariozechner/pi-tui";
|
|
14
|
+
import { Type } from "@sinclair/typebox";
|
|
15
15
|
|
|
16
16
|
interface Todo {
|
|
17
17
|
id: number;
|
|
@@ -76,11 +76,18 @@ const factory: CustomToolFactory = (_pi) => {
|
|
|
76
76
|
switch (params.action) {
|
|
77
77
|
case "list":
|
|
78
78
|
return {
|
|
79
|
-
content: [
|
|
79
|
+
content: [
|
|
80
|
+
{
|
|
81
|
+
type: "text",
|
|
82
|
+
text: todos.length
|
|
83
|
+
? todos.map((t) => `[${t.done ? "x" : " "}] #${t.id}: ${t.text}`).join("\n")
|
|
84
|
+
: "No todos",
|
|
85
|
+
},
|
|
86
|
+
],
|
|
80
87
|
details: { action: "list", todos: [...todos], nextId },
|
|
81
88
|
};
|
|
82
89
|
|
|
83
|
-
case "add":
|
|
90
|
+
case "add": {
|
|
84
91
|
if (!params.text) {
|
|
85
92
|
return {
|
|
86
93
|
content: [{ type: "text", text: "Error: text required for add" }],
|
|
@@ -93,8 +100,9 @@ const factory: CustomToolFactory = (_pi) => {
|
|
|
93
100
|
content: [{ type: "text", text: `Added todo #${newTodo.id}: ${newTodo.text}` }],
|
|
94
101
|
details: { action: "add", todos: [...todos], nextId },
|
|
95
102
|
};
|
|
103
|
+
}
|
|
96
104
|
|
|
97
|
-
case "toggle":
|
|
105
|
+
case "toggle": {
|
|
98
106
|
if (params.id === undefined) {
|
|
99
107
|
return {
|
|
100
108
|
content: [{ type: "text", text: "Error: id required for toggle" }],
|
|
@@ -113,8 +121,9 @@ const factory: CustomToolFactory = (_pi) => {
|
|
|
113
121
|
content: [{ type: "text", text: `Todo #${todo.id} ${todo.done ? "completed" : "uncompleted"}` }],
|
|
114
122
|
details: { action: "toggle", todos: [...todos], nextId },
|
|
115
123
|
};
|
|
124
|
+
}
|
|
116
125
|
|
|
117
|
-
case "clear":
|
|
126
|
+
case "clear": {
|
|
118
127
|
const count = todos.length;
|
|
119
128
|
todos = [];
|
|
120
129
|
nextId = 1;
|
|
@@ -122,6 +131,7 @@ const factory: CustomToolFactory = (_pi) => {
|
|
|
122
131
|
content: [{ type: "text", text: `Cleared ${count} todos` }],
|
|
123
132
|
details: { action: "clear", todos: [], nextId: 1 },
|
|
124
133
|
};
|
|
134
|
+
}
|
|
125
135
|
|
|
126
136
|
default:
|
|
127
137
|
return {
|
|
@@ -133,8 +143,8 @@ const factory: CustomToolFactory = (_pi) => {
|
|
|
133
143
|
|
|
134
144
|
renderCall(args, theme) {
|
|
135
145
|
let text = theme.fg("toolTitle", theme.bold("todo ")) + theme.fg("muted", args.action);
|
|
136
|
-
if (args.text) text +=
|
|
137
|
-
if (args.id !== undefined) text +=
|
|
146
|
+
if (args.text) text += ` ${theme.fg("dim", `"${args.text}"`)}`;
|
|
147
|
+
if (args.id !== undefined) text += ` ${theme.fg("accent", `#${args.id}`)}`;
|
|
138
148
|
return new Text(text, 0, 0);
|
|
139
149
|
},
|
|
140
150
|
|
|
@@ -153,7 +163,7 @@ const factory: CustomToolFactory = (_pi) => {
|
|
|
153
163
|
const todoList = details.todos;
|
|
154
164
|
|
|
155
165
|
switch (details.action) {
|
|
156
|
-
case "list":
|
|
166
|
+
case "list": {
|
|
157
167
|
if (todoList.length === 0) {
|
|
158
168
|
return new Text(theme.fg("dim", "No todos"), 0, 0);
|
|
159
169
|
}
|
|
@@ -162,16 +172,24 @@ const factory: CustomToolFactory = (_pi) => {
|
|
|
162
172
|
for (const t of display) {
|
|
163
173
|
const check = t.done ? theme.fg("success", "✓") : theme.fg("dim", "○");
|
|
164
174
|
const itemText = t.done ? theme.fg("dim", t.text) : theme.fg("muted", t.text);
|
|
165
|
-
listText +=
|
|
175
|
+
listText += `\n${check} ${theme.fg("accent", `#${t.id}`)} ${itemText}`;
|
|
166
176
|
}
|
|
167
177
|
if (!expanded && todoList.length > 5) {
|
|
168
|
-
listText +=
|
|
178
|
+
listText += `\n${theme.fg("dim", `... ${todoList.length - 5} more`)}`;
|
|
169
179
|
}
|
|
170
180
|
return new Text(listText, 0, 0);
|
|
181
|
+
}
|
|
171
182
|
|
|
172
183
|
case "add": {
|
|
173
184
|
const added = todoList[todoList.length - 1];
|
|
174
|
-
return new Text(
|
|
185
|
+
return new Text(
|
|
186
|
+
theme.fg("success", "✓ Added ") +
|
|
187
|
+
theme.fg("accent", `#${added.id}`) +
|
|
188
|
+
" " +
|
|
189
|
+
theme.fg("muted", added.text),
|
|
190
|
+
0,
|
|
191
|
+
0,
|
|
192
|
+
);
|
|
175
193
|
}
|
|
176
194
|
|
|
177
195
|
case "toggle": {
|
|
@@ -28,9 +28,7 @@ export default function (pi: HookAPI) {
|
|
|
28
28
|
if (!ctx.hasUI) return;
|
|
29
29
|
|
|
30
30
|
// Check if there are unsaved changes (messages since last assistant response)
|
|
31
|
-
const hasUnsavedWork = event.entries.some(
|
|
32
|
-
(e) => e.type === "message" && e.message.role === "user",
|
|
33
|
-
);
|
|
31
|
+
const hasUnsavedWork = event.entries.some((e) => e.type === "message" && e.message.role === "user");
|
|
34
32
|
|
|
35
33
|
if (hasUnsavedWork) {
|
|
36
34
|
const confirmed = await ctx.ui.confirm(
|
|
@@ -48,10 +46,10 @@ export default function (pi: HookAPI) {
|
|
|
48
46
|
if (event.reason === "before_branch") {
|
|
49
47
|
if (!ctx.hasUI) return;
|
|
50
48
|
|
|
51
|
-
const choice = await ctx.ui.select(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
);
|
|
49
|
+
const choice = await ctx.ui.select(`Branch from turn ${event.targetTurnIndex}?`, [
|
|
50
|
+
"Yes, create branch",
|
|
51
|
+
"No, stay in current session",
|
|
52
|
+
]);
|
|
55
53
|
|
|
56
54
|
if (choice !== "Yes, create branch") {
|
|
57
55
|
ctx.ui.notify("Branch cancelled", "info");
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* pi --hook examples/hooks/custom-compaction.ts
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import { complete } from "@mariozechner/pi-ai";
|
|
17
|
-
import {
|
|
16
|
+
import { complete, getModel } from "@mariozechner/pi-ai";
|
|
17
|
+
import { messageTransformer } from "@mariozechner/pi-coding-agent";
|
|
18
18
|
import type { HookAPI } from "@mariozechner/pi-coding-agent/hooks";
|
|
19
19
|
|
|
20
20
|
export default function (pi: HookAPI) {
|
|
@@ -23,13 +23,13 @@ export default function (pi: HookAPI) {
|
|
|
23
23
|
|
|
24
24
|
ctx.ui.notify("Custom compaction hook triggered", "info");
|
|
25
25
|
|
|
26
|
-
const { messagesToSummarize, messagesToKeep, previousSummary, tokensBefore, resolveApiKey, entries, signal } =
|
|
26
|
+
const { messagesToSummarize, messagesToKeep, previousSummary, tokensBefore, resolveApiKey, entries, signal } =
|
|
27
|
+
event;
|
|
27
28
|
|
|
28
29
|
// Use Gemini Flash for summarization (cheaper/faster than most conversation models)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
ctx.ui.notify(`Could not find Gemini Flash model: ${error}, using default compaction`, "warning");
|
|
30
|
+
const model = getModel("google", "gemini-2.5-flash");
|
|
31
|
+
if (!model) {
|
|
32
|
+
ctx.ui.notify(`Could not find Gemini Flash model, using default compaction`, "warning");
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
35
|
|
|
@@ -10,11 +10,7 @@ import type { HookAPI } from "@mariozechner/pi-coding-agent/hooks";
|
|
|
10
10
|
export default function (pi: HookAPI) {
|
|
11
11
|
pi.on("session", async (event, ctx) => {
|
|
12
12
|
// Only guard destructive actions
|
|
13
|
-
if (
|
|
14
|
-
event.reason !== "before_clear" &&
|
|
15
|
-
event.reason !== "before_switch" &&
|
|
16
|
-
event.reason !== "before_branch"
|
|
17
|
-
) {
|
|
13
|
+
if (event.reason !== "before_clear" && event.reason !== "before_switch" && event.reason !== "before_branch") {
|
|
18
14
|
return;
|
|
19
15
|
}
|
|
20
16
|
|
|
@@ -46,10 +42,10 @@ export default function (pi: HookAPI) {
|
|
|
46
42
|
? "switch session"
|
|
47
43
|
: "branch";
|
|
48
44
|
|
|
49
|
-
const choice = await ctx.ui.select(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
);
|
|
45
|
+
const choice = await ctx.ui.select(`You have ${changedFiles} uncommitted file(s). ${action} anyway?`, [
|
|
46
|
+
"Yes, proceed anyway",
|
|
47
|
+
"No, let me commit first",
|
|
48
|
+
]);
|
|
53
49
|
|
|
54
50
|
if (choice !== "Yes, proceed anyway") {
|
|
55
51
|
ctx.ui.notify("Commit your changes first", "warning");
|
|
@@ -8,11 +8,7 @@
|
|
|
8
8
|
import type { HookAPI } from "@mariozechner/pi-coding-agent/hooks";
|
|
9
9
|
|
|
10
10
|
export default function (pi: HookAPI) {
|
|
11
|
-
const dangerousPatterns = [
|
|
12
|
-
/\brm\s+(-rf?|--recursive)/i,
|
|
13
|
-
/\bsudo\b/i,
|
|
14
|
-
/\b(chmod|chown)\b.*777/i,
|
|
15
|
-
];
|
|
11
|
+
const dangerousPatterns = [/\brm\s+(-rf?|--recursive)/i, /\bsudo\b/i, /\b(chmod|chown)\b.*777/i];
|
|
16
12
|
|
|
17
13
|
pi.on("tool_call", async (event, ctx) => {
|
|
18
14
|
if (event.toolName !== "bash") return undefined;
|
|
@@ -4,16 +4,27 @@
|
|
|
4
4
|
* Shows how to select a specific model and thinking level.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { getModel } from "@mariozechner/pi-ai";
|
|
8
|
+
import { createAgentSession, discoverAuthStorage, discoverModels } from "../../src/index.js";
|
|
8
9
|
|
|
9
|
-
//
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
// Set up auth storage and model registry
|
|
11
|
+
const authStorage = discoverAuthStorage();
|
|
12
|
+
const modelRegistry = discoverModels(authStorage);
|
|
13
|
+
|
|
14
|
+
// Option 1: Find a specific built-in model by provider/id
|
|
15
|
+
const opus = getModel("anthropic", "claude-opus-4-5");
|
|
16
|
+
if (opus) {
|
|
17
|
+
console.log(`Found model: ${opus.provider}/${opus.id}`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Option 2: Find model via registry (includes custom models from models.json)
|
|
21
|
+
const customModel = modelRegistry.find("my-provider", "my-model");
|
|
22
|
+
if (customModel) {
|
|
23
|
+
console.log(`Found custom model: ${customModel.provider}/${customModel.id}`);
|
|
13
24
|
}
|
|
14
25
|
|
|
15
|
-
// Option
|
|
16
|
-
const available = await
|
|
26
|
+
// Option 3: Pick from available models (have valid API keys)
|
|
27
|
+
const available = await modelRegistry.getAvailable();
|
|
17
28
|
console.log(
|
|
18
29
|
"Available models:",
|
|
19
30
|
available.map((m) => `${m.provider}/${m.id}`),
|
|
@@ -23,6 +34,8 @@ if (available.length > 0) {
|
|
|
23
34
|
const { session } = await createAgentSession({
|
|
24
35
|
model: available[0],
|
|
25
36
|
thinkingLevel: "medium", // off, low, medium, high
|
|
37
|
+
authStorage,
|
|
38
|
+
modelRegistry,
|
|
26
39
|
});
|
|
27
40
|
|
|
28
41
|
session.subscribe((event) => {
|
package/examples/sdk/05-tools.ts
CHANGED
|
@@ -10,31 +10,28 @@
|
|
|
10
10
|
|
|
11
11
|
import { Type } from "@sinclair/typebox";
|
|
12
12
|
import {
|
|
13
|
+
bashTool, // read, bash, edit, write - uses process.cwd()
|
|
14
|
+
type CustomAgentTool,
|
|
13
15
|
createAgentSession,
|
|
14
|
-
discoverCustomTools,
|
|
15
|
-
SessionManager,
|
|
16
|
-
codingTools, // read, bash, edit, write - uses process.cwd()
|
|
17
|
-
readOnlyTools, // read, grep, find, ls - uses process.cwd()
|
|
18
|
-
createCodingTools, // Factory: creates tools for specific cwd
|
|
19
|
-
createReadOnlyTools, // Factory: creates tools for specific cwd
|
|
20
|
-
createReadTool,
|
|
21
16
|
createBashTool,
|
|
17
|
+
createCodingTools, // Factory: creates tools for specific cwd
|
|
22
18
|
createGrepTool,
|
|
23
|
-
|
|
24
|
-
bashTool,
|
|
19
|
+
createReadTool,
|
|
25
20
|
grepTool,
|
|
26
|
-
|
|
21
|
+
readOnlyTools, // read, grep, find, ls - uses process.cwd()
|
|
22
|
+
readTool,
|
|
23
|
+
SessionManager,
|
|
27
24
|
} from "../../src/index.js";
|
|
28
25
|
|
|
29
26
|
// Read-only mode (no edit/write) - uses process.cwd()
|
|
30
|
-
|
|
27
|
+
await createAgentSession({
|
|
31
28
|
tools: readOnlyTools,
|
|
32
29
|
sessionManager: SessionManager.inMemory(),
|
|
33
30
|
});
|
|
34
31
|
console.log("Read-only session created");
|
|
35
32
|
|
|
36
33
|
// Custom tool selection - uses process.cwd()
|
|
37
|
-
|
|
34
|
+
await createAgentSession({
|
|
38
35
|
tools: [readTool, bashTool, grepTool],
|
|
39
36
|
sessionManager: SessionManager.inMemory(),
|
|
40
37
|
});
|
|
@@ -42,7 +39,7 @@ console.log("Custom tools session created");
|
|
|
42
39
|
|
|
43
40
|
// With custom cwd - MUST use factory functions!
|
|
44
41
|
const customCwd = "/path/to/project";
|
|
45
|
-
|
|
42
|
+
await createAgentSession({
|
|
46
43
|
cwd: customCwd,
|
|
47
44
|
tools: createCodingTools(customCwd), // Tools resolve paths relative to customCwd
|
|
48
45
|
sessionManager: SessionManager.inMemory(),
|
|
@@ -50,7 +47,7 @@ const { session: customCwdSession } = await createAgentSession({
|
|
|
50
47
|
console.log("Custom cwd session created");
|
|
51
48
|
|
|
52
49
|
// Or pick specific tools for custom cwd
|
|
53
|
-
|
|
50
|
+
await createAgentSession({
|
|
54
51
|
cwd: customCwd,
|
|
55
52
|
tools: [createReadTool(customCwd), createBashTool(customCwd), createGrepTool(customCwd)],
|
|
56
53
|
sessionManager: SessionManager.inMemory(),
|
package/examples/sdk/06-hooks.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Hooks intercept agent events for logging, blocking, or modification.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { createAgentSession,
|
|
7
|
+
import { createAgentSession, type HookFactory, SessionManager } from "../../src/index.js";
|
|
8
8
|
|
|
9
9
|
// Logging hook
|
|
10
10
|
const loggingHook: HookFactory = (api) => {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* File-based commands that inject content when invoked with /commandname.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { createAgentSession, discoverSlashCommands,
|
|
7
|
+
import { createAgentSession, discoverSlashCommands, type FileSlashCommand, SessionManager } from "../../src/index.js";
|
|
8
8
|
|
|
9
9
|
// Discover commands from cwd/.pi/commands/ and ~/.pi/agent/commands/
|
|
10
10
|
const discovered = discoverSlashCommands();
|
|
@@ -21,12 +21,12 @@ const deployCommand: FileSlashCommand = {
|
|
|
21
21
|
content: `# Deploy Instructions
|
|
22
22
|
|
|
23
23
|
1. Build: npm run build
|
|
24
|
-
2. Test: npm test
|
|
24
|
+
2. Test: npm test
|
|
25
25
|
3. Deploy: npm run deploy`,
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
// Use discovered + custom commands
|
|
29
|
-
|
|
29
|
+
await createAgentSession({
|
|
30
30
|
slashCommands: [...discovered, deployCommand],
|
|
31
31
|
sessionManager: SessionManager.inMemory(),
|
|
32
32
|
});
|
|
@@ -1,45 +1,55 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* API Keys and OAuth
|
|
3
3
|
*
|
|
4
|
-
* Configure API key resolution
|
|
4
|
+
* Configure API key resolution via AuthStorage and ModelRegistry.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
|
+
AuthStorage,
|
|
8
9
|
createAgentSession,
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
discoverAuthStorage,
|
|
11
|
+
discoverModels,
|
|
12
|
+
ModelRegistry,
|
|
11
13
|
SessionManager,
|
|
12
14
|
} from "../../src/index.js";
|
|
13
|
-
import { getAgentDir } from "../../src/config.js";
|
|
14
15
|
|
|
15
|
-
// Default:
|
|
16
|
-
|
|
16
|
+
// Default: discoverAuthStorage() uses ~/.pi/agent/auth.json
|
|
17
|
+
// discoverModels() loads built-in + custom models from ~/.pi/agent/models.json
|
|
18
|
+
const authStorage = discoverAuthStorage();
|
|
19
|
+
const modelRegistry = discoverModels(authStorage);
|
|
20
|
+
|
|
21
|
+
await createAgentSession({
|
|
17
22
|
sessionManager: SessionManager.inMemory(),
|
|
23
|
+
authStorage,
|
|
24
|
+
modelRegistry,
|
|
18
25
|
});
|
|
19
|
-
console.log("Session with default
|
|
26
|
+
console.log("Session with default auth storage and model registry");
|
|
27
|
+
|
|
28
|
+
// Custom auth storage location
|
|
29
|
+
const customAuthStorage = new AuthStorage("/tmp/my-app/auth.json");
|
|
30
|
+
const customModelRegistry = new ModelRegistry(customAuthStorage, "/tmp/my-app/models.json");
|
|
20
31
|
|
|
21
|
-
|
|
22
|
-
const { session: customSession } = await createAgentSession({
|
|
23
|
-
getApiKey: async (model) => {
|
|
24
|
-
// Custom logic (secrets manager, database, etc.)
|
|
25
|
-
if (model.provider === "anthropic") {
|
|
26
|
-
return process.env.MY_ANTHROPIC_KEY;
|
|
27
|
-
}
|
|
28
|
-
// Fall back to default
|
|
29
|
-
return defaultGetApiKey()(model);
|
|
30
|
-
},
|
|
32
|
+
await createAgentSession({
|
|
31
33
|
sessionManager: SessionManager.inMemory(),
|
|
34
|
+
authStorage: customAuthStorage,
|
|
35
|
+
modelRegistry: customModelRegistry,
|
|
32
36
|
});
|
|
33
|
-
console.log("Session with custom
|
|
37
|
+
console.log("Session with custom auth storage location");
|
|
34
38
|
|
|
35
|
-
//
|
|
36
|
-
|
|
39
|
+
// Runtime API key override (not persisted to disk)
|
|
40
|
+
authStorage.setRuntimeApiKey("anthropic", "sk-my-temp-key");
|
|
41
|
+
await createAgentSession({
|
|
42
|
+
sessionManager: SessionManager.inMemory(),
|
|
43
|
+
authStorage,
|
|
44
|
+
modelRegistry,
|
|
45
|
+
});
|
|
46
|
+
console.log("Session with runtime API key override");
|
|
37
47
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
systemPrompt: "You are helpful.",
|
|
42
|
-
skills: [],
|
|
48
|
+
// No models.json - only built-in models
|
|
49
|
+
const simpleRegistry = new ModelRegistry(authStorage); // null = no models.json
|
|
50
|
+
await createAgentSession({
|
|
43
51
|
sessionManager: SessionManager.inMemory(),
|
|
52
|
+
authStorage,
|
|
53
|
+
modelRegistry: simpleRegistry,
|
|
44
54
|
});
|
|
45
|
-
console.log("Session with
|
|
55
|
+
console.log("Session with only built-in models");
|
|
@@ -17,7 +17,7 @@ settingsManager.applyOverrides({
|
|
|
17
17
|
retry: { enabled: true, maxRetries: 5, baseDelayMs: 1000 },
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
await createAgentSession({
|
|
21
21
|
settingsManager,
|
|
22
22
|
sessionManager: SessionManager.inMemory(),
|
|
23
23
|
});
|
|
@@ -30,7 +30,7 @@ const inMemorySettings = SettingsManager.inMemory({
|
|
|
30
30
|
retry: { enabled: false },
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
await createAgentSession({
|
|
34
34
|
settingsManager: inMemorySettings,
|
|
35
35
|
sessionManager: SessionManager.inMemory(),
|
|
36
36
|
});
|
|
@@ -2,38 +2,36 @@
|
|
|
2
2
|
* Full Control
|
|
3
3
|
*
|
|
4
4
|
* Replace everything - no discovery, explicit configuration.
|
|
5
|
-
* Still uses OAuth from ~/.pi/agent for convenience.
|
|
6
5
|
*
|
|
7
6
|
* IMPORTANT: When providing `tools` with a custom `cwd`, use the tool factory
|
|
8
7
|
* functions (createReadTool, createBashTool, etc.) to ensure tools resolve
|
|
9
8
|
* paths relative to your cwd.
|
|
10
9
|
*/
|
|
11
10
|
|
|
11
|
+
import { getModel } from "@mariozechner/pi-ai";
|
|
12
12
|
import { Type } from "@sinclair/typebox";
|
|
13
13
|
import {
|
|
14
|
+
AuthStorage,
|
|
15
|
+
type CustomAgentTool,
|
|
14
16
|
createAgentSession,
|
|
15
|
-
configureOAuthStorage,
|
|
16
|
-
defaultGetApiKey,
|
|
17
|
-
findModel,
|
|
18
|
-
SessionManager,
|
|
19
|
-
SettingsManager,
|
|
20
|
-
createReadTool,
|
|
21
17
|
createBashTool,
|
|
18
|
+
createReadTool,
|
|
22
19
|
type HookFactory,
|
|
23
|
-
|
|
20
|
+
ModelRegistry,
|
|
21
|
+
SessionManager,
|
|
22
|
+
SettingsManager,
|
|
24
23
|
} from "../../src/index.js";
|
|
25
|
-
import { getAgentDir } from "../../src/config.js";
|
|
26
24
|
|
|
27
|
-
//
|
|
28
|
-
|
|
25
|
+
// Custom auth storage location
|
|
26
|
+
const authStorage = new AuthStorage("/tmp/my-agent/auth.json");
|
|
29
27
|
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
// Runtime API key override (not persisted)
|
|
29
|
+
if (process.env.MY_ANTHROPIC_KEY) {
|
|
30
|
+
authStorage.setRuntimeApiKey("anthropic", process.env.MY_ANTHROPIC_KEY);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Model registry with no custom models.json
|
|
34
|
+
const modelRegistry = new ModelRegistry(authStorage);
|
|
37
35
|
|
|
38
36
|
// Inline hook
|
|
39
37
|
const auditHook: HookFactory = (api) => {
|
|
@@ -55,7 +53,7 @@ const statusTool: CustomAgentTool = {
|
|
|
55
53
|
}),
|
|
56
54
|
};
|
|
57
55
|
|
|
58
|
-
const
|
|
56
|
+
const model = getModel("anthropic", "claude-opus-4-5");
|
|
59
57
|
if (!model) throw new Error("Model not found");
|
|
60
58
|
|
|
61
59
|
// In-memory settings with overrides
|
|
@@ -73,7 +71,8 @@ const { session } = await createAgentSession({
|
|
|
73
71
|
|
|
74
72
|
model,
|
|
75
73
|
thinkingLevel: "off",
|
|
76
|
-
|
|
74
|
+
authStorage,
|
|
75
|
+
modelRegistry,
|
|
77
76
|
|
|
78
77
|
systemPrompt: `You are a minimal assistant.
|
|
79
78
|
Available: read, bash, status. Be concise.`,
|
package/examples/sdk/README.md
CHANGED
|
@@ -29,50 +29,63 @@ npx tsx examples/sdk/01-minimal.ts
|
|
|
29
29
|
## Quick Reference
|
|
30
30
|
|
|
31
31
|
```typescript
|
|
32
|
+
import { getModel } from "@mariozechner/pi-ai";
|
|
32
33
|
import {
|
|
34
|
+
AuthStorage,
|
|
33
35
|
createAgentSession,
|
|
34
|
-
|
|
36
|
+
discoverAuthStorage,
|
|
37
|
+
discoverModels,
|
|
35
38
|
discoverSkills,
|
|
36
39
|
discoverHooks,
|
|
37
40
|
discoverCustomTools,
|
|
38
41
|
discoverContextFiles,
|
|
39
42
|
discoverSlashCommands,
|
|
40
|
-
discoverAvailableModels,
|
|
41
|
-
findModel,
|
|
42
|
-
defaultGetApiKey,
|
|
43
43
|
loadSettings,
|
|
44
44
|
buildSystemPrompt,
|
|
45
|
+
ModelRegistry,
|
|
45
46
|
SessionManager,
|
|
46
47
|
codingTools,
|
|
47
48
|
readOnlyTools,
|
|
48
49
|
readTool, bashTool, editTool, writeTool,
|
|
49
50
|
} from "@mariozechner/pi-coding-agent";
|
|
50
51
|
|
|
52
|
+
// Auth and models setup
|
|
53
|
+
const authStorage = discoverAuthStorage();
|
|
54
|
+
const modelRegistry = discoverModels(authStorage);
|
|
55
|
+
|
|
51
56
|
// Minimal
|
|
52
|
-
const { session } = await createAgentSession();
|
|
57
|
+
const { session } = await createAgentSession({ authStorage, modelRegistry });
|
|
53
58
|
|
|
54
59
|
// Custom model
|
|
55
|
-
const
|
|
56
|
-
const { session } = await createAgentSession({ model, thinkingLevel: "high" });
|
|
60
|
+
const model = getModel("anthropic", "claude-opus-4-5");
|
|
61
|
+
const { session } = await createAgentSession({ model, thinkingLevel: "high", authStorage, modelRegistry });
|
|
57
62
|
|
|
58
63
|
// Modify prompt
|
|
59
64
|
const { session } = await createAgentSession({
|
|
60
65
|
systemPrompt: (defaultPrompt) => defaultPrompt + "\n\nBe concise.",
|
|
66
|
+
authStorage,
|
|
67
|
+
modelRegistry,
|
|
61
68
|
});
|
|
62
69
|
|
|
63
70
|
// Read-only
|
|
64
|
-
const { session } = await createAgentSession({ tools: readOnlyTools });
|
|
71
|
+
const { session } = await createAgentSession({ tools: readOnlyTools, authStorage, modelRegistry });
|
|
65
72
|
|
|
66
73
|
// In-memory
|
|
67
74
|
const { session } = await createAgentSession({
|
|
68
75
|
sessionManager: SessionManager.inMemory(),
|
|
76
|
+
authStorage,
|
|
77
|
+
modelRegistry,
|
|
69
78
|
});
|
|
70
79
|
|
|
71
80
|
// Full control
|
|
72
|
-
|
|
81
|
+
const customAuth = new AuthStorage("/my/app/auth.json");
|
|
82
|
+
customAuth.setRuntimeApiKey("anthropic", process.env.MY_KEY!);
|
|
83
|
+
const customRegistry = new ModelRegistry(customAuth);
|
|
84
|
+
|
|
73
85
|
const { session } = await createAgentSession({
|
|
74
86
|
model,
|
|
75
|
-
|
|
87
|
+
authStorage: customAuth,
|
|
88
|
+
modelRegistry: customRegistry,
|
|
76
89
|
systemPrompt: "You are helpful.",
|
|
77
90
|
tools: [readTool, bashTool],
|
|
78
91
|
customTools: [{ tool: myTool }],
|
|
@@ -81,7 +94,6 @@ const { session } = await createAgentSession({
|
|
|
81
94
|
contextFiles: [],
|
|
82
95
|
slashCommands: [],
|
|
83
96
|
sessionManager: SessionManager.inMemory(),
|
|
84
|
-
settings: { compaction: { enabled: false } },
|
|
85
97
|
});
|
|
86
98
|
|
|
87
99
|
// Run prompts
|
|
@@ -97,11 +109,12 @@ await session.prompt("Hello");
|
|
|
97
109
|
|
|
98
110
|
| Option | Default | Description |
|
|
99
111
|
|--------|---------|-------------|
|
|
112
|
+
| `authStorage` | `discoverAuthStorage()` | Credential storage |
|
|
113
|
+
| `modelRegistry` | `discoverModels(authStorage)` | Model registry |
|
|
100
114
|
| `cwd` | `process.cwd()` | Working directory |
|
|
101
115
|
| `agentDir` | `~/.pi/agent` | Config directory |
|
|
102
116
|
| `model` | From settings/first available | Model to use |
|
|
103
117
|
| `thinkingLevel` | From settings/"off" | off, low, medium, high |
|
|
104
|
-
| `getApiKey` | Built-in resolver | API key function |
|
|
105
118
|
| `systemPrompt` | Discovered | String or `(default) => modified` |
|
|
106
119
|
| `tools` | `codingTools` | Built-in tools |
|
|
107
120
|
| `customTools` | Discovered | Replaces discovery |
|
|
@@ -112,7 +125,7 @@ await session.prompt("Hello");
|
|
|
112
125
|
| `contextFiles` | Discovered | AGENTS.md files |
|
|
113
126
|
| `slashCommands` | Discovered | File commands |
|
|
114
127
|
| `sessionManager` | `SessionManager.create(cwd)` | Persistence |
|
|
115
|
-
| `
|
|
128
|
+
| `settingsManager` | From agentDir | Settings overrides |
|
|
116
129
|
|
|
117
130
|
## Events
|
|
118
131
|
|