Pi 项目分析

1. 项目定位与整体架构

Pi 是一个可扩展的编码智能体(coding agent)框架:核心是 Agent 循环 + 多提供商 LLM 抽象 + 工具系统,外层是 CLI/TUI、会话持久化和扩展机制。

  • 根工程:npm workspaces,ESM,Node >= 22.19,TypeScript 7(D:\work\pi\package.json:5-13, :71-73)
  • 11 个包:agent、ai、chord、codemode、coding-agent、durable、env、evals、mcp、telemetry、tui
  • 构建顺序在 D:\work\pi\package.json:16:chord → tui → telemetry → codemode → mcp → ai → durable → env → agent → coding-agent

内部依赖关系(来自各包 package.json):

复制代码
coding-agent → agent, ai, codemode, mcp, tui
agent        → ai
ai           → telemetry
durable      → chord, ai, codemode
env          → chord, durable
evals        → ai, coding-agent (dev)

关键点:durable / env 是独立的持久化运行时与远程执行环境,当前没有被 coding-agent 引用 ;chord 只被 durable / env 使用。

分层视图

复制代码
┌──────────────────────────────────────────────────────────┐
│ 入口/交互层  cli.ts → main.ts → interactive / print / rpc │
├──────────────────────────────────────────────────────────┤
│ 会话编排层  AgentSessionRuntime + AgentSession + Services │
├──────────────────────────────────────────────────────────┤
│ 智能体内核  Agent + agent-loop(流式响应、工具执行、队列)│
├──────────────────────────────────────────────────────────┤
│ 模型层      pi-ai:Models / Provider / API Registry       │
├──────────────────────────────────────────────────────────┤
│ 工具与扩展  内置工具、ExtensionRunner、MCP、codemode       │
├──────────────────────────────────────────────────────────┤
│ 持久化      SessionManager(JSONL);durable(独立运行时)│
├──────────────────────────────────────────────────────────┤
│ 终端 UI     pi-tui(差分渲染、viewport、输入/编辑器组件)  │
└──────────────────────────────────────────────────────────┘

2. 核心模块与调用关系

2.1 启动链路

入口非常薄:

  • packages/coding-agent/src/cli.ts:1-6:调用 setupCli() 和 main(process.argv.slice(2))
  • packages/coding-agent/src/main.ts:574:main() 是真正的启动编排器

main() 的顺序(main.ts:574-1000):

  1. 离线标记、主题校验、内置扩展列表(:578-583)
  2. runAuthCommand() 处理 pi auth ...(:585)
  3. handlePackageCommand() / handleConfigCommand() / pi mcp 子命令(:600-621)
  4. parseArgs(),处理 --version、--export(:623-652)
  5. 运行迁移 runMigrations()(:669)
  6. 创建 SettingsManager、首次设置、主题(:672-684)
  7. createSessionManager() 选择/创建/恢复/fork 会话(:696, 定义在 :358)
  8. 构造 createRuntime 工厂并调用 createAgentSessionRuntime()(:733-870)
  9. 按模式分发(:949-999):
    • runRpcMode(runtime)(RPC)
    • new InteractiveMode(runtime, ...).run()(交互 TUI)
    • runPrintMode(runtime, ...)(单次文本/JSON 输出)

createRuntime 内部完成 cwd 绑定服务的重建(main.ts:733-864):

复制代码
createAgentSessionServices()          // modelRuntime / settings / resourceLoader
  → DefaultResourceLoader.reload()    // 发现 extensions/skills/templates/themes
  → resolveModelScope()
  → createAgentSessionFromServices()
    → sdk.createAgentSession()
      → new Agent(...) + new AgentSession(...)

对应代码:

  • packages/coding-agent/src/core/agent-session-services.ts:135(createAgentSessionServices)
  • packages/coding-agent/src/core/agent-session-services.ts:214(createAgentSessionFromServices)
  • packages/coding-agent/src/core/sdk.ts:191(createAgentSession)
  • packages/coding-agent/src/core/sdk.ts:411(new Agent)
  • packages/coding-agent/src/core/sdk.ts:461(new AgentSession)

2.2 AgentSession:会话编排核心

packages/coding-agent/src/core/agent-session.ts:379 定义 AgentSession,它是三种运行模式共享的会话抽象。构造函数在 :486:

  • 订阅 Agent 事件(持久化、扩展事件、自动压缩、重试)
  • 安装工具钩子 _installAgentToolHooks()(:653)
  • 安装下一轮刷新、请求投影、边界钩子(:516-520)
  • 构建运行时工具集 _buildRuntime()(:522)

