Pi 架构图解Pi, illustrated4130bd5
演示Slides
4130bd5earendil-works/pi · 2026-10-10

读懂 Pi:
一个可扩展的
编码智能体内核
Inside Pi:
an extensible coding-agent core

基于源码逐行核对的架构导读。12 张图覆盖包依赖、Agent 循环、工具执行、会话树、压缩、扩展、运行模式、Provider 与 TUI;每个结论都链接到对应提交中的具体代码行。An architecture walkthrough checked line by line against the source. Twelve diagrams cover packages, the agent loop, tool execution, the session tree, compaction, extensions, run modes, providers and the TUI — every claim links to the exact lines at this commit.

14
个 workspace 包workspace packages
181k
行 TypeScript 源码lines of TS source
191k
行测试代码lines of tests
42
个内置 LLM providerbuilt-in LLM providers
8
个内置工具built-in tools
41
种扩展事件extension events
33
种 RPC 命令RPC command types
4
种运行模式run modes

如何阅读这些图How to read the diagrams

Run modespi-coding-agentExtensionspi-agent-corepi-aipi-tuiInfra
  • 颜色 = 代码所在的层 / 包,所有图、表与幻灯片一致。Colour = the layer / package the code lives in, identical across every diagram, table and slide.
  • 圆角容器 = 包或层;卡片 = 类、函数或组件;深色胶囊 = 起止点;红色 = 错误路径。Rounded containers = packages or layers; cards = classes, functions or components; dark pill = start / end; red = error path.
  • 实线箭头 = 调用 / 依赖;虚线 = 事件、异步返回或 devDependency;流动的虚线标出主路径;圆形数字 = 执行顺序。Solid arrow = call / dependency; dashed = event, async return or devDependency; animated dashes mark the main path; numbered circles = execution order.
  • 每张图右下都有图例。鼠标悬停某个组件会高亮它的连线;点击图可放大、滚轮缩放、拖动平移。Every diagram carries its own legend. Hover a component to highlight its connections; click to enlarge, wheel to zoom, drag to pan.
01pi-coding-agent

包依赖图Package dependency graph#

一句话结论Takeaway14 个 npm workspace 包,pi-coding-agent 位于顶端;运行时栈只有四层,其余包互相解耦。14 npm workspace packages with pi-coding-agent on top; the runtime stack is only four packages deep and everything else is decoupled.

内部依赖:实线 = dependencies,虚线 = devDependenciesInternal deps: solid = dependencies, dashed = devDependencies
← 左右滑动查看,点击放大 →← swipe to scroll, tap to enlarge →
Package dependency graph运行时栈RUNTIME STACK独立库STANDALONE无内部依赖no internal deps持久化与远程会话DURABLE & REMOTE SESSIONSpi-coding-agentAgentSession · 8 工具AgentSession · toolspi-agent-coreAgent · runLoop()pi-ai42 provider · 10 种 API42 providers · 10 APIspi-telemetry遥测契约telemetry contractspi-tui差分渲染differential renderpi-mcpMCP 客户端MCP clientpi-codemode沙箱 JS 执行sandboxed JSpi-server实验性服务端experimental serverpi-client远程会话客户端remote clientpi-protocolCBOR 帧协议CBOR protocolpi-durable持久化运行时durable runtimepi-env经 SSH 远程执行remote exec · SSHpi-evals评测工具eval harnesschord应用组合运行时:services · 复制状态 · RPC · pluginsapplication composition runtime — services · replicated state · RPC · pluginspi-durable → pi-ai5 个包都依赖 chordall 5 depend on chorddevdevDependencies(仅测试):pi-server · pi-client · pi-protocoldevDependencies (tests only): pi-server · pi-client · pi-protocoldependency(运行时依赖)dependencydevDependency(开发依赖)devDependency四层运行时栈the 4-deep runtime stackpi-coding-agentpi-agent-corepi-aipi-tui其他包other packages

要点Key points

  • pi-coding-agent 直接依赖 pi-agent-core、pi-ai、pi-tui、pi-mcp、pi-codemode 和 chord。pi-coding-agent depends on pi-agent-core, pi-ai, pi-tui, pi-mcp, pi-codemode and chord.
  • pi-ai 唯一的内部依赖是 pi-telemetry;pi-tui、pi-mcp、pi-codemode、chord 没有任何内部依赖,可以独立使用。pi-ai's only internal dependency is pi-telemetry; pi-tui, pi-mcp, pi-codemode and chord have none and can be used standalone.
  • Durable 与远程会话是一组独立的包:pi-durable、pi-env、pi-protocol、pi-client、pi-server,都构建在 chord 之上。Durable and remote sessions form a separate cluster — pi-durable, pi-env, pi-protocol, pi-client, pi-server — all built on chord.
  • 虚线是 devDependencies:pi-coding-agent 只在测试中使用 client / protocol / server;pi-evals 依赖 coding-agent 与 ai。Dashed edges are devDependencies: pi-coding-agent only uses client / protocol / server in tests; pi-evals depends on coding-agent and ai.

