4130bd5earendil-works/pi · 2026-10-10

读懂 PiInside Pi

一个可扩展编码智能体内核的架构The architecture of an extensible coding-agent core

Run modespi-coding-agentExtensionspi-agent-corepi-aipi-tui

← → 翻页 · F 全屏 · O 目录 · T 明暗 · L 语言← → navigate · F fullscreen · O overview · T theme · L language

Pi · 4130bd501
一句话In one sentence

Pi 是四层,每层只认识下一层Pi is four layers, each knowing only the next

运行模式 → AgentSession → Agent 循环 → pi-ai 事件流。产品逻辑全部以钩子形式注入通用循环。Run mode → AgentSession → agent loop → pi-ai event stream. All product logic is injected into a generic loop as hooks.

Run modesinteractive · print · json · rpc
↓
pi-coding-agentAgentSession · tools · sessions · extensions
↓
pi-agent-coreAgent · runLoop()
↓
pi-ai42 providers → AssistantMessageEventStream
Pi · 4130bd502
规模By the numbersInfra

一个中等体量、测试充分的 monorepoA mid-sized, well-tested monorepo

14
workspace 包packages
181k
行源码src LOC
191k
行测试test LOC
42
LLM providerLLM providers
8
内置工具built-in tools
41
扩展事件extension events
33
RPC 命令RPC commands
12
流事件类型stream event types
Pi · 4130bd503
01 · 包01 · Packagespi-coding-agent

14 个包,运行时栈只有四层深14 packages, a runtime stack four deep

pi-ai 只依赖 pi-telemetry;pi-tui、pi-mcp、pi-codemode、chord 零内部依赖。pi-ai depends only on pi-telemetry; pi-tui, pi-mcp, pi-codemode and chord have no internal deps.

Pi · 4130bd504
02 · 分层02 · Layerspi-coding-agent

请求自上而下穿过四层A request flows down four layers

  • 模式层只和 AgentSessionRuntime 对话Modes only talk to AgentSessionRuntime
  • AgentSession 把策略挂到 Agent 钩子上AgentSession hangs policy on Agent hooks
  • streamFn = modelRuntime.streamSimple()streamFn = modelRuntime.streamSimple()
  • 只有 interactive 模式使用 pi-tuiOnly interactive mode uses pi-tui
Pi · 4130bd505
03 · Agent 循环03 · Agent looppi-agent-core

两层循环驱动一切Two nested loops drive everything

  • 内层:有工具调用或 steering 消息就继续Inner: continue while tool calls or steering remain
  • 外层:follow-up 消息到达时重启Outer: restart when follow-ups arrive
  • stopReason: length → 所有工具调用失败stopReason: length → every tool call fails
  • finishTurn 可返回 end / continuefinishTurn may return end / continue
Pi · 4130bd506
03 · 消息队列03 · Message queuespi-agent-core

用户可以在 Agent 运行时插话Users can talk while the agent works

SteeringSteering

当前轮工具执行完成后、下一次 LLM 请求前注入。适合“停,换个方向”。Injected after the current turn's tools finish, before the next LLM request. For “stop, go another way”.

agent.steer() · getSteeringMessages()
Follow-upFollow-up

只在 Agent 本该停止时投递,触发外层循环。适合“做完之后再……”。Delivered only when the agent would stop, driving the outer loop. For “when you’re done, also…”.

agent.followUp() · getFollowUpMessages()
finishTurnfinishTurn

每轮结束的决策钩子:end 立即结束;continue 在无新消息时再跑一轮仅含上下文的请求。End-of-turn decision hook: end stops now; continue runs one more context-only turn when nothing is queued.

AgentLoopConfig.finishTurn
Pi · 4130bd507
04 · 工具执行04 · Tool executionpi-agent-core

每个工具调用走同一条管道One pipeline for every tool call

失败永远是结果而不是异常。并行模式:准备按顺序、执行并发、结果按原顺序发出;任何一个 sequential 工具会让整批串行。Failures are results, never throws. Parallel mode: prepare in order, execute concurrently, emit results in source order; one sequential tool serializes the batch.

Pi · 4130bd508
05 · 时序05 · Sequencepi-coding-agent

一次提示:两次请求,一次工具调用One prompt: two requests, one tool call

  • 扩展先拦截:input → before_agent_startExtensions intercept first: input → before_agent_start
  • 每个 delta 变成 message_updateEvery delta becomes message_update
  • 工具结果回到上下文,循环自动发起第二次请求Tool results rejoin the context; the loop sends request 2
  • 每个 message_end 都写入 JSONLEvery message_end is written to JSONL
Pi · 4130bd509
05 · 事件05 · Eventspi-ai

一个协议贯穿所有 providerOne protocol across every provider

pi-ai · AssistantMessageEvent · 12
starttext_starttext_deltatext_endthinking_startthinking_deltathinking_endtoolcall_starttoolcall_deltatoolcall_enddoneerror
→
pi-agent-core · AgentEvent
agent_startturn_startmessage_startmessage_updatemessage_endtool_execution_starttool_execution_updatetool_execution_endturn_endagent_end

provider 增量在 agent 层变成 message_update;工具与轮次事件由循环自己发出。StreamFn 约定:不抛异常,失败以 error 事件编码。Provider deltas become message_update in the agent layer; tool and turn events are emitted by the loop itself. StreamFn contract: never throw, encode failures as error.

Pi · 4130bd510
06 · 核心类型06 · Key typespi-coding-agent

