@mariozechner/pi-coding-agent 0.25.3 → 0.26.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 +18 -0
- package/README.md +47 -5
- package/dist/cli/session-picker.d.ts +2 -2
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js +2 -2
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +1 -13
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction.d.ts.map +1 -1
- package/dist/core/compaction.js +1 -1
- package/dist/core/compaction.js.map +1 -1
- package/dist/core/custom-tools/loader.d.ts +3 -2
- package/dist/core/custom-tools/loader.d.ts.map +1 -1
- package/dist/core/custom-tools/loader.js +5 -4
- package/dist/core/custom-tools/loader.js.map +1 -1
- package/dist/core/export-html.d.ts.map +1 -1
- package/dist/core/export-html.js +1 -1
- package/dist/core/export-html.js.map +1 -1
- package/dist/core/hooks/loader.d.ts +2 -5
- package/dist/core/hooks/loader.d.ts.map +1 -1
- package/dist/core/hooks/loader.js +4 -7
- package/dist/core/hooks/loader.js.map +1 -1
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +1 -1
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-config.d.ts +5 -4
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +12 -19
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/sdk.d.ts +211 -0
- package/dist/core/sdk.d.ts.map +1 -0
- package/dist/core/sdk.js +462 -0
- package/dist/core/sdk.js.map +1 -0
- package/dist/core/session-manager.d.ts +31 -91
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +188 -353
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +12 -2
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +101 -37
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +7 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +7 -5
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts +9 -3
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +12 -9
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts +24 -2
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +18 -16
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +1 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +12 -22
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +2 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +0 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/truncate.d.ts.map +1 -1
- package/dist/core/tools/truncate.js +1 -1
- package/dist/core/tools/truncate.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +4 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +142 -312
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/armin.d.ts.map +1 -1
- package/dist/modes/interactive/components/armin.js +2 -2
- package/dist/modes/interactive/components/armin.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +3 -3
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +6 -6
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/hook-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/hook-selector.js +1 -1
- package/dist/modes/interactive/components/hook-selector.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +2 -2
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts +3 -12
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +1 -3
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +14 -14
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +7 -6
- 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 +10 -6
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +1 -1
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +2 -2
- package/dist/utils/shell.js.map +1 -1
- package/docs/sdk.md +819 -0
- package/examples/README.md +29 -0
- package/examples/sdk/01-minimal.ts +22 -0
- package/examples/sdk/02-custom-model.ts +36 -0
- package/examples/sdk/03-custom-prompt.ts +44 -0
- package/examples/sdk/04-skills.ts +44 -0
- package/examples/sdk/05-tools.ts +67 -0
- package/examples/sdk/06-hooks.ts +61 -0
- package/examples/sdk/07-context-files.ts +36 -0
- package/examples/sdk/08-slash-commands.ts +37 -0
- package/examples/sdk/09-api-keys-and-oauth.ts +45 -0
- package/examples/sdk/10-settings.ts +38 -0
- package/examples/sdk/11-sessions.ts +46 -0
- package/examples/sdk/12-full-control.ts +91 -0
- package/examples/sdk/README.md +138 -0
- package/package.json +4 -4
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Examples
|
|
2
|
+
|
|
3
|
+
Example code for pi-coding-agent.
|
|
4
|
+
|
|
5
|
+
## Directories
|
|
6
|
+
|
|
7
|
+
### [sdk/](sdk/)
|
|
8
|
+
Programmatic usage via `createAgentSession()`. Shows how to customize models, prompts, tools, hooks, and session management.
|
|
9
|
+
|
|
10
|
+
### [hooks/](hooks/)
|
|
11
|
+
Example hooks for intercepting tool calls, adding safety gates, and integrating with external systems.
|
|
12
|
+
|
|
13
|
+
### [custom-tools/](custom-tools/)
|
|
14
|
+
Example custom tools that extend the agent's capabilities.
|
|
15
|
+
|
|
16
|
+
## Running Examples
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
cd packages/coding-agent
|
|
20
|
+
npx tsx examples/sdk/01-minimal.ts
|
|
21
|
+
npx tsx examples/hooks/permission-gate.ts
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Documentation
|
|
25
|
+
|
|
26
|
+
- [SDK Reference](sdk/README.md)
|
|
27
|
+
- [Hooks Documentation](../docs/hooks.md)
|
|
28
|
+
- [Custom Tools Documentation](../docs/custom-tools.md)
|
|
29
|
+
- [Skills Documentation](../docs/skills.md)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal SDK Usage
|
|
3
|
+
*
|
|
4
|
+
* Uses all defaults: discovers skills, hooks, tools, context files
|
|
5
|
+
* from cwd and ~/.pi/agent. Model chosen from settings or first available.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { createAgentSession } from "../../src/index.js";
|
|
9
|
+
|
|
10
|
+
const { session } = await createAgentSession();
|
|
11
|
+
|
|
12
|
+
session.subscribe((event) => {
|
|
13
|
+
if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
|
|
14
|
+
process.stdout.write(event.assistantMessageEvent.delta);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
await session.prompt("What files are in the current directory?");
|
|
19
|
+
session.state.messages.forEach((msg) => {
|
|
20
|
+
console.log(msg);
|
|
21
|
+
});
|
|
22
|
+
console.log();
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom Model Selection
|
|
3
|
+
*
|
|
4
|
+
* Shows how to select a specific model and thinking level.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createAgentSession, findModel, discoverAvailableModels } from "../../src/index.js";
|
|
8
|
+
|
|
9
|
+
// Option 1: Find a specific model by provider/id
|
|
10
|
+
const { model: sonnet } = findModel("anthropic", "claude-sonnet-4-20250514");
|
|
11
|
+
if (sonnet) {
|
|
12
|
+
console.log(`Found model: ${sonnet.provider}/${sonnet.id}`);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Option 2: Pick from available models (have valid API keys)
|
|
16
|
+
const available = await discoverAvailableModels();
|
|
17
|
+
console.log(
|
|
18
|
+
"Available models:",
|
|
19
|
+
available.map((m) => `${m.provider}/${m.id}`),
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
if (available.length > 0) {
|
|
23
|
+
const { session } = await createAgentSession({
|
|
24
|
+
model: available[0],
|
|
25
|
+
thinkingLevel: "medium", // off, low, medium, high
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
session.subscribe((event) => {
|
|
29
|
+
if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
|
|
30
|
+
process.stdout.write(event.assistantMessageEvent.delta);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
await session.prompt("Say hello in one sentence.");
|
|
35
|
+
console.log();
|
|
36
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom System Prompt
|
|
3
|
+
*
|
|
4
|
+
* Shows how to replace or modify the default system prompt.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createAgentSession, SessionManager } from "../../src/index.js";
|
|
8
|
+
|
|
9
|
+
// Option 1: Replace prompt entirely
|
|
10
|
+
const { session: session1 } = await createAgentSession({
|
|
11
|
+
systemPrompt: `You are a helpful assistant that speaks like a pirate.
|
|
12
|
+
Always end responses with "Arrr!"`,
|
|
13
|
+
sessionManager: SessionManager.inMemory(),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
session1.subscribe((event) => {
|
|
17
|
+
if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
|
|
18
|
+
process.stdout.write(event.assistantMessageEvent.delta);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
console.log("=== Replace prompt ===");
|
|
23
|
+
await session1.prompt("What is 2 + 2?");
|
|
24
|
+
console.log("\n");
|
|
25
|
+
|
|
26
|
+
// Option 2: Modify default prompt (receives default, returns modified)
|
|
27
|
+
const { session: session2 } = await createAgentSession({
|
|
28
|
+
systemPrompt: (defaultPrompt) => `${defaultPrompt}
|
|
29
|
+
|
|
30
|
+
## Additional Instructions
|
|
31
|
+
- Always be concise
|
|
32
|
+
- Use bullet points when listing things`,
|
|
33
|
+
sessionManager: SessionManager.inMemory(),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
session2.subscribe((event) => {
|
|
37
|
+
if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
|
|
38
|
+
process.stdout.write(event.assistantMessageEvent.delta);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
console.log("=== Modify prompt ===");
|
|
43
|
+
await session2.prompt("List 3 benefits of TypeScript.");
|
|
44
|
+
console.log();
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills Configuration
|
|
3
|
+
*
|
|
4
|
+
* Skills provide specialized instructions loaded into the system prompt.
|
|
5
|
+
* Discover, filter, merge, or replace them.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { createAgentSession, discoverSkills, SessionManager, type Skill } from "../../src/index.js";
|
|
9
|
+
|
|
10
|
+
// Discover all skills from cwd/.pi/skills, ~/.pi/agent/skills, etc.
|
|
11
|
+
const allSkills = discoverSkills();
|
|
12
|
+
console.log(
|
|
13
|
+
"Discovered skills:",
|
|
14
|
+
allSkills.map((s) => s.name),
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
// Filter to specific skills
|
|
18
|
+
const filteredSkills = allSkills.filter((s) => s.name.includes("browser") || s.name.includes("search"));
|
|
19
|
+
|
|
20
|
+
// Or define custom skills inline
|
|
21
|
+
const customSkill: Skill = {
|
|
22
|
+
name: "my-skill",
|
|
23
|
+
description: "Custom project instructions",
|
|
24
|
+
filePath: "/virtual/SKILL.md",
|
|
25
|
+
baseDir: "/virtual",
|
|
26
|
+
source: "custom",
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Use filtered + custom skills
|
|
30
|
+
const { session } = await createAgentSession({
|
|
31
|
+
skills: [...filteredSkills, customSkill],
|
|
32
|
+
sessionManager: SessionManager.inMemory(),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
console.log(`Session created with ${filteredSkills.length + 1} skills`);
|
|
36
|
+
|
|
37
|
+
// To disable all skills:
|
|
38
|
+
// skills: []
|
|
39
|
+
|
|
40
|
+
// To use discovery with filtering via settings:
|
|
41
|
+
// discoverSkills(process.cwd(), undefined, {
|
|
42
|
+
// ignoredSkills: ["browser-tools"], // glob patterns to exclude
|
|
43
|
+
// includeSkills: ["brave-*"], // glob patterns to include (empty = all)
|
|
44
|
+
// })
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tools Configuration
|
|
3
|
+
*
|
|
4
|
+
* Use built-in tool sets, individual tools, or add custom tools.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Type } from "@sinclair/typebox";
|
|
8
|
+
import {
|
|
9
|
+
createAgentSession,
|
|
10
|
+
discoverCustomTools,
|
|
11
|
+
SessionManager,
|
|
12
|
+
codingTools, // read, bash, edit, write (default)
|
|
13
|
+
readOnlyTools, // read, bash
|
|
14
|
+
readTool,
|
|
15
|
+
bashTool,
|
|
16
|
+
grepTool,
|
|
17
|
+
type CustomAgentTool,
|
|
18
|
+
} from "../../src/index.js";
|
|
19
|
+
|
|
20
|
+
// Read-only mode (no edit/write)
|
|
21
|
+
const { session: readOnly } = await createAgentSession({
|
|
22
|
+
tools: readOnlyTools,
|
|
23
|
+
sessionManager: SessionManager.inMemory(),
|
|
24
|
+
});
|
|
25
|
+
console.log("Read-only session created");
|
|
26
|
+
|
|
27
|
+
// Custom tool selection
|
|
28
|
+
const { session: custom } = await createAgentSession({
|
|
29
|
+
tools: [readTool, bashTool, grepTool],
|
|
30
|
+
sessionManager: SessionManager.inMemory(),
|
|
31
|
+
});
|
|
32
|
+
console.log("Custom tools session created");
|
|
33
|
+
|
|
34
|
+
// Inline custom tool (needs TypeBox schema)
|
|
35
|
+
const weatherTool: CustomAgentTool = {
|
|
36
|
+
name: "get_weather",
|
|
37
|
+
label: "Get Weather",
|
|
38
|
+
description: "Get current weather for a city",
|
|
39
|
+
parameters: Type.Object({
|
|
40
|
+
city: Type.String({ description: "City name" }),
|
|
41
|
+
}),
|
|
42
|
+
execute: async (_toolCallId, params) => ({
|
|
43
|
+
content: [{ type: "text", text: `Weather in ${(params as { city: string }).city}: 22°C, sunny` }],
|
|
44
|
+
details: {},
|
|
45
|
+
}),
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const { session } = await createAgentSession({
|
|
49
|
+
customTools: [{ tool: weatherTool }],
|
|
50
|
+
sessionManager: SessionManager.inMemory(),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
session.subscribe((event) => {
|
|
54
|
+
if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
|
|
55
|
+
process.stdout.write(event.assistantMessageEvent.delta);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
await session.prompt("What's the weather in Tokyo?");
|
|
60
|
+
console.log();
|
|
61
|
+
|
|
62
|
+
// Merge with discovered tools from cwd/.pi/tools and ~/.pi/agent/tools:
|
|
63
|
+
// const discovered = await discoverCustomTools();
|
|
64
|
+
// customTools: [...discovered, { tool: myTool }]
|
|
65
|
+
|
|
66
|
+
// Or add paths without replacing discovery:
|
|
67
|
+
// additionalCustomToolPaths: ["/extra/tools"]
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hooks Configuration
|
|
3
|
+
*
|
|
4
|
+
* Hooks intercept agent events for logging, blocking, or modification.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createAgentSession, discoverHooks, SessionManager, type HookFactory } from "../../src/index.js";
|
|
8
|
+
|
|
9
|
+
// Logging hook
|
|
10
|
+
const loggingHook: HookFactory = (api) => {
|
|
11
|
+
api.on("agent_start", async () => {
|
|
12
|
+
console.log("[Hook] Agent starting");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
api.on("tool_call", async (event) => {
|
|
16
|
+
console.log(`[Hook] Tool: ${event.toolName}`);
|
|
17
|
+
return undefined; // Don't block
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
api.on("agent_end", async (event) => {
|
|
21
|
+
console.log(`[Hook] Done, ${event.messages.length} messages`);
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Blocking hook (returns { block: true, reason: "..." })
|
|
26
|
+
const safetyHook: HookFactory = (api) => {
|
|
27
|
+
api.on("tool_call", async (event) => {
|
|
28
|
+
if (event.toolName === "bash") {
|
|
29
|
+
const cmd = (event.input as { command?: string }).command ?? "";
|
|
30
|
+
if (cmd.includes("rm -rf")) {
|
|
31
|
+
return { block: true, reason: "Dangerous command blocked" };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// Use inline hooks
|
|
39
|
+
const { session } = await createAgentSession({
|
|
40
|
+
hooks: [{ factory: loggingHook }, { factory: safetyHook }],
|
|
41
|
+
sessionManager: SessionManager.inMemory(),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
session.subscribe((event) => {
|
|
45
|
+
if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
|
|
46
|
+
process.stdout.write(event.assistantMessageEvent.delta);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
await session.prompt("List files in the current directory.");
|
|
51
|
+
console.log();
|
|
52
|
+
|
|
53
|
+
// Disable all hooks:
|
|
54
|
+
// hooks: []
|
|
55
|
+
|
|
56
|
+
// Merge with discovered hooks:
|
|
57
|
+
// const discovered = await discoverHooks();
|
|
58
|
+
// hooks: [...discovered, { factory: myHook }]
|
|
59
|
+
|
|
60
|
+
// Add paths without replacing discovery:
|
|
61
|
+
// additionalHookPaths: ["/extra/hooks"]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Files (AGENTS.md)
|
|
3
|
+
*
|
|
4
|
+
* Context files provide project-specific instructions loaded into the system prompt.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createAgentSession, discoverContextFiles, SessionManager } from "../../src/index.js";
|
|
8
|
+
|
|
9
|
+
// Discover AGENTS.md files walking up from cwd
|
|
10
|
+
const discovered = discoverContextFiles();
|
|
11
|
+
console.log("Discovered context files:");
|
|
12
|
+
for (const file of discovered) {
|
|
13
|
+
console.log(` - ${file.path} (${file.content.length} chars)`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Use custom context files
|
|
17
|
+
const { session } = await createAgentSession({
|
|
18
|
+
contextFiles: [
|
|
19
|
+
...discovered,
|
|
20
|
+
{
|
|
21
|
+
path: "/virtual/AGENTS.md",
|
|
22
|
+
content: `# Project Guidelines
|
|
23
|
+
|
|
24
|
+
## Code Style
|
|
25
|
+
- Use TypeScript strict mode
|
|
26
|
+
- No any types
|
|
27
|
+
- Prefer const over let`,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
sessionManager: SessionManager.inMemory(),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
console.log(`Session created with ${discovered.length + 1} context files`);
|
|
34
|
+
|
|
35
|
+
// Disable context files:
|
|
36
|
+
// contextFiles: []
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slash Commands
|
|
3
|
+
*
|
|
4
|
+
* File-based commands that inject content when invoked with /commandname.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createAgentSession, discoverSlashCommands, SessionManager, type FileSlashCommand } from "../../src/index.js";
|
|
8
|
+
|
|
9
|
+
// Discover commands from cwd/.pi/commands/ and ~/.pi/agent/commands/
|
|
10
|
+
const discovered = discoverSlashCommands();
|
|
11
|
+
console.log("Discovered slash commands:");
|
|
12
|
+
for (const cmd of discovered) {
|
|
13
|
+
console.log(` /${cmd.name}: ${cmd.description}`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Define custom commands
|
|
17
|
+
const deployCommand: FileSlashCommand = {
|
|
18
|
+
name: "deploy",
|
|
19
|
+
description: "Deploy the application",
|
|
20
|
+
source: "(custom)",
|
|
21
|
+
content: `# Deploy Instructions
|
|
22
|
+
|
|
23
|
+
1. Build: npm run build
|
|
24
|
+
2. Test: npm test
|
|
25
|
+
3. Deploy: npm run deploy`,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Use discovered + custom commands
|
|
29
|
+
const { session } = await createAgentSession({
|
|
30
|
+
slashCommands: [...discovered, deployCommand],
|
|
31
|
+
sessionManager: SessionManager.inMemory(),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
console.log(`Session created with ${discovered.length + 1} slash commands`);
|
|
35
|
+
|
|
36
|
+
// Disable slash commands:
|
|
37
|
+
// slashCommands: []
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Keys and OAuth
|
|
3
|
+
*
|
|
4
|
+
* Configure API key resolution. Default checks: models.json, OAuth, env vars.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
createAgentSession,
|
|
9
|
+
configureOAuthStorage,
|
|
10
|
+
defaultGetApiKey,
|
|
11
|
+
SessionManager,
|
|
12
|
+
} from "../../src/index.js";
|
|
13
|
+
import { getAgentDir } from "../../src/config.js";
|
|
14
|
+
|
|
15
|
+
// Default: uses env vars (ANTHROPIC_API_KEY, etc.), OAuth, and models.json
|
|
16
|
+
const { session: defaultSession } = await createAgentSession({
|
|
17
|
+
sessionManager: SessionManager.inMemory(),
|
|
18
|
+
});
|
|
19
|
+
console.log("Session with default API key resolution");
|
|
20
|
+
|
|
21
|
+
// Custom resolver
|
|
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
|
+
},
|
|
31
|
+
sessionManager: SessionManager.inMemory(),
|
|
32
|
+
});
|
|
33
|
+
console.log("Session with custom API key resolver");
|
|
34
|
+
|
|
35
|
+
// Use OAuth from ~/.pi/agent while customizing everything else
|
|
36
|
+
configureOAuthStorage(getAgentDir()); // Must call before createAgentSession
|
|
37
|
+
|
|
38
|
+
const { session: hybridSession } = await createAgentSession({
|
|
39
|
+
agentDir: "/tmp/custom-config", // Custom config location
|
|
40
|
+
// But OAuth tokens still come from ~/.pi/agent/oauth.json
|
|
41
|
+
systemPrompt: "You are helpful.",
|
|
42
|
+
skills: [],
|
|
43
|
+
sessionManager: SessionManager.inMemory(),
|
|
44
|
+
});
|
|
45
|
+
console.log("Session with OAuth from default location, custom config elsewhere");
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings Configuration
|
|
3
|
+
*
|
|
4
|
+
* Override settings using SettingsManager.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createAgentSession, loadSettings, SessionManager, SettingsManager } from "../../src/index.js";
|
|
8
|
+
|
|
9
|
+
// Load current settings (merged global + project)
|
|
10
|
+
const settings = loadSettings();
|
|
11
|
+
console.log("Current settings:", JSON.stringify(settings, null, 2));
|
|
12
|
+
|
|
13
|
+
// Override specific settings
|
|
14
|
+
const settingsManager = SettingsManager.create();
|
|
15
|
+
settingsManager.applyOverrides({
|
|
16
|
+
compaction: { enabled: false },
|
|
17
|
+
retry: { enabled: true, maxRetries: 5, baseDelayMs: 1000 },
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const { session } = await createAgentSession({
|
|
21
|
+
settingsManager,
|
|
22
|
+
sessionManager: SessionManager.inMemory(),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
console.log("Session created with custom settings");
|
|
26
|
+
|
|
27
|
+
// For testing without file I/O:
|
|
28
|
+
const inMemorySettings = SettingsManager.inMemory({
|
|
29
|
+
compaction: { enabled: false },
|
|
30
|
+
retry: { enabled: false },
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const { session: testSession } = await createAgentSession({
|
|
34
|
+
settingsManager: inMemorySettings,
|
|
35
|
+
sessionManager: SessionManager.inMemory(),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
console.log("Test session created with in-memory settings");
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Management
|
|
3
|
+
*
|
|
4
|
+
* Control session persistence: in-memory, new file, continue, or open specific.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createAgentSession, SessionManager } from "../../src/index.js";
|
|
8
|
+
|
|
9
|
+
// In-memory (no persistence)
|
|
10
|
+
const { session: inMemory } = await createAgentSession({
|
|
11
|
+
sessionManager: SessionManager.inMemory(),
|
|
12
|
+
});
|
|
13
|
+
console.log("In-memory session:", inMemory.sessionFile ?? "(none)");
|
|
14
|
+
|
|
15
|
+
// New persistent session
|
|
16
|
+
const { session: newSession } = await createAgentSession({
|
|
17
|
+
sessionManager: SessionManager.create(process.cwd()),
|
|
18
|
+
});
|
|
19
|
+
console.log("New session file:", newSession.sessionFile);
|
|
20
|
+
|
|
21
|
+
// Continue most recent session (or create new if none)
|
|
22
|
+
const { session: continued, modelFallbackMessage } = await createAgentSession({
|
|
23
|
+
sessionManager: SessionManager.continueRecent(process.cwd()),
|
|
24
|
+
});
|
|
25
|
+
if (modelFallbackMessage) console.log("Note:", modelFallbackMessage);
|
|
26
|
+
console.log("Continued session:", continued.sessionFile);
|
|
27
|
+
|
|
28
|
+
// List and open specific session
|
|
29
|
+
const sessions = SessionManager.list(process.cwd());
|
|
30
|
+
console.log(`\nFound ${sessions.length} sessions:`);
|
|
31
|
+
for (const info of sessions.slice(0, 3)) {
|
|
32
|
+
console.log(` ${info.id.slice(0, 8)}... - "${info.firstMessage.slice(0, 30)}..."`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (sessions.length > 0) {
|
|
36
|
+
const { session: opened } = await createAgentSession({
|
|
37
|
+
sessionManager: SessionManager.open(sessions[0].path),
|
|
38
|
+
});
|
|
39
|
+
console.log(`\nOpened: ${opened.sessionId}`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Custom session directory
|
|
43
|
+
// const { session } = await createAgentSession({
|
|
44
|
+
// agentDir: "/custom/agent",
|
|
45
|
+
// sessionManager: SessionManager.create(process.cwd(), "/custom/agent"),
|
|
46
|
+
// });
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Full Control
|
|
3
|
+
*
|
|
4
|
+
* Replace everything - no discovery, explicit configuration.
|
|
5
|
+
* Still uses OAuth from ~/.pi/agent for convenience.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Type } from "@sinclair/typebox";
|
|
9
|
+
import {
|
|
10
|
+
createAgentSession,
|
|
11
|
+
configureOAuthStorage,
|
|
12
|
+
defaultGetApiKey,
|
|
13
|
+
findModel,
|
|
14
|
+
SessionManager,
|
|
15
|
+
SettingsManager,
|
|
16
|
+
readTool,
|
|
17
|
+
bashTool,
|
|
18
|
+
type HookFactory,
|
|
19
|
+
type CustomAgentTool,
|
|
20
|
+
} from "../../src/index.js";
|
|
21
|
+
import { getAgentDir } from "../../src/config.js";
|
|
22
|
+
|
|
23
|
+
// Use OAuth from default location
|
|
24
|
+
configureOAuthStorage(getAgentDir());
|
|
25
|
+
|
|
26
|
+
// Custom API key with fallback
|
|
27
|
+
const getApiKey = async (model: { provider: string }) => {
|
|
28
|
+
if (model.provider === "anthropic" && process.env.MY_ANTHROPIC_KEY) {
|
|
29
|
+
return process.env.MY_ANTHROPIC_KEY;
|
|
30
|
+
}
|
|
31
|
+
return defaultGetApiKey()(model as any);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// Inline hook
|
|
35
|
+
const auditHook: HookFactory = (api) => {
|
|
36
|
+
api.on("tool_call", async (event) => {
|
|
37
|
+
console.log(`[Audit] ${event.toolName}`);
|
|
38
|
+
return undefined;
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Inline custom tool
|
|
43
|
+
const statusTool: CustomAgentTool = {
|
|
44
|
+
name: "status",
|
|
45
|
+
label: "Status",
|
|
46
|
+
description: "Get system status",
|
|
47
|
+
parameters: Type.Object({}),
|
|
48
|
+
execute: async () => ({
|
|
49
|
+
content: [{ type: "text", text: `Uptime: ${process.uptime()}s, Node: ${process.version}` }],
|
|
50
|
+
details: {},
|
|
51
|
+
}),
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const { model } = findModel("anthropic", "claude-sonnet-4-20250514");
|
|
55
|
+
if (!model) throw new Error("Model not found");
|
|
56
|
+
|
|
57
|
+
// In-memory settings with overrides
|
|
58
|
+
const settingsManager = SettingsManager.inMemory({
|
|
59
|
+
compaction: { enabled: false },
|
|
60
|
+
retry: { enabled: true, maxRetries: 2 },
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const { session } = await createAgentSession({
|
|
64
|
+
cwd: process.cwd(),
|
|
65
|
+
agentDir: "/tmp/my-agent",
|
|
66
|
+
|
|
67
|
+
model,
|
|
68
|
+
thinkingLevel: "off",
|
|
69
|
+
getApiKey,
|
|
70
|
+
|
|
71
|
+
systemPrompt: `You are a minimal assistant.
|
|
72
|
+
Available: read, bash, status. Be concise.`,
|
|
73
|
+
|
|
74
|
+
tools: [readTool, bashTool],
|
|
75
|
+
customTools: [{ tool: statusTool }],
|
|
76
|
+
hooks: [{ factory: auditHook }],
|
|
77
|
+
skills: [],
|
|
78
|
+
contextFiles: [],
|
|
79
|
+
slashCommands: [],
|
|
80
|
+
sessionManager: SessionManager.inMemory(),
|
|
81
|
+
settingsManager,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
session.subscribe((event) => {
|
|
85
|
+
if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
|
|
86
|
+
process.stdout.write(event.assistantMessageEvent.delta);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
await session.prompt("Get status and list files.");
|
|
91
|
+
console.log();
|