PiPi
快速开始
使用 Pi
  • 简体中文
  • English
快速开始
使用 Pi
  • 简体中文
  • English
  • 从这里开始

    • 快速开始
    • 使用 Pi
    • 提供商
    • 安全
    • 容器化
    • 设置
    • 键位绑定
    • 会话
    • 压缩与分支总结
  • 自定义

    • 扩展
    • 技能
    • 提示词模板
    • 主题
    • Pi 包
    • 自定义模型
    • 自定义提供商
  • 参考

    • 会话文件格式
  • 编程式使用

    • SDK
    • RPC 模式
    • JSON 事件流模式
    • TUI 组件
  • 平台设置

    • Windows 设置
    • Termux(Android)设置
    • tmux 设置
    • 终端设置
    • Shell 别名
  • 开发

    • 开发

Pi 可以帮助你使用 SDK。让它为你的使用场景构建集成。

SDK

SDK 提供对 Pi 代理能力的程序化访问。使用它可以将 Pi 嵌入其他应用程序、构建自定义界面,或与自动化工作流集成。

示例使用场景:

  • 构建自定义 UI(Web、桌面、移动端)
  • 将代理能力集成到现有应用程序中
  • 创建带有代理推理能力的自动化流水线
  • 构建可生成子代理的自定义工具
  • 以编程方式测试代理行为

请参阅 examples/sdk/ 获取从最小化到完全控制的可运行示例。

快速开始

import {
  AuthStorage,
  createAgentSession,
  ModelRegistry,
  SessionManager,
} from '@earendil-works/pi-coding-agent'

// Set up credential storage and model registry
const 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?')

安装

npm install @earendil-works/pi-coding-agent

SDK 已包含在主包中。无需单独安装。

核心概念

createAgentSession()

用于单个 AgentSession 的主工厂函数。

createAgentSession() 使用 ResourceLoader 来提供扩展、技能、提示词模板、主题和上下文文件。如果你未提供,它会使用带有标准发现机制的 DefaultResourceLoader。

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(),
})

AgentSession

会话负责管理代理生命周期、消息历史、模型状态、压缩以及事件流。

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
}

诸如 new-session、resume、fork 和 import 等会话替换 API 位于 AgentSessionRuntime 上,而不在 AgentSession 上。

createAgentSessionRuntime() 和 AgentSessionRuntime

当你需要替换活动会话并重建与 cwd 绑定的运行时状态时,请使用运行时 API。 这是内置 interactive、print 和 RPC 模式使用的同一层。

createAgentSessionRuntime() 接收一个运行时工厂以及初始 cwd/会话目标。该工厂闭包捕获进程全局的固定输入,为有效 cwd 重新创建与 cwd 绑定的服务,基于这些服务解析会话选项,并返回完整的运行时结果。

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 负责在以下场景中替换活动运行时:

  • newSession()
  • switchSession()
  • fork()
  • 通过 fork(entryId, { position: "at" }) 进行克隆流程
  • importFromJsonl()

重要行为:

  • 执行这些操作后,runtime.session 会发生变化
  • 事件订阅绑定到特定的 AgentSession,因此替换后需要重新订阅
  • 如果你使用扩展,需要为新会话再次调用 runtime.session.bindExtensions(...)
  • 创建会在 runtime.diagnostics 上返回诊断信息
  • 如果运行时创建或替换失败,该方法会抛出异常,由调用方决定如何处理
let session = runtime.session
let unsubscribe = session.subscribe(() => {})

await runtime.newSession()

unsubscribe()
session = runtime.session
unsubscribe = session.subscribe(() => {})

提示与消息排队

PromptOptions 控制提示词展开、流式输出期间的排队行为,以及提示词预检通知:

interface PromptOptions {
  expandPromptTemplates?: boolean
  images?: ImageContent[]
  streamingBehavior?: 'steer' | 'followUp'
  source?: InputSource
  preflightResult?: (success: boolean) => void
}

每次调用 prompt() 时,preflightResult 会被调用一次:

  • 当提示被接受、排队或立即处理时为 true
  • 当提示在被接受前被预检拒绝时为 false

它会在 prompt() 解析前触发。prompt() 仍然只会在完整的已接受运行结束后解析,包括重试。接受后的失败会通过常规事件和消息流报告,而不是通过 preflightResult(false)。

prompt() 方法会处理提示词模板、扩展命令和消息发送:

// 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' })

