SDK
pi puede ayudarte a usar el SDK. Pídele que construya una integración para tu caso de uso.
El SDK proporciona acceso programático a las capacidades del agente de pi. Úsalo para integrar pi en otras aplicaciones, crear interfaces personalizadas o integrarlo en flujos de trabajo automatizados.
Casos de uso de ejemplo:
- Construir una UI personalizada (web, escritorio, móvil)
- Integrar capacidades del agente en aplicaciones existentes
- Crear pipelines automatizados con razonamiento del agente
- Construir herramientas personalizadas que generen subagentes
- Probar el comportamiento del agente de forma programática
Consulta examples/sdk/ para ejemplos funcionales, desde configuraciones mínimas hasta control total.
Inicio rápido
Sección titulada «Inicio rápido»import { AuthStorage, createAgentSession, ModelRegistry, SessionManager } from "@earendil-works/pi-coding-agent";
// Set up credential storage and model registryconst authStorage = AuthStorage.create();const modelRegistry = ModelRegistry.create(authStorage);
const { session } = await createAgentSession({ sessionManager: SessionManager.inMemory(), authStorage, modelRegistry,});
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?");Instalación
Sección titulada «Instalación»npm install @earendil-works/pi-coding-agentEl SDK está incluido en el paquete principal. No se necesita instalación por separado.
Conceptos principales
Sección titulada «Conceptos principales»createAgentSession()
Sección titulada «createAgentSession()»La función de fábrica principal para una única AgentSession.
createAgentSession() usa un ResourceLoader para proporcionar extensiones, skills, plantillas de prompt, temas y archivos de contexto. Si no proporcionas uno, usa DefaultResourceLoader con descubrimiento estándar.
import { createAgentSession, SessionManager } from "@earendil-works/pi-coding-agent";
// Minimal: defaults with DefaultResourceLoaderconst { session } = await createAgentSession();
// Custom: override specific optionsconst { session } = await createAgentSession({ model: myModel, tools: ["read", "bash"], sessionManager: SessionManager.inMemory(),});AgentSession
Sección titulada «AgentSession»La sesión gestiona el ciclo de vida del agente, el historial de mensajes, el estado del modelo, la compactación y la transmisión de eventos.
interface AgentSession { // Send a prompt and wait for completion prompt(text: string, options?: PromptOptions): Promise<void>;
// Queue messages during streaming steer(text: string): Promise<void>; followUp(text: string): Promise<void>;
// Subscribe to events (returns unsubscribe function) subscribe(listener: (event: AgentSessionEvent) => void): () => void;
// Session info sessionFile: string | undefined; sessionId: string;
// Model control setModel(model: Model): Promise<void>; setThinkingLevel(level: ThinkingLevel): void; cycleModel(): Promise<ModelCycleResult | undefined>; cycleThinkingLevel(): ThinkingLevel | undefined;
// State access agent: Agent; model: Model | undefined; thinkingLevel: ThinkingLevel; messages: AgentMessage[]; isStreaming: boolean;
// In-place tree navigation within the current session file navigateTree(targetId: string, options?: { summarize?: boolean; customInstructions?: string; replaceInstructions?: boolean; label?: string }): Promise<{ editorText?: string; cancelled: boolean }>;
// Compaction compact(customInstructions?: string): Promise<CompactionResult>; abortCompaction(): void;
// Abort current operation abort(): Promise<void>;
// Cleanup dispose(): void;}Las API de reemplazo de sesión como new-session, resume, fork e import están en AgentSessionRuntime, no en AgentSession.
createAgentSessionRuntime() y AgentSessionRuntime
Sección titulada «createAgentSessionRuntime() y AgentSessionRuntime»Usa la API de runtime cuando necesites reemplazar la sesión activa y reconstruir el estado de runtime vinculado al cwd. Es la misma capa que usan los modos interactivo, print y RPC integrados.
createAgentSessionRuntime() recibe una fábrica de runtime más el cwd/sesión inicial. La fábrica cierra sobre entradas fijas globales del proceso, recrea servicios vinculados al cwd para el cwd efectivo, resuelve opciones de sesión contra esos servicios y devuelve un resultado de runtime completo.
import { type CreateAgentSessionRuntimeFactory, createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, getAgentDir, SessionManager,} from "@earendil-works/pi-coding-agent";
const createRuntime: CreateAgentSessionRuntimeFactory = async ({ cwd, sessionManager, sessionStartEvent }) => { const services = await createAgentSessionServices({ cwd }); return { ...(await createAgentSessionFromServices({ services, sessionManager, sessionStartEvent, })), services, diagnostics: services.diagnostics, };};
const runtime = await createAgentSessionRuntime(createRuntime, { cwd: process.cwd(), agentDir: getAgentDir(), sessionManager: SessionManager.create(process.cwd()),});AgentSessionRuntime gestiona el reemplazo del runtime activo en:
newSession()switchSession()fork()- flujos de clonación mediante
fork(entryId, { position: "at" }) importFromJsonl()
Comportamiento importante:
runtime.sessioncambia después de esas operaciones- las suscripciones a eventos están adjuntas a una
AgentSessionespecífica; vuelve a suscribirte tras el reemplazo - si usas extensiones, llama de nuevo a
runtime.session.bindExtensions(...)para la nueva sesión - la creación devuelve diagnósticos en
runtime.diagnostics - si la creación o el reemplazo del runtime falla, el método lanza una excepción y el llamador decide cómo manejarla
let session = runtime.session;let unsubscribe = session.subscribe(() => {});
await runtime.newSession();
unsubscribe();session = runtime.session;unsubscribe = session.subscribe(() => {});Prompts y cola de mensajes
Sección titulada «Prompts y cola de mensajes»PromptOptions controla la expansión de prompts, el comportamiento de cola durante el streaming y las notificaciones de preflight del prompt:
interface PromptOptions { expandPromptTemplates?: boolean; images?: ImageContent[]; streamingBehavior?: "steer" | "followUp"; source?: InputSource; preflightResult?: (success: boolean) => void;}preflightResult se llama una vez por invocación de prompt():
truecuando el prompt fue aceptado, encolado o manejado de inmediatofalsecuando el preflight del prompt rechazó antes de la aceptación
Se dispara antes de que prompt() se resuelva. prompt() solo se resuelve después de que termine la ejecución aceptada completa, incluidos los reintentos. Los fallos posteriores a la aceptación se reportan mediante el flujo normal de eventos y mensajes, no mediante preflightResult(false).
El método prompt() gestiona plantillas de prompt, comandos de extensión y envío de mensajes:
// Basic prompt (when not streaming)await session.prompt("What files are here?");
// With imagesawait session.prompt("What's in this image?", { images: [{ type: "image", source: { type: "base64", mediaType: "image/png", data: "..." } }]});
// During streaming: must specify how to queue the messageawait session.prompt("Stop and do this instead", { streamingBehavior: "steer" });await session.prompt("After you're done, also check X", { streamingBehavior: "followUp" });Comportamiento:
- Comandos de extensión (p. ej.,
/mycommand): se ejecutan de inmediato, incluso durante el streaming. Gestionan su propia interacción con el LLM mediantepi.sendMessage(). - Plantillas de prompt basadas en archivos (desde archivos
.md): se expanden a su contenido antes de enviarse o encolarse. - Durante el streaming sin
streamingBehavior: lanza un error. Usasteer()ofollowUp()directamente, o especifica la opción. preflightResult(true): significa que el prompt fue aceptado, encolado o manejado de inmediato.preflightResult(false): significa que el preflight rechazó antes de la aceptación.
Para encolar explícitamente durante el streaming:
// Queue a steering message for delivery after the current assistant turn finishes its tool callsawait session.steer("New instruction");
// Wait for agent to finish (delivered only when agent stops)await session.followUp("After you're done, also do this");Tanto steer() como followUp() expanden plantillas de prompt basadas en archivos, pero fallan con comandos de extensión (los comandos de extensión no se pueden encolar).
Agent y AgentState
Sección titulada «Agent y AgentState»La clase Agent (de @earendil-works/pi-agent-core) gestiona la interacción principal con el LLM. Accede mediante session.agent.
// Access current stateconst state = session.agent.state;
// state.messages: AgentMessage[] - conversation history// state.model: Model - current model// state.thinkingLevel: ThinkingLevel - current thinking level// state.systemPrompt: string - system prompt// state.tools: AgentTool[] - available tools// state.streamingMessage?: AgentMessage - current partial assistant message// state.errorMessage?: string - latest assistant error
// Replace messages (useful for branching or restoration)session.agent.state.messages = messages; // copies the top-level array
// Replace toolssession.agent.state.tools = tools; // copies the top-level array
// Wait for agent to finish processingawait session.agent.waitForIdle();Eventos
Sección titulada «Eventos»Suscríbete a eventos para recibir salida en streaming y notificaciones del ciclo de vida.
session.subscribe((event) => { switch (event.type) { // Streaming text from assistant case "message_update": if (event.assistantMessageEvent.type === "text_delta") { process.stdout.write(event.assistantMessageEvent.delta); } if (event.assistantMessageEvent.type === "thinking_delta") { // Thinking output (if thinking enabled) } break;
// Tool execution case "tool_execution_start": console.log(`Tool: ${event.toolName}`); break; case "tool_execution_update": // Streaming tool output break; case "tool_execution_end": console.log(`Result: ${event.isError ? "error" : "success"}`); break;
// Message lifecycle case "message_start": // New message starting break; case "message_end": // Message complete break;
// Agent lifecycle case "agent_start": // Agent started processing prompt break; case "agent_end": // Agent finished (event.messages contains new messages) break;
// Turn lifecycle (one LLM response + tool calls) case "turn_start": break; case "turn_end": // event.message: assistant response // event.toolResults: tool results from this turn break;
// Session events (queue, compaction, retry) case "queue_update": console.log(event.steering, event.followUp); break; case "compaction_start": case "compaction_end": case "auto_retry_start": case "auto_retry_end": break; }});Referencia de opciones
Sección titulada «Referencia de opciones»Directorios
Sección titulada «Directorios»const { session } = await createAgentSession({ // Working directory for DefaultResourceLoader discovery cwd: process.cwd(), // default
// Global config directory agentDir: "~/.pi/agent", // default (expands ~)});cwd lo usa DefaultResourceLoader para:
- Extensiones del proyecto (
.pi/extensions/) - Skills del proyecto:
.pi/skills/.agents/skills/encwdy directorios ancestros (hasta la raíz del repositorio git, o la raíz del sistema de archivos si no hay repo)
- Prompts del proyecto (
.pi/prompts/) - Archivos de contexto (
AGENTS.mdrecorriendo hacia arriba desde cwd) - Nomenclatura del directorio de sesiones
agentDir lo usa DefaultResourceLoader para:
- Extensiones globales (
extensions/) - Skills globales:
skills/bajoagentDir(por ejemplo~/.pi/agent/skills/)~/.agents/skills/
- Prompts globales (
prompts/) - Archivo de contexto global (
AGENTS.md) - Configuración (
settings.json) - Modelos personalizados (
models.json) - Credenciales (
auth.json) - Sesiones (
sessions/)
Cuando pasas un ResourceLoader personalizado, cwd y agentDir ya no controlan el descubrimiento de recursos. Siguen influyendo en el nombre de sesión y la resolución de rutas de herramientas.
import { getModel } from "@earendil-works/pi-ai";import { AuthStorage, ModelRegistry } from "@earendil-works/pi-coding-agent";
const authStorage = AuthStorage.create();const modelRegistry = ModelRegistry.create(authStorage);
// Find specific built-in model (doesn't check if API key exists)const opus = getModel("anthropic", "claude-opus-4-5");if (!opus) throw new Error("Model not found");
// Find any model by provider/id, including custom models from models.json// (doesn't check if API key exists)const customModel = modelRegistry.find("my-provider", "my-model");
// Get only models that have valid API keys configuredconst available = await modelRegistry.getAvailable();
const { session } = await createAgentSession({ model: opus, thinkingLevel: "medium", // off, minimal, low, medium, high, xhigh
// Models for cycling (Ctrl+P in interactive mode) scopedModels: [ { model: opus, thinkingLevel: "high" }, { model: haiku, thinkingLevel: "off" }, ],
authStorage, modelRegistry,});Si no se proporciona modelo:
- Intenta restaurar desde la sesión (si continúas)
- Usa el valor predeterminado de la configuración
- Recurre al primer modelo disponible
Consulta examples/sdk/02-custom-model.ts
Claves API y OAuth
Sección titulada «Claves API y OAuth»Prioridad de resolución de claves API (gestionada por AuthStorage):
- Sobrescrituras en runtime (mediante
setRuntimeApiKey, no persistidas) - Credenciales almacenadas en
auth.json(claves API o tokens OAuth) - Variables de entorno (
ANTHROPIC_API_KEY,OPENAI_API_KEY, etc.) - Resolvedor de respaldo (para claves de proveedores personalizados de
models.json)
import { AuthStorage, ModelRegistry } from "@earendil-works/pi-coding-agent";
// Default: uses ~/.pi/agent/auth.json and ~/.pi/agent/models.jsonconst authStorage = AuthStorage.create();const modelRegistry = ModelRegistry.create(authStorage);
const { session } = await createAgentSession({ sessionManager: SessionManager.inMemory(), authStorage, modelRegistry,});
// Runtime API key override (not persisted to disk)authStorage.setRuntimeApiKey("anthropic", "sk-my-temp-key");
// Custom auth storage locationconst customAuth = AuthStorage.create("/my/app/auth.json");const customRegistry = ModelRegistry.create(customAuth, "/my/app/models.json");
const { session } = await createAgentSession({ sessionManager: SessionManager.inMemory(), authStorage: customAuth, modelRegistry: customRegistry,});
// No custom models.json (built-in models only)const simpleRegistry = ModelRegistry.inMemory(authStorage);Prompt del sistema
Sección titulada «Prompt del sistema»Usa un ResourceLoader para sobrescribir el prompt del sistema:
import { createAgentSession, DefaultResourceLoader } from "@earendil-works/pi-coding-agent";
const loader = new DefaultResourceLoader({ systemPromptOverride: () => "You are a helpful assistant.",});await loader.reload();
const { session } = await createAgentSession({ resourceLoader: loader });Consulta examples/sdk/03-custom-prompt.ts
Herramientas
Sección titulada «Herramientas»Especifica qué herramientas integradas habilitar:
- Nombres de herramientas integradas:
read,bash,edit,write,grep,find,ls - Integradas predeterminadas:
read,bash,edit,write noTools: "all"deshabilita todas las herramientasnoTools: "builtin"deshabilita las integradas predeterminadas manteniendo habilitadas las de extensión y personalizadasexcludeToolsdeshabilita nombres específicos de herramientas integradas, de extensión o personalizadas después de aplicar cualquier lista permitida detools
La herramienta edit devuelve details.diff para la visualización TUI de Pi y details.patch como parche unificado estándar para consumidores del SDK.
import { createAgentSession } from "@earendil-works/pi-coding-agent";
// Read-only modeconst { session } = await createAgentSession({ tools: ["read", "grep", "find", "ls"],});
// Pick specific toolsconst { session } = await createAgentSession({ tools: ["read", "bash", "grep"],});
// Disable one tool while keeping the rest availableconst { session } = await createAgentSession({ excludeTools: ["ask_question"],});Herramientas con cwd personalizado
Sección titulada «Herramientas con cwd personalizado»Cuando pasas un cwd personalizado, createAgentSession() construye las herramientas integradas seleccionadas para ese cwd.
import { createAgentSession, SessionManager } from "@earendil-works/pi-coding-agent";
const cwd = "/path/to/project";
// Use default tools for custom cwdconst { session } = await createAgentSession({ cwd, sessionManager: SessionManager.inMemory(cwd),});
// Or pick specific tools for custom cwdconst { session } = await createAgentSession({ cwd, tools: ["read", "bash", "grep"], sessionManager: SessionManager.inMemory(cwd),});Consulta examples/sdk/05-tools.ts
Herramientas personalizadas
Sección titulada «Herramientas personalizadas»import { Type } from "typebox";import { createAgentSession, defineTool } from "@earendil-works/pi-coding-agent";
// Inline custom toolconst myTool = defineTool({ name: "my_tool", label: "My Tool", description: "Does something useful", parameters: Type.Object({ input: Type.String({ description: "Input value" }), }), execute: async (_toolCallId, params) => ({ content: [{ type: "text", text: `Result: ${params.input}` }], details: {}, }),});
// Pass custom tools directlyconst { session } = await createAgentSession({ customTools: [myTool],});Usa defineTool() para definiciones independientes y arrays como customTools: [myTool]. El pi.registerTool({ ... }) en línea ya infiere correctamente los tipos de parámetros.
Las herramientas personalizadas pasadas mediante customTools se combinan con las registradas por extensiones. Las extensiones cargadas por el ResourceLoader también pueden registrar herramientas mediante pi.registerTool().
Si pasas tools, incluye cada nombre de herramienta personalizada o de extensión que quieras habilitar, por ejemplo tools: ["read", "bash", "my_tool"].
Consulta examples/sdk/05-tools.ts
Extensiones
Sección titulada «Extensiones»Las extensiones las carga el ResourceLoader. DefaultResourceLoader descubre extensiones desde ~/.pi/agent/extensions/, .pi/extensions/ y fuentes de extensión en settings.json.
import { createAgentSession, DefaultResourceLoader } from "@earendil-works/pi-coding-agent";
const loader = new DefaultResourceLoader({ additionalExtensionPaths: ["/path/to/my-extension.ts"], extensionFactories: [ (pi) => { pi.on("agent_start", () => { console.log("[Inline Extension] Agent starting"); }); }, ],});await loader.reload();
const { session } = await createAgentSession({ resourceLoader: loader });Las extensiones pueden registrar herramientas, suscribirse a eventos, añadir comandos y más. Consulta extensions.md para la API completa.
Bus de eventos: las extensiones pueden comunicarse mediante pi.events. Pasa un eventBus compartido a DefaultResourceLoader si necesitas emitir o escuchar desde fuera:
import { createEventBus, DefaultResourceLoader } from "@earendil-works/pi-coding-agent";
const eventBus = createEventBus();const loader = new DefaultResourceLoader({ eventBus,});await loader.reload();
eventBus.on("my-extension:status", (data) => console.log(data));Consulta examples/sdk/06-extensions.ts y docs/extensions.md
import { createAgentSession, DefaultResourceLoader, type Skill,} from "@earendil-works/pi-coding-agent";
const customSkill: Skill = { name: "my-skill", description: "Custom instructions", filePath: "/path/to/SKILL.md", baseDir: "/path/to", source: "custom",};
const loader = new DefaultResourceLoader({ skillsOverride: (current) => ({ skills: [...current.skills, customSkill], diagnostics: current.diagnostics, }),});await loader.reload();
const { session } = await createAgentSession({ resourceLoader: loader });Consulta examples/sdk/04-skills.ts
Archivos de contexto
Sección titulada «Archivos de contexto»import { createAgentSession, DefaultResourceLoader } from "@earendil-works/pi-coding-agent";
const loader = new DefaultResourceLoader({ agentsFilesOverride: (current) => ({ agentsFiles: [ ...current.agentsFiles, { path: "/virtual/AGENTS.md", content: "# Guidelines\n\n- Be concise" }, ], }),});await loader.reload();
const { session } = await createAgentSession({ resourceLoader: loader });Consulta examples/sdk/07-context-files.ts
Comandos con barra
Sección titulada «Comandos con barra»import { createAgentSession, DefaultResourceLoader, type PromptTemplate,} from "@earendil-works/pi-coding-agent";
const customCommand: PromptTemplate = { name: "deploy", description: "Deploy the application", source: "(custom)", content: "# Deploy\n\n1. Build\n2. Test\n3. Deploy",};
const loader = new DefaultResourceLoader({ promptsOverride: (current) => ({ prompts: [...current.prompts, customCommand], diagnostics: current.diagnostics, }),});await loader.reload();
const { session } = await createAgentSession({ resourceLoader: loader });Consulta examples/sdk/08-prompt-templates.ts
Gestión de sesiones
Sección titulada «Gestión de sesiones»Las sesiones usan una estructura de árbol con enlaces id/parentId, lo que permite ramificación in situ.
import { type CreateAgentSessionRuntimeFactory, createAgentSession, createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, getAgentDir, SessionManager,} from "@earendil-works/pi-coding-agent";
// In-memory (no persistence)const { session } = await createAgentSession({ sessionManager: SessionManager.inMemory(),});
// New persistent sessionconst { session: persisted } = await createAgentSession({ sessionManager: SessionManager.create(process.cwd()),});
// Continue most recentconst { session: continued, modelFallbackMessage } = await createAgentSession({ sessionManager: SessionManager.continueRecent(process.cwd()),});if (modelFallbackMessage) { console.log("Note:", modelFallbackMessage);}
// Open specific fileconst { session: opened } = await createAgentSession({ sessionManager: SessionManager.open("/path/to/session.jsonl"),});
// List sessionsconst currentProjectSessions = await SessionManager.list(process.cwd());const allSessions = await SessionManager.listAll(process.cwd());
// Session replacement API for /new, /resume, /fork, /clone, and import flows.const createRuntime: CreateAgentSessionRuntimeFactory = async ({ cwd, sessionManager, sessionStartEvent }) => { const services = await createAgentSessionServices({ cwd }); return { ...(await createAgentSessionFromServices({ services, sessionManager, sessionStartEvent, })), services, diagnostics: services.diagnostics, };};
const runtime = await createAgentSessionRuntime(createRuntime, { cwd: process.cwd(), agentDir: getAgentDir(), sessionManager: SessionManager.create(process.cwd()),});
// Replace the active session with a fresh oneawait runtime.newSession();
// Replace the active session with another saved sessionawait runtime.switchSession("/path/to/session.jsonl");
// Replace the active session with a fork from a specific user entryawait runtime.fork("entry-id");
// Clone the active path through a specific entryawait runtime.fork("entry-id", { position: "at" });API de árbol de SessionManager:
const sm = SessionManager.open("/path/to/session.jsonl");
// Session listingconst currentProjectSessions = await SessionManager.list(process.cwd());const allSessions = await SessionManager.listAll(process.cwd());
// Tree traversalconst entries = sm.getEntries(); // All entries (excludes header)const tree = sm.getTree(); // Full tree structureconst path = sm.getPath(); // Path from root to current leafconst leaf = sm.getLeafEntry(); // Current leaf entryconst entry = sm.getEntry(id); // Get entry by IDconst children = sm.getChildren(id); // Direct children of entry
// Labelsconst label = sm.getLabel(id); // Get label for entrysm.appendLabelChange(id, "checkpoint"); // Set label
// Branchingsm.branch(entryId); // Move leaf to earlier entrysm.branchWithSummary(id, "Summary..."); // Branch with context summarysm.createBranchedSession(leafId); // Extract path to new fileConsulta examples/sdk/11-sessions.ts y Formato de sesión
Gestión de configuración
Sección titulada «Gestión de configuración»import { createAgentSession, SettingsManager, SessionManager } from "@earendil-works/pi-coding-agent";
// Default: loads from files (global + project merged)const { session } = await createAgentSession({ settingsManager: SettingsManager.create(),});
// With overridesconst settingsManager = SettingsManager.create();settingsManager.applyOverrides({ compaction: { enabled: false }, retry: { enabled: true, maxRetries: 5 },});const { session } = await createAgentSession({ settingsManager });
// In-memory (no file I/O, for testing)const { session } = await createAgentSession({ settingsManager: SettingsManager.inMemory({ compaction: { enabled: false } }), sessionManager: SessionManager.inMemory(),});
// Custom directoriesconst { session } = await createAgentSession({ settingsManager: SettingsManager.create("/custom/cwd", "/custom/agent"),});Fábricas estáticas:
SettingsManager.create(cwd?, agentDir?)- Cargar desde archivosSettingsManager.inMemory(settings?)- Sin E/S de archivos
Configuración específica del proyecto:
La configuración se carga desde dos ubicaciones y se fusiona:
- Global:
~/.pi/agent/settings.json - Proyecto:
<cwd>/.pi/settings.json
El proyecto sobrescribe lo global. Los objetos anidados fusionan claves. Los setters modifican la configuración global por defecto.
Semántica de persistencia y manejo de errores:
- Los getters/setters de configuración son síncronos para el estado en memoria.
- Los setters encolan escrituras de persistencia de forma asíncrona.
- Llama a
await settingsManager.flush()cuando necesites un límite de durabilidad (por ejemplo, antes de salir del proceso o antes de comprobar contenidos de archivos en pruebas). SettingsManagerno imprime errores de E/S de configuración. UsasettingsManager.drainErrors()y repórtalos en tu capa de aplicación.
Consulta examples/sdk/10-settings.ts
ResourceLoader
Sección titulada «ResourceLoader»Usa DefaultResourceLoader para descubrir extensiones, skills, prompts, temas y archivos de contexto.
import { DefaultResourceLoader, getAgentDir,} from "@earendil-works/pi-coding-agent";
const loader = new DefaultResourceLoader({ cwd, agentDir: getAgentDir(),});await loader.reload();
const extensions = loader.getExtensions();const skills = loader.getSkills();const prompts = loader.getPrompts();const themes = loader.getThemes();const contextFiles = loader.getAgentsFiles().agentsFiles;Valor de retorno
Sección titulada «Valor de retorno»createAgentSession() devuelve:
interface CreateAgentSessionResult { // The session session: AgentSession;
// Extensions result (for runner setup) extensionsResult: LoadExtensionsResult;
// Warning if session model couldn't be restored modelFallbackMessage?: string;}
interface LoadExtensionsResult { extensions: Extension[]; errors: Array<{ path: string; error: string }>; runtime: ExtensionRuntime;}Ejemplo completo
Sección titulada «Ejemplo completo»import { getModel } from "@earendil-works/pi-ai";import { Type } from "typebox";import { AuthStorage, createAgentSession, DefaultResourceLoader, defineTool, ModelRegistry, SessionManager, SettingsManager,} from "@earendil-works/pi-coding-agent";
// Set up auth storage (custom location)const authStorage = AuthStorage.create("/custom/agent/auth.json");
// Runtime API key override (not persisted)if (process.env.MY_KEY) { authStorage.setRuntimeApiKey("anthropic", process.env.MY_KEY);}
// Model registry (no custom models.json)const modelRegistry = ModelRegistry.create(authStorage);
// Inline toolconst statusTool = defineTool({ name: "status", label: "Status", description: "Get system status", parameters: Type.Object({}), execute: async () => ({ content: [{ type: "text", text: `Uptime: ${process.uptime()}s` }], details: {}, }),});
const model = getModel("anthropic", "claude-opus-4-5");if (!model) throw new Error("Model not found");
// In-memory settings with overridesconst settingsManager = SettingsManager.inMemory({ compaction: { enabled: false }, retry: { enabled: true, maxRetries: 2 },});
const loader = new DefaultResourceLoader({ cwd: process.cwd(), agentDir: "/custom/agent", settingsManager, systemPromptOverride: () => "You are a minimal assistant. Be concise.",});await loader.reload();
const { session } = await createAgentSession({ cwd: process.cwd(), agentDir: "/custom/agent",
model, thinkingLevel: "off", authStorage, modelRegistry,
tools: ["read", "bash", "status"], customTools: [statusTool], resourceLoader: loader,
sessionManager: SessionManager.inMemory(), settingsManager,});
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.");Modos de ejecución
Sección titulada «Modos de ejecución»El SDK exporta utilidades de modo de ejecución para construir interfaces personalizadas sobre createAgentSession():
InteractiveMode
Sección titulada «InteractiveMode»Modo interactivo TUI completo con editor, historial de chat y todos los comandos integrados:
import { type CreateAgentSessionRuntimeFactory, createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, getAgentDir, InteractiveMode, SessionManager,} from "@earendil-works/pi-coding-agent";
const createRuntime: CreateAgentSessionRuntimeFactory = async ({ cwd, sessionManager, sessionStartEvent }) => { const services = await createAgentSessionServices({ cwd }); return { ...(await createAgentSessionFromServices({ services, sessionManager, sessionStartEvent })), services, diagnostics: services.diagnostics, };};const runtime = await createAgentSessionRuntime(createRuntime, { cwd: process.cwd(), agentDir: getAgentDir(), sessionManager: SessionManager.create(process.cwd()),});
const mode = new InteractiveMode(runtime, { migratedProviders: [], modelFallbackMessage: undefined, initialMessage: "Hello", initialImages: [], initialMessages: [],});
await mode.run();runPrintMode
Sección titulada «runPrintMode»Modo de una sola ejecución: enviar prompts, mostrar resultado y salir:
import { type CreateAgentSessionRuntimeFactory, createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, getAgentDir, runPrintMode, SessionManager,} from "@earendil-works/pi-coding-agent";
const createRuntime: CreateAgentSessionRuntimeFactory = async ({ cwd, sessionManager, sessionStartEvent }) => { const services = await createAgentSessionServices({ cwd }); return { ...(await createAgentSessionFromServices({ services, sessionManager, sessionStartEvent })), services, diagnostics: services.diagnostics, };};const runtime = await createAgentSessionRuntime(createRuntime, { cwd: process.cwd(), agentDir: getAgentDir(), sessionManager: SessionManager.create(process.cwd()),});
await runPrintMode(runtime, { mode: "text", initialMessage: "Hello", initialImages: [], messages: ["Follow up"],});runRpcMode
Sección titulada «runRpcMode»Modo JSON-RPC para integración con subprocesos:
import { type CreateAgentSessionRuntimeFactory, createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, getAgentDir, runRpcMode, SessionManager,} from "@earendil-works/pi-coding-agent";
const createRuntime: CreateAgentSessionRuntimeFactory = async ({ cwd, sessionManager, sessionStartEvent }) => { const services = await createAgentSessionServices({ cwd }); return { ...(await createAgentSessionFromServices({ services, sessionManager, sessionStartEvent })), services, diagnostics: services.diagnostics, };};const runtime = await createAgentSessionRuntime(createRuntime, { cwd: process.cwd(), agentDir: getAgentDir(), sessionManager: SessionManager.create(process.cwd()),});
await runRpcMode(runtime);Consulta la documentación RPC para el protocolo JSON.
Alternativa al modo RPC
Sección titulada «Alternativa al modo RPC»Para integración basada en subprocesos sin compilar con el SDK, usa el CLI directamente:
pi --mode rpc --no-sessionConsulta la documentación RPC para el protocolo JSON.
Se prefiere el SDK cuando:
- Quieres seguridad de tipos
- Estás en el mismo proceso de Node.js
- Necesitas acceso directo al estado del agente
- Quieres personalizar herramientas/extensiones de forma programática
Se prefiere el modo RPC cuando:
- Integras desde otro lenguaje
- Quieres aislamiento de procesos
- Construyes un cliente independiente del lenguaje
Exportaciones
Sección titulada «Exportaciones»El punto de entrada principal exporta:
// FactorycreateAgentSessioncreateAgentSessionRuntimeAgentSessionRuntime
// Auth and ModelsAuthStorageModelRegistry
// Resource loadingDefaultResourceLoadertype ResourceLoadercreateEventBus
// Constants and helpersCONFIG_DIR_NAMEdefineToolgetAgentDirgetPackageDirgetReadmePathgetDocsPathgetExamplesPath
// Session managementSessionManagerSettingsManager
// Tool factoriescreateCodingToolscreateReadOnlyToolscreateReadTool, createBashTool, createEditTool, createWriteToolcreateGrepTool, createFindTool, createLsTool
// Typestype CreateAgentSessionOptionstype CreateAgentSessionResulttype ExtensionFactorytype ExtensionAPItype ToolDefinitiontype Skilltype PromptTemplatetype ToolPara tipos de extensión, consulta extensions.md para la API completa.