Pi Agent Harness 源码解析:TypeScript 实现的模块化 Coding Agent
深入剖析 Earendil Works 开源的 Pi Agent Harness——一个基于 TypeScript Monorepo 构建的模块化交互式编程代理
项目简介
Pi Agent Harness 是由 Earendil Works 开发的开源 coding agent 项目。其核心定位是提供一个可扩展的交互式编程代理,能运行在终端中,通过多 LLM provider 驱动,完成代码编写、搜索、编辑等任务。
核心特点:
- 🔌 多 LLM Provider 支持:OpenAI、Anthropic、Google、GitHub Copilot、OpenRouter、xAI、Mistral 等 20+ 个 provider 的统一接口
- 🧩 自扩展:coding agent 可以通过 skill、extension、prompt template 等方式进行扩展
- 🖥️ 交互式终端 UI:支持差分渲染的 TUI、alt-screen 全屏模式、overlay、滚动视图等
- 📦 会话持久化与分支:支持 JSONL 格式的会话存储、会话 fork、恢复、continue
- 🔗 RPC 模式:支持通过 JSON 行进行程序化控制,可嵌入到其他应用中
- 🔐 供应链安全:pin 依赖版本、npm shrinkwrap、install lock、lifecycle script 审计
发布包:
| npm 包名 |
描述 |
@earendil-works/pi-coding-agent |
交互式 coding agent CLI |
@earendil-works/pi-agent-core |
Agent 运行时(工具调用、状态管理) |
@earendil-works/pi-ai |
统一多 provider LLM API |
@earendil-works/pi-tui |
终端 UI 库(差分渲染) |
整体架构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| ┌─────────────────────────────────────────────────────────────┐ │ 用户终端 │ └────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ packages/coding-agent (交互式 CLI 主程序) │ │ ┌───────────┐ ┌──────────────┐ ┌──────────────────┐ │ │ │ main.ts │→ │ AgentSession │→ │ SessionManager │ │ │ │ cli.ts │ │ Runtime │ │ (会话持久化) │ │ │ └───────────┘ └──────┬───────┘ └──────────────────┘ │ │ │ │ │ ┌───────────────────┐ │ ┌────────────────────────┐ │ │ │ Extensions / Skills│←─┘→│ SettingsManager │ │ │ │ (扩展与技能) │ │ (配置管理) │ │ │ └───────────────────┘ └────────────────────────┘ │ └────────────────────────┬────────────────────────────────────┘ │ ┌──────────────┼──────────────┐ ▼ ▼ ▼ ┌──────────────┐ ┌────────────┐ ┌──────────────┐ │ packages/ │ │ packages/ │ │ packages/ │ │ agent │ │ tui │ │ protocol │ │ (Agent 运行时)│ │ (终端 UI) │ │ (RPC 协议) │ └──────┬───────┘ └────────────┘ └──────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ packages/ai (统一 LLM API 层) │ │ ┌────────────┐ ┌──────────┐ ┌────────────────┐ │ │ │ stream() │→ │ Provider │→ │ HTTP Client │ │ │ │ (统一入口) │ │ Registry │ │ (fetch/SSE) │ │ │ └────────────┘ └──────────┘ └────────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ OpenAI / Anthropic / Google / Copilot / OpenRouter / xAI │ │ Mistral / Ollama / Groq / Cerebras / DeepSeek / ... │ └─────────────────────────────────────────────────────────────┘
|
分层结构(自底向上):
- AI 层(
packages/ai):统一 LLM API,屏蔽不同 provider 的协议差异
- Agent 层(
packages/agent):Agent 运行时,管理状态、工具调用、消息队列
- TUI 层(
packages/tui):终端 UI 组件库,差分渲染、事件处理
- 协议层(
packages/protocol):RPC 协议的 schema 定义
- Client 层(
packages/client):RPC 客户端 SDK
- Server 层(
packages/server):RPC 服务端框架
- Coding Agent 层(
packages/coding-agent):组装所有模块的 CLI 主程序
Monorepo 结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| pi-monorepo/ ├── packages/ │ ├── ai/ │ ├── agent/ │ ├── coding-agent/ │ ├── tui/ │ ├── protocol/ │ ├── client/ │ ├── server/ │ ├── evals/ │ └── storage/ ├── scripts/ ├── .pi/ ├── package.json ├── tsconfig.json ├── biome.json └── vitest.base.ts
|
构建顺序(npm run build 的依赖链):
1
| tui → ai → agent → storage/sqlite-node → protocol → client → coding-agent → server
|
这种依赖链设计非常清晰——底层模块不依赖上层,每一层只依赖其下的层。
核心模块详解
1. coding-agent:交互式 CLI 主程序
这是整个项目的主程序包,将 agent 运行时、TUI、会话管理、配置管理、工具系统等组合为一个完整的交互式 coding agent。
入口文件
src/main.ts — main() 函数是整个 CLI 的入口点。
启动流程概览:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| main() ├── 1. 初始化 │ ├── resetTimings() │ ├── 合并 builtInExtensions │ ├── 检查 offline 模式 │ └── applyHttpProxySettings() │ ├── 2. 命令处理(短路) │ ├── handlePackageCommand() │ ├── handleConfigCommand() │ └── runCredentialPrintCommand() │ ├── 3. 参数解析 │ ├── parseArgs() │ └── resolveAppMode() │ ├── 4. 迁移与设置 │ ├── runMigrations() │ └── SettingsManager.create() │ ├── 5. 会话管理 │ ├── createSessionManager() │ └── getMissingSessionCwdIssue() │ ├── 6. 运行时创建 │ ├── createRuntime() │ │ ├── ModelRuntime │ │ ├── ResourceLoader │ │ ├── AuthStorage │ │ ├── ExtensionManager │ │ └── SkillRegistry │ └── createAgentSession() │ └── 7. 运行模式分派 ├── runInteractiveMode() ├── runRpcMode() └── runPrintMode()
|
核心子模块
AgentSession(src/core/agent-session.ts)
编码 agent 的会话对象,封装了:
- 底层
Agent(来自 packages/agent)实例
- 系统提示词管理(system prompt)
- 工具注册(内置工具 + 扩展工具)
- 模型切换(Ctrl+P 循环)
- 自动压缩(auto-compaction,当 token 接近上限时自动摘要)
- 会话事件分发
AgentSessionRuntime(src/core/agent-session-runtime.ts)
与特定 CWD 绑定的运行时环境,包含:
ModelRuntime:模型查询、切换、API 兼容性处理
SettingsManager:全局/项目/会话级设置
ResourceLoader:资源文件(CLAUDE.md 等)加载
AuthStorage:认证凭据存储
ExtensionManager:扩展加载与管理
SkillRegistry:技能(/command)注册
SessionManager(src/core/session-manager.ts)
会话的生命周期管理:
- 创建新会话(
create())
- 打开已有会话(
open())
- 继续最近会话(
continueRecent())
- Fork 会话(
forkSessionOrExit())
- 列出所有会话(
list()、listAll())
会话文件存储在 ~/.pi/agent/sessions/<encoded-cwd>/ 下,格式为 JSONL。
运行模式
交互式模式(src/modes/interactive/):
- 使用
TuiMainScreen 进行全屏或滚动渲染
- 支持键盘快捷键(Ctrl+C、Ctrl+P、Escape 等)
- 输入编辑器、自动补全、overlay 弹窗
- 流式输出渲染
RPC 模式(src/modes/rpc/):
- 通过 stdin/stdout 交换 JSON-lines 消息
- 支持
get_state、prompt、steer、abort、set_model 等命令
- 可嵌入到 IDE、web 应用等外部宿主
Print 模式(src/modes/print/):
- 非交互式单次执行
- 输出到 stdout,适合脚本和管道
2. agent:Agent 运行时
Agent 运行时是与 UI 无关的核心引擎,负责:
- 管理 Agent 状态(消息、工具、模型)
- 驱动 Agent Loop(LLM 调用 → 工具执行 → 继续)
- 消息队列(steering queue、follow-up queue)
- 事件分发
- 会话持久化抽象
Agent 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Agent { state: AgentState;
steer(message: AgentMessage): void; followUp(message: AgentMessage): void;
prompt(input: string | AgentMessage): Promise<void>; continue(): Promise<void>; abort(): void;
addListener(listener: (event: AgentEvent) => void): void; }
|
状态模型(AgentState 接口):
1 2 3 4 5 6 7 8 9 10 11
| interface AgentState { systemPrompt: string; model: Model; thinkingLevel: ThinkingLevel; tools: AgentTool[]; messages: AgentMessage[]; readonly isStreaming: boolean; readonly streamingMessage?: AgentMessage; readonly pendingToolCalls: ReadonlySet<string>; readonly errorMessage?: string; }
|
Agent Loop
Agent Loop 是整个系统的核心循环,位于 src/agent-loop.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| runAgentLoop(context, streamFn, config) │ ├── 1. 准备上下文 │ ├── transformContext() │ ├── convertToLlm() │ └── 构建 streamFn 参数 │ ├── 2. 调用 LLM │ ├── streamFn(model, context) │ └── 处理流事件: │ ├── text_delta │ ├── thinking_delta │ ├── toolcall_start/delta/end │ └── done / error │ ├── 3. 工具执行 │ ├── 识别工具调用(从 assistant message 中) │ ├── prepareToolCall() │ ├── beforeToolCall() │ ├── 并行/串行执行工具 │ │ ├── tool.execute() │ │ └── 收集 AgentToolResult │ ├── afterToolCall() │ └── 将工具结果追加到 messages │ ├── 4. 检查终止条件 │ ├── stopReason === "stop" │ ├── terminate === true │ ├── 队列消息处理 │ └── prepareNextTurn() │ └── 5. 继续或结束 ├── 有工具结果 → 继续循环 ├── 有队列消息 → 注入消息继续 └── 否则 → 结束循环
|
关键设计决策:
- 工具执行模式:支持
sequential(逐个执行)和 parallel(并行执行)两种模式,每个工具可通过 executionMode 属性覆盖默认行为
- 消息队列:
steering 队列在每轮结束后注入,followUp 队列在 agent 即将停止时注入,支持不同的 QueueMode(all / one-at-a-time)
- 流式处理:LLM 返回的流通过
AssistantMessageEventStream 处理,支持增量更新 UI
工具接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| interface AgentTool<TParameters, TDetails> { name: string; description: string; parameters: TSchema; label: string; executionMode?: ToolExecutionMode;
prepareArguments?: (args: unknown) => Static<TParameters>;
execute: ( toolCallId: string, params: Static<TParameters>, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<TDetails>, ) => Promise<AgentToolResult<TDetails>>; }
|
3. ai:统一多 Provider LLM 接口
AI 层是 LLM 调用的统一抽象层,将不同 provider 的协议差异屏蔽,为上层提供一致的 API。
核心 API
1 2 3 4 5
| streamSimple(model, context, options): AssistantMessageEventStream
stream(model, context, options): AssistantMessageEventStream
|
API 实现
每种 API 协议有一个独立的实现文件:
| 文件 |
协议 |
使用的 Provider |
src/api/openai-completions.ts |
OpenAI Chat Completions |
OpenAI、Azure、Mistral、Groq、Cerebras、DeepSeek、xAI 等 |
src/api/openai-responses.ts |
OpenAI Responses API |
OpenAI (GPT-5 等) |
src/api/openai-codex-responses.ts |
OpenAI Codex Responses |
Codex |
src/api/anthropic.ts |
Anthropic Messages |
Anthropic (Claude) |
src/api/google.ts |
Google Gemini |
Google |
src/api/bedrock.ts |
AWS Bedrock |
Amazon |
src/api/ollama.ts |
Ollama |
Ollama (本地) |
src/api/github-copilot.ts |
GitHub Copilot |
GitHub Copilot |
流式处理流程(以 OpenAI Completions 为例)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| stream(model, context, options) │ ├── 1. 初始化 │ ├── getClientApiKey() │ ├── getCompat() │ ├── createGrammarToolInputProperties() │ ├── resolveCacheRetention() │ └── createClient() │ ├── 2. 构建请求参数 │ └── buildParams() │ ├── convertMessages() │ ├── 设置 prompt_cache_key │ ├── 设置 tools │ └── 设置 reasoning_effort │ ├── 3. 发送请求 │ ├── retryProviderRequest() │ └── client.chat.completions.create() │ ├── 4. 处理流式响应 │ └── for await (chunk of openaiStream) │ ├── 解析 usage │ ├── 解析 finish_reason │ ├── 解析 text delta │ ├── 解析 reasoning delta │ ├── 解析 tool_calls delta │ └── 解析 reasoning_details │ └── 5. 完成/错误处理 ├── finishBlock() ├── stream.push(done) └── stream.end()
|
模型管理
1 2 3 4 5 6 7
| interface Model<TApi> { id: string; provider: string; api: TApi; baseUrl?: string; headers?: Record<string, string>; }
|
ModelsRuntime 负责:
- 内置模型数据(编译时生成)
- 远程 catalog 更新(运行时刷新)
- 模型查询和匹配
4. tui:终端 UI 库
TUI 是一个独立的终端 UI 库,提供类似 React 的组件化开发模型,支持差分渲染。
核心接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| interface Component { render(width: number): string[];
handleInput?(data: string): void;
wantsKeyRelease?: boolean;
invalidate(): void; }
interface TUI extends Component { children: Component[]; terminal: Terminal;
addChild(component: Component): void; removeChild(component: Component): void; clear(): void;
setFocus(component: Component | null): void;
showOverlay(component: Component, options?: OverlayOptions): OverlayHandle; hideOverlay(): void;
start(): void; stop(): void;
requestRender(force?: boolean): void;
addInputListener(listener: TuiInputListener): () => void;
queryTerminalBackgroundColor(options): Promise<RgbColor | undefined>; queryTerminalColorScheme(options): Promise<TerminalColorScheme | undefined>; }
|
TUI 实现层次
1 2 3 4
| TUI (interface) └── TuiBase (abstract class, extends Container) ├── TuiMainScreen └── TuiAltScreen
|
TuiMainScreen:
- 使用终端的主屏幕(normal screen buffer)
- 输出追加到终端滚动缓冲区
- 支持差分渲染:只重绘变化的行
- 适用于常规 chat 模式
TuiAltScreen:
- 使用终端的替代屏幕(alternate screen buffer,
ESC[?1049h)
- 应用完全控制视口内容
- 支持滚动、鼠标事件、文本选择
- 适用于全屏模式
差分渲染机制
TUI 的核心性能优化是差分渲染:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| requestRender(force?) │ ├── 1. 收集所有子组件的 render() 输出 │ └── 合并为完整的文档行数组 │ ├── 2. 与上一帧对比 │ ├── 找到变化的行范围 │ └── 处理 Kitty 图片(特殊协议) │ ├── 3. 生成终端指令 │ ├── 移动光标到变化区域 │ ├── 输出变化的行 │ └── 清理多余行 │ └── 4. 更新缓存状态 ├── lastDocument = newDocument └── fullRedraws++(如果是强制重绘)
|
Overlay 系统
Overlay 是 TUI 的浮层/弹窗机制:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| interface OverlayOptions { width?: SizeValue; maxHeight?: SizeValue; anchor?: OverlayAnchor; offsetX?: number; offsetY?: number; margin?: OverlayMargin | number; visible?: (w, h) => boolean; nonCapturing?: boolean; }
interface OverlayHandle { hide(): void; setHidden(hidden: boolean): void; focus(): void; unfocus(options?): void; isFocused(): boolean; }
|
5. server / client / protocol
这三个包提供了 RPC(远程过程调用) 能力,允许外部程序通过 JSON-lines 协议控制 agent。
- protocol:定义了 RPC 协议的消息格式(请求、响应、事件)
- server:RPC 服务端框架(
PiSessionBackend、PiSessionRuntime、LiveSession)
- client:RPC 客户端 SDK(
PiClient、RemoteSession,支持自动重连、状态同步)
工具系统
内置工具
coding-agent 提供了一组内置工具(packages/agent/src/harness/tools/):
| 工具 |
文件 |
功能 |
Bash |
bash.ts |
执行 shell 命令 |
Edit |
edit.ts |
文本替换编辑 |
Read |
read.ts |
读取文件内容 |
Write |
write.ts |
写入文件 |
Find |
find.ts |
文件搜索(按名称/glob) |
Grep |
grep.ts |
内容搜索(正则表达式) |
Ls |
ls.ts |
列出目录内容 |
NotebookEdit |
notebook-edit.ts |
Jupyter notebook 编辑 |
TodoRead |
todo-read.ts |
读取待办事项 |
TodoWrite |
todo-write.ts |
写入待办事项 |
Edit 工具的模糊匹配
Edit 工具(packages/agent/src/harness/tools/edit-diff.ts)实现了模糊匹配机制:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| applyEditsToNormalizedContent(content, edits) │ ├── 1. 尝试精确匹配 │ └── content.indexOf(oldText) │ ├── 2. 如果失败,尝试模糊匹配 │ ├── normalizeForFuzzyMatch(content) │ │ ├── 标准化 Unicode 引号 │ │ ├── 标准化 Unicode 破折号 │ │ ├── 标准化特殊空格 │ │ └── 去除行尾空白 │ └── fuzzyContent.indexOf(fuzzyOldText) │ ├── 3. 检查重复匹配 │ └── countOccurrences() > 1 → 报错 │ ├── 4. 检查重叠 │ └── 排序后检查相邻 edit 是否重叠 │ └── 5. 应用替换 ├── 精确匹配:直接替换 └── 模糊匹配:保留原始行的未变部分
|
这个设计很巧妙——AI 生成的代码经常会有 Unicode 引号(如 " 和 ")或行尾空白不一致的问题,模糊匹配能有效解决这些场景。
会话管理与持久化
会话文件格式
会话文件采用 JSONL 格式(每行一个 JSON 对象),存储在 ~/.pi/agent/sessions/<encoded-cwd>/ 下。
文件命名:<timestamp>_<session-id>.jsonl
1 2 3 4 5
| {"type":"session","version":3,"id":"<uuid>","timestamp":"2026-08-02T...","cwd":"/path/to/project"} {"type":"message","id":"msg_001","message":{"role":"user","content":[{"type":"text","text":"Hello"}]}} {"type":"message","id":"msg_002","message":{"role":"assistant","content":[{"type":"text","text":"Hi!"}]}} {"type":"label","id":"lbl_001","targetId":"msg_002","label":"Greeting"} {"type":"compaction","id":"cmp_001","usage":{"input":1000,"output":200,...}}
|
条目类型:
| 类型 |
说明 |
session |
会话头(必须第一行) |
message |
对话消息 |
label |
消息标签(可引用其他条目) |
compaction |
压缩摘要记录 |
branch_summary |
分支摘要 |
session_info |
会话元信息(名称等) |
自动压缩
当 token 使用接近上下文窗口限制时,系统会自动触发压缩:
1 2 3 4 5 6 7 8 9 10 11 12
| 检查 token 使用量 │ ├── 如果超过阈值: │ ├── 保留最近 N 条消息 │ ├── 将早期消息摘要为压缩文本 │ ├── 将摘要作为新的 system prompt 前缀 │ └── 记录 compaction 条目 │ └── 设置: ├── compaction.enabled(默认 true) ├── compaction.reserveTokens(默认 16384) └── compaction.keepRecentTokens(默认 20000)
|
配置系统
三级配置合并
1 2 3 4 5
| 全局设置 (~/.pi/settings.json) ↓ 合并 项目设置 (<project>/.pi/settings.json) ↓ 合并 运行时覆盖 (CLI 参数 / 会话内设置)
|
合并策略:深度合并(deepMergeSettings),嵌套对象递归合并,后者覆盖前者。
主要配置项
| 配置项 |
类型 |
默认值 |
说明 |
defaultProvider |
string |
- |
默认 LLM provider |
defaultModel |
string |
- |
默认模型 |
defaultThinkingLevel |
ThinkingLevel |
“off” |
默认推理等级 |
transport |
TransportSetting |
“auto” |
传输协议 |
steeringMode |
“all” | “one-at-a-time” |
- |
转向队列模式 |
followUpMode |
“all” | “one-at-a-time” |
- |
后续队列模式 |
theme |
string |
- |
UI 主题 |
uiMode |
“regular” | “fullscreen” |
“regular” |
UI 模式 |
compaction.enabled |
boolean |
true |
是否启用自动压缩 |
compaction.reserveTokens |
number |
16384 |
预留 token 数 |
compaction.keepRecentTokens |
number |
20000 |
保留最近消息的 token 数 |
terminal.showImages |
boolean |
true |
是否显示图片 |
httpProxy |
string |
- |
HTTP 代理 URL |
packages |
PackageSource[] |
- |
npm/git 包源 |
extensions |
string[] |
- |
扩展文件路径 |
skills |
string[] |
- |
技能文件路径 |
enabledModels |
string[] |
- |
可循环的模型模式 |
扩展机制
Extensions(扩展)
扩展是 TypeScript 文件,可以:
- 注册新工具
- 添加 UI 组件(overlay)
- 修改系统提示词
- 注册新的 LLM provider
- 添加自定义消息类型
1 2 3 4 5 6 7
| interface Extension { name: string; tools?: AgentTool[]; uiComponents?: UIComponent[]; systemPrompt?: string; providers?: Provider[]; }
|
扩展加载顺序:
- 内置扩展(
builtInExtensions)
- Settings 中
extensions 配置的扩展
- CLI
--extensions 参数指定的扩展
Skills(技能)
技能是可以通过 /skill:name 命令调用的功能模块:
- 技能文件可以是 TypeScript 或 Markdown
- 支持参数传递
- 在
settings.skills 中配置路径
Prompt Templates(提示词模板)
可复用的提示词模板:
- 存储在
settings.prompts 指定的路径
- 支持变量替换
- 通过
/prompt 命令或 API 调用
Themes(主题)
UI 主题定制:
- 定义颜色、样式
- 存储在
settings.themes 指定的路径
- 通过
settings.theme 激活
关键数据流
用户输入到 LLM 响应的完整流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| 用户输入 "帮我写一个函数" │ ├── TUI 层 │ ├── 键盘事件 → InputHandler │ ├── 输入编辑器收集文本 │ └── 按 Enter 提交 │ ├── AgentSession │ ├── 创建 UserMessage │ ├── 追加到 state.messages │ └── 调用 agent.prompt() │ ├── Agent │ ├── 将消息放入队列 │ └── 启动 Agent Loop │ ├── Agent Loop │ ├── convertToLlm(messages) │ ├── transformContext() │ └── streamFn(model, context) │ ├── AI 层 │ ├── 选择 API 实现(如 openai-completions) │ ├── buildParams() │ ├── client.chat.completions.create() │ └── 返回 AssistantMessageEventStream │ ├── 流处理 │ ├── text_delta → AgentEvent → TUI 渲染 │ ├── toolcall_start → 工具准备 │ ├── tool_execution → 工具运行 │ ├── tool_result → 追加到 messages │ └── done → 检查是否继续 │ └── 输出渲染 ├── 文本增量 → 差分渲染到终端 ├── 工具调用 → overlay/状态更新 └── 完成 → 恢复输入
|
关键文件索引
入口文件
| 文件 |
说明 |
packages/coding-agent/src/main.ts |
CLI 主入口(main() 函数) |
packages/coding-agent/src/cli.ts |
CLI 分派入口 |
packages/coding-agent/src/rpc-entry.ts |
RPC 模式入口 |
核心模块
| 文件 |
说明 |
packages/agent/src/agent.ts |
Agent 核心类 |
packages/agent/src/agent-loop.ts |
Agent Loop 实现 |
packages/agent/src/types.ts |
Agent 类型定义 |
packages/coding-agent/src/core/agent-session.ts |
AgentSession 实现 |
packages/coding-agent/src/core/agent-session-runtime.ts |
AgentSessionRuntime |
packages/coding-agent/src/core/session-manager.ts |
SessionManager |
packages/coding-agent/src/core/settings-manager.ts |
SettingsManager |
packages/coding-agent/src/core/model-runtime.ts |
ModelRuntime |
AI 层
| 文件 |
说明 |
packages/ai/src/index.ts |
AI 包入口 |
packages/ai/src/api/openai-completions.ts |
OpenAI Completions API |
packages/ai/src/api/anthropic.ts |
Anthropic Messages API |
packages/ai/src/api/google.ts |
Google Gemini API |
packages/ai/src/models.ts |
Model 类型和管理 |
packages/ai/src/models-runtime.ts |
ModelsRuntime |
TUI 层
| 文件 |
说明 |
packages/tui/src/tui.ts |
TUI 接口和基础类 |
packages/tui/src/tui-main-screen.ts |
主屏幕 TUI |
packages/tui/src/tui-alt-screen.ts |
替代屏幕 TUI |
packages/tui/src/terminal.ts |
终端抽象 |
工具
| 文件 |
说明 |
packages/agent/src/harness/tools/bash.ts |
Bash 工具 |
packages/agent/src/harness/tools/edit.ts |
Edit 工具 |
packages/agent/src/harness/tools/edit-diff.ts |
Edit 模糊匹配算法 |
packages/agent/src/harness/tools/read.ts |
Read 工具 |
packages/agent/src/harness/tools/find.ts |
Find 工具 |
packages/agent/src/harness/tools/grep.ts |
Grep 工具 |
总结
Pi Agent Harness 是一个工程质量极高的 TypeScript Monorepo 项目,几个亮点:
- 模块化极致:7 个独立 npm 包,每一层职责清晰
- 差分渲染 TUI:独立的终端 UI 库,性能优化到位
- 模糊匹配 Edit:解决 AI 生成代码的 Unicode 引号/空白问题
- RPC 模式:让 agent 可以被嵌入到 IDE、Web 应用等外部宿主
- 三级配置合并:全局 + 项目 + 运行时的灵活配置
- 会话 Fork 与分支:支持树形会话结构
- 供应链安全:pin 依赖、shrinkwrap、lifecycle script 审计
对于想要用 TypeScript 构建 AI Agent 工具的开发者来说,Pi 的架构设计(尤其是分层结构、Agent Loop、TUI 差分渲染、RPC 模式)非常值得学习。
项目地址:https://github.com/earendil-works/pi-monorepo
许可证:开源