行为:

  • 扩展命令(例如 /mycommand):立即执行,即使在流式输出期间也是如此。它们通过 pi.sendMessage() 管理自己的 LLM 交互。
  • 基于文件的提示词模板(来自 .md 文件):在发送或排队前展开为其内容。
  • 流式输出期间未指定 streamingBehavior:抛出错误。请直接使用 steer() 或 followUp(),或指定该选项。
  • preflightResult(true):表示提示已被接受、排队或立即处理。
  • preflightResult(false):表示预检在接受前拒绝了提示。

在流式输出期间显式排队:

// 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")

steer() 和 followUp() 都会展开基于文件的提示词模板,但对扩展命令会报错(扩展命令不能排队)。

Agent 和 AgentState

Agent 类(来自 @earendil-works/pi-agent-core)处理核心 LLM 交互。可通过 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()

事件

订阅事件以接收流式输出和生命周期通知。

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
  }
})

选项参考

目录

const { session } = await createAgentSession({
  // Working directory for DefaultResourceLoader discovery
  cwd: process.cwd(), // default

  // Global config directory
  agentDir: '~/.pi/agent', // default (expands ~)
})

cwd 被 DefaultResourceLoader 用于:

  • 项目扩展(.pi/extensions/)
  • 项目技能:
    • .pi/skills/
    • cwd 及其祖先目录中的 .agents/skills/(直到 git 仓库根目录;若不在仓库中,则直到文件系统根目录)
  • 项目提示词(.pi/prompts/)
  • 上下文文件(从 cwd 向上查找 AGENTS.md)
  • 会话目录命名

agentDir 被 DefaultResourceLoader 用于:

  • 全局扩展(extensions/)
  • 全局技能:
    • agentDir 下的 skills/(例如 ~/.pi/agent/skills/)
    • ~/.agents/skills/
  • 全局提示词(prompts/)
  • 全局上下文文件(AGENTS.md)
  • 设置(settings.json)
  • 自定义模型(models.json)
  • 凭据(auth.json)
  • 会话(sessions/)

当你传入自定义 ResourceLoader 时,cwd 和 agentDir 不再控制资源发现。它们仍会影响会话命名和工具路径解析。

模型

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 configured
const 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,
})

如果未提供模型:

  1. 尝试从会话恢复(如果正在继续)
  2. 使用设置中的默认值
  3. 回退到第一个可用模型

要匹配 CLI 模型解析,请使用导出的解析器辅助函数:

import { resolveCliModel, resolveModelScopeWithDiagnostics } from '@earendil-works/pi-coding-agent'

const cliModel = resolveCliModel({
  cliModel: 'anthropic/claude-opus-4-5:high',
  modelRegistry,
})
if (cliModel.error) throw new Error(cliModel.error)
if (cliModel.warning) console.warn(cliModel.warning)

const { scopedModels, diagnostics } = await resolveModelScopeWithDiagnostics(
  ['anthropic/*:high', 'gpt-5'],
  modelRegistry,
)
for (const diagnostic of diagnostics) {
  console.warn(diagnostic.message)
}

resolveCliModel() 使用所有已注册模型,因此 --api-key 风格的首次设置可以在存储认证存在之前解析模型。resolveModelScopeWithDiagnostics() 匹配 --models 和 enabledModels 语义,同时返回警告而不是打印它们。

请参阅 examples/sdk/02-custom-model.ts

API 密钥和 OAuth

API 密钥解析优先级(由 AuthStorage 处理):

  1. 运行时覆盖(通过 setRuntimeApiKey,不持久化)
  2. auth.json 中存储的凭据(API 密钥或 OAuth 令牌)
  3. 环境变量(ANTHROPIC_API_KEY、OPENAI_API_KEY 等)
  4. 回退解析器(用于来自 models.json 的自定义提供商密钥)
import { AuthStorage, ModelRegistry } from '@earendil-works/pi-coding-agent'

// Default: uses ~/.pi/agent/auth.json and ~/.pi/agent/models.json
const 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 location
const 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)

请参阅 examples/sdk/09-api-keys-and-oauth.ts

系统提示词

使用 ResourceLoader 覆盖系统提示词:

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 })

请参阅 examples/sdk/03-custom-prompt.ts

工具

