@mariozechner/pi-coding-agent 0.25.4 → 0.26.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.
Files changed (118) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +47 -5
  3. package/dist/cli/file-processor.d.ts.map +1 -1
  4. package/dist/cli/file-processor.js +1 -1
  5. package/dist/cli/file-processor.js.map +1 -1
  6. package/dist/cli/session-picker.d.ts +2 -2
  7. package/dist/cli/session-picker.d.ts.map +1 -1
  8. package/dist/cli/session-picker.js +2 -2
  9. package/dist/cli/session-picker.js.map +1 -1
  10. package/dist/core/agent-session.d.ts.map +1 -1
  11. package/dist/core/agent-session.js +1 -13
  12. package/dist/core/agent-session.js.map +1 -1
  13. package/dist/core/custom-tools/loader.d.ts +3 -2
  14. package/dist/core/custom-tools/loader.d.ts.map +1 -1
  15. package/dist/core/custom-tools/loader.js +5 -4
  16. package/dist/core/custom-tools/loader.js.map +1 -1
  17. package/dist/core/hooks/loader.d.ts +2 -5
  18. package/dist/core/hooks/loader.d.ts.map +1 -1
  19. package/dist/core/hooks/loader.js +4 -7
  20. package/dist/core/hooks/loader.js.map +1 -1
  21. package/dist/core/model-config.d.ts +5 -4
  22. package/dist/core/model-config.d.ts.map +1 -1
  23. package/dist/core/model-config.js +12 -19
  24. package/dist/core/model-config.js.map +1 -1
  25. package/dist/core/sdk.d.ts +211 -0
  26. package/dist/core/sdk.d.ts.map +1 -0
  27. package/dist/core/sdk.js +466 -0
  28. package/dist/core/sdk.js.map +1 -0
  29. package/dist/core/session-manager.d.ts +31 -91
  30. package/dist/core/session-manager.d.ts.map +1 -1
  31. package/dist/core/session-manager.js +187 -352
  32. package/dist/core/session-manager.js.map +1 -1
  33. package/dist/core/settings-manager.d.ts +12 -2
  34. package/dist/core/settings-manager.d.ts.map +1 -1
  35. package/dist/core/settings-manager.js +101 -37
  36. package/dist/core/settings-manager.js.map +1 -1
  37. package/dist/core/skills.d.ts +7 -1
  38. package/dist/core/skills.d.ts.map +1 -1
  39. package/dist/core/skills.js +7 -5
  40. package/dist/core/skills.js.map +1 -1
  41. package/dist/core/slash-commands.d.ts +9 -3
  42. package/dist/core/slash-commands.d.ts.map +1 -1
  43. package/dist/core/slash-commands.js +10 -7
  44. package/dist/core/slash-commands.js.map +1 -1
  45. package/dist/core/system-prompt.d.ts +24 -2
  46. package/dist/core/system-prompt.d.ts.map +1 -1
  47. package/dist/core/system-prompt.js +18 -16
  48. package/dist/core/system-prompt.js.map +1 -1
  49. package/dist/core/tools/bash.d.ts +6 -1
  50. package/dist/core/tools/bash.d.ts.map +1 -1
  51. package/dist/core/tools/bash.js +149 -144
  52. package/dist/core/tools/bash.js.map +1 -1
  53. package/dist/core/tools/edit.d.ts +7 -1
  54. package/dist/core/tools/edit.d.ts.map +1 -1
  55. package/dist/core/tools/edit.js +105 -102
  56. package/dist/core/tools/edit.js.map +1 -1
  57. package/dist/core/tools/find.d.ts +7 -1
  58. package/dist/core/tools/find.d.ts.map +1 -1
  59. package/dist/core/tools/find.js +128 -124
  60. package/dist/core/tools/find.js.map +1 -1
  61. package/dist/core/tools/grep.d.ts +11 -1
  62. package/dist/core/tools/grep.d.ts.map +1 -1
  63. package/dist/core/tools/grep.js +198 -194
  64. package/dist/core/tools/grep.js.map +1 -1
  65. package/dist/core/tools/index.d.ts +31 -29
  66. package/dist/core/tools/index.d.ts.map +1 -1
  67. package/dist/core/tools/index.js +44 -16
  68. package/dist/core/tools/index.js.map +1 -1
  69. package/dist/core/tools/ls.d.ts +6 -1
  70. package/dist/core/tools/ls.d.ts.map +1 -1
  71. package/dist/core/tools/ls.js +90 -86
  72. package/dist/core/tools/ls.js.map +1 -1
  73. package/dist/core/tools/path-utils.d.ts +6 -1
  74. package/dist/core/tools/path-utils.d.ts.map +1 -1
  75. package/dist/core/tools/path-utils.js +17 -5
  76. package/dist/core/tools/path-utils.js.map +1 -1
  77. package/dist/core/tools/read.d.ts +7 -1
  78. package/dist/core/tools/read.d.ts.map +1 -1
  79. package/dist/core/tools/read.js +118 -115
  80. package/dist/core/tools/read.js.map +1 -1
  81. package/dist/core/tools/write.d.ts +6 -1
  82. package/dist/core/tools/write.d.ts.map +1 -1
  83. package/dist/core/tools/write.js +63 -59
  84. package/dist/core/tools/write.js.map +1 -1
  85. package/dist/index.d.ts +2 -1
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +14 -0
  88. package/dist/index.js.map +1 -1
  89. package/dist/main.d.ts +4 -1
  90. package/dist/main.d.ts.map +1 -1
  91. package/dist/main.js +142 -312
  92. package/dist/main.js.map +1 -1
  93. package/dist/modes/interactive/components/session-selector.d.ts +3 -12
  94. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  95. package/dist/modes/interactive/components/session-selector.js +1 -3
  96. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  97. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  98. package/dist/modes/interactive/interactive-mode.js +3 -2
  99. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  100. package/dist/utils/shell.d.ts.map +1 -1
  101. package/dist/utils/shell.js +1 -1
  102. package/dist/utils/shell.js.map +1 -1
  103. package/docs/sdk.md +864 -0
  104. package/examples/README.md +29 -0
  105. package/examples/sdk/01-minimal.ts +22 -0
  106. package/examples/sdk/02-custom-model.ts +36 -0
  107. package/examples/sdk/03-custom-prompt.ts +44 -0
  108. package/examples/sdk/04-skills.ts +44 -0
  109. package/examples/sdk/05-tools.ts +93 -0
  110. package/examples/sdk/06-hooks.ts +61 -0
  111. package/examples/sdk/07-context-files.ts +36 -0
  112. package/examples/sdk/08-slash-commands.ts +37 -0
  113. package/examples/sdk/09-api-keys-and-oauth.ts +45 -0
  114. package/examples/sdk/10-settings.ts +38 -0
  115. package/examples/sdk/11-sessions.ts +46 -0
  116. package/examples/sdk/12-full-control.ts +99 -0
  117. package/examples/sdk/README.md +138 -0
  118. 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,93 @@