工作原理How it works

  1. 根 package.json 用 npm workspaces 管理 packages/*。The root package.json manages packages/* with npm workspaces.
  2. npm run build 按拓扑顺序依次构建:chord → tui → telemetry → codemode → mcp → ai → durable → env → agent → protocol → client → server → coding-agent。npm run build builds in topological order: chord → tui → telemetry → codemode → mcp → ai → durable → env → agent → protocol → client → server → coding-agent.
  3. 图中的边直接取自每个包 package.json 里的 @earendil-works/* 依赖。Edges are read from each package's @earendil-works/* entries in package.json.

关键文件Key files · 4130bd5

文件File符号Symbol作用Role
package.jsonL15scripts.buildworkspace 与构建顺序workspaces and build order
packages/coding-agent/package.jsonL51dependencies顶层 CLI 的依赖top-level CLI dependencies
packages/agent/package.jsonL25dependenciesagent core 只依赖 pi-aiagent core depends only on pi-ai
packages/ai/package.jsonL69dependenciesLLM 层与 vendor SDKLLM layer and vendor SDKs
02pi-coding-agent

分层架构Layered architecture#

一句话结论Takeaway请求自上而下穿过四层:运行模式 → AgentSession → Agent 循环 → pi-ai 统一事件流。A request passes down four layers: run mode → AgentSession → the Agent loop → pi-ai's normalized event stream.

自上而下的四层运行时栈The four-layer runtime stack, top to bottom
← 左右滑动查看,点击放大 →← swipe to scroll, tap to enlarge →
Layered architecture运行模式RUN MODES共享同一个运行时all share one runtimepi-coding-agent会话编排session orchestrationAgentSessionprompt() · steer() · followUp() · compact() · bindExtensions()pi-agent-coreAgentSession 注入的钩子hooks set by AgentSessionpi-aipi-tui仅 interactiveinteractive onlyJSONL宿主应用 / IDEHost app / IDEpipe脚本 / CIScripts / CITTY开发者DeveloperrunRpcMode()33 种 JSONL 命令 · 事件33 JSONL commands · eventsrunPrintMode()text · json,一次性text · json, one-shotInteractiveMode编辑器 · 聊天视图 · /命令editor · chat view · /commandsAgentSessionRuntime持有当前会话 · newSession() · switchSession() · fork() 时整体替换owns the current session · replaced wholesale on newSession() · switchSession() · fork()SessionManager只追加的 JSONL 树append-only JSONL treeExtensionRunner41 种事件 · register*41 events · register*8 个内置工具8 built-in toolsread · bash · edit · write …compaction摘要 + 保留尾部summary + kept tailModelRuntime实现 pi-ai 的 Modelsimplements pi-ai ModelsResourceLoader扩展 · skills · promptsextensions · skills · promptsAgent状态 · 两个消息队列state · two message queuesrunLoop()内层 + 外层循环inner + outer looptransformContextconvertToLlmprepareNextTurnprepareRequestbeforeToolCallafterToolCallfinishTurnModelsgetModel · checkAuthproviders/*42 个内置 provider42 built-in providersapi/*.lazy.ts10 种对话 API · 懒加载10 chat APIs · lazyAssistantMessageEventStreamstart · text_* · thinking_* · toolcall_* · done · errorTuiMainScreen主屏 · 保留 scrollbackmain buffer · scrollbackTuiAltScreen备用屏 · 全屏alt screen · fullscreenComponentrender(width) → string[]ProcessTerminalStdinBuffer → 按键StdinBuffer → keysEditorMarkdownSelectListLoaderImageScrollView内置组件,还有 Input、Stack …built-ins, plus Input, Stack …prompt ↓ · 事件 ↑prompt ↓ · events ↑agent.prompt()注入installsstreamFn = modelRuntime.streamSimple()事件流回到循环events back to the loop12345

要点Key points

  • pi-ai:把 42 个内置 provider 归一为一套流式事件协议 AssistantMessageEventStream。pi-ai normalizes 42 built-in providers into one streaming protocol, AssistantMessageEventStream.
  • pi-agent-core:与具体产品无关的工具调用循环,所有策略通过 AgentLoopConfig 钩子注入。pi-agent-core is a product-agnostic tool-calling loop; all policy is injected through AgentLoopConfig hooks.
  • pi-coding-agent:AgentSession 组装会话、8 个内置工具、扩展、压缩、设置与模型解析。pi-coding-agent: AgentSession wires in sessions, 8 built-in tools, extensions, compaction, settings and model resolution.
  • 运行模式:interactive、print(text / json)和 rpc 共享同一个 AgentSessionRuntime;只有 interactive 使用 pi-tui。Run modes: interactive, print (text / json) and rpc share one AgentSessionRuntime; only interactive uses pi-tui.

工作原理How it works

  1. 模式层调用 AgentSessionRuntime,它持有当前 AgentSession,并在 new / switch / fork 时整体替换会话。Modes call AgentSessionRuntime, which owns the current AgentSession and replaces it wholesale on new / switch / fork.
  2. AgentSession 把自己的逻辑挂到 Agent 的钩子上:prepareNextTurn、prepareRequest、finishTurn、beforeToolCall 等。AgentSession attaches its logic to the Agent hooks: prepareNextTurn, prepareRequest, finishTurn, beforeToolCall and more.
  3. sdk.ts 把 streamFn 设为 modelRuntime.streamSimple(),由 Models 注册表找到 provider 和对应的 API 实现。sdk.ts sets streamFn to modelRuntime.streamSimple(); the Models registry resolves the provider and its API implementation.

关键文件Key files · 4130bd5

文件File符号Symbol作用Role
packages/coding-agent/src/core/agent-session.tsL378AgentSession核心编排对象(约 4.4k 行)the core orchestrator (~4.4k lines)
packages/coding-agent/src/core/agent-session-runtime.tsL74AgentSessionRuntime会话生命周期与替换session lifecycle and replacement
packages/coding-agent/src/core/sdk.tsL420streamFn把 Agent 接到 ModelRuntimeconnects Agent to ModelRuntime
packages/agent/src/agent.tsL188Agent状态、队列与钩子state, queues and hooks
packages/ai/src/models.tsL250Modelsprovider / model 注册表provider / model registry
03pi-agent-core

Agent 循环Agent loop#

一句话结论TakeawayrunLoop 是两层嵌套循环:内层处理工具调用与 steering 消息,外层在 follow-up 消息到达时重新启动。runLoop is two nested loops: the inner one drains tool calls and steering messages, the outer one restarts when follow-up messages arrive.

runLoop():内层循环与外层循环runLoop(): inner and outer loop
← 左右滑动查看,点击放大 →← swipe to scroll, tap to enlarge →
Agent loop消息队列MESSAGE QUEUESrunLoop()prompt() / continue()Steering 队列Steering queueagent.steer()Follow-up 队列Follow-up queueagent.followUp()注入待处理消息Inject pending messagesprepared + steering → message_start/endstreamAssistantResponse()transformContext → convertToLlm → streamFnexecuteToolCalls()sequential | parallel · length → 全部失败sequential | parallel · length → all failfinishTurn() · turn_end决策 end | continue,再轮询 steeringdecision end | continue, then poll steeringgetFollowUpMessages()Agent 本该停止时才检查checked only when the agent would stopagent_end运行结束,回到 idlerun finished → idle用户在 Agent 运行时输入typed while the agent runs模式:one-at-a-time(默认)| allmode: one-at-a-time (default) | all有工具调用tool calls无工具调用no tool callsprepareNextTurn() · turn_start仍有工具调用 / steeringtool calls or steering left轮询poll都没有neither决策 = enddecision = end无 follow-upnone queuederror / aborted外层循环:follow-up 到达(或 finishTurn → continue)outer loop: follow-ups arrived (or finishTurn → continue)内层inner循环loop012345

要点Key points

  • Steering:Agent 运行中用户插入的消息,在当前轮的工具执行完成后、下一次 LLM 请求之前注入。Steering messages typed while the agent runs are injected after the current turn's tools finish, before the next LLM request.
  • Follow-up:只在 Agent 本该停止时才投递,触发外层循环。Follow-up messages are delivered only when the agent would otherwise stop, and drive the outer loop.
  • stopReason 为 length 时,该消息中所有工具调用直接判为失败,因为参数可能被截断。On stopReason: "length" every tool call in that message fails, because its arguments may be truncated.
  • finishTurn 可返回 end(立即结束)或 continue(在无新消息时追加一次仅含上下文的轮次)。finishTurn can return end (stop now) or continue (run one more context-only turn when nothing else is queued).

工作原理How it works

  1. 开始时先轮询一次 getSteeringMessages(),因为用户可能在等待时已经输入。It first polls getSteeringMessages(), since the user may have typed while waiting.
  2. 从第二轮起调用 prepareNextTurn();coding agent 在这里做阈值压缩并刷新工具清单。From the second turn it calls prepareNextTurn(); the coding agent compacts at threshold and refreshes the tool loadout here.
  3. prepareRequest() 可覆盖 model 与 thinking level,然后 streamAssistantResponse() 依次执行 transformContext → convertToLlm → getApiKey → streamFn。prepareRequest() may override model and thinking level; then streamAssistantResponse() runs transformContext → convertToLlm → getApiKey → streamFn.
  4. 若所有工具结果都带 terminate: true,内层循环在本轮后停止。If every tool result carries terminate: true, the inner loop stops after this turn.

关键文件Key files · 4130bd5

文件File符号Symbol作用Role
packages/agent/src/agent-loop.tsL163runLoop()双层循环本体the two nested loops
packages/agent/src/agent-loop.tsL381streamAssistantResponse()上下文转换与流式请求context transform and streaming call
packages/agent/src/types.tsL193AgentLoopConfig所有循环钩子的类型types for every loop hook
packages/coding-agent/src/core/agent-session.tsL888finishTurncoding agent 的轮次收尾coding agent's end-of-turn hook
04pi-agent-core

工具调用执行Tool call execution#

一句话结论Takeaway每个工具调用都走同一条管道:查找 → 参数准备 → schema 校验 → beforeToolCall → 执行 → afterToolCall;任何失败都变成错误结果,而不是异常。Every tool call runs one pipeline — lookup → prepare → schema validation → beforeToolCall → execute → afterToolCall — and every failure becomes an error result, never a throw.

单个工具调用的处理管道The pipeline for one tool call
← 左右滑动查看,点击放大 →← swipe to scroll, tap to enlarge →
Tool call execution扩展(经 ExtensionRunner)EXTENSIONS (via ExtensionRunner)一批工具调用A BATCH OF TOOL CALLSassistant 消息含多个 toolCall 时when one assistant message has several tool calls查找工具Find tooltools.find(name)准备参数Prepare argsprepareArguments()校验ValidatevalidateToolArguments()beforeToolCall()ext · tool_calltool.execute()(…, signal, onUpdate)afterToolCall()ext · tool_result完成Finishtool_execution_endtoolCall来自 assistant 消息from assistant messageToolResultMessagemessage_start / endtool_call可阻止 · blockmay blocktool_result可改写结果may rewrite resulttool_execution_update流式输出 · 例如 bashstreamed output, e.g. bashcreateErrorToolResult(message)isError: true —— 失败是结果,不是异常isError: true — a failure is a result, never a throwexecute 抛错execute throws→ isError 结果→ isError resulttool_execution_startonUpdate未找到not found抛错throws不合法invalidblock / abort跳过 afterToolCallskips afterToolCallsequentialparallelprep 1exec 1msg 1prep 2exec 2msg 2prep 3exec 3msg 3prep 1prep 2prep 3并发执行 · 每个完成即发 tool_execution_endrun concurrently · tool_execution_end as each finishesmsg 1msg 2msg 3结果按原顺序发出results in source order任一工具声明 executionMode: "sequential" → 整批串行any tool with executionMode: "sequential" serializes the batch1234567

要点Key points

  • 参数用工具的 TypeBox schema 通过 validateToolArguments() 校验。Arguments are validated against the tool's TypeBox schema via validateToolArguments().
  • coding agent 把 beforeToolCall / afterToolCall 映射为扩展事件 tool_call(可阻止)和 tool_result(可改写结果)。The coding agent maps beforeToolCall / afterToolCall to the extension events tool_call (can block) and tool_result (can rewrite).
  • 模式为 ToolExecutionMode = "sequential" | "parallel";只要批次中有一个工具声明 executionMode: "sequential",整批就串行。ToolExecutionMode = "sequential" | "parallel"; if any tool in the batch declares executionMode: "sequential", the whole batch runs sequentially.
  • runToolCall() 对外导出,供调用其他工具的工具复用同一套钩子(例如权限检查)。runToolCall() is exported so tools that call other tools reuse the same hooks (e.g. permission checks).

工作原理How it works

  1. 并行模式下,准备阶段(含 beforeToolCall)按源顺序逐个进行,执行阶段并发。In parallel mode, preparation (including beforeToolCall) runs one by one in source order; execution runs concurrently.
  2. tool_execution_end 在每个工具完成时发出;ToolResultMessage 则按原始顺序统一发出。tool_execution_end fires as each tool finishes; ToolResultMessages are emitted afterwards in the original order.
  3. 执行中的 onUpdate 回调被转成 tool_execution_update 事件,用于流式显示 bash 输出等。onUpdate during execution becomes tool_execution_update events, used to stream bash output and similar.

关键文件Key files · 4130bd5

文件File符号Symbol作用Role
packages/agent/src/agent-loop.tsL708prepareToolCall()查找、校验与 beforeToolCalllookup, validation, beforeToolCall
packages/agent/src/agent-loop.tsL586executeToolCallsParallel()并发执行与有序结果concurrent execution, ordered results
packages/agent/src/agent-loop.tsL811runToolCall()可复用的单次调用reusable single call
packages/coding-agent/src/core/agent-session.tsL668emitToolCall接入扩展事件bridges to extension events
packages/coding-agent/src/core/tools/index.tsL95ToolName8 个内置工具the 8 built-in tools
05pi-coding-agent

一次提示的完整时序One prompt, end to end#

一句话结论Takeaway一次用户输入会经过扩展拦截、两次 LLM 请求和一次工具执行;每条消息在 message_end 时写入会话文件。One user prompt passes extension interception, two LLM requests and a tool run; every message is persisted to the session file on message_end.

Interactive 模式下的一次提示(含一次 bash 工具调用)One prompt in interactive mode, with one bash tool call
← 左右滑动查看,点击放大 →← swipe to scroll, tap to enlarge →
One prompt, end to end运行模式run modepi-coding-agentpi-agent-corepi-aiInteractiveModeAgentSessionExtensionRunnerSessionManager工具 · bashTool · bashAgent · runLoopstreamFn · pi-ai1 · 预处理1 · Preprocess2 · 请求 12 · Request 13 · 工具调用3 · Tool call4 · 请求 24 · Request 2prompt(text)input · 可改写或接管input · may rewrite / handle展开 skill 与模板expand skills · templatesbefore_agent_startagent.prompt() → runAgentLoop()message_end(user)appendMessage()context · 每次请求前context · before every requeststreamFn(model, ctx)text_delta …message_update重绘(批处理)re-render (batched)done(toolUse)message_end(assistant)appendMessage()tool_call · 可阻止tool_call · may blockexecute(…)onUpdate … 结果onUpdate … resulttool_result · 可改写tool_result · may rewritemessage_end(toolResult)appendMessage()streamFn(含结果)streamFn(+ result)done(stop)message_end · turn_end · agent_endappendMessage()idle · 等待输入idle · ready for input每个 message_end 都追加到会话 JSONLevery message_end is appended to the session JSONL1234567891011121314151617181920212223242526调用call事件 / 返回event / return1顺序编号,颜色 = 发起方order · colour = caller

要点Key points

  • AgentSession.prompt() 的顺序:扩展命令 → input 事件 → 展开 skill 与 prompt template → 若正在流式输出则排队为 steer / follow-up → 预检压缩 → before_agent_start → agent.prompt()。AgentSession.prompt() order: extension commands → input event → expand skills and prompt templates → queue as steer / follow-up if streaming → pre-prompt compaction check → before_agent_start → agent.prompt().
  • pi-ai 的流事件(text_delta、toolcall_delta 等)在 agent 层变成 message_update。pi-ai stream events (text_delta, toolcall_delta, …) become message_update agent events.
  • transformContext 在 coding agent 中调用 emitContext(),扩展可以在每次请求前改写消息。In the coding agent transformContext calls emitContext(), so extensions can rewrite messages before every request.

工作原理How it works

  1. Interactive 模式订阅会话事件,每个 delta 都触发一次(批处理后的)重绘。Interactive mode subscribes to session events; each delta triggers a (batched) re-render.
  2. AgentSession 在每个 message_end 时调用 sessionManager.appendMessage(),会话文件随每条完成的消息增量写入。AgentSession calls sessionManager.appendMessage() on every message_end, so the session file grows with each completed message.
  3. 工具结果追加到上下文后,循环自动发起下一次请求,直到模型以 stop 结束。After tool results join the context the loop issues the next request automatically, until the model ends with stop.

关键文件Key files · 4130bd5

文件File符号Symbol作用Role
packages/coding-agent/src/core/agent-session.tsL1968AgentSession.prompt()提示预处理流水线prompt preprocessing pipeline
packages/coding-agent/src/core/agent-session.tsL1162appendMessagemessage_end 时持久化persists on message_end
packages/coding-agent/src/core/sdk.tsL439emitContexttransformContext → 扩展transformContext → extensions
packages/ai/src/types.tsL801AssistantMessageEvent12 种流事件the 12 stream event types
06pi-coding-agent

核心类型Key types#

一句话结论TakeawayAgentSessionRuntime 持有 AgentSession,后者组合 Agent、SessionManager、ExtensionRunner 和 ModelRuntime。AgentSessionRuntime owns an AgentSession, which composes Agent, SessionManager, ExtensionRunner and ModelRuntime.

主要类与接口及其组合关系Main classes and interfaces and how they compose
← 左右滑动查看,点击放大 →← swipe to scroll, tap to enlarge →
Key typesAgentSessionRuntime+session: AgentSession+services+newSession()+switchSession()+fork()+importFromJsonl()+dispose()SessionManager−byId · leafId+appendMessage()+appendCompaction()+getBranch() · getTree()+branch() · branchWithSummary()+buildSessionContext()+createBranchedSession()AgentSession+agent: Agent+sessionManager+settingsManager−_extensionRunner · _modelRuntime+prompt(text, options)+steer() · followUp()+setModel() · cycleModel()+compact() · navigateTree()+bindExtensions() · reload()+executeBash() · subscribe()ExtensionRunner+bindCore(actions)+setUIContext(ui, mode)+emit(event)+emitToolCall() · emitToolResult()Agent+state: AgentState+streamFunction: StreamFn+toolExecution+convertToLlm · transformContext+beforeToolCall · afterToolCall+prepareRequest · prepareNextTurn+finishTurn+prompt() · continue()+steer() · followUp()+abort() · waitForIdle()«interface»AgentTool+name · label · parameters+executionMode?+prepareArguments?(args)+execute(toolCallId, params, …)ModelRuntime+streamSimple(model, ctx)+getAuth() · checkAuth()+registerProvider(id, config)+resolveModel()«interface» pi-aiModels+getProviders() · getModel()+getAvailable() · refresh()+streamSimple()«interface»Provider+id · name · auth+getModels()+stream() · streamSimple()sessionagentsessionManager创建并 bindCore()creates · bindCore()_modelRuntimestate.tools *implementsgetProviders() *字段与方法均为节选members are a selection组合(持有)composition (owns)聚合 / 引用aggregation / reference实现接口implements调用 / 依赖calls / uses

要点Key points

  • Agent 的钩子都是公开字段(beforeToolCall、prepareRequest、finishTurn …),由上层直接赋值或包装。Agent hooks are public fields (beforeToolCall, prepareRequest, finishTurn, …) that the layer above assigns or wraps.
  • ModelRuntime 实现 pi-ai 的 Models 接口,并允许扩展通过 registerProvider 注册 provider。ModelRuntime implements pi-ai's Models interface and lets extensions register providers via registerProvider.
  • ExtensionRunner 在 AgentSession 内部创建,bindCore() 把会话动作暴露给扩展。ExtensionRunner is created inside AgentSession; bindCore() exposes session actions to extensions.

工作原理How it works

  1. Agent 维护 steering 与 follow-up 两个队列(PendingMessageQueue),转化为循环的 getSteeringMessages / getFollowUpMessages。Agent keeps two queues (PendingMessageQueue) for steering and follow-up and exposes them to the loop as getSteeringMessages / getFollowUpMessages.
  2. AgentSessionRuntime.fork() / switchSession() 先发出 session_before_* 扩展事件,再拆除当前会话并创建新会话。AgentSessionRuntime.fork() / switchSession() emit session_before_* extension events, then tear down the current session and create a new one.

关键文件Key files · 4130bd5

文件File符号Symbol作用Role
packages/agent/src/agent.tsL188Agent队列、状态与订阅queues, state, subscription
packages/coding-agent/src/core/agent-session-runtime.tsL262fork()会话替换session replacement
packages/coding-agent/src/core/session-manager.tsL987SessionManagerJSONL 树存储JSONL tree store
packages/coding-agent/src/core/extensions/runner.tsL357ExtensionRunner事件分发event dispatch
packages/coding-agent/src/core/model-runtime.tsL172ModelRuntimeimplements Modelsimplements Models
07pi-coding-agent

会话持久化与分支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.

一个会话文件中的条目树(示例)The entry tree inside one session file (example)
← 左右滑动查看,点击放大 →← swipe to scroll, tap to enlarge →
Session persistence & branching~/.pi/agent/sessions/<cwd>/<id>.jsonl只追加append-onlysessionmessagemessagemessagemessagemodel_changemessagemessagebranch_summarymessagea1f0 · messageuser · 修复失败的测试user · fix the failing testb2c4 · messageassistant · toolCall(bash)c3d9 · messagetoolResult · exit 0d4e1 · messageassistant · “已修复”assistant · “fixed”e5a2 · model_changeprovider · modelIdf6b3 · messageuser · 顺便加测试user · also add testsg7c8 · messageassistant · …h8d5 · branch_summaryfromId: g7c8 · summaryi9e6 · messageuser · 换个思路user · try another approachleafIdmessagethinking_level_changemodel_changeusagecompactionbranch_summarycustomcustom_messagelabelsession_infocontext_edit1文件头 · version 3 · id · cwd · parentSession?header · version 3 · id · cwd · parentSession?2a1f0← nulluser · 修复失败的测试user · fix the failing test3b2c4← a1f0assistant · toolCall(bash)4c3d9← b2c4toolResult · exit 05d4e1← c3d9assistant · “已修复”assistant · “fixed”6e5a2← d4e1provider · modelId7f6b3← e5a2user · 顺便加测试user · also add tests8g7c8← f6b3assistant · …9h8d5← d4e1fromId: g7c8 · summary10i9e6← h8d5user · 换个思路user · try another approach每行一个 JSON 对象;id 为 8 位 hex,← 是 parentIdone JSON object per line · 8-hex ids · ← is parentId分支点branch pointleaf 移回 d4e1 后追加leaf → d4e1, then appendfromId被放弃的路径仍留在文件里abandoned path stays in the filebuildSessionContext()leaf → root11 种条目11 entry types当前分支(进入上下文)active branch (in context)引用字段reference field上下文重建方向context rebuild direction

要点Key points

  • 第 1 行是 session 头(version 3、id、cwd、可选 parentSession)。Line 1 is the session header (version 3, id, cwd, optional parentSession).
  • 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_edit is append-only and can drop an earlier entry from model context (replacement: null) or replace its content.

工作原理How it works

  1. branchWithSummary() 把 leaf 移到分支点,并追加一个 branch_summary(fromId 指向被放弃的 leaf),记录那条路径做过什么。branchWithSummary() moves the leaf to the branch point and appends a branch_summary (with fromId pointing at the abandoned leaf) describing that path.
  2. 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.
  3. 文件位于 ~/.pi/agent/sessions/<cwd>/,custom 条目供扩展保存状态但不进入上下文,custom_message 则会进入。Files live under ~/.pi/agent/sessions/<cwd>/; custom entries store extension state outside the context, custom_message entries enter it.

关键文件Key files · 4130bd5

文件File符号Symbol作用Role
packages/coding-agent/src/core/session-manager.tsL43SessionHeader文件头file header
packages/coding-agent/src/core/session-manager.tsL183SessionEntry条目联合类型entry union type
packages/coding-agent/src/core/session-manager.tsL1600branchWithSummary()带摘要的分支branch with summary
packages/coding-agent/src/core/session-manager.tsL175ContextEditEntry追加式上下文编辑append-only context edit
08pi-coding-agent

上下文压缩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.

三种触发方式共享的压缩路径One compaction path shared by three triggers
← 左右滑动查看,点击放大 →← swipe to scroll, tap to enlarge →
Compaction上下文窗口里发生了什么WHAT HAPPENS TO THE CONTEXT WINDOW手动manual/compact · compact()阈值threshold超过 window − reservetokens > window − reserve溢出overflow上下文溢出 / 截断context overflow / truncationprepareCompaction()getBranch() → findCutPoint()compaction_start(reason)session_before_compact扩展钩子extension hook已取消cancelled不追加任何条目nothing appended扩展自带结果extension's resultfromExtension: truecompact()generateSummary() · LLMappendCompaction(summary, firstKeptEntryId, tokensBefore, …)随后 session_compact · compaction_endthen session_compact · compaction_endagent.continue()overflow 且 willRetry:仅一次overflow + willRetry: once完成done否则:等待下一次提示otherwise: wait for next promptcancelcompaction无nonewillRetry压缩前before较早的条目 → 交给 LLM 总结older entries → summarized by the LLM保留尾部 ≈ keepRecentTokens 20,000kept tail ≈ keepRecentTokens 20,000reserveTokens 16,384切点:user 或 assistant 消息,绝不切在 toolResult(firstKeptEntryId)cut point: a user or assistant message, never a toolResult (firstKeptEntryId)压缩后aftercompaction 摘要compaction summary同一段保留尾部the same kept tail腾出的空间freed space阈值:contextTokens > contextWindow − reserveTokens · 保留尾部按 estimateTokens()(chars/4)累加threshold: contextTokens > contextWindow − reserveTokens · kept tail sized with estimateTokens() (chars / 4)12345

要点Key points

  • threshold:contextTokens > contextWindow − reserveTokens(默认 reserveTokens = 16384)。threshold: contextTokens > contextWindow − reserveTokens (default reserveTokens = 16384).
  • overflow:provider 返回上下文溢出错误或可恢复的 length 截断;删除失败消息、压缩,并只重试一次。overflow: a context-overflow error or a recoverable length stop; drop the failed message, compact, and retry exactly once.
  • findCutPoint() 保留约 keepRecentTokens(默认 20000)的最近内容,并让切点落在轮次边界上。findCutPoint() keeps about keepRecentTokens (default 20000) of recent content and puts the cut on a turn boundary.
  • 扩展可在 session_before_compact 中取消压缩,或直接提供自己的压缩结果。Extensions can cancel compaction in session_before_compact or supply their own result.

工作原理How it works

  1. 自动检查发生在三处:agent_end 之后、提交新提示之前,以及 prepareNextTurn 中(同一次运行的轮次之间)。Automatic checks run in three places: after agent_end, before a new prompt, and inside prepareNextTurn (between turns of one run).
  2. 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.
  3. appendCompaction(summary, firstKeptEntryId, tokensBefore, …) 之后,上下文重建为“摘要 + 保留的消息”。After appendCompaction(summary, firstKeptEntryId, tokensBefore, …) the context is rebuilt as summary + kept messages.

关键文件Key files · 4130bd5

文件File符号Symbol作用Role
packages/coding-agent/src/core/compaction/compaction.tsL267shouldCompact()阈值判断threshold test
packages/coding-agent/src/core/compaction/compaction.tsL446findCutPoint()选择保留的尾部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/settings-defaults.tsL10SETTINGS_DEFAULTS默认 token 参数default token budgets
09Extensions

扩展生命周期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.

从发现、加载到事件分发From discovery and loading to event dispatch
← 左右滑动查看,点击放大 →← swipe to scroll, tap to enlarge →
Extension lifecyclemain.ts · ResourceLoader扩展模块extension moduleAgentSession · ExtensionRunner运行模式run modereload()packageManager.resolve()loadExtensionsCached()按路径加载by resolved pathAgentSession由运行时创建created by runtime~/.pi/agent/extensions.pi/extensionssettings 里的包settings packages-e <path>factory(pi)jiti.import(path)registerTool · on(event)…ExtensionRunnerbindCore():接上真实动作bindCore(): real actionsbindExtensions(){ uiContext, mode }setUIContext()UI 由模式提供UI from the modesession_startresources_discoveremit(event)分发 41 种事件dispatches 41 event typesinputcontexttool_calltool_resultturn_endmessage_endagent_endmodel_selectsession_compactsession_shutdown发现Discover加载Load绑定核心Bind core绑定 UIBind UI运行期Runtime动作先是占位桩actions start as stubsregisterProvider 排队registerProvider queued来源sourcesimportnew注册表registrations事件为 41 种中的节选 · 实心 = 处理器可改写数据events: a selection of 41 · solid = handler may change data12345主流程main flow事件 / 回传event / hand-back调用call

要点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 等。The register* 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

  1. createAgentSessionServices() 创建 DefaultResourceLoader,reload() 解析路径并调用 loadExtensionsCached()。createAgentSessionServices() creates a DefaultResourceLoader; reload() resolves paths and calls loadExtensionsCached().
  2. 加载期间 ExtensionRuntime 的动作方法是会抛错的占位,registerProvider 则先排队;AgentSession 创建 ExtensionRunner 并 bindCore() 后换成真实动作。While loading, ExtensionRuntime action methods are throwing stubs and registerProvider calls are queued; once AgentSession creates the ExtensionRunner, bindCore() swaps in real actions.
  3. 模式调用 session.bindExtensions({ uiContext, mode }) 绑定 UI,随后发出 session_start 与 resources_discover。The mode calls session.bindExtensions({ uiContext, mode }) to bind UI, then session_start and resources_discover fire.

关键文件Key files · 4130bd5

文件File符号Symbol作用Role
packages/coding-agent/src/core/extensions/loader.tsL828discoverAndLoadExtensions()目录发现directory discovery
packages/coding-agent/src/core/resource-loader.tsL699loadCurrentExtensionSet()实际加载路径the real load path
packages/coding-agent/src/core/extensions/types.tsL1564ExtensionAPI扩展可用的全部 APIthe full extension API
packages/coding-agent/src/core/extensions/runner.tsL410bindCore()接入会话动作binds session actions
packages/coding-agent/src/core/agent-session.tsL3258bindExtensions()UI 绑定与 session_startUI binding and session_start
10Run modes

运行模式Run modes#

一句话结论TakeawayresolveAppMode() 根据参数和 TTY 选出四种模式之一;它们都驱动同一个 AgentSessionRuntime。resolveAppMode() picks one of four modes from flags and TTY state; all of them drive the same AgentSessionRuntime.

resolveAppMode() 的分派Dispatch in resolveAppMode()
← 左右滑动查看,点击放大 →← swipe to scroll, tap to enlarge →
Run modespi <args>命令行入口CLI entryresolveAppMode()1--mode rpc→ rpc2--mode json→ json3-p · stdin/stdout ≠ TTY→ print4否则otherwise→ interactivestdiorunRpcMode()33 种 JSONL 命令 · 响应与事件33 JSONL commands · events outstdoutrunPrintMode() · json每个事件一行 JSONevery event as a JSON linestdoutrunPrintMode() · text一次性运行,只输出最终文本one-shot, prints the final textTTYInteractiveMode编辑器 · 聊天视图 · /命令editor · chat viewport · /commandsAgentSessionRuntime→ AgentSession四种模式驱动同一个运行时all four modes drive one runtime并各自调用and each callsbindExtensions({ mode })非交互模式会先接管non-interactive modesstdout,日志转到 stderrtake over stdout firstso logs go to stderrRPC 把扩展 UI 请求RPC forwards extension转成UI requests asextension_ui_requestpi-tuiTuiMainScreen | TuiAltScreencreateInteractiveTui()调用 / 驱动calls / drives运行模式run modepi-coding-agentpi-tui

要点Key points

  • --mode rpc → rpc;--mode json → json;-p 或 stdin / stdout 非 TTY → print;否则 interactive。--mode rpc → rpc; --mode json → json; -p or 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 as extension_ui_request.

工作原理How it works

  1. 非 interactive 模式会先接管 stdout,避免日志污染协议输出。Non-interactive modes take over stdout first so logs cannot corrupt protocol output.
  2. 每种模式都调用 session.bindExtensions(),传入各自的 mode 和 UI 上下文。Each mode calls session.bindExtensions() with its own mode and UI context.
  3. interactive 模式通过 createInteractiveTui() 选择 TuiMainScreen(regular)或 TuiAltScreen(fullscreen)。Interactive mode uses createInteractiveTui() to pick TuiMainScreen (regular) or TuiAltScreen (fullscreen).

关键文件Key files · 4130bd5

文件File符号Symbol作用Role
packages/coding-agent/src/main.tsL112resolveAppMode()模式选择mode selection
packages/coding-agent/src/modes/rpc/rpc-types.tsL20RpcCommandRPC 命令联合类型RPC command union
packages/coding-agent/src/modes/rpc/rpc-mode.tsL54runRpcMode()JSONL 服务循环JSONL service loop
packages/coding-agent/src/modes/print-mode.tsL33runPrintMode()一次性输出one-shot output
packages/coding-agent/src/modes/interactive/interactive-mode.tsL451InteractiveMode终端交互界面terminal UI
11pi-ai

Provider 抽象Provider abstraction#

一句话结论Takeawaypi-ai 把 Provider(身份、认证、模型目录)与 API(线协议)分开:42 个 provider 复用少数几种 API 实现。pi-ai separates a Provider (identity, auth, model catalog) from an API (wire protocol): 42 providers reuse a handful of API implementations.

Provider → API 实现 → 统一事件流Provider → API implementation → normalized event stream
← 左右滑动查看,点击放大 →← swipe to scroll, tap to enlarge →
Provider abstractionproviders/*.ts42 个内置 · createProvider()42 built-in · createProvider()api/*.lazy.ts10 种对话 API(KnownApi)10 chat APIs (KnownApi)AssistantMessageEventStream每个 API 都归一成这 12 种事件 · 失败也是事件,从不抛出every API normalizes to these 12 events · failures are events, never throwsrunLoop()streamFn(model, context)ModelRuntime实现 Models · registerProvider()implements Models · registerProvider()ant-lingbasetencerebrascloudflare-workers-aideepseekgroqhuggingfacemoonshotaimoonshotai-cnnvidiaqwen-token-planqwen-token-plan-cnqwen-token-plan-individualtogetherxiaomixiaomi-token-plan-amsxiaomi-token-plan-cnxiaomi-token-plan-sgpzaizai-coding-cnanthropickimi-codingminimaxminimax-cnvercel-ai-gatewaymetaopenaixaigoogleopenai-codexmistralgoogle-vertexamazon-bedrockradiustypesafecloudflare-ai-gatewayfireworksgithub-copilotopencodeopencode-goopenrouterazureModelsprovider / model 注册表provider · model registrygetModel(provider, id)checkAuth · getAuthprovider.streamSimple()×27openai-completions×11anthropic-messages×7openai-responses×2google-generative-ai×1azure-openai-responses×1openai-codex-responses×1mistral-conversations×1google-vertex×1bedrock-converse-stream×1pi-messagesstarttext_starttext_deltatext_endthinking_startthinking_deltathinking_endtoolcall_starttoolcall_deltatoolcall_enddoneerrorinterface Provider {id · name · baseUrl? · headers? · authgetModels() · stream() · streamSimple() }= provider 使用的对话 API(typesafe 只有分类器 API)= chat APIs a provider uses (typesafe has only a classifier API)streamSimple()lazyApi():首次流式调用时才 import 模块lazyApi(): module imported on its first stream callstream() · streamSimple()1调用call事件流回到 runLoopevent stream back to runLoop1顺序order234

要点Key points

  • 每个 provider 一个文件,用 createProvider() 创建,并在 providers/all.ts 中汇总。One file per provider, created with createProvider() and collected in providers/all.ts.
  • API 实现位于 api/,经 *.lazy.ts 中的 lazyApi() 包装:模块在第一次流式调用时才 import。API implementations live in api/, wrapped by lazyApi() in *.lazy.ts: a module is imported on its first stream call.
  • KnownApi 列出 10 种对话 API(另有 1 种图像 API、4 种分类器 API)。KnownApi lists 10 chat APIs (plus 1 image API and 4 classifier APIs).
  • 例:groq、deepseek 走 openai-completions;xai 走 openai-responses;openrouter 和 github-copilot 同时使用多种 API。e.g. groq and deepseek use openai-completions; xai uses openai-responses; openrouter and github-copilot use several APIs.

工作原理How it works

  1. 每个 API 导出 stream 与 streamSimple,返回 AssistantMessageEventStream。Every API exports stream and streamSimple, returning an AssistantMessageEventStream.
  2. 事件共 12 种:start、text_*、thinking_*、toolcall_*(各 start / delta / end)、done、error。There are 12 event types: start, text_*, thinking_*, toolcall_* (start / delta / end each), done, error.
  3. StreamFn 约定不抛异常:认证、模块加载或请求失败都编码为流中的 error 事件(见 lazyStream())。The StreamFn contract forbids throwing: auth, module-load and request failures become an error event in the stream (see lazyStream()).

关键文件Key files · 4130bd5

文件File符号Symbol作用Role
packages/ai/src/models.tsL1041createProvider()provider 工厂provider factory
packages/ai/src/providers/all.tsL4providers/all.ts42 个内置 providerthe 42 built-in providers
packages/ai/src/api/anthropic-messages.tsL928streamSimple一个 API 实现示例an example API implementation
packages/ai/src/types.tsL61KnownApi10 种对话 APIthe 10 chat APIs
packages/ai/src/utils/event-stream.tsL97AssistantMessageEventStream统一事件流the normalized stream
packages/agent/src/types.tsL20StreamFn不抛异常的约定the no-throw contract
12pi-tui

TUI 渲染TUI rendering#

一句话结论Takeawaypi-tui 的组件只需实现 render(width) → string[];渲染器批量合并请求,每帧最多 16 ms 一次,只重写变化的行。A pi-tui component only implements render(width) → string[]; the renderer batches requests, caps frames at one per 16 ms, and rewrites only changed lines.

从按键 / 事件到终端输出的一帧One frame, from keypress or event to terminal output
← 左右滑动查看,点击放大 →← swipe to scroll, tap to enlarge →
TUI renderingstdin批量到达的字节bytes arrive in batchesProcessTerminalStdinBuffer 切分按键StdinBuffer splits keys焦点组件focused ComponenthandleInput(data)requestRender()nextTick 合并coalesced on nextTickscheduleRender()帧间隔 ≥ 16 ms≥ 16 ms between framesagent 事件agent eventsInteractiveMode 更新InteractiveMode updatesdoRender()render(width) → string[]合成 overlaycomposite overlays弹窗、选择器叠在上面dialogs · selectors on top对比 previousLinesdiff previousLines找出变化的行find changed lines只写变化的行write changed linesCSI ?2026h … ?2026l> fix the failing test● read math.test.ts● bash npm test ✓ 41 passed ✓ 1 fixedDone. The test now…──────────────────────▌render(width): string[]handleInput?(data)invalidate()force = true高亮 = 本帧重写的行highlighted = rewritten this frame组件契约COMPONENT CONTRACT123456789一帧的路径one frame异步事件async eventforce:重置并立即全量重绘force: reset + immediate full redraw

要点Key points

  • Container 组合子组件;可选的 handleInput / handleMouse 处理输入。Container composes children; optional handleInput / handleMouse handle input.
  • 两种屏幕:TuiMainScreen(主屏,保留 scrollback)与 TuiAltScreen(备用屏全屏)。Two screens: TuiMainScreen (main buffer, keeps scrollback) and TuiAltScreen (alternate-screen fullscreen).
  • 内置组件:Editor、Input、Markdown、SelectList、Image、Loader、ScrollView、Stack 等。Built-in components: Editor, Input, Markdown, SelectList, Image, Loader, ScrollView, Stack and more.

工作原理How it works

  1. ProcessTerminal 用 StdinBuffer 把批量到达的输入拆成完整的按键序列,交给获得焦点的组件。ProcessTerminal uses StdinBuffer to split batched input into complete key sequences for the focused component.
  2. requestRender() 在 process.nextTick 中合并请求,scheduleRender() 保证两帧间隔 ≥ MIN_RENDER_INTERVAL_MS(16 ms);force 会立即渲染。requestRender() coalesces on process.nextTick; scheduleRender() keeps frames ≥ MIN_RENDER_INTERVAL_MS (16 ms) apart; force renders immediately.
  3. TuiMainScreen.doRender() 合成 overlay 后与 previousLines 比较,在同步输出(CSI ?2026h)中只写出变化的行。TuiMainScreen.doRender() composites overlays, diffs against previousLines, and writes only changed lines inside synchronized output (CSI ?2026h).

关键文件Key files · 4130bd5

文件File符号Symbol作用Role
packages/tui/src/tui.tsL117Component最小组件接口minimal component interface
packages/tui/src/tui.tsL1001requestRender()批量与节流batching and throttling
packages/tui/src/tui-main-screen.tsL124TuiMainScreen差分渲染differential rendering
packages/tui/src/terminal.tsL150ProcessTerminal终端 I/Oterminal I/O
packages/coding-agent/src/modes/interactive/tui-renderer.tsL22createInteractiveTui()选择屏幕类型picks the screen type
13Repository

仓库统计Repository stats#

一句话结论Takeaway约 181k 行源码、191k 行测试;coding-agent 一个包就占了 48% 的源码,测试代码量与源码相当。About 181k lines of source and 191k of tests; coding-agent alone is 48% of the source, and test code roughly matches source code.

统计自提交 4130bd5:只计 .ts(不含 .d.ts),排除 node_modules 与 dist;src = src/ 下,test = test*/ 下或 *.test.*。Counted at commit 4130bd5: .ts only (no .d.ts), node_modules and dist excluded; src = under src/, test = under test*/ or *.test.*.

源码行数src LOC测试行数test LOC
包Package源文件src files源码行src LOC测试文件test files测试行test LOC全部 .tsall .ts
coding-agent30386,11133271,535742
ai19827,23817443,102382
durable7222,42710235,081176
tui4619,5055120,07297
chord298,817309,72659
mcp183,24461,53225
codemode162,57851,34224
agent62,51974,05816
env62,073689713
server161,95861,05423
evals51,446782923
client81,135479913
telemetry693522438
protocol8869356712
合计Total737180,855735190,8371,613