谁持有谁Who owns what

ModelRuntime 实现 pi-ai 的 Models 接口;ExtensionRunner 由 AgentSession 创建。ModelRuntime implements pi-ai's Models; ExtensionRunner is created by AgentSession.

Pi · 4130bd511
07 · 会话07 · Sessionspi-coding-agent

一个 JSONL 文件就是一棵树One JSONL file is a tree

  • 每个条目带 id + parentIdEvery entry has id + parentId
  • leafId 指向当前位置leafId marks the current position
  • 分支 = 移动 leaf,从不改写历史Branching = moving the leaf, never rewriting
  • 11 种条目类型,含 compaction、context_edit11 entry types incl. compaction, context_edit
Pi · 4130bd512
08 · 压缩08 · Compactionpi-coding-agent

三种触发,一条路径Three triggers, one path

16,384
默认 reserveTokensdefault reserveTokens
20,000
默认 keepRecentTokensdefault keepRecentTokens
1×
溢出后只重试一次retry once after overflow
Pi · 4130bd513
09 · 扩展09 · ExtensionsExtensions

从发现到事件分发From discovery to dispatch

  • 来源:~/.pi/agent/extensions、.pi/extensions、settings packages、-eSources: ~/.pi/agent/extensions, .pi/extensions, settings packages, -e
  • jiti 直接加载 TypeScript,无需构建jiti loads TypeScript directly, no build step
  • bindCore() 之后注册才连到真实会话Registrations reach the real session after bindCore()
  • UI 由运行模式通过 bindExtensions() 提供UI is supplied by the mode via bindExtensions()
Pi · 4130bd514
09 · ExtensionAPI09 · ExtensionAPIExtensions

扩展几乎能改变一切Extensions can change almost anything

注册能力Register
registerToolregisterCommandregisterShortcutregisterFlagregisterProviderregisterMcpServerregisterMessageRendererregisterEntryRendererregisterToolRendererregisterVirtualModel
会话动作Act on the session
sendMessagesendUserMessageappendEntryexecsetActiveToolssetSessionNamesetLabelon(event)
41 种事件中可改写数据的Of 41 events, the ones that change data
input改写或吞掉输入rewrite or swallow input
context改写发给模型的消息rewrite messages sent to the model
before_provider_request改写请求负载rewrite the request payload
tool_call阻止工具调用block a tool call
tool_result改写工具结果rewrite a tool result
session_before_compact取消或替换压缩cancel or replace compaction
Pi · 4130bd515
10 · 运行模式10 · Run modesRun modes

四种模式,一个运行时Four modes, one runtime

RPC 模式:33 种 JSONL 命令,扩展 UI 请求以 extension_ui_request 代理给宿主。RPC mode: 33 JSONL command types; extension UI requests are proxied as extension_ui_request.

Pi · 4130bd516
11 · Provider11 · Providerspi-ai

42 个 provider,10 种对话 API42 providers, 10 chat APIs

API 模块经 lazyApi() 在首次调用时才 import;失败编码为 error 事件,从不抛出。API modules are imported on first use via lazyApi(); failures become error events, never throws.

Pi · 4130bd517
12 · TUI12 · TUIpi-tui

只重写变化的行Rewrite only what changed

组件只实现 render(width) → string[];requestRender() 在 nextTick 合并,两帧间隔 ≥ 16 ms,再与 previousLines 做差分,在同步输出中只写变化的行。Components implement only render(width) → string[]; requestRender() coalesces on nextTick, frames are ≥ 16 ms apart, then a diff against previousLines writes only changed lines inside synchronized output.

16 ms
两帧之间的最小间隔minimum gap between frames
string[]
组件 render(width) 的返回值what render(width) returns
Pi · 4130bd518
13 · 仓库13 · RepositoryInfra

代码都在哪里Where the code lives

48%
的源码在 coding-agentof source is coding-agent
1.06×
测试 / 源码 行数比test-to-source line ratio

实色 = 源码,浅色 = 测试。仅 .ts,不含 .d.ts。Solid = source, light = tests. .ts only, no .d.ts.

coding-agent86,111
ai27,238
durable22,427
tui19,505
chord8,817
mcp3,244
codemode2,578
agent2,519
env2,073
server1,958
evals1,446
client1,135
telemetry935
protocol869
Pi · 4130bd519
总结Takeawayspi-coding-agent

值得借鉴的五个设计Five design choices worth stealing

1
通用循环 + 钩子Generic loop + hooks

pi-agent-core 不知道“编码”;压缩、权限、工具清单全部通过 AgentLoopConfig 注入。pi-agent-core knows nothing about coding; compaction, permissions and tool loadout arrive through AgentLoopConfig.

2
失败即数据Failures are data

流错误是 error 事件,工具错误是 isError 结果——循环从不需要 try/catch 逃逸。Stream errors are error events and tool errors are isError results — the loop never unwinds.

3
追加式会话树Append-only session tree

分支、压缩、上下文编辑都是新条目,历史永不改写。Branches, compactions and context edits are all new entries; history is never rewritten.

4
Provider ≠ APIProvider ≠ API

42 个 provider 复用 10 种对话 API(KnownApi),并且按需懒加载。42 providers reuse 10 chat APIs (KnownApi), loaded lazily.

5
一切皆可扩展Everything is extensible

41 种事件 + register* API,用 jiti 直接加载 TypeScript。41 events plus the register* API, TypeScript loaded directly with jiti.

Pi · 4130bd520
←
1 / 20