指定要启用的内置工具:

  • 内置工具名称:read、bash、edit、write、grep、find、ls
  • 默认内置工具:read、bash、edit、write
  • noTools: "all" 禁用所有工具
  • noTools: "builtin" 禁用默认内置工具,同时保留扩展和自定义工具启用
  • excludeTools 在应用任何 tools 允许列表后,禁用指定的内置、扩展或自定义工具名称

edit 工具为 Pi 的 TUI 显示返回 details.diff,并为 SDK 使用者返回标准统一补丁格式的 details.patch。

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'],
})

使用自定义 cwd 的工具

当你传入自定义 cwd 时,createAgentSession() 会为该 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),
})

请参阅 examples/sdk/05-tools.ts

自定义工具

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],
})

使用 defineTool() 创建独立定义,以及像 customTools: [myTool] 这样的数组。内联 pi.registerTool({ ... }) 已经可以正确推断参数类型。

通过 customTools 传入的自定义工具会与扩展注册的工具合并。由 ResourceLoader 加载的扩展也可以通过 pi.registerTool() 注册工具。

如果你传入 tools,请包含每个想要启用的自定义或扩展工具名称,例如 tools: ["read", "bash", "my_tool"]。

请参阅 examples/sdk/05-tools.ts

扩展

扩展由 ResourceLoader 加载。DefaultResourceLoader 会从 ~/.pi/agent/extensions/、.pi/extensions/ 和 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 })

扩展可以注册工具、订阅事件、添加命令等。完整 API 请参阅 extensions.md。

事件总线: 扩展可以通过 pi.events 通信。如果你需要从外部发出或监听事件,请向 DefaultResourceLoader 传入共享的 eventBus:

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))

请参阅 examples/sdk/06-extensions.ts 和 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 })

请参阅 examples/sdk/04-skills.ts

上下文文件

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 })

请参阅 examples/sdk/07-context-files.ts

斜杠命令

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 })

请参阅 examples/sdk/08-prompt-templates.ts

会话管理

会话使用带有 id/parentId 链接的树结构,支持就地分支。

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' })

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 file

请参阅 examples/sdk/11-sessions.ts 和 Session Format

设置管理

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'),
})

静态工厂:

  • SettingsManager.create(cwd?, agentDir?) - 从文件加载
  • SettingsManager.inMemory(settings?) - 无文件 I/O

项目特定设置:

设置从两个位置加载并合并:

  1. 全局:~/.pi/agent/settings.json
  2. 项目:<cwd>/.pi/settings.json

项目设置会覆盖全局设置。嵌套对象会合并键。设置器默认修改全局设置。

持久化和错误处理语义:

  • 设置 getter/setter 对内存状态是同步的。
  • setter 会异步排队持久化写入。
  • 当你需要持久性边界时(例如在进程退出前或在测试中断言文件内容前),请调用 await settingsManager.flush()。
  • SettingsManager 不会打印设置 I/O 错误。请使用 settingsManager.drainErrors() 并在你的应用层报告它们。

请参阅 examples/sdk/10-settings.ts

ResourceLoader

使用 DefaultResourceLoader 发现扩展、技能、提示词、主题和上下文文件。

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

返回值

createAgentSession() 返回:

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
}

完整示例

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 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',
  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.')

运行模式

SDK 导出运行模式工具,用于在 createAgentSession() 之上构建自定义界面:

InteractiveMode

完整的 TUI 交互模式,包含编辑器、聊天历史和所有内置命令:

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

单次模式:发送提示词、输出结果并退出:

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

用于子进程集成的 JSON-RPC 模式:

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)

JSON 协议请参阅 RPC documentation。

RPC 模式替代方案

对于不使用 SDK 构建的基于子进程的集成,请直接使用 CLI:

pi --mode rpc --no-session

JSON 协议请参阅 RPC documentation。

以下情况优先使用 SDK:

  • 你想要类型安全
  • 你在同一个 Node.js 进程中
  • 你需要直接访问代理状态
  • 你想以编程方式自定义工具/扩展

以下情况优先使用 RPC 模式:

  • 你从另一种语言集成
  • 你想要进程隔离
  • 你正在构建与语言无关的客户端

导出

主入口导出:

// Factory
createAgentSession
createAgentSessionRuntime
AgentSessionRuntime

// Auth and Models
AuthStorage
ModelRegistry
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 ExtensionAPI
type ToolDefinition
type Skill
type PromptTemplate
type Tool

扩展类型请参阅 extensions.md 获取完整 API。

最近更新:: 2026/7/6 09:32
Contributors: seepine
Next
RPC 模式