@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.
Files changed (125) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +47 -5
  3. package/dist/cli/session-picker.d.ts +2 -2
  4. package/dist/cli/session-picker.d.ts.map +1 -1
  5. package/dist/cli/session-picker.js +2 -2
  6. package/dist/cli/session-picker.js.map +1 -1
  7. package/dist/core/agent-session.d.ts.map +1 -1
  8. package/dist/core/agent-session.js +1 -13
  9. package/dist/core/agent-session.js.map +1 -1
  10. package/dist/core/compaction.d.ts.map +1 -1
  11. package/dist/core/compaction.js +1 -1
  12. package/dist/core/compaction.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/export-html.d.ts.map +1 -1
  18. package/dist/core/export-html.js +1 -1
  19. package/dist/core/export-html.js.map +1 -1
  20. package/dist/core/hooks/loader.d.ts +2 -5
  21. package/dist/core/hooks/loader.d.ts.map +1 -1
  22. package/dist/core/hooks/loader.js +4 -7
  23. package/dist/core/hooks/loader.js.map +1 -1
  24. package/dist/core/messages.d.ts.map +1 -1
  25. package/dist/core/messages.js +1 -1
  26. package/dist/core/messages.js.map +1 -1
  27. package/dist/core/model-config.d.ts +5 -4
  28. package/dist/core/model-config.d.ts.map +1 -1
  29. package/dist/core/model-config.js +12 -19
  30. package/dist/core/model-config.js.map +1 -1
  31. package/dist/core/sdk.d.ts +211 -0
  32. package/dist/core/sdk.d.ts.map +1 -0
  33. package/dist/core/sdk.js +462 -0
  34. package/dist/core/sdk.js.map +1 -0
  35. package/dist/core/session-manager.d.ts +31 -91
  36. package/dist/core/session-manager.d.ts.map +1 -1
  37. package/dist/core/session-manager.js +188 -353
  38. package/dist/core/session-manager.js.map +1 -1
  39. package/dist/core/settings-manager.d.ts +12 -2
  40. package/dist/core/settings-manager.d.ts.map +1 -1
  41. package/dist/core/settings-manager.js +101 -37
  42. package/dist/core/settings-manager.js.map +1 -1
  43. package/dist/core/skills.d.ts +7 -1
  44. package/dist/core/skills.d.ts.map +1 -1
  45. package/dist/core/skills.js +7 -5
  46. package/dist/core/skills.js.map +1 -1
  47. package/dist/core/slash-commands.d.ts +9 -3
  48. package/dist/core/slash-commands.d.ts.map +1 -1
  49. package/dist/core/slash-commands.js +12 -9
  50. package/dist/core/slash-commands.js.map +1 -1
  51. package/dist/core/system-prompt.d.ts +24 -2
  52. package/dist/core/system-prompt.d.ts.map +1 -1
  53. package/dist/core/system-prompt.js +18 -16
  54. package/dist/core/system-prompt.js.map +1 -1
  55. package/dist/core/tools/grep.d.ts.map +1 -1
  56. package/dist/core/tools/grep.js +1 -1
  57. package/dist/core/tools/grep.js.map +1 -1
  58. package/dist/core/tools/index.d.ts +12 -22
  59. package/dist/core/tools/index.d.ts.map +1 -1
  60. package/dist/core/tools/index.js +2 -0
  61. package/dist/core/tools/index.js.map +1 -1
  62. package/dist/core/tools/read.d.ts.map +1 -1
  63. package/dist/core/tools/read.js +0 -1
  64. package/dist/core/tools/read.js.map +1 -1
  65. package/dist/core/tools/truncate.d.ts.map +1 -1
  66. package/dist/core/tools/truncate.js +1 -1
  67. package/dist/core/tools/truncate.js.map +1 -1
  68. package/dist/index.d.ts +2 -1
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +12 -0
  71. package/dist/index.js.map +1 -1
  72. package/dist/main.d.ts +4 -1
  73. package/dist/main.d.ts.map +1 -1
  74. package/dist/main.js +142 -312
  75. package/dist/main.js.map +1 -1
  76. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  77. package/dist/modes/interactive/components/armin.js +2 -2
  78. package/dist/modes/interactive/components/armin.js.map +1 -1
  79. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  80. package/dist/modes/interactive/components/bash-execution.js +3 -3
  81. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  82. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  83. package/dist/modes/interactive/components/footer.js +6 -6
  84. package/dist/modes/interactive/components/footer.js.map +1 -1
  85. package/dist/modes/interactive/components/hook-selector.d.ts.map +1 -1
  86. package/dist/modes/interactive/components/hook-selector.js +1 -1
  87. package/dist/modes/interactive/components/hook-selector.js.map +1 -1
  88. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  89. package/dist/modes/interactive/components/model-selector.js +2 -2
  90. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  91. package/dist/modes/interactive/components/session-selector.d.ts +3 -12
  92. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  93. package/dist/modes/interactive/components/session-selector.js +1 -3
  94. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  95. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  96. package/dist/modes/interactive/components/tool-execution.js +14 -14
  97. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  98. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  99. package/dist/modes/interactive/interactive-mode.js +7 -6
  100. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  101. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  102. package/dist/modes/interactive/theme/theme.js +10 -6
  103. package/dist/modes/interactive/theme/theme.js.map +1 -1
  104. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  105. package/dist/modes/rpc/rpc-client.js +1 -1
  106. package/dist/modes/rpc/rpc-client.js.map +1 -1
  107. package/dist/utils/shell.d.ts.map +1 -1
  108. package/dist/utils/shell.js +2 -2
  109. package/dist/utils/shell.js.map +1 -1
  110. package/docs/sdk.md +819 -0
  111. package/examples/README.md +29 -0
  112. package/examples/sdk/01-minimal.ts +22 -0
  113. package/examples/sdk/02-custom-model.ts +36 -0
  114. package/examples/sdk/03-custom-prompt.ts +44 -0
  115. package/examples/sdk/04-skills.ts +44 -0
  116. package/examples/sdk/05-tools.ts +67 -0
  117. package/examples/sdk/06-hooks.ts +61 -0
  118. package/examples/sdk/07-context-files.ts +36 -0
  119. package/examples/sdk/08-slash-commands.ts +37 -0
  120. package/examples/sdk/09-api-keys-and-oauth.ts +45 -0
  121. package/examples/sdk/10-settings.ts +38 -0
  122. package/examples/sdk/11-sessions.ts +46 -0
  123. package/examples/sdk/12-full-control.ts +91 -0
  124. package/examples/sdk/README.md +138 -0
  125. 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();