主要职责:

职责 位置
发送 prompt、排队 steer/followUp prompt() :2058,_startRun() :1837
运行前准备(压缩、扩展钩子、图像、工具装载) _prepareRun() :1890
工具调用前后拦截 _beforeToolCall() :659,_afterToolCall() :685
嵌套工具调用 _executeNestedToolCall() :731
手动/自动压缩 compact() :2794,_runAutoCompaction() :3127
模型与思考等级切换 setModel() :2507,setThinkingLevel() :2642
扩展绑定 bindExtensions() :3288
会话统计、导出、树导航 getSessionStats() :4213,exportToHtml() :4318,navigateTree() :3994

2.3 Agent 内核:状态机与循环

packages/agent/src/agent.ts:188 定义 Agent,负责状态、事件、队列和生命周期:

  • prompt() :371 → runPromptMessages() :432 → runAgentLoop()
  • continue() :384 → runAgentLoopContinue()
  • runWithLifecycle() :507:创建 AbortController、设置 isStreaming、失败时生成错误消息
  • processEvents() :565:归约 message_start/update/end、tool_execution_*、turn_end、agent_end,再按订阅顺序 await 监听器
  • steer() / followUp() 队列::299-332

packages/agent/src/agent-loop.ts 是实际循环:

  • runAgentLoop() :102:加入 prompt、声明工具变更、发出 agent_start/turn_start
  • runLoop() :163:外层处理 follow-up,内层处理工具调用与 steering
  • streamAssistantResponse() :381:transformContext → convertToLlm → getApiKey → streamFunction,逐事件转发并生成最终 AssistantMessage
  • executeToolCalls() :508:根据 toolExecution 和工具自身的 executionMode 选择串行/并行
  • 工具结果消息在 :930 构造;截断响应中的工具调用在 :478 统一失败,避免执行不完整参数

消息类型扩展(bashExecution、custom、branchSummary、compactionSummary)在 packages/coding-agent/src/core/messages.ts:29-77,并通过 convertToLlm() 转成 LLM 可接受的消息。

2.4 pi-ai:多提供商模型层

packages/ai/src/index.ts 明确只导出"无副作用核心",不导出生成目录、provider 工厂或 API 注册表;这些通过子路径导入(index.ts:4-8)。

核心抽象在 packages/ai/src/types.ts:

  • Model / ImageModel / ClassifierModel::825-898
  • ProviderStreams::311
  • Context / TranscriptContext::771-785
  • AssistantMessageEvent::806

运行时实现:

  • ModelsImpl:packages/ai/src/models.ts:395
  • createModels()::998
  • createProvider()::1047
  • ModelsImpl.streamSimple()::907
  • builtinProviders():packages/ai/src/providers/all.ts:136(约 40 个提供商)
  • 兼容层 API 注册表:packages/ai/src/compat.ts:180-191 注册 anthropic-messages、openai-completions、openai-responses、google-generative-ai、bedrock-converse-stream、pi-messages 等
  • compat.streamSimple()::278 按模型 API 选择内置 provider 或注册表实现

每个 provider 的典型结构(以 Anthropic 为例,packages/ai/src/providers/anthropic.ts:74-90):

ts 复制代码
createProvider({
  id: "anthropic",
  baseUrl: "https://api.anthropic.com",
  auth: { apiKey: ..., oauth: ... },
  models: Object.values(ANTHROPIC_MODELS),
  api: anthropicMessagesApi(),
})

API 实现通过 .lazy.ts 延迟加载(packages/ai/src/api/lazy.ts:46-99),避免启动时加载所有提供商 SDK。模型目录由 models.generated.ts + 运行时 catalog 刷新组成(models-store.ts、model-catalog.ts)。

coding-agent 的 ModelRuntime(packages/coding-agent/src/core/model-runtime.ts:173)在 Models 之上增加了:认证同步、provider 动态注册、虚拟模型路由、可用性刷新。streamSimple() 在 :723。

2.5 工具系统

内置 8 个工具,统一由工厂函数 + TypeBox schema 定义:

  • 导出与名称集合:packages/coding-agent/src/core/tools/index.ts:95
  • 默认编码工具集::164(read/bash/edit/write)
  • 只读工具集::173(read/grep/find/ls)
  • 单工具工厂::141

