SDK
pi dapat membantu Anda menggunakan SDK. Mintalah untuk membangun integrasi untuk kasus penggunaan Anda.
SDK menyediakan akses terprogram ke kemampuan agen pi. Gunakan untuk menyematkan pi di aplikasi lain, membuat antarmuka khusus, atau berintegrasi dengan alur kerja otomatis.
Contoh kasus penggunaan:
- Bangun UI khusus (web, desktop, seluler)
- Integrasikan kemampuan agen ke dalam aplikasi yang ada
- Buat saluran pipa otomatis dengan alasan agen
- Bangun alat khusus yang menghasilkan sub-agen
- Uji perilaku agen secara terprogram
Lihat examples/sdk/ untuk contoh kerja dari kontrol minimal hingga kontrol penuh.
Mulai Cepat
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?");Instalasi
npm install @earendil-works/pi-coding-agentSDK disertakan dalam paket utama. Tidak diperlukan instalasi terpisah.
Konsep Inti
buatAgentSession()
Fungsi pabrik utama untuk satu AgentSession.
createAgentSession() menggunakan ResourceLoader untuk menyediakan ekstensi, keterampilan, prompt templates, tema, dan context files. Jika Anda tidak menyediakannya, ia akan menggunakan DefaultResourceLoader dengan penemuan standar.
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(),
});AgenSesi
Sesi ini mengelola siklus hidup agen, riwayat pesan, status model, pemadatan, dan streaming peristiwa.
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;
}Penggantian sesi API seperti sesi baru, resume, fork, dan impor langsung di AgentSessionRuntime, bukan di AgentSession.
createAgentSessionRuntime() dan AgentSessionRuntime
Gunakan runtime API ketika Anda perlu mengganti sesi aktif dan membangun kembali status runtime yang terikat cwd. Ini adalah lapisan yang sama yang digunakan oleh mode interaktif, cetak, dan RPC bawaan.
createAgentSessionRuntime() membutuhkan pabrik runtime ditambah target cwd/sesi awal. Pabrik menutup input tetap global proses, membuat ulang layanan terikat cwd untuk cwd yang efektif, menyelesaikan opsi sesi terhadap layanan tersebut, dan mengembalikan hasil runtime penuh.
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 memiliki penggantian runtime aktif di:
newSession()switchSession()fork()- aliran klon melalui
fork(entryId, { position: "at" }) importFromJsonl()
Perilaku penting:
runtime.sessionperubahan setelah operasi tersebut- langganan acara terikat pada
AgentSessiontertentu, jadi berlangganan kembali setelah penggantian - jika Anda menggunakan ekstensi, panggil
runtime.session.bindExtensions(...)lagi untuk sesi baru - kreasi mengembalikan diagnostik pada
runtime.diagnostics - jika pembuatan atau penggantian runtime gagal, metode akan dilempar dan pemanggil memutuskan bagaimana menanganinya
let session = runtime.session;
let unsubscribe = session.subscribe(() => {});
await runtime.newSession();
unsubscribe();
session = runtime.session;
unsubscribe = session.subscribe(() => {});Anjuran dan Antrian Pesan
PromptOptions mengontrol perluasan cepat, perilaku antrian saat streaming, dan pemberitahuan pra-penerbangan cepat:
interface PromptOptions {
expandPromptTemplates?: boolean;
images?: ImageContent[];
streamingBehavior?: "steer" | "followUp";
source?: InputSource;
preflightResult?: (success: boolean) => void;
}preflightResult dipanggil sekali per prompt() pemanggilan:
trueketika perintah diterima, dimasukkan dalam antrean, atau ditangani dengan segerafalseketika preflight cepat ditolak sebelum diterima
Ini menyala sebelum prompt() terselesaikan. prompt() masih terselesaikan hanya setelah proses yang diterima sepenuhnya selesai, termasuk percobaan ulang. Kegagalan setelah penerimaan dilaporkan melalui peristiwa normal dan aliran pesan, bukan melalui preflightResult(false).
Metode prompt() menangani prompt templates, perintah ekstensi, dan pengiriman pesan:
// 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" });Perilaku:
- Perintah ekstensi (mis.,
/mycommand): Jalankan segera, bahkan saat streaming. Mereka mengelola interaksi LLM mereka sendiri melaluipi.sendMessage(). - Berbasis file prompt templates (dari
.mdfile): Diperluas ke kontennya sebelum mengirim atau mengantri. - Selama streaming tanpa
streamingBehavior: Terjadi kesalahan. Gunakansteer()ataufollowUp()secara langsung, atau tentukan opsinya. preflightResult(true): Berarti perintah diterima, dimasukkan dalam antrean, atau ditangani dengan segera.preflightResult(false): Berarti preflight ditolak sebelum diterima.
Untuk antrian eksplisit selama streaming:
// 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");Baik steer() dan followUp() memperluas berbasis file prompt templates tetapi kesalahan pada perintah ekstensi (perintah ekstensi tidak dapat dimasukkan dalam antrean).
Agen dan AgentState
Kelas Agent (dari @earendil-works/pi-agent-core) menangani interaksi inti LLM. Akses melalui 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();Acara
Berlangganan acara untuk menerima keluaran streaming dan pemberitahuan siklus hidup.
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;
}
});Referensi Pilihan
Direktori
const { session } = await createAgentSession({
// Working directory for DefaultResourceLoader discovery
cwd: process.cwd(), // default
// Global config directory
agentDir: "~/.pi/agent", // default (expands ~)
});cwd digunakan oleh DefaultResourceLoader untuk:
- Ekstensi proyek (
.pi/extensions/) - Keterampilan proyek:
.pi/skills/.agents/skills/dicwddan direktori leluhur (hingga git repo root, atau root sistem file jika tidak ada dalam repo)
- Perintah proyek (
.pi/prompts/) - File konteks (
AGENTS.mdberjalan dari cwd) - Penamaan direktori sesi
agentDir digunakan oleh DefaultResourceLoader untuk:
- Ekstensi global (
extensions/) - Keterampilan global:
skills/di bawahagentDir(misalnya~/.pi/agent/skills/)~/.agents/skills/
- Perintah global (
prompts/) - File konteks global (
AGENTS.md) - Pengaturan (
settings.json) - Model khusus (
models.json) - Kredensial (
auth.json) - Sesi (
sessions/)
Saat Anda meneruskan ResourceLoader khusus, cwd dan agentDir tidak lagi mengontrol penemuan sumber daya. Mereka masih mempengaruhi penamaan sesi dan resolusi jalur alat.
Model
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,
});Jika tidak ada model yang disediakan:
- Mencoba memulihkan dari sesi (jika melanjutkan)
- Menggunakan default dari pengaturan
- Kembali ke model pertama yang tersedia
Untuk mencocokkan penguraian model CLI, gunakan bantuan penyelesai yang diekspor:
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() menggunakan semua model terdaftar sehingga pengaturan pertama kali gaya --api-key dapat menyelesaikan model sebelum autentikasi yang disimpan ada. resolveModelScopeWithDiagnostics() cocok dengan semantik --models dan enabledModels sambil mengembalikan peringatan alih-alih mencetaknya.
API Kunci dan OAuth
Prioritas resolusi autentikasi (ditangani oleh ModelRuntime):
- Penggantian waktu proses (melalui
setRuntimeApiKey, tidak dipertahankan) - Kredensial yang disimpan dalam
auth.json(API keys atau OAuth token) - Variabel lingkungan (
ANTHROPIC_API_KEY,OPENAI_API_KEY, dll.) - Penyelesai cadangan (untuk kunci penyedia khusus dari
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(), dan removeRuntimeApiKey() diselesaikan setelah katalog, komposisi, dan snapshot ketersediaan yang di-cache/bawaan dari penyedia yang terpengaruh konsisten secara lokal. Mereka tidak menunggu kesegaran katalog yang jauh. Jika kredensial telah diterapkan tetapi sinkronisasi lokal gagal, kredensial akan ditolak dengan CredentialSynchronizationError yang diekspor; periksa bidang providerId, operation, credential, dan cause daripada mencoba ulang mutasi kredensial secara membabi buta.
Operasi model publik/autentikasi dan ModelRuntime.create({ signal }) menerima sinyal pembatalan opsional dan tidak dibatasi saat dihilangkan. SDK aplikasi memiliki kebijakan tenggat waktu untuk kesegaran katalog jarak jauh:
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);
}Penyegaran jaringan yang gagal atau habis waktunya tidak membatalkan operasi kredensial yang berhasil. refresh() memulai generasi penyedia baru, sehingga tidak menunggu penyegaran lama yang terhenti dan generasi lama tidak dapat mempublikasikannya setelahnya.
Perintah Sistem
Gunakan ResourceLoader untuk mengganti perintah sistem:
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 });Peralatan
Tentukan alat bawaan mana yang akan diaktifkan:
- Nama alat bawaan:
read,bash,edit,write,grep,find,ls - Bawaan bawaan:
read,bash,edit,write noTools: "all"menonaktifkan semua alatnoTools: "builtin"menonaktifkan bawaan bawaan sambil tetap mengaktifkan ekstensi dan alat khususexcludeToolsmenonaktifkan nama alat bawaan, ekstensi, atau khusus tertentu setelahtoolsdaftar yang diizinkan diterapkan
Alat edit mengembalikan details.diff untuk tampilan Pi TUI dan details.patch sebagai patch terpadu standar untuk SDK konsumen.
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"],
});Alat dengan Custom cwd
Saat Anda meneruskan cwd khusus, createAgentSession() membuat alat bawaan yang dipilih untuk cwd tersebut.
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),
});Lihat examples/sdk/05-tools.ts
Alat Kustom
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],
});Gunakan defineTool() untuk definisi mandiri dan array seperti customTools: [myTool]. Inline pi.registerTool({... }) sudah menyimpulkan tipe parameter dengan benar.
Alat khusus yang diteruskan melalui customTools digabungkan dengan alat yang terdaftar dengan ekstensi. Extensions yang dimuat oleh ResourceLoader juga dapat mendaftarkan alat melalui pi.registerTool().
Jika Anda meneruskan tools, sertakan setiap nama alat khusus atau ekstensi yang ingin Anda aktifkan, misalnya tools: ["read", "bash", "my_tool"].
Lihat examples/sdk/05-tools.ts
Extensions
Extensions dimuat oleh ResourceLoader. DefaultResourceLoader menemukan ekstensi dari ~/.pi/agent/extensions/, .pi/extensions/, dan sumber ekstensi 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 dapat mendaftarkan alat, berlangganan acara, menambahkan perintah, dan banyak lagi. Lihat extensions.md untuk API selengkapnya.
Ekstensi inline yang diberi nama: Secara default, pabrik inline ditampilkan sebagai <inline:1>, <inline:2>, dll. di daftar startup Extensions. Untuk menampilkan nama deskriptif, bungkus pabriknya:
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],
});Ini ditampilkan sebagai <inline:my-provider> bukannya <inline:1>. Fungsi pabrik yang kosong masih diterima untuk kompatibilitas ke belakang.
Bus Acara: Extensions dapat berkomunikasi melalui pi.events. Berikan eventBus ke DefaultResourceLoader bersama jika Anda perlu memancarkan atau mendengarkan dari luar:
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 });File Konteks
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 });Perintah Tebas
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 });Manajemen Sesi
Sesi menggunakan struktur pohon dengan tautan id/parentId, sehingga memungkinkan percabangan di tempat.
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" });Pohon Manajer Sesi 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 fileLihat examples/sdk/11-sessions.ts dan Session Format
Manajemen Pengaturan
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"),
});Pabrik statis:
SettingsManager.create(cwd?, agentDir?)- Muat dari fileSettingsManager.inMemory(settings?)- Tidak ada I/O berkas
Setelan spesifik proyek:
Pengaturan dimuat dari dua lokasi dan digabungkan:
- Global:
~/.pi/agent/settings.json - Proyek:
<cwd>/.pi/settings.json
Proyek menggantikan global. Objek bersarang menggabungkan kunci. Setter mengubah pengaturan global secara default.
Semantik penanganan kesalahan dan persistensi:
- Pengambil/penyetel pengaturan sinkron untuk status dalam memori.
- Penyetel membuat persistensi antrean menulis secara asinkron.
- Panggil
await settingsManager.flush()ketika Anda memerlukan batas ketahanan (misalnya, sebelum proses keluar atau sebelum menegaskan konten file dalam pengujian). SettingsManagertidak mencetak kesalahan pengaturan I/O. GunakansettingsManager.drainErrors()dan laporkan di lapisan aplikasi Anda.
ResourceLoader
Gunakan DefaultResourceLoader untuk menemukan ekstensi, keterampilan, petunjuk, tema, dan 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;Nilai Pengembalian
createAgentSession() kembali:
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;
}Contoh Lengkap
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.");Jalankan Mode
Utilitas mode proses ekspor SDK untuk membangun antarmuka khusus di atas createAgentSession():
Mode Interaktif
Mode interaktif TUI penuh dengan editor, riwayat obrolan, dan semua perintah bawaan:
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();jalankanPrintMode
Mode pengambilan tunggal: kirim petunjuk, hasil keluaran, keluar:
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"],
});jalankanRpcMode
Mode JSON-RPC untuk integrasi subproses:
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);Lihat RPC documentation untuk protokol JSON.
RPC Mode Alternatif
Untuk integrasi berbasis subproses tanpa membangun dengan SDK, gunakan CLI secara langsung:
pi --mode rpc --no-sessionLihat RPC documentation untuk protokol JSON.
SDK lebih disukai ketika:
- Anda ingin mengetik keamanan
- Anda berada dalam proses Node.js yang sama
- Anda memerlukan akses langsung ke negara agen
- Anda ingin menyesuaikan alat/ekstensi secara terprogram
Mode RPC lebih disukai ketika:
- Anda mengintegrasikan dari bahasa lain
- Anda ingin proses isolasi
- Anda sedang membangun klien tanpa bahasa
Ekspor
Ekspor titik masuk utama:
// 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 ToolUntuk jenis ekstensi, lihat extensions.md untuk API selengkapnya.