Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

附录

A. 核心类型速查表

pi-ai 层

类型文件用途关键字段
Model<TApi>types.ts模型定义id: string — 唯一标识(如 claude-sonnet-4-5
provider: string — 提供方(如 anthropic
api: TApi — API 类型标记
cost: { input, output, cacheRead, cacheWrite } — 每 token 价格
contextWindow: number — 上下文窗口大小
maxOutput?: number — 最大输出 token 数
Contexttypes.tsLLM 调用上下文systemPrompt?: string — 可选系统提示词
messages: Message[] — 对话历史
tools?: Tool[] — 可用工具定义
AssistantMessageEventtypes.ts流式事件start — 初始化 partial assistant message
text_* / thinking_* / toolcall_* — 分块流式更新
done — 成功结束并携带最终消息
error — 失败或中止结束并携带错误消息
StreamFunctiontypes.tsProvider 必须实现的流式函数签名:(model, context, options?) => AssistantMessageEventStream
契约:返回事件流,不通过抛异常传递运行期错误
Usagetypes.tsToken 使用量input: number — 输入 token
output: number — 输出 token
cacheRead: number — 缓存读取
cacheWrite: number — 缓存写入
cost: { input, output, cacheRead, cacheWrite, total }

pi-agent-core 层

类型文件用途关键字段
AgentMessagetypes.ts扩展消息类型联合类型:Message | CustomAgentMessages[...]
标准消息来自 pi-aiuser / assistant / toolResult
产品层可通过声明合并追加自定义消息
AgentTool<TParams>types.ts工具定义name: string — 工具名称
parameters: TParams — 参数(继承 Tool<TParameters>)
label: string — UI 显示的可读名称
prepareArguments?: (args) => Static<TParams> — 可选的参数预处理
execute(toolCallId, params, signal, onUpdate): Promise<AgentToolResult> — 执行函数
AgentEventtypes.ts循环生命周期事件type 联合:
agent_start / agent_end — 本轮运行开始/结束
turn_start / turn_end — 一轮 assistant turn 开始/结束
message_start / message_update / message_end — 消息流式生命周期
tool_execution_start / tool_execution_update / tool_execution_end — 工具执行生命周期
AgentLoopConfigtypes.ts循环引擎配置model: Model — 本轮使用的模型
convertToLlmAgentMessage[] -> Message[] 转换
transformContext? — LLM 调用前的上下文变换
beforeToolCall? / afterToolCall? — 工具调用前后钩子
getSteeringMessages? / getFollowUpMessages? — 运行中注入消息
AgentStateagent.tsAgent 可变状态systemPrompt: string — 当前系统提示词
model: Model — 当前模型
thinkingLevel: ThinkingLevel — 后续 turn 的思考级别
tools / messages — 以 copy-on-assign 方式暴露的数组状态
isStreaming / streamingMessage / pendingToolCalls / errorMessage — 当前运行态

pi-coding-agent 层

类型文件用途关键字段
SessionEntrysession-manager.ts会话持久化条目9 种类型联合:
message — 用户/助手消息
thinking_level_change — 思考级别变更
model_change — 模型切换
compaction — 压缩记录
branch_summary — 分支摘要
custom — 自定义条目
custom_message — 自定义消息
label — 标签
session_info — 会话信息
每条有 id, parentId, timestamp
AgentSessionEventagent-session.ts产品层事件AgentEvent 的超集:额外包含 queue_updatecompaction_start / compaction_endauto_retry_start / auto_retry_end
AgentSessionagent-session.ts产品层 agent 包装组合了 Agent + SessionManager + SettingsManager
prompt(text, options?) — 发送消息并运行循环
compact(customInstructions?) — 主动触发压缩
subscribe(listener) — 订阅 AgentSessionEvent
abort() — 中止当前循环
Skillskills.ts能力扩展定义name: string — 技能名称
description: string — 描述
filePath: string — SKILL.md 路径
baseDir: string — 技能目录
sourceInfo — 来源信息
disableModelInvocation — 是否从 prompt 中隐藏
Extensioncore/extensions/types.ts运行时扩展name: string — 扩展名称
setup(api) — 初始化函数
API 提供:registerTool, registerCommand, on(event, handler)

B. 设计模式索引

模式出现位置章节模式说明
插件注册(Map + register/get)api-registry.ts, oauth/index.ts第 4、7 章用注册表 Map 存储,register() 添加,get() 查找。api-registry 按 api 键控,不用 DI 框架,不用反射
有损变换(isSameModel 判断)transform-messages.ts第 5 章跨模型消息变换时,标记信息丢失(如 thinking 块),便于下游处理
流式契约(Must not throw)StreamFn type, AgentLoopConfig第 6、8 章Provider 的 stream 函数承诺不抛异常,错误通过事件流传递。调用方不需要 try-catch
双层循环(steering + follow-up)agent-loop.ts runLoop()第 8 章外层 steering 循环处理模型切换和重试,内层 follow-up 循环处理工具调用后的后续对话
三阶段工具执行(prepare/execute/finalize)agent-loop.ts第 9 章prepare 获取资源/确认权限,execute 执行操作,finalize 清理/格式化结果。任何阶段可中止
声明合并扩展(CustomAgentMessages)types.ts第 10 章TypeScript declare module + interface merging,让产品层添加自定义消息类型而不修改内核
Copy-on-assign(getter/setter + slice)agent.ts MutableAgentState第 10 章读取 messages 返回浅拷贝,赋值 messages = [...] 替换整个数组。防止外部意外修改内部状态
Append-only 树(JSONL + parentId)session-manager.ts第 11 章每条记录有唯一 id 和 parentId。新分支从分支点的 id 开始,旧分支保留不删除。JSONL 格式支持崩溃恢复
三级配置覆盖(全局/项目/目录)settings-manager.ts, resource-loader第 13 章全局配置 < 项目配置 < 目录配置。就近原则,越具体越优先。类似 CSS 的层叠覆盖
Pluggable I/O(EditOperations, BashOperations)edit.ts, bash.ts, find.ts第 19-23 章工具不直接调用 fschild_process,而是通过接口注入。测试用 mock,Docker 用远程执行
极简组件接口(Component)tui.ts第 24 章UI 组件实现 render(width: number): string[],可选 handleInput?(data),并要求实现 invalidate()。没有虚拟 DOM、没有状态管理框架
消息队列串行化agent.ts (mom)第 28 章所有 Slack API 调用通过 Promise 链串行执行,避免消息乱序。enqueue() 返回 void,错误内部处理
委托模式(DockerExecutor → HostExecutor)sandbox.ts第 28 章DockerExecutor 把命令包装为 docker exec,委托给 HostExecutor 执行。关注点分离

C. 一次完整请求的时序图

sequenceDiagram
    participant User
    participant Editor as Editor - TUI
    participant Agent as Agent
    participant Loop as agentLoop
    participant Transform as transformContext
    participant Convert as convertToLlm
    participant Provider as LLM Provider
    participant Tool as Tool Execute
    participant Session as SessionManager

    User->>Editor: 输入消息 + Enter
    Editor->>Agent: agent.prompt(msg)
    Note over Agent: 添加用户消息到 state.messages
    Agent->>Loop: runAgentLoop(prompts, context, config)
    
    rect rgb(230, 245, 255)
        Note over Loop,Convert: 上下文准备阶段
        Loop->>Transform: transformContext(messages)
        Note over Transform: 可注入 plan 指令、截断历史、<br/>过滤敏感信息
        Transform-->>Loop: pruned messages
        Loop->>Convert: convertToLlm(messages)
        Note over Convert: AgentMessage → ai 层 Message<br/>过滤/转换应用层消息
        Convert-->>Loop: LLM-compatible messages
    end
    
    rect rgb(255, 245, 230)
        Note over Loop,Provider: 模型调用阶段
        Loop->>Provider: streamSimple(model, context)
        Note over Provider: HTTP SSE 流式调用
        Provider-->>Loop: events (text_delta, toolcall_end, done)
        Loop->>Agent: emit(message_end)
        Agent->>Session: persist entry
    end
    
    alt has tool calls
        rect rgb(230, 255, 230)
            Note over Loop,Tool: 三阶段工具执行
            Loop->>Tool: prepareToolCall()
            Note over Tool: 获取资源、权限检查<br/>beforeToolCall 钩子在此触发
            Tool-->>Loop: prepared (or denied)
            Loop->>Tool: executePreparedToolCall()
            Note over Tool: 实际执行操作<br/>(bash 命令、文件读写等)
            Tool-->>Loop: result
            Loop->>Tool: finalizeExecutedToolCall()
            Note over Tool: 格式化结果、截断过长输出
            Tool-->>Loop: final result
        end
        Loop->>Agent: emit(tool_execution_end)
        Note over Agent: UI / extension 观察工具完成
        Loop->>Agent: emit(message_end)
        Agent->>Session: persist toolResult message
        Note over Loop: 回到上下文准备阶段,进入下一轮
        Loop->>Provider: next LLM call (with tool results)
    end
    
    Loop->>Agent: emit(agent_end)
    Agent->>Session: session complete
    Agent->>Editor: render final state

关键节点说明

  1. transformContext 是 AgentMessage[] 级的预处理点。裁剪历史、注入额外上下文、实现 plan-like 控制通常放在这里
  2. convertToLlm 是 AgentMessage[] -> Message[] 的边界转换。它负责过滤或改写应用层消息;真正的跨 provider 兼容处理还会在 pi-ai 的 provider 层继续发生
  3. 三阶段工具执行保证了安全性。prepare 阶段可以拒绝执行(beforeToolCall 钩子),execute 阶段实际操作,finalize 阶段格式化输出
  4. 事件驱动的持久化主要挂在 message_endtool_execution_end 主要用于 UI 和 extension 观测,真正写入会话的是随后产生的 toolResult 消息

D. /compact 命令的端到端追踪

下面追踪用户在 pi CLI 中输入 /compact 命令时,系统内部发生的完整过程。

Phase 1:命令解析

用户输入: /compact
    ↓
interactive-mode: 识别 `/compact` 或 `/compact ...`
    ↓
handleCompactCommand(customInstructions)
    ↓
AgentSession.compact(customInstructions?)

/compact 不经过 agent 循环本身。它先由 interactive mode 在本地识别,再直接调用 AgentSession.compact(...)

Phase 2:Compaction 触发

compact handler
    ↓
SessionManager.getEntries()  → 获取当前所有会话条目
    ↓
estimateTokens(messages)     → 估算当前 context token 数
    ↓
Agent.state.messages         → 获取当前消息列表
    ↓
emit("compaction_start", { reason: "manual" })

Phase 3:LLM 总结

compaction_start 事件
    ↓
构建 compaction prompt:
  "请总结以下对话的关键信息..."
  + 当前所有消息
    ↓
completeSimple(compactionModel, compactionContext)
  → 调用 LLM 生成总结
    ↓
收集 LLM 输出 → summary text

Compaction 使用的模型可能和主对话模型不同(通常用更快更便宜的模型)。

Phase 4:状态更新

summary text
    ↓
SessionManager.appendCompaction(
  summary,
  firstKeptEntryId,
  tokensBefore,
  details?
)
  → 将 compaction 记录追加到 JSONL
    ↓
buildSessionContext()
  → 从 entries 重建完整的 session context
    ↓
agent.state.messages = sessionContext.messages
  → 用重建后的消息列表替换 agent 状态
    ↓
emit("compaction_end", { result: { summary, firstKeptEntryId, tokensBefore, details } })

Phase 5:UI 更新

compaction_end 事件
    ↓
TUI 订阅者收到事件
    ↓
清空并重建 chat
    ↓
插入 compaction summary message
    ↓
刷新 footer / 状态显示

完整数据流

sequenceDiagram
    participant User
    participant TUI
    participant Session as AgentSession
    participant SM as SessionManager
    participant LLM as Compaction LLM

    User->>TUI: /compact
    TUI->>TUI: 识别 /compact 并提取自定义指令
    TUI->>Session: compact(customInstructions?)
    Session->>SM: getEntries()
    SM-->>Session: all entries
    Session->>Session: estimateTokens()
    Note over Session: tokensBefore = 150,000
    
    Session->>Session: emit(compaction_start)
    TUI-->>TUI: 显示 "Compacting..."
    
    Session->>LLM: completeSimple(summary prompt)
    LLM-->>Session: summary text
    
    Session->>SM: appendCompaction(summary, firstKeptEntryId, tokensBefore, details)
    Note over SM: 写入 JSONL:<br/>{type: "compaction", summary, ...}
    
    Session->>SM: buildSessionContext()
    SM-->>Session: sessionContext
    Note over Session: 从 entries 重建上下文
    Session->>Session: agent.state.messages = sessionContext.messages
    
    Session->>Session: emit(compaction_end)
    TUI-->>TUI: 重建 chat + 插入 summary message
    
    Note over User: 下次 LLM 调用只看到<br/>重建后的 context

关键观察

  1. /compact 不经过 agent 循环。它是一次本地命令处理 + 一次独立的 LLM 调用
  2. 状态重建而非直接替换appendCompaction 记录压缩事件后,buildSessionContext() 从 entries 重建上下文,再赋值给 agent.state.messages。不是直接构造一条 summary 消息替换
  3. 持久化保留历史。SessionManager 记录 compaction 事件,但不删除历史条目。JSONL 是 append-only 的,buildSessionContext() 负责根据 compaction 记录决定哪些 entries 构成当前 context
  4. 事件驱动 UI。TUI 不直接参与 compaction 逻辑,只订阅事件更新显示

E. 二次开发入口清单

我想做什么起点文件/函数参考章节
加一个新 LLM providerpackages/ai 中实现 provider + registerApiProvider() + model wiring第 4、18 章
加一个新工具Extension API → registerTool()第 15、19 章
加一个新 slash commandExtension API → registerCommand()第 15 章
改 system prompt创建 SYSTEM.mdAGENTS.md第 13-14 章
自定义权限策略beforeToolCall 钩子第 9 章
改 compaction 策略Extension hook: on("session_before_compact", handler)第 12 章
加一个新 UI 模式参考 modes/rpc/ 实现新 mode第 26 章
支持新的消息类型CustomAgentMessages 声明合并第 10 章
加一个新 OAuth providerregisterOAuthProvider()第 7 章
自定义上下文管理transformContext 回调第 8 章
构建 Slack bot 产品参考 packages/mom/ 完整实现第 28 章
部署自有模型参考 packages/pods/ 的 SSH + vLLM 流程第 29 章
实现审计日志订阅 AgentEvent,写入日志系统第 10 章
实现成本预算控制transformContext 中检查累计 token 使用量第 8 章
实现 A/B 测试(模型对比)getModel() 中随机选择模型第 4 章

F. 术语对照表

英文术语本书用法说明
Agent Loop循环引擎 / agent 循环agentLoop() 函数实现的 LLM 调用 → 工具执行 → 再调用循环
Compaction上下文压缩用 LLM 总结对话历史,减少 token 使用
Extension扩展运行时代码扩展,可注册工具、命令、事件处理器
Provider提供方LLM API 提供方(Anthropic、OpenAI 等)
Skill技能纯 markdown 文件,注入 system prompt 引导 agent 行为
Session会话一次用户与 agent 的完整交互,持久化为 JSONL
Stream流式LLM 的流式响应,通过 SSE 或 WebSocket 传输
Tool Call工具调用LLM 请求执行一个工具的指令
Transform Context上下文变换在 LLM 调用前修改消息列表的回调
TUI终端 UITerminal User Interface,基于 ANSI 转义码的终端渲染

版本演化说明

本附录基于 pi-mono v0.66.0。类型名、文件路径、函数签名可能随版本更新而变化。 设计模式和二次开发入口的结构性建议预计长期有效。