From 56121dcac1b85334d24051196909e9003807db9c Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Mon, 22 Dec 2025 03:14:30 +0100 Subject: [PATCH] Add SDK usage examples 12 examples showing increasing levels of customization: - 01-minimal: all defaults - 02-custom-model: model and thinking level - 03-custom-prompt: replace or modify prompt - 04-skills: discover, filter, merge skills - 05-tools: built-in tools, custom tools - 06-hooks: logging, blocking, result modification - 07-context-files: AGENTS.md files - 08-slash-commands: file-based commands - 09-api-keys-and-oauth: API key resolution, OAuth config - 10-settings: compaction, retry, terminal settings - 11-sessions: persistence options - 12-full-control: replace everything Also exports FileSlashCommand type from index.ts --- packages/coding-agent/examples/README.md | 29 ++++ .../coding-agent/examples/sdk/01-minimal.ts | 22 +++ .../examples/sdk/02-custom-model.ts | 36 +++++ .../examples/sdk/03-custom-prompt.ts | 44 ++++++ .../coding-agent/examples/sdk/04-skills.ts | 44 ++++++ .../coding-agent/examples/sdk/05-tools.ts | 67 +++++++++ .../coding-agent/examples/sdk/06-hooks.ts | 61 ++++++++ .../examples/sdk/07-context-files.ts | 36 +++++ .../examples/sdk/08-slash-commands.ts | 37 +++++ .../examples/sdk/09-api-keys-and-oauth.ts | 45 ++++++ .../coding-agent/examples/sdk/10-settings.ts | 33 +++++ .../coding-agent/examples/sdk/11-sessions.ts | 46 ++++++ .../examples/sdk/12-full-control.ts | 84 +++++++++++ packages/coding-agent/examples/sdk/README.md | 138 ++++++++++++++++++ packages/coding-agent/src/index.ts | 1 + 15 files changed, 723 insertions(+) create mode 100644 packages/coding-agent/examples/README.md create mode 100644 packages/coding-agent/examples/sdk/01-minimal.ts create mode 100644 packages/coding-agent/examples/sdk/02-custom-model.ts create mode 100644 packages/coding-agent/examples/sdk/03-custom-prompt.ts create mode 100644 packages/coding-agent/examples/sdk/04-skills.ts create mode 100644 packages/coding-agent/examples/sdk/05-tools.ts create mode 100644 packages/coding-agent/examples/sdk/06-hooks.ts create mode 100644 packages/coding-agent/examples/sdk/07-context-files.ts create mode 100644 packages/coding-agent/examples/sdk/08-slash-commands.ts create mode 100644 packages/coding-agent/examples/sdk/09-api-keys-and-oauth.ts create mode 100644 packages/coding-agent/examples/sdk/10-settings.ts create mode 100644 packages/coding-agent/examples/sdk/11-sessions.ts create mode 100644 packages/coding-agent/examples/sdk/12-full-control.ts create mode 100644 packages/coding-agent/examples/sdk/README.md diff --git a/packages/coding-agent/examples/README.md b/packages/coding-agent/examples/README.md new file mode 100644 index 00000000..9b9ba0c6 --- /dev/null +++ b/packages/coding-agent/examples/README.md @@ -0,0 +1,29 @@ +# Examples + +Example code for pi-coding-agent. + +## Directories + +### [sdk/](sdk/) +Programmatic usage via `createAgentSession()`. Shows how to customize models, prompts, tools, hooks, and session management. + +### [hooks/](hooks/) +Example hooks for intercepting tool calls, adding safety gates, and integrating with external systems. + +### [custom-tools/](custom-tools/) +Example custom tools that extend the agent's capabilities. + +## Running Examples + +```bash +cd packages/coding-agent +npx tsx examples/sdk/01-minimal.ts +npx tsx examples/hooks/permission-gate.ts +``` + +## Documentation + +- [SDK Reference](sdk/README.md) +- [Hooks Documentation](../docs/hooks.md) +- [Custom Tools Documentation](../docs/custom-tools.md) +- [Skills Documentation](../docs/skills.md) diff --git a/packages/coding-agent/examples/sdk/01-minimal.ts b/packages/coding-agent/examples/sdk/01-minimal.ts new file mode 100644 index 00000000..b257fccc --- /dev/null +++ b/packages/coding-agent/examples/sdk/01-minimal.ts @@ -0,0 +1,22 @@ +/** + * Minimal SDK Usage + * + * Uses all defaults: discovers skills, hooks, tools, context files + * from cwd and ~/.pi/agent. Model chosen from settings or first available. + */ + +import { createAgentSession } from "../../src/index.js"; + +const { session } = await createAgentSession(); + +session.subscribe((event) => { + if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") { + process.stdout.write(event.assistantMessageEvent.delta); + } +}); + +await session.prompt("What files are in the current directory?"); +session.state.messages.forEach((msg) => { + console.log(msg); +}); +console.log(); diff --git a/packages/coding-agent/examples/sdk/02-custom-model.ts b/packages/coding-agent/examples/sdk/02-custom-model.ts new file mode 100644 index 00000000..4a2690da --- /dev/null +++ b/packages/coding-agent/examples/sdk/02-custom-model.ts @@ -0,0 +1,36 @@ +/** + * Custom Model Selection + * + * Shows how to select a specific model and thinking level. + */ + +import { createAgentSession, findModel, discoverAvailableModels } from "../../src/index.js"; + +// Option 1: Find a specific model by provider/id +const { model: sonnet } = findModel("anthropic", "claude-sonnet-4-20250514"); +if (sonnet) { + console.log(`Found model: ${sonnet.provider}/${sonnet.id}`); +} + +// Option 2: Pick from available models (have valid API keys) +const available = await discoverAvailableModels(); +console.log( + "Available models:", + available.map((m) => `${m.provider}/${m.id}`), +); + +if (available.length > 0) { + const { session } = await createAgentSession({ + model: available[0], + thinkingLevel: "medium", // off, low, medium, high + }); + + session.subscribe((event) => { + if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") { + process.stdout.write(event.assistantMessageEvent.delta); + } + }); + + await session.prompt("Say hello in one sentence."); + console.log(); +} diff --git a/packages/coding-agent/examples/sdk/03-custom-prompt.ts b/packages/coding-agent/examples/sdk/03-custom-prompt.ts new file mode 100644 index 00000000..9f19d67c --- /dev/null +++ b/packages/coding-agent/examples/sdk/03-custom-prompt.ts @@ -0,0 +1,44 @@ +/** + * Custom System Prompt + * + * Shows how to replace or modify the default system prompt. + */ + +import { createAgentSession, SessionManager } from "../../src/index.js"; + +// Option 1: Replace prompt entirely +const { session: session1 } = await createAgentSession({ + systemPrompt: `You are a helpful assistant that speaks like a pirate. +Always end responses with "Arrr!"`, + sessionManager: SessionManager.inMemory(), +}); + +session1.subscribe((event) => { + if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") { + process.stdout.write(event.assistantMessageEvent.delta); + } +}); + +console.log("=== Replace prompt ==="); +await session1.prompt("What is 2 + 2?"); +console.log("\n"); + +// Option 2: Modify default prompt (receives default, returns modified) +const { session: session2 } = await createAgentSession({ + systemPrompt: (defaultPrompt) => `${defaultPrompt} + +## Additional Instructions +- Always be concise +- Use bullet points when listing things`, + sessionManager: SessionManager.inMemory(), +}); + +session2.subscribe((event) => { + if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") { + process.stdout.write(event.assistantMessageEvent.delta); + } +}); + +console.log("=== Modify prompt ==="); +await session2.prompt("List 3 benefits of TypeScript."); +console.log(); diff --git a/packages/coding-agent/examples/sdk/04-skills.ts b/packages/coding-agent/examples/sdk/04-skills.ts new file mode 100644 index 00000000..f4a3babd --- /dev/null +++ b/packages/coding-agent/examples/sdk/04-skills.ts @@ -0,0 +1,44 @@ +/** + * Skills Configuration + * + * Skills provide specialized instructions loaded into the system prompt. + * Discover, filter, merge, or replace them. + */ + +import { createAgentSession, discoverSkills, SessionManager, type Skill } from "../../src/index.js"; + +// Discover all skills from cwd/.pi/skills, ~/.pi/agent/skills, etc. +const allSkills = discoverSkills(); +console.log( + "Discovered skills:", + allSkills.map((s) => s.name), +); + +// Filter to specific skills +const filteredSkills = allSkills.filter((s) => s.name.includes("browser") || s.name.includes("search")); + +// Or define custom skills inline +const customSkill: Skill = { + name: "my-skill", + description: "Custom project instructions", + filePath: "/virtual/SKILL.md", + baseDir: "/virtual", + source: "custom", +}; + +// Use filtered + custom skills +const { session } = await createAgentSession({ + skills: [...filteredSkills, customSkill], + sessionManager: SessionManager.inMemory(), +}); + +console.log(`Session created with ${filteredSkills.length + 1} skills`); + +// To disable all skills: +// skills: [] + +// To use discovery with filtering via settings: +// discoverSkills(process.cwd(), undefined, { +// ignoredSkills: ["browser-tools"], // glob patterns to exclude +// includeSkills: ["brave-*"], // glob patterns to include (empty = all) +// }) diff --git a/packages/coding-agent/examples/sdk/05-tools.ts b/packages/coding-agent/examples/sdk/05-tools.ts new file mode 100644 index 00000000..a2547847 --- /dev/null +++ b/packages/coding-agent/examples/sdk/05-tools.ts @@ -0,0 +1,67 @@ +/** + * Tools Configuration + * + * Use built-in tool sets, individual tools, or add custom tools. + */ + +import { Type } from "@sinclair/typebox"; +import { + createAgentSession, + discoverCustomTools, + SessionManager, + codingTools, // read, bash, edit, write (default) + readOnlyTools, // read, bash + readTool, + bashTool, + grepTool, + type CustomAgentTool, +} from "../../src/index.js"; + +// Read-only mode (no edit/write) +const { session: readOnly } = await createAgentSession({ + tools: readOnlyTools, + sessionManager: SessionManager.inMemory(), +}); +console.log("Read-only session created"); + +// Custom tool selection +const { session: custom } = await createAgentSession({ + tools: [readTool, bashTool, grepTool], + sessionManager: SessionManager.inMemory(), +}); +console.log("Custom tools session created"); + +// Inline custom tool (needs TypeBox schema) +const weatherTool: CustomAgentTool = { + name: "get_weather", + label: "Get Weather", + description: "Get current weather for a city", + parameters: Type.Object({ + city: Type.String({ description: "City name" }), + }), + execute: async (_toolCallId, params) => ({ + content: [{ type: "text", text: `Weather in ${(params as { city: string }).city}: 22°C, sunny` }], + details: {}, + }), +}; + +const { session } = await createAgentSession({ + customTools: [{ tool: weatherTool }], + sessionManager: SessionManager.inMemory(), +}); + +session.subscribe((event) => { + if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") { + process.stdout.write(event.assistantMessageEvent.delta); + } +}); + +await session.prompt("What's the weather in Tokyo?"); +console.log(); + +// Merge with discovered tools from cwd/.pi/tools and ~/.pi/agent/tools: +// const discovered = await discoverCustomTools(); +// customTools: [...discovered, { tool: myTool }] + +// Or add paths without replacing discovery: +// additionalCustomToolPaths: ["/extra/tools"] diff --git a/packages/coding-agent/examples/sdk/06-hooks.ts b/packages/coding-agent/examples/sdk/06-hooks.ts new file mode 100644 index 00000000..3519231f --- /dev/null +++ b/packages/coding-agent/examples/sdk/06-hooks.ts @@ -0,0 +1,61 @@ +/** + * Hooks Configuration + * + * Hooks intercept agent events for logging, blocking, or modification. + */ + +import { createAgentSession, discoverHooks, SessionManager, type HookFactory } from "../../src/index.js"; + +// Logging hook +const loggingHook: HookFactory = (api) => { + api.on("agent_start", async () => { + console.log("[Hook] Agent starting"); + }); + + api.on("tool_call", async (event) => { + console.log(`[Hook] Tool: ${event.toolName}`); + return undefined; // Don't block + }); + + api.on("agent_end", async (event) => { + console.log(`[Hook] Done, ${event.messages.length} messages`); + }); +}; + +// Blocking hook (returns { block: true, reason: "..." }) +const safetyHook: HookFactory = (api) => { + api.on("tool_call", async (event) => { + if (event.toolName === "bash") { + const cmd = (event.input as { command?: string }).command ?? ""; + if (cmd.includes("rm -rf")) { + return { block: true, reason: "Dangerous command blocked" }; + } + } + return undefined; + }); +}; + +// Use inline hooks +const { session } = await createAgentSession({ + hooks: [{ factory: loggingHook }, { factory: safetyHook }], + sessionManager: SessionManager.inMemory(), +}); + +session.subscribe((event) => { + if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") { + process.stdout.write(event.assistantMessageEvent.delta); + } +}); + +await session.prompt("List files in the current directory."); +console.log(); + +// Disable all hooks: +// hooks: [] + +// Merge with discovered hooks: +// const discovered = await discoverHooks(); +// hooks: [...discovered, { factory: myHook }] + +// Add paths without replacing discovery: +// additionalHookPaths: ["/extra/hooks"] diff --git a/packages/coding-agent/examples/sdk/07-context-files.ts b/packages/coding-agent/examples/sdk/07-context-files.ts new file mode 100644 index 00000000..424bb786 --- /dev/null +++ b/packages/coding-agent/examples/sdk/07-context-files.ts @@ -0,0 +1,36 @@ +/** + * Context Files (AGENTS.md) + * + * Context files provide project-specific instructions loaded into the system prompt. + */ + +import { createAgentSession, discoverContextFiles, SessionManager } from "../../src/index.js"; + +// Discover AGENTS.md files walking up from cwd +const discovered = discoverContextFiles(); +console.log("Discovered context files:"); +for (const file of discovered) { + console.log(` - ${file.path} (${file.content.length} chars)`); +} + +// Use custom context files +const { session } = await createAgentSession({ + contextFiles: [ + ...discovered, + { + path: "/virtual/AGENTS.md", + content: `# Project Guidelines + +## Code Style +- Use TypeScript strict mode +- No any types +- Prefer const over let`, + }, + ], + sessionManager: SessionManager.inMemory(), +}); + +console.log(`Session created with ${discovered.length + 1} context files`); + +// Disable context files: +// contextFiles: [] diff --git a/packages/coding-agent/examples/sdk/08-slash-commands.ts b/packages/coding-agent/examples/sdk/08-slash-commands.ts new file mode 100644 index 00000000..188fbd44 --- /dev/null +++ b/packages/coding-agent/examples/sdk/08-slash-commands.ts @@ -0,0 +1,37 @@ +/** + * Slash Commands + * + * File-based commands that inject content when invoked with /commandname. + */ + +import { createAgentSession, discoverSlashCommands, SessionManager, type FileSlashCommand } from "../../src/index.js"; + +// Discover commands from cwd/.pi/commands/ and ~/.pi/agent/commands/ +const discovered = discoverSlashCommands(); +console.log("Discovered slash commands:"); +for (const cmd of discovered) { + console.log(` /${cmd.name}: ${cmd.description}`); +} + +// Define custom commands +const deployCommand: FileSlashCommand = { + name: "deploy", + description: "Deploy the application", + source: "(custom)", + content: `# Deploy Instructions + +1. Build: npm run build +2. Test: npm test +3. Deploy: npm run deploy`, +}; + +// Use discovered + custom commands +const { session } = await createAgentSession({ + slashCommands: [...discovered, deployCommand], + sessionManager: SessionManager.inMemory(), +}); + +console.log(`Session created with ${discovered.length + 1} slash commands`); + +// Disable slash commands: +// slashCommands: [] diff --git a/packages/coding-agent/examples/sdk/09-api-keys-and-oauth.ts b/packages/coding-agent/examples/sdk/09-api-keys-and-oauth.ts new file mode 100644 index 00000000..103130f4 --- /dev/null +++ b/packages/coding-agent/examples/sdk/09-api-keys-and-oauth.ts @@ -0,0 +1,45 @@ +/** + * API Keys and OAuth + * + * Configure API key resolution. Default checks: models.json, OAuth, env vars. + */ + +import { + createAgentSession, + configureOAuthStorage, + defaultGetApiKey, + SessionManager, +} from "../../src/index.js"; +import { getAgentDir } from "../../src/config.js"; + +// Default: uses env vars (ANTHROPIC_API_KEY, etc.), OAuth, and models.json +const { session: defaultSession } = await createAgentSession({ + sessionManager: SessionManager.inMemory(), +}); +console.log("Session with default API key resolution"); + +// Custom resolver +const { session: customSession } = await createAgentSession({ + getApiKey: async (model) => { + // Custom logic (secrets manager, database, etc.) + if (model.provider === "anthropic") { + return process.env.MY_ANTHROPIC_KEY; + } + // Fall back to default + return defaultGetApiKey()(model); + }, + sessionManager: SessionManager.inMemory(), +}); +console.log("Session with custom API key resolver"); + +// Use OAuth from ~/.pi/agent while customizing everything else +configureOAuthStorage(getAgentDir()); // Must call before createAgentSession + +const { session: hybridSession } = await createAgentSession({ + agentDir: "/tmp/custom-config", // Custom config location + // But OAuth tokens still come from ~/.pi/agent/oauth.json + systemPrompt: "You are helpful.", + skills: [], + sessionManager: SessionManager.inMemory(), +}); +console.log("Session with OAuth from default location, custom config elsewhere"); diff --git a/packages/coding-agent/examples/sdk/10-settings.ts b/packages/coding-agent/examples/sdk/10-settings.ts new file mode 100644 index 00000000..c42fab24 --- /dev/null +++ b/packages/coding-agent/examples/sdk/10-settings.ts @@ -0,0 +1,33 @@ +/** + * Settings Configuration + * + * Override settings from agentDir/settings.json. + */ + +import { createAgentSession, loadSettings, SessionManager } from "../../src/index.js"; + +// Load current settings +const settings = loadSettings(); +console.log("Current settings:", JSON.stringify(settings, null, 2)); + +// Override specific settings +const { session } = await createAgentSession({ + settings: { + // Disable auto-compaction + compaction: { enabled: false }, + + // Custom retry behavior + retry: { + enabled: true, + maxRetries: 5, + baseDelayMs: 1000, + }, + + // Terminal options + terminal: { showImages: true }, + hideThinkingBlock: true, + }, + sessionManager: SessionManager.inMemory(), +}); + +console.log("Session created with custom settings"); diff --git a/packages/coding-agent/examples/sdk/11-sessions.ts b/packages/coding-agent/examples/sdk/11-sessions.ts new file mode 100644 index 00000000..8a7052db --- /dev/null +++ b/packages/coding-agent/examples/sdk/11-sessions.ts @@ -0,0 +1,46 @@ +/** + * Session Management + * + * Control session persistence: in-memory, new file, continue, or open specific. + */ + +import { createAgentSession, SessionManager } from "../../src/index.js"; + +// In-memory (no persistence) +const { session: inMemory } = await createAgentSession({ + sessionManager: SessionManager.inMemory(), +}); +console.log("In-memory session:", inMemory.sessionFile ?? "(none)"); + +// New persistent session +const { session: newSession } = await createAgentSession({ + sessionManager: SessionManager.create(process.cwd()), +}); +console.log("New session file:", newSession.sessionFile); + +// Continue most recent session (or create new if none) +const { session: continued, modelFallbackMessage } = await createAgentSession({ + sessionManager: SessionManager.continueRecent(process.cwd()), +}); +if (modelFallbackMessage) console.log("Note:", modelFallbackMessage); +console.log("Continued session:", continued.sessionFile); + +// List and open specific session +const sessions = SessionManager.list(process.cwd()); +console.log(`\nFound ${sessions.length} sessions:`); +for (const info of sessions.slice(0, 3)) { + console.log(` ${info.id.slice(0, 8)}... - "${info.firstMessage.slice(0, 30)}..."`); +} + +if (sessions.length > 0) { + const { session: opened } = await createAgentSession({ + sessionManager: SessionManager.open(sessions[0].path), + }); + console.log(`\nOpened: ${opened.sessionId}`); +} + +// Custom session directory +// const { session } = await createAgentSession({ +// agentDir: "/custom/agent", +// sessionManager: SessionManager.create(process.cwd(), "/custom/agent"), +// }); diff --git a/packages/coding-agent/examples/sdk/12-full-control.ts b/packages/coding-agent/examples/sdk/12-full-control.ts new file mode 100644 index 00000000..f2efba49 --- /dev/null +++ b/packages/coding-agent/examples/sdk/12-full-control.ts @@ -0,0 +1,84 @@ +/** + * Full Control + * + * Replace everything - no discovery, explicit configuration. + * Still uses OAuth from ~/.pi/agent for convenience. + */ + +import { Type } from "@sinclair/typebox"; +import { + createAgentSession, + configureOAuthStorage, + defaultGetApiKey, + findModel, + SessionManager, + readTool, + bashTool, + type HookFactory, + type CustomAgentTool, +} from "../../src/index.js"; +import { getAgentDir } from "../../src/config.js"; + +// Use OAuth from default location +configureOAuthStorage(getAgentDir()); + +// Custom API key with fallback +const getApiKey = async (model: { provider: string }) => { + if (model.provider === "anthropic" && process.env.MY_ANTHROPIC_KEY) { + return process.env.MY_ANTHROPIC_KEY; + } + return defaultGetApiKey()(model as any); +}; + +// Inline hook +const auditHook: HookFactory = (api) => { + api.on("tool_call", async (event) => { + console.log(`[Audit] ${event.toolName}`); + return undefined; + }); +}; + +// Inline custom tool +const statusTool: CustomAgentTool = { + name: "status", + label: "Status", + description: "Get system status", + parameters: Type.Object({}), + execute: async () => ({ + content: [{ type: "text", text: `Uptime: ${process.uptime()}s, Node: ${process.version}` }], + details: {}, + }), +}; + +const { model } = findModel("anthropic", "claude-sonnet-4-20250514"); +if (!model) throw new Error("Model not found"); + +const { session } = await createAgentSession({ + cwd: process.cwd(), + agentDir: "/tmp/my-agent", + + model, + thinkingLevel: "off", + getApiKey, + + systemPrompt: `You are a minimal assistant. +Available: read, bash, status. Be concise.`, + + tools: [readTool, bashTool], + customTools: [{ tool: statusTool }], + hooks: [{ factory: auditHook }], + skills: [], + contextFiles: [], + slashCommands: [], + sessionManager: SessionManager.inMemory(), + settings: { compaction: { enabled: false } }, +}); + +session.subscribe((event) => { + if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") { + process.stdout.write(event.assistantMessageEvent.delta); + } +}); + +await session.prompt("Get status and list files."); +console.log(); diff --git a/packages/coding-agent/examples/sdk/README.md b/packages/coding-agent/examples/sdk/README.md new file mode 100644 index 00000000..501b8d3f --- /dev/null +++ b/packages/coding-agent/examples/sdk/README.md @@ -0,0 +1,138 @@ +# SDK Examples + +Programmatic usage of pi-coding-agent via `createAgentSession()`. + +## Examples + +| File | Description | +|------|-------------| +| `01-minimal.ts` | Simplest usage with all defaults | +| `02-custom-model.ts` | Select model and thinking level | +| `03-custom-prompt.ts` | Replace or modify system prompt | +| `04-skills.ts` | Discover, filter, or replace skills | +| `05-tools.ts` | Built-in tools, custom tools | +| `06-hooks.ts` | Logging, blocking, result modification | +| `07-context-files.ts` | AGENTS.md context files | +| `08-slash-commands.ts` | File-based slash commands | +| `09-api-keys-and-oauth.ts` | API key resolution, OAuth config | +| `10-settings.ts` | Override compaction, retry, terminal settings | +| `11-sessions.ts` | In-memory, persistent, continue, list sessions | +| `12-full-control.ts` | Replace everything, no discovery | + +## Running + +```bash +cd packages/coding-agent +npx tsx examples/sdk/01-minimal.ts +``` + +## Quick Reference + +```typescript +import { + createAgentSession, + configureOAuthStorage, + discoverSkills, + discoverHooks, + discoverCustomTools, + discoverContextFiles, + discoverSlashCommands, + discoverAvailableModels, + findModel, + defaultGetApiKey, + loadSettings, + buildSystemPrompt, + SessionManager, + codingTools, + readOnlyTools, + readTool, bashTool, editTool, writeTool, +} from "@mariozechner/pi-coding-agent"; + +// Minimal +const { session } = await createAgentSession(); + +// Custom model +const { model } = findModel("anthropic", "claude-sonnet-4-20250514"); +const { session } = await createAgentSession({ model, thinkingLevel: "high" }); + +// Modify prompt +const { session } = await createAgentSession({ + systemPrompt: (defaultPrompt) => defaultPrompt + "\n\nBe concise.", +}); + +// Read-only +const { session } = await createAgentSession({ tools: readOnlyTools }); + +// In-memory +const { session } = await createAgentSession({ + sessionManager: SessionManager.inMemory(), +}); + +// Full control +configureOAuthStorage(); // Use OAuth from ~/.pi/agent +const { session } = await createAgentSession({ + model, + getApiKey: async (m) => process.env.MY_KEY, + systemPrompt: "You are helpful.", + tools: [readTool, bashTool], + customTools: [{ tool: myTool }], + hooks: [{ factory: myHook }], + skills: [], + contextFiles: [], + slashCommands: [], + sessionManager: SessionManager.inMemory(), + settings: { compaction: { enabled: false } }, +}); + +// Run prompts +session.subscribe((event) => { + if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") { + process.stdout.write(event.assistantMessageEvent.delta); + } +}); +await session.prompt("Hello"); +``` + +## Options + +| Option | Default | Description | +|--------|---------|-------------| +| `cwd` | `process.cwd()` | Working directory | +| `agentDir` | `~/.pi/agent` | Config directory | +| `model` | From settings/first available | Model to use | +| `thinkingLevel` | From settings/"off" | off, low, medium, high | +| `getApiKey` | Built-in resolver | API key function | +| `systemPrompt` | Discovered | String or `(default) => modified` | +| `tools` | `codingTools` | Built-in tools | +| `customTools` | Discovered | Replaces discovery | +| `additionalCustomToolPaths` | `[]` | Merge with discovery | +| `hooks` | Discovered | Replaces discovery | +| `additionalHookPaths` | `[]` | Merge with discovery | +| `skills` | Discovered | Skills for prompt | +| `contextFiles` | Discovered | AGENTS.md files | +| `slashCommands` | Discovered | File commands | +| `sessionManager` | `SessionManager.create(cwd)` | Persistence | +| `settings` | From agentDir | Overrides | + +## Events + +```typescript +session.subscribe((event) => { + switch (event.type) { + case "message_update": + if (event.assistantMessageEvent.type === "text_delta") { + process.stdout.write(event.assistantMessageEvent.delta); + } + break; + case "tool_execution_start": + console.log(`Tool: ${event.toolName}`); + break; + case "tool_execution_end": + console.log(`Result: ${event.result}`); + break; + case "agent_end": + console.log("Done"); + break; + } +}); +``` diff --git a/packages/coding-agent/src/index.ts b/packages/coding-agent/src/index.ts index 93056daa..42a8e611 100644 --- a/packages/coding-agent/src/index.ts +++ b/packages/coding-agent/src/index.ts @@ -103,6 +103,7 @@ export { discoverModels, discoverSkills, discoverSlashCommands, + type FileSlashCommand, findModel as findModelByProviderAndId, loadSettings, // Tools