这个包是什么What this package ispi-coding-agent 是产品本身:pi 命令、SDK 与 RPC 服务器都从这里出来。它把 pi-agent-core 的通用 Agent 装配成一个编码智能体——加上会话树(JSONL)、内置工具、扩展系统、设置与资源加载,以及 interactive / print / json / rpc 四种运行模式。pi-coding-agent is the product: the pi command, the SDK and the RPC server all come from here. It turns the generic Agent from pi-agent-core into a coding agent — adding the session tree (JSONL), built-in tools, the extension system, settings and resource loading, and four run modes: interactive, print, json and rpc.
位于最上层:依赖 pi-agent-core、pi-ai、pi-tui,以及 pi-mcp、pi-codemode、chord。这里的核心类是 AgentSession(一次会话)和 AgentSessionRuntime(可替换会话的宿主)。The top layer: depends on pi-agent-core, pi-ai, pi-tui, plus pi-mcp, pi-codemode and chord. The central classes are AgentSession (one session) and AgentSessionRuntime (the host that can swap sessions).
模块结构Module structure#
一句话结论Takeaway四个入口共用一个内核:cli.ts(pi 命令)与 rpc-entry.ts 都进入 main.ts;index.ts 是 SDK 入口。真正的逻辑在 core/,三种 UI 形态在 modes/。Four entry points share one core: cli.ts (the pi command) and rpc-entry.ts both enter main.ts; index.ts is the SDK entry. The real logic lives in core/; the three UI shapes live in modes/.
要点Key points
core/agent-session.ts是 core/ 里最大的文件(interactive 模式的interactive-mode.ts更大):它持有Agent、SessionManager、ExtensionRunner与模型运行时,并负责重试、压缩和排队消息。core/agent-session.tsis the largest file in core/ (only interactive mode'sinteractive-mode.tsis bigger): it owns theAgent, theSessionManager, theExtensionRunnerand the model runtime, and handles retry, compaction and queued messages.rpc-entry.ts只做一件事:调用main(["--mode", "rpc", …]),并通过./rpc-entry导出路径对外提供。rpc-entry.tsdoes one thing: callmain(["--mode", "rpc", …]); it is published as the./rpc-entryexport path.src/extensions/里是随包附带的内置扩展(MCP、codemode、tool-search 等),走的是和用户扩展相同的 API。src/extensions/holds the bundled built-in extensions (MCP, codemode, tool-search …); they use the same API as user extensions.
工作原理How it works
pi→setupCli()→main(argv):解析参数、决定模式、建会话。pi→setupCli()→main(argv): parse args, pick a mode, build the session.- SDK 用户直接调用
createAgentSession()或createAgentSessionRuntime(),跳过 CLI。SDK users callcreateAgentSession()orcreateAgentSessionRuntime()directly and skip the CLI. - 所有模式拿到的都是同一个
AgentSessionRuntime,区别只在输入输出方式。Every mode receives the sameAgentSessionRuntime; they differ only in how input and output flow.
关键文件Key files · v1.1.0
| 文件File | 符号Symbol | 作用Role |
|---|---|---|
| packages/coding-agent/src/cli/setup.tsL4 | setupCli() | bin 入口的准备工作bin-entry setup |
| packages/coding-agent/src/main.tsL573 | main() | CLI 主流程the CLI main flow |
| packages/coding-agent/src/rpc-entry.tsL13 | main(["--mode","rpc"]) | RPC 入口RPC entry |
| packages/coding-agent/src/index.tsL259 | export … | SDK 入口SDK entry |
| packages/coding-agent/src/core/agent-session.tsL378 | AgentSession | 一次会话的全部状态all state of one session |
公共 APIPublic API#
一句话结论Takeaway一个命令(pi → dist/bundle/cli.js)加 4 个导入路径。SDK 根入口从 40 个模块重新导出 154 个值和 304 个类型;最常用的是 createAgentSession、createAgentSessionRuntime、SessionManager、SettingsManager、createCodingTools 和扩展类型。One command (pi → dist/bundle/cli.js) plus 4 import paths. The SDK root re-exports 154 values and 304 types from 40 modules; the most used are createAgentSession, createAgentSessionRuntime, SessionManager, SettingsManager, createCodingTools and the extension types.
| 导入路径Import path | 目标Target | 说明Notes |
|---|---|---|
@earendil-works/pi-coding-agent | ./dist/index.js | SDK:createAgentSession、AgentSessionRuntime、SessionManager、工具、扩展类型、主题与组件SDK: createAgentSession, AgentSessionRuntime, SessionManager, tools, extension types, theme and components |
@earendil-works/pi-coding-agent/rpc-entry | ./dist/bundle/rpc-entry.js | 以 RPC 模式启动(等同 pi --mode rpc)start in RPC mode (same as pi --mode rpc) |
@earendil-works/pi-coding-agent/client | ./src/client/index.ts | 源码入口:客户端(仓库内使用)source entry: client (used inside the repo) |
@earendil-works/pi-coding-agent/experimental/plugin | ./src/experimental/plugin.ts | 源码入口:实验性插件 APIsource entry: experimental plugin API |
常用导出Key exports
| 模块Module | 常用导出Key exports | 用途Use |
|---|---|---|
| packages/coding-agent/src/core/sdk.ts | createAgentSession | 一次性建好会话build a session in one call |
| packages/coding-agent/src/core/agent-session-runtime.ts | AgentSessionRuntime createAgentSessionRuntime | 可替换会话的宿主the host that swaps sessions |
| packages/coding-agent/src/core/agent-session.ts | AgentSession | 一次会话one session |
| packages/coding-agent/src/core/session-manager.ts | SessionManager | JSONL 会话树the JSONL session tree |
| packages/coding-agent/src/core/settings-manager.ts | SettingsManager | 两层设置two-layer settings |
| packages/coding-agent/src/core/resource-loader.ts | DefaultResourceLoader | 扩展 · 技能 · 提示 · 主题extensions · skills · prompts · themes |
| packages/coding-agent/src/core/tools/index.ts | createCodingTools createReadOnlyTools | 内置工具built-in tools |
| packages/coding-agent/src/modes/interactive/interactive-mode.ts | InteractiveMode | 交互界面the interactive UI |
| packages/coding-agent/src/modes/rpc/rpc-client.ts | RpcClient | RPC 客户端RPC client |
根入口 index.ts 的全部导出(按来源模块)Every root index.ts export, by source module
展开全部 40 个来源模块Show all 40 source modules154 values304 types
| 来源模块Source module | 值导出Value exports | 类型导出Type exports |
|---|---|---|
| packages/coding-agent/src/cli/args.ts | parseArgs | Args |
| packages/coding-agent/src/config.ts | CONFIG_DIR_NAME getAgentDir getDocsPath getExamplesPath getPackageDir getReadmePath VERSION | — |
| packages/coding-agent/src/core/agent-session.ts | AgentSession parseSkillBlock | AgentSessionConfig AgentSessionEvent AgentSessionEventListener ModelCycleResult ParsedSkillBlock PromptOptions SessionStats |
| packages/coding-agent/src/core/auth-storage.ts | readStoredCredential | — |
| packages/coding-agent/src/core/cache-warmer.ts | — | CacheWarmingDecision CacheWarmingStatus |
| packages/coding-agent/src/core/compaction/index.ts | calculateContextTokens collectEntriesForBranchSummary compact DEFAULT_COMPACTION_SETTINGS estimateTokens findCutPoint findTurnStartIndex generateBranchSummary generateSummary generateSummaryWithUsage getLastAssistantUsage prepareBranchEntries serializeConversation shouldCompact | BranchPreparation BranchSummaryResult CollectEntriesResult CompactionResult CutPointResult FileOperations GenerateBranchSummaryOptions |
| packages/coding-agent/src/core/event-bus.ts | createEventBus | EventBus EventBusController |
| packages/coding-agent/src/core/extensions/index.ts | createExtensionRuntime defineTool discoverAndLoadExtensions ExtensionRunner isBashToolResult isEditToolResult isFindToolResult isGrepToolResult isLsToolResult isPowerShellToolResult isReadToolResult isToolCallEventType isWriteToolResult wrapRegisteredTool +1 | AfterProviderResponseEvent AgentActivityOutcome AgentBeforeSettleEvent AgentBeforeSettleEventResult AgentEndEvent AgentSettledEvent AgentStartEvent AgentToolResult AgentToolUpdateCallback AppKeybinding +133 |
| packages/coding-agent/src/core/footer-data-provider.ts | — | ReadonlyFooterDataProvider |
| packages/coding-agent/src/core/mcp-servers.ts | — | RegisteredMcpServer |
| packages/coding-agent/src/core/messages.ts | convertToLlm | — |
| packages/coding-agent/src/core/model-registry.ts | ModelRegistry | — |
| packages/coding-agent/src/core/model-resolver.ts | resolveCliModel resolveModelScopeWithDiagnostics | ModelScopeDiagnostic ResolveCliModelResult ResolveModelScopeResult ScopedModel |
| packages/coding-agent/src/core/model-runtime.ts | CredentialSynchronizationError ModelRuntime | CreateModelRuntimeOptions CredentialSynchronizationOperation ModelRuntimeAuthOverrides |
| packages/coding-agent/src/core/package-manager.ts | DefaultPackageManager | PackageManager PathMetadata ProgressCallback ProgressEvent ResolvedPaths ResolvedResource |
| packages/coding-agent/src/core/resource-loader.ts | DefaultResourceLoader loadProjectContextFiles | ResourceCollision ResourceDiagnostic ResourceLoader |
| packages/coding-agent/src/core/sdk.ts | AgentSessionRuntime createAgentSessionFromServices createAgentSessionRuntime createAgentSessionServices createBashTool createEditTool createFindTool createGrepTool createLsTool createPowerShellTool createReadOnlyTools createReadTool createWriteTool | AgentSessionRuntimeDiagnostic AgentSessionServices CreateAgentSessionFromServicesOptions CreateAgentSessionOptions CreateAgentSessionResult CreateAgentSessionRuntimeFactory CreateAgentSessionRuntimeResult CreateAgentSessionServicesOptions PromptTemplate |
| packages/coding-agent/src/core/session-manager.ts | buildContextEntries buildSessionContext buildSessionProjection CURRENT_SESSION_VERSION getLatestCompactionEntry migrateSessionEntries parseSessionEntries SessionManager sessionEntryToContextMessages | BranchSummaryEntry CompactionEntry ContextEditableContent ContextEditEntry CustomEntry CustomMessageEntry FileEntry ModelChangeEntry NewSessionOptions ProjectedSessionEntry +10 |
| packages/coding-agent/src/core/settings-manager.ts | SettingsManager | CacheWarmingMode CompactionModelOverride CompactionSettings DefaultProjectTrust FullscreenExitOutput ImageSettings PackageSource QuietStartup RetrySettings SettingsManagerCreateOptions +1 |
| packages/coding-agent/src/core/skills.ts | formatSkillsForPrompt loadSkills loadSkillsFromDir | LoadSkillsFromDirOptions LoadSkillsResult Skill SkillFrontmatter |
| packages/coding-agent/src/core/source-info.ts | createSyntheticSourceInfo | — |
| packages/coding-agent/src/core/tools/edit-diff.ts | generateDiffString generateUnifiedPatch | EditDiffResult |
| packages/coding-agent/src/core/tools/index.ts | createBashToolDefinition createEditToolDefinition createFindToolDefinition createGrepToolDefinition createLocalBashOperations createLocalPowerShellOperations createLsToolDefinition createPowerShellToolDefinition createReadToolDefinition createWriteToolDefinition DEFAULT_MAX_BYTES DEFAULT_MAX_LINES formatSize truncateHead +3 | BashOperations BashSpawnContext BashSpawnHook BashToolDetails BashToolInput BashToolOptions EditOperations EditToolDetails EditToolInput EditToolOptions +28 |
| packages/coding-agent/src/core/trust-manager.ts | hasTrustRequiringProjectResources ProjectTrustStore | ProjectTrustDecision ProjectTrustStoreEntry ProjectTrustUpdate |
| packages/coding-agent/src/core/virtual-models.ts | VIRTUAL_MODEL_STATE_ENTRY | ModelRoute ModelRouteReason ModelRouteRequest VirtualModelDefinition VirtualModelStateData |
| packages/coding-agent/src/extensions/codemode/index.ts | createCodemodeExtension | CodemodeExtensionOptions |
| packages/coding-agent/src/extensions/codemode/tool.ts | — | CodemodeStoreEntryData CodemodeToolDetails |
| packages/coding-agent/src/extensions/mcp/config.ts | — | LoadedMcpConfig McpExposure McpServerConfig McpServerEntry |
| packages/coding-agent/src/extensions/mcp/index.ts | createMcpExtension | McpExtensionOptions McpTransportFactory |
| packages/coding-agent/src/extensions/tool-search/index.ts | createToolSearchExtension | — |
| packages/coding-agent/src/main.ts | main | MainOptions |
| packages/coding-agent/src/modes/index.ts | InteractiveMode RpcClient runPrintMode runRpcMode | InteractiveModeOptions JsonAgentSessionEvent ModelInfo PrintModeOptions RpcClientOptions RpcCommand RpcEventListener RpcExtensionUIRequest RpcExtensionUIResponse RpcResponse +1 |
| packages/coding-agent/src/modes/interactive/components/index.ts | ArminComponent AssistantMessageComponent BashExecutionComponent BorderedLoader BranchSummaryMessageComponent CompactionSummaryMessageComponent CustomEditor CustomMessageComponent DynamicBorder ExtensionEditorComponent ExtensionInputComponent ExtensionSelectorComponent FooterComponent keyHint +17 | CustomEditorOptions RenderDiffOptions SettingsCallbacks SettingsConfig ToolExecutionOptions VisualTruncateResult |
| packages/coding-agent/src/modes/interactive/theme/theme.ts | getLanguageFromPath getMarkdownTheme getSelectListTheme getSettingsListTheme highlightCode initTheme Theme | ThemeAppearance ThemeBg ThemeColor ThemeStyle ThemeToken |
| packages/coding-agent/src/utils/clipboard.ts | copyToClipboard | — |
| packages/coding-agent/src/utils/frontmatter.ts | parseFrontmatter stripFrontmatter | — |
| packages/coding-agent/src/utils/image-convert.ts | convertToPng | — |
| packages/coding-agent/src/utils/image-resize.ts | formatDimensionNote resizeImage | ResizedImage |
| packages/coding-agent/src/utils/mime.ts | detectSupportedImageMimeTypeFromFile | — |
| packages/coding-agent/src/utils/shell.ts | getPowerShellConfig getShellConfig | — |
由构建脚本解析 export { … } from 语句生成;每个模块最多列出 14 个值、10 个类型。Generated by parsing the export { … } from statements at build time; at most 14 values and 10 types are listed per module.
CLI 启动流程CLI start-up#
一句话结论Takeawaymain() 是一条直线:先处理一次性命令,再解析参数、决定模式、跑迁移、读设置、建 SessionManager、确认项目信任、创建 runtime,最后把 runtime 交给 RPC、interactive 或 print 模式。main() is a straight line: handle one-shot commands, then parse args, resolve the mode, run migrations, load settings, create the SessionManager, settle project trust, create the runtime, and hand it to RPC, interactive or print mode.
要点Key points
resolveAppMode()同时看参数和 stdin/stdout 是否为 TTY:-p、或 stdin / stdout 任一不是 TTY 时走 print,--mode json/--mode rpc显式指定。resolveAppMode()looks at both args and whether stdin/stdout are TTYs:-p, or a non-TTY stdin or stdout, means print;--mode json/--mode rpcare explicit.runMigrations(cwd)在任何会话读写之前执行,迁移旧的认证文件、会话目录、工具目录、按键配置与扩展布局。runMigrations(cwd)runs before any session I/O and migrates old auth files, session directories, tool dirs, keybinding config and extension layout.- 项目信任(
ProjectTrustStore)决定是否加载<cwd>/.pi/下的设置与扩展;它在创建 runtime 之前确定。Project trust (ProjectTrustStore) decides whether settings and extensions under<cwd>/.pi/load at all; it is settled before the runtime is created. prepareInitialMessage()把命令行里的文字、@file附件和管道输入合成第一条用户消息。prepareInitialMessage()combines command-line text,@fileattachments and piped stdin into the first user message.
工作原理How it works
parseArgs(argv)→resolveAppMode(parsed, stdinIsTTY, stdoutIsTTY)。parseArgs(argv)→resolveAppMode(parsed, stdinIsTTY, stdoutIsTTY).createSessionManager():按--no-session/--fork/--session/--resume/--continue选择内存会话、分叉、打开指定会话或选择器。createSessionManager(): in-memory, fork, open a given session or show the picker according to--no-session/--fork/--session/--resume/--continue.createAgentSessionRuntime()构造 services 与第一个AgentSession。createAgentSessionRuntime()builds the services and the firstAgentSession.- 按模式分派:
runRpcMode(runtime)、new InteractiveMode(runtime).run()或runPrintMode(runtime, …)。Dispatch by mode:runRpcMode(runtime),new InteractiveMode(runtime).run()orrunPrintMode(runtime, …).
关键文件Key files · v1.1.0
| 文件File | 符号Symbol | 作用Role |
|---|---|---|
| packages/coding-agent/src/cli/args.tsL72 | parseArgs() | 参数解析argument parsing |
| packages/coding-agent/src/main.tsL112 | resolveAppMode() | 选择运行模式pick the run mode |
| packages/coding-agent/src/main.tsL211 | prepareInitialMessage() | 第一条消息the first message |
| packages/coding-agent/src/main.tsL358 | createSessionManager() | 打开 / 新建会话open / create a session |
| packages/coding-agent/src/migrations.tsL305 | runMigrations() | 布局迁移layout migrations |
| packages/coding-agent/src/core/trust-manager.tsL210 | ProjectTrustStore | 项目信任project trust |
运行模式Run modes#
一句话结论TakeawayresolveAppMode() 根据参数和 TTY 选出四种模式之一;它们都驱动同一个 AgentSessionRuntime。resolveAppMode() picks one of four modes from flags and TTY state; all of them drive the same AgentSessionRuntime.
本节沿用第一版的图(原位于总览页),已按 v1.1.0 重新核对。This section keeps its first-edition diagram (formerly on the overview page), re-checked against v1.1.0.
要点Key points
--mode rpc→ rpc;--mode json→ json;-p或 stdin / stdout 非 TTY → print;否则 interactive。--mode rpc→ rpc;--mode json→ json;-por non-TTY stdin / stdout → print; otherwise interactive.- RPC 模式读取 JSONL 命令(共 33 种:
prompt、steer、follow_up、abort、compact、set_model、fork、get_tree、bash…),回写响应与事件。RPC mode reads JSONL commands (33 kinds:prompt,steer,follow_up,abort,compact,set_model,fork,get_tree,bash, …) and writes responses and events. - RPC 通过
extension_ui_request把扩展的 UI 请求代理给宿主。RPC proxies extension UI requests to the host asextension_ui_request.
工作原理How it works
- 非 interactive 模式会先接管 stdout,避免日志污染协议输出。Non-interactive modes take over stdout first so logs cannot corrupt protocol output.
- 每种模式都调用
session.bindExtensions(),传入各自的mode和 UI 上下文。Each mode callssession.bindExtensions()with its ownmodeand UI context. - interactive 模式通过
createInteractiveTui()选择TuiMainScreen(regular)或TuiAltScreen(fullscreen)。Interactive mode usescreateInteractiveTui()to pickTuiMainScreen(regular) orTuiAltScreen(fullscreen).
关键文件Key files · v1.1.0
| 文件File | 符号Symbol | 作用Role |
|---|---|---|
| packages/coding-agent/src/main.tsL112 | resolveAppMode() | 模式选择mode selection |
| packages/coding-agent/src/modes/rpc/rpc-types.tsL20 | RpcCommand | RPC 命令联合类型RPC command union |
| packages/coding-agent/src/modes/rpc/rpc-mode.tsL54 | runRpcMode() | JSONL 服务循环JSONL service loop |
| packages/coding-agent/src/modes/print-mode.tsL33 | runPrintMode() | 一次性输出one-shot output |
| packages/coding-agent/src/modes/interactive/interactive-mode.tsL451 | InteractiveMode | 终端交互界面terminal UI |
AgentSession 如何装配 AgentHow AgentSession wires the Agent#
一句话结论TakeawayAgentSession 不改写 Agent 的循环,而是把每个钩子接到编码场景的实现上:streamFn 走 ModelRuntime,transformContext 交给扩展的 context 事件,beforeToolCall / afterToolCall 交给 tool_call / tool_result 事件,subscribe() 把每条消息写进会话文件。AgentSession does not rewrite the Agent loop; it plugs each hook into a coding-specific implementation: streamFn goes through ModelRuntime, transformContext to the extensions' context event, beforeToolCall / afterToolCall to the tool_call / tool_result events, and subscribe() writes every message into the session file.
要点Key points
- 事件先交给扩展、再交给 UI 监听器(
_handleAgentEvent),所以扩展总能先看到并改写。Events reach extensions before UI listeners (_handleAgentEvent), so extensions always see and rewrite first. - 一次运行结束后由
_handlePostAgentRun()决定是否再跑一次:可重试错误 → 退避重试;超出上下文或超过阈值 → 压缩;还有排队消息 →continue()。After a run,_handlePostAgentRun()decides whether to go again: retryable error → back off and retry; context overflow or over threshold → compact; queued messages →continue(). - 扩展的
tool_call处理器出错时,工具调用会被阻止,而不是放行。If an extension'stool_callhandler throws, the tool call is blocked rather than allowed. turn_end是边界点:扩展可以在两轮之间往会话里追加条目。turn_endis a boundary: extensions may append entries to the session between turns.
工作原理How it works
createAgentSession()(sdk.ts)构造new Agent({ streamFn, convertToLlm, … }),再把它交给new AgentSession(…)。createAgentSession()(sdk.ts) buildsnew Agent({ streamFn, convertToLlm, … })and passes it tonew AgentSession(…).AgentSession构造时安装其余钩子并agent.subscribe()。TheAgentSessionconstructor installs the remaining hooks and callsagent.subscribe().prompt(text):运行中按streamingBehavior转成steer()/followUp(),空闲时开始新一轮。prompt(text): while running it becomessteer()/followUp()perstreamingBehavior; when idle it starts a run.- 运行结束 →
_handlePostAgentRun()→ 必要时再次continue(),直到agent_settled。Run ends →_handlePostAgentRun()→continue()again if needed, untilagent_settled.
关键文件Key files · v1.1.0
| 文件File | 符号Symbol | 作用Role |
|---|---|---|
| packages/coding-agent/src/core/sdk.tsL191 | createAgentSession() | 构造 Agent 与 AgentSessionbuild Agent and AgentSession |
| packages/coding-agent/src/core/agent-session.tsL378 | AgentSession | 钩子与状态hooks and state |
| packages/coding-agent/src/core/agent-session.tsL1968 | prompt() | 入口entry point |
| packages/coding-agent/src/core/agent-session.tsL1853 | _handlePostAgentRun() | 重试 · 压缩 · 排队retry · compact · queue |
| packages/coding-agent/src/core/agent-session.tsL2947 | _checkCompaction() | 自动压缩判断auto-compaction check |
| packages/coding-agent/src/core/agent-session.tsL1369 | subscribe() | UI 监听UI listeners |
AgentSessionRuntime:替换会话AgentSessionRuntime: replacing the session#
一句话结论Takeaway/new、/resume、/fork、导入都不是在原会话上“改”,而是整个换掉:先问扩展是否取消,再关闭旧 AgentSession,用新的 SessionManager 和新的 services 建一个新 AgentSession,最后让 UI 和扩展重新绑定。/new, /resume, /fork and import never edit the current session; they replace it: ask extensions whether to cancel, shut down the old AgentSession, build a fresh one with a new SessionManager and fresh services, then let the UI and extensions rebind.
要点Key points
session_before_switch/session_before_fork返回{ cancel: true }时,整个替换中止,方法返回{ cancelled: true }。Ifsession_before_switch/session_before_forkreturns{ cancel: true }, the replacement stops and the method returns{ cancelled: true }.- 旧会话按 abort →
session_shutdown→dispose()的顺序关闭;扩展的 TUI 组件被同步卸下。The old session closes in the order abort →session_shutdown→dispose(); extension TUI widgets are detached synchronously. - 扩展中捕获的旧
ctx在替换后失效;需要在替换后继续工作的扩展应使用withSession回调里的新ctx。A capturedctxgoes stale after replacement; extensions that must keep working should use the freshctxpassed towithSession.
工作原理How it works
switchSession()/newSession()/fork()先触发对应的session_before_*事件。switchSession()/newSession()/fork()first emit the matchingsession_before_*event.- 打开或新建
SessionManager(fork 时newSession({ parentSession })记录来源)。Open or create aSessionManager(fork records the origin vianewSession({ parentSession })). createAgentSessionServices()+createAgentSessionFromServices()建新会话。createAgentSessionServices()+createAgentSessionFromServices()build the new session.- 替换 runtime 内的 session / services / diagnostics,再
rebindSession()。Swap session / services / diagnostics inside the runtime, thenrebindSession().
关键文件Key files · v1.1.0
| 文件File | 符号Symbol | 作用Role |
|---|---|---|
| packages/coding-agent/src/core/agent-session-runtime.tsL74 | AgentSessionRuntime | 可替换会话的宿主the host that swaps sessions |
| packages/coding-agent/src/core/agent-session-runtime.tsL196 | switchSession() | 切换 / 恢复switch / resume |
| packages/coding-agent/src/core/agent-session-runtime.tsL262 | fork() | 分叉fork |
| packages/coding-agent/src/core/agent-session-runtime.tsL420 | createAgentSessionRuntime() | 首次创建first creation |
| packages/coding-agent/src/core/agent-session-services.tsL135 | createAgentSessionServices() | 模型运行时 · 设置 · 资源model runtime · settings · resources |
内置工具Built-in tools#
一句话结论Takeaway8 个内置工具(read、bash、powershell、edit、write、grep、find、ls),默认启用 read / bash / edit / write。所有输出都经过统一截断(2000 行或 50KB),文件与进程操作通过可替换的 *Operations 接口完成。Eight built-in tools (read, bash, powershell, edit, write, grep, find, ls), with read / bash / edit / write on by default. All output goes through one truncation policy (2000 lines or 50 KB), and file and process access goes through swappable *Operations interfaces.
要点Key points
read从头截断(truncateHead),bash从尾截断(truncateTail)——命令最后的输出通常最重要。readtruncates from the head (truncateHead),bashfrom the tail (truncateTail) — the end of a command's output usually matters most.*Operations接口让 SDK 宿主把文件系统和 shell 换成远程、容器或测试实现,而不改工具逻辑。The*Operationsinterfaces let SDK hosts swap the filesystem and shell for remote, container or test implementations without touching tool logic.- 扩展用
pi.registerTool()注册的工具与内置工具并列,可通过setActiveTools()开关。Tools registered by extensions viapi.registerTool()sit alongside the built-ins and are toggled withsetActiveTools().
工作原理How it works
createAllTools(cwd, options)返回Record<ToolName, Tool>;createCodingTools()/createReadOnlyTools()是常用子集。createAllTools(cwd, options)returnsRecord<ToolName, Tool>;createCodingTools()/createReadOnlyTools()are the common subsets.- 工具执行结果 → 截断 → 必要时写临时文件并在结果里给出路径。Tool result → truncation → when needed, the full output goes to a temp file and the result names its path.
afterToolCall再把结果交给扩展的tool_result事件。afterToolCallthen hands the result to the extensions'tool_resultevent.
关键文件Key files · v1.1.0
| 文件File | 符号Symbol | 作用Role |
|---|---|---|
| packages/coding-agent/src/core/tools/index.tsL95 | ToolName | 8 个工具名the eight tool names |
| packages/coding-agent/src/core/tools/index.tsL213 | createAllTools() | 工具工厂tool factory |
| packages/coding-agent/src/core/tools/truncate.tsL11 | DEFAULT_MAX_LINES | 2000 行 / 50KB2000 lines / 50 KB |
| packages/coding-agent/src/core/tools/truncate.tsL168 | truncateTail() | bash 的尾部截断tail truncation for bash |
| packages/coding-agent/src/core/tools/edit.tsL43 | edit | 精确替换exact replacement |
会话文件:JSONL 格式The session file: JSONL format#
一句话结论Takeaway每个会话是一个追加写入的 JSONL 文件:第 1 行是会话头(version: 3),之后每行一个条目,共 11 种条目类型。条目用 id / parentId 组成树,分支、标签和压缩摘要都只是新的条目。Each session is an append-only JSONL file: line 1 is the header (version: 3), then one entry per line across 11 entry types. Entries form a tree through id / parentId; branches, labels and compaction summaries are just more entries.
要点Key points
- 文件按 cwd 分目录存放在
~/.pi/agent/sessions/下,文件名带时间戳与 UUIDv7。Files live under~/.pi/agent/sessions/, one directory per cwd, named with a timestamp and a UUIDv7. - 写入是惰性的:出现第一条 user 或 assistant 消息之前不落盘,首次写入用
wx标志,避免并发覆盖。Writes are lazy: nothing hits disk before the first user or assistant message, and the first write uses thewxflag to avoid clobbering. - 读取时按版本迁移(v1 → v2 → v3),必要时整文件重写,然后从叶子沿
parentId回溯得到当前上下文。On load, entries migrate by version (v1 → v2 → v3), the file is rewritten if needed, and the current context is rebuilt by walkingparentIdback from the leaf.
工作原理How it works
SessionManager.create()/open()→loadEntriesFromFile()。SessionManager.create()/open()→loadEntriesFromFile().migrateSessionEntries()原地升级到CURRENT_SESSION_VERSION。migrateSessionEntries()upgrades in place toCURRENT_SESSION_VERSION.buildSessionContext()处理压缩条目与分支摘要,产出发给模型的消息列表。buildSessionContext()applies compaction entries and branch summaries to produce the messages sent to the model.
关键文件Key files · v1.1.0
| 文件File | 符号Symbol | 作用Role |
|---|---|---|
| packages/coding-agent/src/core/session-manager.tsL41 | CURRENT_SESSION_VERSION | = 3= 3 |
| packages/coding-agent/src/core/session-manager.tsL183 | SessionEntry | 11 种条目11 entry types |
| packages/coding-agent/src/core/session-manager.tsL350 | migrateSessionEntries() | 版本迁移version migration |
| packages/coding-agent/src/core/session-manager.tsL576 | buildSessionContext() | 树 → 上下文tree → context |
| packages/coding-agent/src/core/session-manager.tsL987 | SessionManager | 读写与分支I/O and branching |
会话持久化与分支Session persistence & branching#
一句话结论Takeaway会话是只追加的 JSONL 文件;每个条目带 id 与 parentId,所以一个文件就是一棵树,leafId 指向当前位置。A session is an append-only JSONL file; every entry has id and parentId, so one file is a tree and leafId marks the current position.
本节沿用第一版的图(原位于总览页),已按 v1.1.0 重新核对。This section keeps its first-edition diagram (formerly on the overview page), re-checked against v1.1.0.
要点Key points
- 第 1 行是
session头(version3、id、cwd、可选parentSession)。Line 1 is thesessionheader (version3,id,cwd, optionalparentSession). - 11 种条目:message、thinking_level_change、model_change、usage、compaction、branch_summary、custom、custom_message、label、session_info、context_edit。11 entry types: message, thinking_level_change, model_change, usage, compaction, branch_summary, custom, custom_message, label, session_info, context_edit.
- 分支不会改写历史:把 leaf 移回旧条目,下一次追加自然形成兄弟分支。Branching never rewrites history: move the leaf to an older entry and the next append becomes a sibling branch.
context_edit只追加,能把某个旧条目从模型上下文中删除(replacement: null)或替换其内容。context_editis append-only and can drop an earlier entry from model context (replacement: null) or replace its content.
工作原理How it works
branchWithSummary()把 leaf 移到分支点,并追加一个branch_summary(fromId指向被放弃的 leaf),记录那条路径做过什么。branchWithSummary()moves the leaf to the branch point and appends abranch_summary(withfromIdpointing at the abandoned leaf) describing that path.buildSessionContext()从 leaf 走到根,应用最新的 compaction 与 context_edit,再转换为 LLM 消息。buildSessionContext()walks from leaf to root, applies the latest compaction and context edits, and converts entries to LLM messages.- 文件位于
~/.pi/agent/sessions/<cwd>/,custom条目供扩展保存状态但不进入上下文,custom_message则会进入。Files live under~/.pi/agent/sessions/<cwd>/;customentries store extension state outside the context,custom_messageentries enter it.
关键文件Key files · v1.1.0
| 文件File | 符号Symbol | 作用Role |
|---|---|---|
| packages/coding-agent/src/core/session-manager.tsL43 | SessionHeader | 文件头file header |
| packages/coding-agent/src/core/session-manager.tsL183 | SessionEntry | 条目联合类型entry union type |
| packages/coding-agent/src/core/session-manager.tsL1600 | branchWithSummary() | 带摘要的分支branch with summary |
| packages/coding-agent/src/core/session-manager.tsL175 | ContextEditEntry | 追加式上下文编辑append-only context edit |
上下文压缩Compaction#
一句话结论Takeaway三种触发(manual / threshold / overflow)走同一条路径:保留最近的尾部,用 LLM 总结更早的部分,存为一个 compaction 条目。Three triggers (manual / threshold / overflow) share one path: keep the recent tail, summarize the rest with the LLM, store it as a compaction entry.
本节沿用第一版的图(原位于总览页),已按 v1.1.0 重新核对。This section keeps its first-edition diagram (formerly on the overview page), re-checked against v1.1.0.
要点Key points
- threshold:
contextTokens > contextWindow − reserveTokens(默认reserveTokens= 16384)。threshold:contextTokens > contextWindow − reserveTokens(defaultreserveTokens= 16384). - overflow:provider 返回上下文溢出错误或可恢复的
length截断;删除失败消息、压缩,并只重试一次。overflow: a context-overflow error or a recoverablelengthstop; drop the failed message, compact, and retry exactly once. findCutPoint()保留约keepRecentTokens(默认 20000)的最近内容,并让切点落在轮次边界上。findCutPoint()keeps aboutkeepRecentTokens(default 20000) of recent content and puts the cut on a turn boundary.- 扩展可在
session_before_compact中取消压缩,或直接提供自己的压缩结果。Extensions can cancel compaction insession_before_compactor supply their own result.
工作原理How it works
- 自动检查发生在三处:
agent_end之后、提交新提示之前,以及prepareNextTurn中(同一次运行的轮次之间)。Automatic checks run in three places: afteragent_end, before a new prompt, and insideprepareNextTurn(between turns of one run). - token 数优先取最后一条 assistant 的 usage;出错或 usage 为 0 时按 chars/4 估算。Token counts come from the last assistant usage; on errors or zero usage they are estimated at chars/4.
appendCompaction(summary, firstKeptEntryId, tokensBefore, …)之后,上下文重建为“摘要 + 保留的消息”。AfterappendCompaction(summary, firstKeptEntryId, tokensBefore, …)the context is rebuilt as summary + kept messages.
关键文件Key files · v1.1.0
| 文件File | 符号Symbol | 作用Role |
|---|---|---|
| packages/coding-agent/src/core/compaction/compaction.tsL267 | shouldCompact() | 阈值判断threshold test |
| packages/coding-agent/src/core/compaction/compaction.tsL446 | findCutPoint() | 选择保留的尾部chooses the kept tail |
| packages/coding-agent/src/core/agent-session.tsL2947 | _checkCompaction() | 三种自动情形the automatic cases |
| packages/coding-agent/src/core/agent-session.tsL3097 | _runAutoCompaction() | 扩展钩子与追加extension hook and append |
| packages/coding-agent/src/core/compaction/compaction.tsL126 | DEFAULT_COMPACTION_SETTINGS | 默认 token 参数default token budgets |
扩展 API:能力面与事件The extension API: capabilities and events#
一句话结论Takeaway扩展是一个默认导出函数 (pi) => { … }。pi 上有 32 个方法(注册工具 / 命令 / 快捷键 / provider / 渲染器,行动,读取),pi.on() 可以订阅 41 种事件,其中 18 种的处理器可以返回结果来改写或拦截。An extension is a default-exported function (pi) => { … }. pi has 32 methods (register tools / commands / shortcuts / providers / renderers, act, read), and pi.on() subscribes to 41 events, 18 of which let handlers return a result that rewrites or intercepts.
要点Key points
- 每个处理器的第二个参数是
ctx:ExtensionContext有 18 个成员(cwd、模型、会话、ui…),命令处理器拿到的ExtensionCommandContext还能新建 / 分叉 / 切换会话。Every handler's second argument isctx:ExtensionContexthas 18 members (cwd, model, session,ui…); command handlers getExtensionCommandContext, which can also create / fork / switch sessions. ctx.ui有 28 个成员:对话框、通知、状态栏、widget、自定义组件;在 RPC 模式下它们变成extension_ui_request。ctx.uihas 28 members: dialogs, notifications, status, widgets, custom components; in RPC mode they becomeextension_ui_requests.- 可拦截事件的典型用法:
input改写或接管输入,tool_call阻止工具,context替换本次上下文,session_before_*取消会话操作。Typical interceptions:inputrewrites or handles input,tool_callblocks a tool,contextreplaces this request's context,session_before_*cancels a session operation.
工作原理How it works
- 加载器用 jiti 导入扩展文件,调用工厂函数,把注册内容收集到
ExtensionRunner。The loader imports extension files with jiti, calls the factory, and collects registrations into theExtensionRunner. AgentSession在各个时机调用runner.emit*();有结果的事件按扩展顺序依次处理。AgentSessioncallsrunner.emit*()at each point; result-returning events run through extensions in order./reload重新执行整个加载过程;旧的pi与ctx随之失效。/reloadreruns the whole load; the oldpiandctxbecome stale.
关键文件Key files · v1.1.0
| 文件File | 符号Symbol | 作用Role |
|---|---|---|
| packages/coding-agent/src/core/extensions/types.tsL1564 | ExtensionAPI | pi 对象the pi object |
| packages/coding-agent/src/core/extensions/types.tsL325 | ExtensionContext | 处理器的 ctxthe handler ctx |
| packages/coding-agent/src/core/extensions/types.tsL149 | ExtensionUIContext | ctx.uictx.ui |
| packages/coding-agent/src/core/extensions/types.tsL574 | ToolDefinition | registerTool 的参数registerTool's argument |
| packages/coding-agent/src/core/extensions/runner.tsL357 | ExtensionRunner | 事件分发event dispatch |
| packages/coding-agent/src/core/extensions/loader.tsL718 | loadExtensions() | 加载loading |
扩展生命周期Extension lifecycle#
一句话结论Takeaway扩展是用 jiti 加载的 TypeScript 模块:工厂函数拿到 ExtensionAPI 注册能力,ExtensionRunner 在 41 个事件上分发。Extensions are TypeScript modules loaded with jiti: a factory receives an ExtensionAPI to register capabilities, and ExtensionRunner dispatches 41 events.
本节沿用第一版的图(原位于总览页),已按 v1.1.0 重新核对。This section keeps its first-edition diagram (formerly on the overview page), re-checked against v1.1.0.
要点Key points
- 发现来源:全局
~/.pi/agent/extensions、项目.pi/extensions、settings 中的 packages,以及命令行-e。Sources: global~/.pi/agent/extensions, project.pi/extensions, packages in settings, and CLI-e. register*家族:Tool、Command、Shortcut、Flag、Provider、McpServer、MessageRenderer、EntryRenderer、ToolRenderer、VirtualModel 等。Theregister*family: Tool, Command, Shortcut, Flag, Provider, McpServer, MessageRenderer, EntryRenderer, ToolRenderer, VirtualModel and more.- 可改写数据的事件:
input、context、before_provider_request、tool_call(可阻止)、tool_result、session_before_compact(可取消)。Events that can change data:input,context,before_provider_request,tool_call(block),tool_result,session_before_compact(cancel).
工作原理How it works
createAgentSessionServices()创建DefaultResourceLoader,reload()解析路径并调用loadExtensionsCached()。createAgentSessionServices()creates aDefaultResourceLoader;reload()resolves paths and callsloadExtensionsCached().- 加载期间
ExtensionRuntime的动作方法是会抛错的占位,registerProvider则先排队;AgentSession创建ExtensionRunner并bindCore()后换成真实动作。While loading,ExtensionRuntimeaction methods are throwing stubs andregisterProvidercalls are queued; onceAgentSessioncreates theExtensionRunner,bindCore()swaps in real actions. - 模式调用
session.bindExtensions({ uiContext, mode })绑定 UI,随后发出session_start与resources_discover。The mode callssession.bindExtensions({ uiContext, mode })to bind UI, thensession_startandresources_discoverfire.
关键文件Key files · v1.1.0
| 文件File | 符号Symbol | 作用Role |
|---|---|---|
| packages/coding-agent/src/core/extensions/loader.tsL828 | discoverAndLoadExtensions() | 目录发现directory discovery |
| packages/coding-agent/src/core/resource-loader.tsL695 | loadCurrentExtensionSet() | 实际加载路径the real load path |
| packages/coding-agent/src/core/extensions/types.tsL1564 | ExtensionAPI | 扩展可用的全部 APIthe full extension API |
| packages/coding-agent/src/core/extensions/runner.tsL410 | bindCore() | 接入会话动作binds session actions |
| packages/coding-agent/src/core/agent-session.tsL3258 | bindExtensions() | UI 绑定与 session_startUI binding and session_start |
RPC 协议The RPC protocol#
一句话结论Takeawaypi --mode rpc 把智能体变成一个子进程服务:stdin 每行一个 JSON 命令(33 种,分 11 组),stdout 每行一个 JSON——命令响应、会话事件流、扩展 UI 请求混在同一条流里,靠 type 字段区分。pi --mode rpc turns the agent into a subprocess service: one JSON command per stdin line (33 types in 11 groups), one JSON value per stdout line — command responses, the session event stream and extension UI requests share one stream, told apart by type.
要点Key points
prompt不等运行结束:预检通过就回响应(带disposition),之后的一切以事件到达。promptdoes not wait for the run: it responds once preflight passes (with adisposition), and everything after arrives as events.- 需要回答的扩展 UI(select / confirm / input / editor)发出
extension_ui_request,宿主用同一个id回extension_ui_response;通知类请求不需要回答。Extension UI that needs an answer (select / confirm / input / editor) emits anextension_ui_request; the host replies with anextension_ui_responsecarrying the sameid. Notification-style requests need no answer. - JSONL 读取器只按
\n切分:JSON 字符串里合法的 U+2028 / U+2029 不会把一行切断(Node 的 readline 会)。The JSONL reader splits on\nonly: U+2028 / U+2029, legal inside JSON strings, never break a line (Node's readline would). - TypeScript 宿主可以直接用
RpcClient,它负责启动子进程、配对请求与响应。TypeScript hosts can useRpcClient, which spawns the process and pairs requests with responses.
工作原理How it works
runRpcMode(runtime)接管 stdout,订阅会话事件并逐条输出toJsonEvent(event)。runRpcMode(runtime)takes over stdout, subscribes to session events and writestoJsonEvent(event)for each.attachJsonlLineReader(stdin)逐行解析命令,handleCommand()按type分派。attachJsonlLineReader(stdin)parses commands line by line;handleCommand()dispatches ontype.- 响应形如
{ type: "response", id, command, success, data | error }。Responses look like{ type: "response", id, command, success, data | error }.
关键文件Key files · v1.1.0
| 文件File | 符号Symbol | 作用Role |
|---|---|---|
| packages/coding-agent/src/modes/rpc/rpc-types.tsL20 | RpcCommand | 33 种命令33 commands |
| packages/coding-agent/src/modes/rpc/rpc-types.tsL116 | RpcResponse | 响应responses |
| packages/coding-agent/src/modes/rpc/rpc-mode.tsL54 | runRpcMode() | 服务循环the service loop |
| packages/coding-agent/src/modes/rpc/jsonl.tsL21 | attachJsonlLineReader() | 按 \n 切行split on \n |
| packages/coding-agent/src/modes/rpc/rpc-client.tsL56 | RpcClient | TS 客户端TS client |
设置、资源与 system promptSettings, resources and the system prompt#
一句话结论Takeaway配置分全局(~/.pi/agent/)和项目(<cwd>/.pi/)两层,项目层只在项目受信任时生效。DefaultResourceLoader.reload() 依次确定信任、重读设置、解析 pi 包、加载扩展与其余资源;system prompt 由一组有序、可单独替换的分段组成。Configuration has a global layer (~/.pi/agent/) and a project layer (<cwd>/.pi/); the project layer applies only to trusted projects. DefaultResourceLoader.reload() settles trust, re-reads settings, resolves pi packages, then loads extensions and the other resources; the system prompt is a set of ordered, independently replaceable sections.
要点Key points
deepMergeSettings(global, project):项目值覆盖全局值,嵌套对象逐键合并。deepMergeSettings(global, project): project values win, nested objects merge key by key.- pi 包可以来自
npm:、git:或本地路径,一个包里可以同时带扩展、技能、提示模板和主题。pi packages come fromnpm:,git:or local paths; one package can ship extensions, skills, prompt templates and themes together. SYSTEM.md整段替换默认开头,并去掉 tools / rules / docs 分段;APPEND_SYSTEM.md只追加<addendum>。两者都是项目优先于全局。SYSTEM.mdreplaces the default preamble and drops the tools / rules / docs sections;APPEND_SYSTEM.mdonly adds<addendum>. For both, project beats global.- 上下文文件(AGENTS.md、CLAUDE.md …)从全局目录和 cwd 的每一级祖先目录收集,放进
<project_context>。Context files (AGENTS.md, CLAUDE.md …) are collected from the global dir and every ancestor of cwd into<project_context>.
工作原理How it works
createAgentSessionServices()创建SettingsManager、ModelRuntime与DefaultResourceLoader,并调用reload()。createAgentSessionServices()creates theSettingsManager,ModelRuntimeandDefaultResourceLoader, and callsreload().reload():resolveProjectTrust→settingsManager.reload()→packageManager.resolve()→ CLI 路径 →loadFinalExtensionSet()→ 技能 / 提示 / 主题。reload():resolveProjectTrust→settingsManager.reload()→packageManager.resolve()→ CLI paths →loadFinalExtensionSet()→ skills / prompts / themes.buildSystemPromptSections()组装 preamble、tools、rules、docs、addendum、project_context、skills、cwd 与扩展追加的分段。buildSystemPromptSections()assembles preamble, tools, rules, docs, addendum, project_context, skills, cwd and extension-added sections.
关键文件Key files · v1.1.0
| 文件File | 符号Symbol | 作用Role |
|---|---|---|
| packages/coding-agent/src/core/settings-manager.tsL273 | deepMergeSettings() | 两层合并two-layer merge |
| packages/coding-agent/src/core/settings-manager.tsL402 | SettingsManager | 设置读写settings I/O |
| packages/coding-agent/src/core/resource-loader.tsL509 | reload() | 资源加载流程the load pipeline |
| packages/coding-agent/src/core/resource-loader.tsL1210 | SYSTEM.md | 项目优先project first |
| packages/coding-agent/src/core/system-prompt.tsL128 | buildSystemPromptSections() | 分段组装section assembly |
扩展点Extension points#
pi.registerTool()增加模型可调用的工具,与内置工具并列。Add tools the model can call, alongside the built-ins.pi.on(event, handler)41 种事件,18 种可返回结果来改写或拦截。41 events; 18 can return a result to rewrite or intercept.pi.registerCommand() · registerShortcut()斜杠命令与快捷键。Slash commands and keyboard shortcuts.pi.registerProvider() · registerVirtualModel()接入新的模型 provider 或虚拟模型路由。Add model providers or virtual-model routing.ctx.ui.custom() · setWidget()在 TUI 中放入自定义组件。Put custom components into the TUI.*OperationsSDK 宿主替换文件系统与 shell 的实现。SDK hosts swap the filesystem and shell implementations.SYSTEM.md · APPEND_SYSTEM.md · AGENTS.md不写代码也能改 system prompt。Change the system prompt without code.--mode rpc作为子进程嵌入任何语言的宿主:33 种 JSONL 命令。Embed as a subprocess from any language: 33 JSONL commands.测试Tests#
一句话结论Takeaway测试最多的是会话与交互:AgentSession(重试、压缩、排队)、SessionManager 的树与迁移、扩展事件、RPC 协议与各个工具都有独立测试文件。Most tests cover sessions and interaction: AgentSession (retry, compaction, queues), the SessionManager tree and migrations, extension events, the RPC protocol and each tool have their own test files.
另有 294 个测试文件未列出(共 314 个,2593 个用例)。294 more test files not listed (314 files, 2593 cases in total).
用例数 = 源码中 it( / test( 的出现次数(静态统计,不运行测试)。Cases = occurrences of it( / test( in the source (static count; tests were not run).