实现文件:

  • read.ts:读取文件/图片、截断、图像缩放
  • bash.ts:shell 执行、超时、输出累积、进程树清理
  • edit.ts / write.ts:带 file-mutation-queue.ts 串行化同一文件的修改
  • grep.ts / find.ts / ls.ts:检索类工具
  • powershell.ts:Windows 专用
  • truncate.ts:统一的头/尾截断策略

工具最终实现 AgentTool.execute(id, args, signal, onUpdate),由 agent-loop 调用。

2.6 扩展系统

内置扩展注册在 packages/coding-agent/src/extensions/index.ts:7-14:

  • llama.cpp
  • codemode(可替换)
  • tool-search(可替换)
  • mcp(可替换)

ExtensionRunner(packages/coding-agent/src/core/extensions/runner.ts:364)负责:

  • bindCore() :417:把宿主能力注入扩展运行时
  • 事件分发:emitToolCall() :1249、emitToolResult() :1190、emitInput() :1525、emitBeforeAgentStart() :1427、emitContext() :1305、provider 请求/响应钩子 :1368-1399、会话边界 :1036
  • UI 上下文、命令、快捷键、工具渲染器

资源发现由 DefaultResourceLoader(packages/coding-agent/src/core/resource-loader.ts:315)完成:扩展、skills、prompt templates、themes、context files、项目信任。扩展加载在 packages/coding-agent/src/core/extensions/loader.ts:718。

2.7 MCP 与 codemode

  • pi-mcp 是独立 MCP 客户端:McpClient(packages/mcp/src/client.ts:155),支持 stdio 与 Streamable HTTP 传输、OAuth、工具/资源调用。
  • coding-agent 内置 MCP 扩展:packages/coding-agent/src/extensions/mcp/index.ts:279(createMcpExtension)。它把 MCP 工具映射为 mcp__<server>__<tool>,并支持 codemode / deferred / direct / hidden 暴露模式。
  • pi-codemode 在 QuickJS/WASM 沙箱中执行模型写的 JavaScript,只暴露工具调用能力;嵌套工具调用不进入 LLM 上下文(packages/codemode/src/runtime/execution.ts:460、packages/codemode/src/runtime/vm.ts:160)。
  • coding-agent 的 codemode 扩展入口:packages/coding-agent/src/extensions/codemode/index.ts:32。

2.8 TUI

