SDK
pi puede ayudarte a usar el SDK. Pídale que cree una integración para su caso de uso.
El SDK proporciona acceso programático a las capacidades del agente de pi. Úselo para integrar pi en otras aplicaciones, crear interfaces personalizadas o integrarlo con flujos de trabajo automatizados.
Casos de uso de ejemplo:
- Cree una interfaz de usuario personalizada (web, escritorio, móvil)
- Integre las capacidades del agente en las aplicaciones existentes
- Cree canales automatizados con razonamiento de agentes
- Cree herramientas personalizadas que generen subagentes
- Probar el comportamiento del agente mediante programación
Consulte examples/sdk/ para ver ejemplos de trabajo desde control mínimo hasta control total.
Inicio rápido
import { createAgentSession, ModelRuntime, SessionManager } from "@earendil-works/pi-coding-agent";
const modelRuntime = await ModelRuntime.create();
const { session } = await createAgentSession({
sessionManager: SessionManager.inMemory(),
modelRuntime,
});
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
npm install @earendil-works/pi-coding-agentEl SDK está incluido en el paquete principal. No se necesita instalación separada.
Conceptos básicos
crear sesión de agente()
La función principal de fábrica para un solo AgentSession.
createAgentSession() usa un ResourceLoader para proporcionar extensiones, habilidades, prompt templates, temas y context files. Si no proporciona uno, utiliza DefaultResourceLoader con descubrimiento estándar.
import { createAgentSession, SessionManager } from "@earendil-works/pi-coding-agent";
// Minimal: defaults with DefaultResourceLoader
const { session } = await createAgentSession();
// Custom: override specific options
const { session } = await createAgentSession({
model: myModel,
tools: ["read", "bash"],
sessionManager: SessionManager.inMemory(),
});Sesión de agente
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;
}Reemplazo de sesión API, como nueva sesión, reanudar, bifurcar e importar, se activa en AgentSessionRuntime, no en AgentSession.
crearAgentSessionRuntime() y AgentSessionRuntime
Utilice el tiempo de ejecución API cuando necesite reemplazar la sesión activa y reconstruir el estado del tiempo de ejecución vinculado a cwd. Esta es la misma capa que utilizan los modos integrados interactivo, de impresión y RPC.
createAgentSessionRuntime() toma una fábrica de tiempo de ejecución más el objetivo inicial de sesión/cwd. La fábrica cierra las entradas fijas del proceso global, recrea los servicios vinculados a cwd para el cwd efectivo, resuelve las opciones de sesión contra esos servicios y devuelve un resultado de tiempo de ejecución 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 posee el reemplazo del tiempo de ejecución activo en:
newSession()switchSession()fork()- clon fluye a través de
fork(entryId, { position: "at" }) importFromJsonl()
Comportamiento importante:
runtime.sessioncambios después de esas operaciones- las suscripciones a eventos están adjuntas a un
AgentSessionespecífico, así que vuelva a suscribirse después del reemplazo - si usa extensiones, llame nuevamente al
runtime.session.bindExtensions(...)para la nueva sesión - la creación devuelve diagnósticos en
runtime.diagnostics - Si falla la creación o el reemplazo del tiempo de ejecución, el método se lanza y la persona que llama decide cómo manejarlo.
let session = runtime.session;
let unsubscribe = session.subscribe(() => {});
await runtime.newSession();
unsubscribe();
session = runtime.session;
unsubscribe = session.subscribe(() => {});Solicitudes y colas de mensajes
PromptOptions controla la expansión de avisos, el comportamiento de cola durante la transmisión y las notificaciones de verificación previa:
interface PromptOptions {
expandPromptTemplates?: boolean;
images?: ImageContent[];
streamingBehavior?: "steer" | "followUp";
source?: InputSource;
preflightResult?: (success: boolean) => void;
}preflightResult se llama una vez por cada prompt() invocación:
truecuando el mensaje fue aceptado, puesto en cola o manejado inmediatamentefalsecuando se rechaza la verificación previa antes de la aceptación
Se dispara antes de que se resuelva prompt(). prompt() todavía se resuelve solo después de que finaliza la ejecución completa aceptada, incluidos los reintentos. Los errores después de la aceptación se informan a través del flujo normal de eventos y mensajes, no a través de preflightResult(false).
El método prompt() maneja prompt templates, comandos de extensión y envío de mensajes:
// Basic prompt (when not streaming)
await session.prompt("What files are here?");
// With images
await 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 message
await 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 (por ejemplo,
/mycommand): se ejecutan inmediatamente, incluso durante la transmisión. Gestionan su propia interacción LLM a través depi.sendMessage(). - Basado en archivos prompt templates (de archivos
.md): ampliado a su contenido antes de enviarlos o ponerlos en cola. - Durante la transmisión sin
streamingBehavior: arroja un error. Utilicesteer()ofollowUp()directamente, o especifique la opción. preflightResult(true): Significa que el mensaje fue aceptado, puesto en cola o manejado inmediatamente.preflightResult(false): Significa verificación previa rechazada antes de la aceptación.
Para colas explícitas durante la transmisión:
// Queue a steering message for delivery after the current assistant turn finishes its tool calls
await 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 prompt templates según archivos, pero se produce un error en los comandos de extensión (los comandos de extensión no se pueden poner en cola).
Agente y EstadoAgente
La clase Agent (de @earendil-works/pi-agent-core) maneja la interacción principal de LLM. Accede a través de session.agent.
// Access current state
const 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 tools
session.agent.state.tools = tools; // copies the top-level array
// Wait for agent to finish processing
await session.agent.waitForIdle();Eventos
Suscríbase a eventos para recibir resultados de transmisión 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":
case "summarization_retry_scheduled":
case "summarization_retry_attempt_start":
case "summarization_retry_finished":
break;
}
});Referencia de opciones
Directorios
const { session } = await createAgentSession({
// Working directory for DefaultResourceLoader discovery
cwd: process.cwd(), // default
// Global config directory
agentDir: "~/.pi/agent", // default (expands ~)
});cwd es utilizado por DefaultResourceLoader para:
- Extensiones de proyecto (
.pi/extensions/) - Habilidades de proyecto:
.pi/skills/.agents/skills/encwdy directorios ancestrales (hasta la raíz del repositorio de git o la raíz del sistema de archivos cuando no está en un repositorio)
- Indicaciones del proyecto (
.pi/prompts/) - Archivos de contexto (
AGENTS.mdsubiendo desde cwd) - Nomenclatura del directorio de sesiones
agentDir es utilizado por DefaultResourceLoader para:
- Extensiones globales (
extensions/) - Habilidades globales:
skills/debajo deagentDir(por ejemplo~/.pi/agent/skills/)~/.agents/skills/
- Avisos globales (
prompts/) - Archivo de contexto global (
AGENTS.md) - Configuración (
settings.json) - Modelos personalizados (
models.json) - Credenciales (
auth.json) - Sesiones (
sessions/)
Cuando pasa un ResourceLoader personalizado, cwd y agentDir ya no controlan el descubrimiento de recursos. Todavía influyen en la denominación de las sesiones y la resolución de la ruta de la herramienta.
Modelo
import { getModel } from "@earendil-works/pi-ai";
import { ModelRuntime } from "@earendil-works/pi-coding-agent";
const modelRuntime = await ModelRuntime.create();
// 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 = modelRuntime.getModel("my-provider", "my-model");
// Get only models that have valid authentication configured
const available = await modelRuntime.getAvailable();
const { session } = await createAgentSession({
model: opus,
thinkingLevel: "medium", // off, minimal, low, medium, high, xhigh, max
// Models for cycling (Ctrl+P in interactive mode)
scopedModels: [
{ model: opus, thinkingLevel: "high" },
{ model: haiku, thinkingLevel: "off" },
],
modelRuntime,
});Si no se proporciona ningún modelo:
- Intenta restaurar desde la sesión (si continúa)
- Utiliza la configuración predeterminada
- Vuelve al primer modelo disponible
Para hacer coincidir el análisis del modelo CLI, utilice los ayudantes de resolución exportados:
import {
resolveCliModel,
resolveModelScopeWithDiagnostics,
} from "@earendil-works/pi-coding-agent";
const cliModel = resolveCliModel({
cliModel: "anthropic/claude-opus-4-5:high",
modelRuntime,
});
if (cliModel.error) throw new Error(cliModel.error);
if (cliModel.warning) console.warn(cliModel.warning);
const { scopedModels, diagnostics } = await resolveModelScopeWithDiagnostics(
["anthropic/*:high", "gpt-5"],
modelRuntime,
);
for (const diagnostic of diagnostics) {
console.warn(diagnostic.message);
}resolveCliModel() utiliza todos los modelos registrados, por lo que la configuración inicial del estilo --api-key puede resolver un modelo antes de que exista la autenticación almacenada. resolveModelScopeWithDiagnostics() coincide con la semántica --models y enabledModels y devuelve advertencias en lugar de imprimirlas.
API Teclas y OAuth
Prioridad de resolución de autenticación (manejada por ModelRuntime):
- Anulaciones de tiempo de ejecución (a través de
setRuntimeApiKey, no persistentes) - Credenciales almacenadas en
auth.json(API keys o OAuth tokens) - Variables de entorno (
ANTHROPIC_API_KEY,OPENAI_API_KEY, etc.) - Resolución alternativa (para claves de proveedor personalizadas de
models.json)
import { InMemoryCredentialStore } from "@earendil-works/pi-ai";
import { createAgentSession, ModelRuntime } from "@earendil-works/pi-coding-agent";
// Default: uses ~/.pi/agent/auth.json and ~/.pi/agent/models.json
const modelRuntime = await ModelRuntime.create();
// Provider-owned auth methods and current status
for (const provider of modelRuntime.getProviders()) {
const status = await modelRuntime.checkAuth(provider.id);
console.log(provider.name, provider.auth, status);
}
// Runtime API key override (not persisted to disk)
await modelRuntime.setRuntimeApiKey("anthropic", "sk-my-temp-key");
// Custom credential and model locations
const customRuntime = await ModelRuntime.create({
authPath: "/my/app/auth.json",
modelsPath: "/my/app/models.json",
});
// Or inject any pi-ai CredentialStore
const credentials = new InMemoryCredentialStore();
const inMemoryRuntime = await ModelRuntime.create({ credentials });
const { session } = await createAgentSession({
modelRuntime: customRuntime,
});login(), logout(), setRuntimeApiKey() y removeRuntimeApiKey() se resuelven después de que el catálogo integrado/en caché, la composición y la instantánea de disponibilidad del proveedor afectado sean coherentes localmente. No esperan la actualización remota del catálogo. Si se confirmaron las credenciales pero falla la sincronización local, se rechazan con el CredentialSynchronizationError exportado; inspeccione sus campos providerId, operation, credential y cause en lugar de volver a intentar la mutación de credenciales a ciegas.
Las operaciones públicas de modelo/autenticación y ModelRuntime.create({ signal }) aceptan señales de cancelación opcionales y son ilimitadas cuando se omiten. SDK Política de plazos propios de las aplicaciones para la actualización remota del catálogo:
const signal = AbortSignal.timeout(15_000);
const result = await modelRuntime.refresh({
providers: ["anthropic"],
signal,
});
if (result.aborted) console.warn("Catalog refresh timed out; using cached models");
for (const [providerId, error] of result.errors) {
console.warn(`Could not refresh ${providerId}:`, error);
}Una actualización de red fallida o con tiempo de espera agotado no deshace una operación de credencial exitosa. refresh() inicia una nueva generación de proveedores, por lo que no espera detrás de una actualización anterior estancada y las generaciones obsoletas no pueden publicar después.
Aviso del sistema
Utilice un ResourceLoader para anular el mensaje 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 });Herramientas
Especifique qué herramientas integradas habilitar:
- Nombres de herramientas integradas:
read,bash,edit,write,grep,find,ls - Integrados predeterminados:
read,bash,edit,write noTools: "all"desactiva todas las herramientasnoTools: "builtin"deshabilita las funciones integradas predeterminadas mientras mantiene habilitadas las extensiones y las herramientas personalizadasexcludeToolsdeshabilita nombres específicos de herramientas integradas, de extensión o personalizadas después de aplicar cualquier lista de permitidostools
La herramienta edit devuelve details.diff para la pantalla TUI de Pi y details.patch como un parche unificado estándar para los consumidores SDK.
import { createAgentSession } from "@earendil-works/pi-coding-agent";
// Read-only mode
const { session } = await createAgentSession({
tools: ["read", "grep", "find", "ls"],
});
// Pick specific tools
const { session } = await createAgentSession({
tools: ["read", "bash", "grep"],
});
// Disable one tool while keeping the rest available
const { session } = await createAgentSession({
excludeTools: ["ask_question"],
});Herramientas con cwd personalizado
Cuando pasas un cwd personalizado, createAgentSession() crea 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 cwd
const { session } = await createAgentSession({
cwd,
sessionManager: SessionManager.inMemory(cwd),
});
// Or pick specific tools for custom cwd
const { session } = await createAgentSession({
cwd,
tools: ["read", "bash", "grep"],
sessionManager: SessionManager.inMemory(cwd),
});Herramientas personalizadas
import { Type } from "typebox";
import { createAgentSession, defineTool } from "@earendil-works/pi-coding-agent";
// Inline custom tool
const 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 directly
const { session } = await createAgentSession({
customTools: [myTool],
});Utilice defineTool() para definiciones y matrices independientes como customTools: [myTool]. Inline pi.registerTool({... }) ya infiere los tipos de parámetros correctamente.
Las herramientas personalizadas pasadas a través de customTools se combinan con herramientas registradas en extensión. Extensions cargado por ResourceLoader también puede registrar herramientas a través de pi.registerTool().
Si pasa tools, incluya cada nombre de herramienta personalizada o de extensión que desee habilitar, por ejemplo tools: ["read", "bash", "my_tool"].
Extensions
Extensions se cargan con el ResourceLoader. DefaultResourceLoader descubre extensiones de ~/.pi/agent/extensions/, .pi/extensions/ y fuentes de extensión 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 });Extensions puede registrar herramientas, suscribirse a eventos, agregar comandos y más. Consulte extensions.md para ver el API completo.
Extensiones en línea con nombre: De forma predeterminada, las fábricas en línea se muestran como <inline:1>, <inline:2>, etc. en la lista de inicio Extensions. Para mostrar un nombre descriptivo, ajuste la fábrica:
import type { InlineExtension } from "@earendil-works/pi-coding-agent";
const myProvider: InlineExtension = {
name: "my-provider",
factory: (pi) => {
pi.on("agent_start", () => {
console.log("[my-provider] Agent starting");
});
},
};
const loader = new DefaultResourceLoader({
extensionFactories: [myProvider],
});Esto se muestra como <inline:my-provider> en lugar de <inline:1>. Las funciones básicas de fábrica todavía se aceptan por compatibilidad con versiones anteriores.
Bus de eventos: Extensions puede comunicarse a través de pi.events. Pasa un eventBus compartido al DefaultResourceLoader si necesitas emitir o escuchar desde el exterior:
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));Skills
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 });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 });Comandos de barra diagonal
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 });Gestión de sesiones
Las sesiones utilizan una estructura de árbol con enlaces id/parentId, lo que permite la 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 session
const { session: persisted } = await createAgentSession({
sessionManager: SessionManager.create(process.cwd()),
});
// Continue most recent
const { session: continued, modelFallbackMessage } = await createAgentSession({
sessionManager: SessionManager.continueRecent(process.cwd()),
});
if (modelFallbackMessage) {
console.log("Note:", modelFallbackMessage);
}
// Open specific file
const { session: opened } = await createAgentSession({
sessionManager: SessionManager.open("/path/to/session.jsonl"),
});
// List sessions
const 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 one
await runtime.newSession();
// Replace the active session with another saved session
await runtime.switchSession("/path/to/session.jsonl");
// Replace the active session with a fork from a specific user entry
await runtime.fork("entry-id");
// Clone the active path through a specific entry
await runtime.fork("entry-id", { position: "at" });árbol de SessionManager API:
const sm = SessionManager.open("/path/to/session.jsonl");
// Session listing
const currentProjectSessions = await SessionManager.list(process.cwd());
const allSessions = await SessionManager.listAll(process.cwd());
// Tree traversal
const entries = sm.getEntries(); // All entries (excludes header)
const tree = sm.getTree(); // Full tree structure
const path = sm.getPath(); // Path from root to current leaf
const leaf = sm.getLeafEntry(); // Current leaf entry
const entry = sm.getEntry(id); // Get entry by ID
const children = sm.getChildren(id); // Direct children of entry
// Labels
const label = sm.getLabel(id); // Get label for entry
sm.appendLabelChange(id, "checkpoint"); // Set label
// Branching
sm.branch(entryId); // Move leaf to earlier entry
sm.branchWithSummary(id, "Summary..."); // Branch with context summary
sm.createBranchedSession(leafId); // Extract path to new fileGestió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 overrides
const 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 directories
const { 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
Configuraciones específicas del proyecto:
Las configuraciones se cargan desde dos ubicaciones y se fusionan:
- Global:
~/.pi/agent/settings.json - Proyecto:
<cwd>/.pi/settings.json
El proyecto anula lo global. Los objetos anidados fusionan claves. Los configuradores modifican la configuración global de forma predeterminada.
Semántica de persistencia y manejo de errores:
- Los captadores/definidores de configuración son sincrónicos para el estado en memoria.
- Los configuradores ponen en cola las escrituras persistentes de forma asincrónica.
- Llame a
await settingsManager.flush()cuando necesite un límite de durabilidad (por ejemplo, antes de salir del proceso o antes de afirmar el contenido del archivo en las pruebas). SettingsManagerno imprime los errores de E/S de configuración. UtilicesettingsManager.drainErrors()e infórmelo en su capa de aplicación.
Cargador de recursos
Utilice DefaultResourceLoader para descubrir extensiones, habilidades, indicaciones, temas y context files.
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
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
import { getModel } from "@earendil-works/pi-ai";
import { Type } from "typebox";
import {
createAgentSession,
DefaultResourceLoader,
defineTool,
ModelRuntime,
SessionManager,
SettingsManager,
} from "@earendil-works/pi-coding-agent";
const modelRuntime = await ModelRuntime.create({
authPath: "/custom/agent/auth.json",
modelsPath: "/custom/agent/models.json",
});
if (process.env.MY_KEY) {
await modelRuntime.setRuntimeApiKey("anthropic", process.env.MY_KEY);
}
// Inline tool
const 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 overrides
const 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",
modelRuntime,
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
Las utilidades del modo de ejecución de exportaciones SDK para crear interfaces personalizadas además de createAgentSession():
Modo interactivo
Modo interactivo completo TUI 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();ejecutarModoImpresión
Modo de disparo único: enviar mensajes, generar resultados, 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"],
});ejecutarRpcMode
Modo JSON-RPC para integración de 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);Consulte RPC documentation para conocer el protocolo JSON.
RPC Modo alternativo
Para la integración basada en subprocesos sin compilar con SDK, use CLI directamente:
pi --mode rpc --no-sessionConsulte RPC documentation para conocer el protocolo JSON.
Se prefiere el SDK cuando:
- Quieres seguridad tipográfica
- Estás en el mismo proceso Node.js
- Necesita acceso directo al estado del agente
- Quiere personalizar herramientas/extensiones mediante programación
Se prefiere el modo RPC cuando:
- Te estás integrando desde otro idioma
- Quieres aislamiento del proceso
- Estás creando un cliente independiente del idioma
Exportaciones
El principal punto de entrada exporta:
// Factory
createAgentSession
createAgentSessionRuntime
AgentSessionRuntime
// Auth and Models
ModelRuntime // implements pi-ai Models and owns credential storage
ModelRegistry // synchronous extension compatibility facade
CredentialSynchronizationError
resolveCliModel
resolveModelScopeWithDiagnostics
// Resource loading
DefaultResourceLoader
type ResourceLoader
createEventBus
// Constants and helpers
CONFIG_DIR_NAME
defineTool
getAgentDir
getPackageDir
getReadmePath
getDocsPath
getExamplesPath
// Session management
SessionManager
SettingsManager
// Tool factories
createCodingTools
createReadOnlyTools
createReadTool, createBashTool, createEditTool, createWriteTool
createGrepTool, createFindTool, createLsTool
// Types
type CreateAgentSessionOptions
type CreateAgentSessionResult
type ExtensionFactory
type InlineExtension
type ExtensionAPI
type ToolDefinition
type Skill
type PromptTemplate
type ToolPara conocer los tipos de extensión, consulte extensions.md para obtener el API completo.