1
+ /**
2
+ * Tools Configuration
3
+ *
4
+ * Use built-in tool sets, individual tools, or add custom tools.
5
+ *
6
+ * IMPORTANT: When using a custom `cwd`, you must use the tool factory functions
7
+ * (createCodingTools, createReadOnlyTools, createReadTool, etc.) to ensure
8
+ * tools resolve paths relative to your cwd, not process.cwd().
9
+ */
10
+
11
+ import { Type } from "@sinclair/typebox";
12
+ import {
13
+ 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
+ createBashTool,
22
+ createGrepTool,
23
+ readTool,
24
+ bashTool,
25
+ grepTool,
26
+ type CustomAgentTool,
27
+ } from "../../src/index.js";
28
+
29
+ // Read-only mode (no edit/write) - uses process.cwd()
30
+ const { session: readOnly } = await createAgentSession({
31
+ tools: readOnlyTools,
32
+ sessionManager: SessionManager.inMemory(),
33
+ });
34
+ console.log("Read-only session created");
35
+
36
+ // Custom tool selection - uses process.cwd()
37
+ const { session: custom } = await createAgentSession({
38
+ tools: [readTool, bashTool, grepTool],
39
+ sessionManager: SessionManager.inMemory(),
40
+ });
41
+ console.log("Custom tools session created");
42
+
43
+ // With custom cwd - MUST use factory functions!
44
+ const customCwd = "/path/to/project";
45
+ const { session: customCwdSession } = await createAgentSession({
46
+ cwd: customCwd,
47
+ tools: createCodingTools(customCwd), // Tools resolve paths relative to customCwd
48
+ sessionManager: SessionManager.inMemory(),
49
+ });
50
+ console.log("Custom cwd session created");
51
+
52
+ // Or pick specific tools for custom cwd
53
+ const { session: specificTools } = await createAgentSession({
54
+ cwd: customCwd,
55
+ tools: [createReadTool(customCwd), createBashTool(customCwd), createGrepTool(customCwd)],
56
+ sessionManager: SessionManager.inMemory(),
57
+ });
58
+ console.log("Specific tools with custom cwd session created");
59
+
60
+ // Inline custom tool (needs TypeBox schema)
61
+ const weatherTool: CustomAgentTool = {
62
+ name: "get_weather",
63
+ label: "Get Weather",
64
+ description: "Get current weather for a city",
65
+ parameters: Type.Object({
66
+ city: Type.String({ description: "City name" }),
67
+ }),
68
+ execute: async (_toolCallId, params) => ({
69
+ content: [{ type: "text", text: `Weather in ${(params as { city: string }).city}: 22°C, sunny` }],
70
+ details: {},
71
+ }),
72
+ };
73
+
74
+ const { session } = await createAgentSession({
75
+ customTools: [{ tool: weatherTool }],
76
+ sessionManager: SessionManager.inMemory(),
77
+ });
78
+
79
+ session.subscribe((event) => {
80
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
81
+ process.stdout.write(event.assistantMessageEvent.delta);
82
+ }
83
+ });
84
+
85
+ await session.prompt("What's the weather in Tokyo?");
86
+ console.log();
87
+
88
+ // Merge with discovered tools from cwd/.pi/tools and ~/.pi/agent/tools:
89
+ // const discovered = await discoverCustomTools();
90
+ // customTools: [...discovered, { tool: myTool }]
91
+
92
+ // Or add paths without replacing discovery:
93
+ // 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,99 @@
1
+ /**
2
+ * Full Control
3
+ *
4
+ * Replace everything - no discovery, explicit configuration.
5
+ * Still uses OAuth from ~/.pi/agent for convenience.
6
+ *
7
+ * IMPORTANT: When providing `tools` with a custom `cwd`, use the tool factory
8
+ * functions (createReadTool, createBashTool, etc.) to ensure tools resolve
9
+ * paths relative to your cwd.
10
+ */
11
+
12
+ import { Type } from "@sinclair/typebox";
13
+ import {
14
+ createAgentSession,
15
+ configureOAuthStorage,
16
+ defaultGetApiKey,
17
+ findModel,
18
+ SessionManager,
19
+ SettingsManager,
20
+ createReadTool,
21
+ createBashTool,
22
+ type HookFactory,
23
+ type CustomAgentTool,
24
+ } from "../../src/index.js";
25
+ import { getAgentDir } from "../../src/config.js";
26
+
27
+ // Use OAuth from default location
28
+ configureOAuthStorage(getAgentDir());
29
+
30
+ // Custom API key with fallback
31
+ const getApiKey = async (model: { provider: string }) => {
32
+ if (model.provider === "anthropic" && process.env.MY_ANTHROPIC_KEY) {
33
+ return process.env.MY_ANTHROPIC_KEY;
34
+ }
35
+ return defaultGetApiKey()(model as any);
36
+ };
37
+
38
+ // Inline hook
39
+ const auditHook: HookFactory = (api) => {
40
+ api.on("tool_call", async (event) => {
41
+ console.log(`[Audit] ${event.toolName}`);
42
+ return undefined;
43
+ });
44
+ };
45
+
46
+ // Inline custom tool
47
+ const statusTool: CustomAgentTool = {
48
+ name: "status",
49
+ label: "Status",
50
+ description: "Get system status",
51
+ parameters: Type.Object({}),
52
+ execute: async () => ({
53
+ content: [{ type: "text", text: `Uptime: ${process.uptime()}s, Node: ${process.version}` }],
54
+ details: {},
55
+ }),
56
+ };
57
+
58
+ const { model } = findModel("anthropic", "claude-sonnet-4-20250514");
59
+ if (!model) throw new Error("Model not found");
60
+
61
+ // In-memory settings with overrides
62
+ const settingsManager = SettingsManager.inMemory({
63
+ compaction: { enabled: false },
64
+ retry: { enabled: true, maxRetries: 2 },
65
+ });
66
+
67
+ // When using a custom cwd with explicit tools, use the factory functions
68
+ const cwd = process.cwd();
69
+
70
+ const { session } = await createAgentSession({
71
+ cwd,
72
+ agentDir: "/tmp/my-agent",
73
+
74
+ model,
75
+ thinkingLevel: "off",
76
+ getApiKey,
77
+
78
+ systemPrompt: `You are a minimal assistant.
79
+ Available: read, bash, status. Be concise.`,
80
+
81
+ // Use factory functions with the same cwd to ensure path resolution works correctly
82
+ tools: [createReadTool(cwd), createBashTool(cwd)],
83
+ customTools: [{ tool: statusTool }],
84
+ hooks: [{ factory: auditHook }],
85
+ skills: [],
86
+ contextFiles: [],
87
+ slashCommands: [],
88
+ sessionManager: SessionManager.inMemory(),
89
+ settingsManager,
90
+ });
91
+
92
+ session.subscribe((event) => {
93
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
94
+ process.stdout.write(event.assistantMessageEvent.delta);
95
+ }
96
+ });
97
+
98
+ await session.prompt("Get status and list files.");
99
+ console.log();