pi-tui 是独立的终端 UI 库,只被 coding-agent 使用:

  • 组件模型:Component.render(width) + handleInput + invalidate(packages/tui/src/tui.ts:117)
  • Container::358;TUI / TuiBase::464 / :506
  • 主屏差分渲染:packages/tui/src/tui-main-screen.ts:124
  • 备用屏视口:packages/tui/src/tui-alt-screen.ts:202
  • 布局引擎:packages/tui/src/layout.ts:379
  • 输入/按键:packages/tui/src/keys.ts:163、packages/tui/src/keybindings.ts:231
  • 编辑器、Markdown、SelectList、ScrollView 等组件:packages/tui/src/components/*

coding-agent 的交互模式在 packages/coding-agent/src/modes/interactive/interactive-mode.ts:451(InteractiveMode),init() :943,run() :1146,事件处理 handleEvent() :3408。

2.9 durable / env(独立运行时)

  • pi-durable:以"先提交、后发布"为核心的可恢复 agent 运行时。
    • Session 内核:packages/durable/src/session/session.ts:69
    • Harness:packages/durable/src/harness/harness.ts:181 / :460
    • Storage:memory / JSONL / SQLite(packages/durable/src/storage/*)
    • 任务调度:packages/durable/src/harness/scheduler.ts:200
  • pi-env:通过 SSH + Rust daemon 提供远程 ExecutionEnv。
    • Connection:packages/env/src/connection.ts:181
    • RemoteExecutionEnv:packages/env/src/remote-env.ts:354
    • SSH 部署:packages/env/src/ssh.ts

这两个包当前不参与 coding-agent 的启动链路,属于可独立使用的运行时/执行环境。


3. 关键入口文件与函数

作用 文件:行
CLI 可执行入口 packages/coding-agent/src/cli.ts:1
启动编排 packages/coding-agent/src/main.ts:574
参数解析 packages/coding-agent/src/cli/args.ts(parseArgs)
创建会话管理器 packages/coding-agent/src/main.ts:358
创建运行时 packages/coding-agent/src/core/agent-session-runtime.ts:420
创建 cwd 服务 packages/coding-agent/src/core/agent-session-services.ts:135
SDK 入口 packages/coding-agent/src/core/sdk.ts:191
会话编排类 packages/coding-agent/src/core/agent-session.ts:379
发送 prompt packages/coding-agent/src/core/agent-session.ts:2058
Agent 类 packages/agent/src/agent.ts:188
Agent 循环 packages/agent/src/agent-loop.ts:102
流式响应 packages/agent/src/agent-loop.ts:381
工具执行 packages/agent/src/agent-loop.ts:508
模型集合 packages/ai/src/models.ts:395
提供商注册表 packages/ai/src/providers/all.ts:136
API 注册表 packages/ai/src/compat.ts:180
内置工具注册 packages/coding-agent/src/core/tools/index.ts:95
内置扩展列表 packages/coding-agent/src/extensions/index.ts:7
扩展事件运行器 packages/coding-agent/src/core/extensions/runner.ts:364
MCP 扩展 packages/coding-agent/src/extensions/mcp/index.ts:279
打印模式 packages/coding-agent/src/modes/print-mode.ts:33
RPC 模式 packages/coding-agent/src/modes/rpc/rpc-mode.ts:54
交互模式 packages/coding-agent/src/modes/interactive/interactive-mode.ts:451
会话持久化 packages/coding-agent/src/core/session-manager.ts:987
TUI 核心 packages/tui/src/tui.ts:506

4. 主要业务逻辑

4.1 一次 prompt 的完整调用链

以交互模式输入一条消息为例:

  1. InteractiveMode 提交文本 → AgentSession.prompt()(agent-session.ts:2058)
  2. 扩展命令拦截(/command)、input 事件、skill/prompt template 展开(:2065-2100)
  3. 如果正在流式输出,进入 steer / followUp 队列(:2102-2116)
  4. 校验模型与认证(:2118-2136)
  5. _startRun()(:1837):
    • _prepareRun():必要时先压缩、触发 before_agent_start、处理图片、更新工具装载(:1890)
    • agent.prompt(messages)(:1863)
  6. Agent.prompt() → runPromptMessages() → runAgentLoop()(agent.ts:432,agent-loop.ts:102)
  7. runLoop()(agent-loop.ts:163):
    • 处理 steering / follow-up
    • streamAssistantResponse():convertToLlm → 选择模型认证 → streamFunction
    • 收集 toolCall,执行工具(串行/并行)
    • 发出 turn_end;如果还有工具调用或排队消息则继续
  8. AgentSession 通过订阅的 _handleAgentEvent 持久化消息、转发扩展事件、触发自动压缩/重试(agent-session.ts:1288, :3127, :3792)
  9. 最终 agent_end → UI 更新或 print/RPC 输出

4.2 工具调用与扩展拦截

工具执行前后各有一层扩展钩子:

  • _beforeToolCall()(agent-session.ts:659)→ tool_call 扩展事件,可阻止或修改调用
  • _afterToolCall()(:685)→ tool_result 扩展事件,可替换内容/错误状态,并统一做图像归一化
  • 嵌套工具调用(工具内部通过 ctx.executeTool() 再调用工具)复用同一套钩子(:731)

agent-loop 对未知工具、参数校验失败、被阻止、抛异常都返回 isError: true 的工具结果,而不是让循环崩溃(agent-loop.ts:708-777)。

4.3 会话持久化、恢复与分支

SessionManager(session-manager.ts:987)以 JSONL 文件保存会话:

  • 条目类型:message、thinking_level_change、model_change、usage、compaction、branch_summary、custom、label、session_info、context_edit(:57-197)
  • 当前版本 CURRENT_SESSION_VERSION = 3,带 v1→v2→v3 迁移(:41, :287-350)
  • 创建/打开/继续/内存/fork::1755-1874
  • 上下文投影:buildSessionProjection() :1493,buildSessionContext() :1497
  • 分支:branch() :1579,createBranchedSession() :1632

AgentSessionRuntime(agent-session-runtime.ts:74)负责运行时替换:switchSession()、newSession()、fork()、importFromJsonl(),每次先 teardown 旧会话、再重建 cwd 服务和新 AgentSession。

4.4 上下文压缩与重试

  • 压缩算法在 packages/coding-agent/src/core/compaction/compaction.ts,入口聚合在 index.ts
  • 阈值判断:AgentSession._exceedsCompactionThreshold()(agent-session.ts:768)
  • 自动压缩:_checkCompaction() :2977、_runAutoCompaction() :3127
  • 手动压缩:compact() :2794
  • 重试:_prepareRetry() :3792,判断可重试错误 _isRetryableError() :3739,取消 _finishCancelledRetry() :3776

4.5 三种运行模式

模式 文件 行为
Interactive modes/interactive/interactive-mode.ts:451 TUI、编辑器、选择器、主题、扩展 UI
Print modes/print-mode.ts:33 单次执行,text 只输出最终文本,json 输出事件流
RPC modes/rpc/rpc-mode.ts:54 stdin/stdout JSON 协议,供外部程序嵌入

三种模式共享同一个 AgentSessionRuntime 和 AgentSession,只是 I/O 层不同。

4.6 模型、认证与目录刷新

  • ModelRuntime.create()(model-runtime.ts:217)加载 auth.json、models.json,组合内置 + 动态 provider
  • 认证解析:getAuth() :557,支持 API key、OAuth、订阅、环境变量
  • 运行时刷新:refresh() :848,离线时只读缓存
  • 模型选择:resolveCliModel() / resolveModelScope()(core/model-resolver.ts),支持 --model provider/pattern、--models、思考等级
  • 虚拟模型路由:registerVirtualModel() :964、resolveModel() :1003

4.7 扩展、MCP 与 codemode 的协作

  • 扩展在 DefaultResourceLoader.reload() 中加载,ExtensionRunner.bindCore() 注入宿主能力
  • MCP 扩展把服务器工具注册为普通 Pi 工具,因此 AgentSession 的工具装载、权限过滤、codemode 可见性都无需特殊分支
  • codemode 扩展把工具集合渲染为 TypeScript 声明,在 QuickJS 沙箱中执行,工具调用通过 executeTool() 回到同一工具管线(agent-session.ts:731)
  • tool-search 扩展用于按需暴露大量 MCP 工具,避免一次性塞满系统提示

5. 证据清单(主要文件)

  • 启动与模式:packages/coding-agent/src/cli.ts、main.ts、modes/index.ts、modes/print-mode.ts、modes/rpc/rpc-mode.ts、modes/interactive/interactive-mode.ts
  • 会话编排:core/agent-session.ts、core/agent-session-runtime.ts、core/agent-session-services.ts、core/sdk.ts
  • 智能体内核:packages/agent/src/agent.ts、agent-loop.ts、types.ts、stream-fn.ts
  • 模型层:packages/ai/src/index.ts、models.ts、types.ts、compat.ts、providers/all.ts、providers/*.ts、api/*.ts
  • 工具:packages/coding-agent/src/core/tools/*.ts
  • 扩展:packages/coding-agent/src/core/extensions/{loader,runner,types}.ts、extensions/index.ts、extensions/mcp/*、extensions/codemode/*
  • 持久化:packages/coding-agent/src/core/session-manager.ts;独立运行时 packages/durable/src/session/session.ts、harness/harness.ts、storage/*
  • 终端 UI:packages/tui/src/index.ts、tui.ts、tui-main-screen.ts、tui-alt-screen.ts、layout.ts
  • 远程执行:packages/env/src/connection.ts、remote-env.ts、ssh.ts
相关推荐
用户3134672143542 小时前
learn-claude-code笔记3: Permission — 执行前做权限判断
llm·agent
墨心@3 小时前
AgentSession 详细分析
agent·pi·coding agent
for_ever_love__3 小时前
检索工具化封装:把 Elasticsearch、SQL、Confluence 包装成 Agent 的统一工具
agent·工具·封装·调用·rag·检索·做成
guslegend3 小时前
注意力稀释:当 113 个工具让模型降智时,工程师该怎么做?
agent
梦醒江南3 小时前
Agent 卡在网页上时,为什么不能换个真实入口继续?
人工智能·agent
用户460381291943 小时前
MCP 给了 Agent 一堆“手”,Skill 才教它怎么干活:两者到底什么关系?
agent·mcp
for_ever_love__3 小时前
Agentic RAG 实战:让 Agent 自己决定怎么检索、检索几次
人工智能·后端·agent·控制·自适应·rag·检索策略
大模型真好玩3 小时前
用TRAE、DeepSeek-Harness、DeepSeek-V4.1-Flash-1017再现特斯拉Roadster汽车飞行名场面
人工智能·agent·deepseek
遇码4 小时前
不用转场引擎做幻灯片转场:相机滑动、黑场淡入与真全屏的完整做法
人工智能·数码相机·ai·rust·大模型·agent