跳转到内容

Monorepo 分层与工程理念

内容状态
已校验
校验日期
2026/10/1

复核基线:Pi main 的提交 8ce69e9d2b171d173fe4b6b2b6256f1f4411e69d。 本文区分当前 coding-agent 主路径、agent 包中的 AgentHarness 与独立的 pi-durable Harness。

完成本阶段后,需要能够:

  • 解释 Pi 是什么,以及它与普通聊天 CLI 的区别
  • 画出 monorepo 的包级依赖图
  • 说明 ai、agent、coding-agent、tui 的职责边界
  • 追踪 CLI 从入口到 AgentSession 创建完成的启动链
  • 解释 minimal core、extension-first 和事件驱动 UI
  • 区分产品设计理念与仓库开发规范

英文原文:

  • README.md
  • packages/coding-agent/README.md
  • AGENTS.md
  • 根目录及各 package 的 package.json

中文整理:资料待整理。

中文整理用于学习,发生差异时以仓库英文原文为准。

当前 coding-agent README 的定位是“minimal, extensible AI agent for the terminal”,而不是将一套固定工作流写死的 AI 编程产品。 这个定位直接来自 packages/coding-agent/README.md。

从运行时工程的角度,harness 可以理解为:

用工具、状态、事件、会话和扩展边界,组织概率性的模型输出。

这是本文的工程化理解,不是仓库对 harness 的逐字定义。 其中也有两套不能混为一谈的 Session 路径:

  • 当前 coding-agent 主路径使用 AgentSession + SessionManager,将会话保存为 JSONL Tree;
  • packages/agent/src/harness 保留 AgentHarness 实现;当前还新增 packages/durable/src/harness 的 Harness,两者都需与 coding-agent 主路径分开阅读。

Pi 同时提供两类能力:

  1. 通用底层能力:
  • 多 Provider 模型访问
  • Agent Loop
  • Tool Calling
  • 事件流
  • Session
  1. coding-agent 产品能力:
  • CLI 和 TUI
  • 文件与 Shell 工具
  • 项目上下文
  • Skills 和 Extensions
  • 会话分支与压缩
  • Print、JSON、RPC、SDK 等运行模式

因此,不能把 Pi 简化成:

CLI + 一个很长的 System Prompt + 模型 API

更准确的模型是:

产品表面
+ 产品编排
+ Agent Runtime
+ 模型协议适配
+ 持久化与扩展

当前根 README 列出 chord、telemetry、ai、durable、agent、coding-agent、tui。client、protocol、server 与 session-backends/sqlite-node 仍存在于 workspace/build 链;根 README 的展示清单并非全部目录。

flowchart LR
    Coding["coding-agent 产品"] --> Agent["agent 执行引擎"]
    Coding --> AI["ai 模型协议"]
    Coding --> TUI["tui 终端组件"]
    Agent --> AI

这张图只画本系列追踪的主要依赖。完整依赖以各包的 package.json 为准;chord 提供应用组合运行时,durable 是新的持久化 conversation/task/document 运行时,不能因为它们存在就认定 CLI 已切换到它们。

CLI → createAgentSessionRuntime() → AgentSession → Agent → runAgentLoop()
→ SessionManager(coding-agent JSONL)

学习边界由实际调用链决定。agent 不反向依赖 coding-agent 产品,TUI 组件也不负责控制 Tool Loop。

定位:统一多 Provider 的模型运行时。

主要职责:

  • Model 和 Provider 注册
  • API Key、OAuth 和 Provider 认证
  • 模型目录和能力信息
  • 统一 Context、Message 和 Tool
  • 统一流式事件
  • thinking/reasoning 适配
  • Tool Call 参数流
  • 跨 Provider 消息兼容
  • Faux Provider 测试能力

它不负责:

  • 决定何时执行工具
  • 保存 Agent Session
  • 构造 coding-agent 系统提示词
  • 渲染 TUI

核心抽象:

Model + Context + StreamOptions
→ AssistantMessageEventStream
→ AssistantMessage

定位:通用 Agent Runtime。

主要职责:

  • Agent 状态
  • LLM 与 Tool 的循环
  • Tool 参数校验与执行
  • steering 和 follow-up 队列
  • abort 和 settlement
  • Agent 生命周期事件
  • 正在演进的 AgentHarness 和通用 Session 存储底座

它不负责:

  • CLI 参数
  • 项目 AGENTS.md
  • coding-agent 的默认 Prompt
  • 内置 coding tools 的产品配置
  • 终端 UI

核心抽象:

Agent
= State
+ Agent Loop
+ Queues
+ Awaited Events
+ Abort

Agent 是当前 coding-agent 真正调用的执行引擎。 AgentHarness 现在通过 createAgentHarness() 委托到 harness/runtime;已有执行与恢复代码,但不在本文追踪的 coding-agent 主路径。

定位:基于 Agent Core 构建的完整 coding-agent 产品。

主要职责:

  • CLI 启动与参数解析
  • Interactive、Print、JSON、RPC、SDK
  • ModelRuntime 和认证选择
  • AgentSession 产品编排
  • 默认 coding tools
  • ResourceLoader
  • AGENTS.md、Skills、Prompt Templates
  • Extension Runtime
  • JSONL Session Tree
  • Retry、Compaction 和 Branch Summary
  • Project Trust

核心抽象:

AgentSession
= Agent
+ Product Policy
+ Persistence
+ Resources
+ Extensions
+ Recovery

定位:与 Agent 业务无关的终端 UI 框架。

主要职责:

  • Component 树
  • 输入和焦点管理
  • Editor、Markdown、Selector、Overlay
  • 终端能力检测
  • Kitty/iTerm 图片
  • 差量渲染
  • 同步终端输出

它不理解:

  • 什么是 Agent Turn
  • 什么是 Tool Result
  • 什么是 Session Compaction

这些业务概念由 coding-agent 转换成普通 TUI Component。

旧模块 packages/agent/src/harness 中 AgentHarness 的 create() 委托给 harness/runtime/harness.ts 的 createAgentHarness()。执行进一步拆入 runtime/drive/*,恢复进入 runtime/restore.ts。旧文“prompt/resume 都是 scaffold、create.restore 固定抛错”的判断已经失效。

coding-agent: AgentSession → Agent → agentLoop
SessionManager → JSONL Tree
agent-core Harness: AgentHarness.create → createAgentHarness
→ runtime / lane / drive / restore
→ harness/session
另有 packages/durable 与 harness/pico3 的演进实现

这些路径的 Session、Entry、恢复与副作用语义不应互相套用。本章只核对当前 CLI 的入口与对象装配,不把另一路 runtime 的实现存在当作其完整生产恢复能力的证明。

四、静态架构与运行时对象的区别

Section titled “四、静态架构与运行时对象的区别”

Package 是发布和依赖边界,运行时对象是一次进程中真正协作的组件。

flowchart LR
    Main["main()"]
    Services["AgentSessionServices"]
    Runtime["AgentSessionRuntime"]
    Session["AgentSession"]
    Agent["Agent"]
    Loop["agentLoop"]
    StreamFn["injected streamFunction"]
    ModelRuntime["ModelRuntime"]
    ResourceLoader["ResourceLoader"]
    SessionManager["SessionManager"]
    Mode["Interactive / Print / RPC"]

    Main --> Services
    Services --> ModelRuntime
    Services --> ResourceLoader
    Main --> Runtime
    Runtime --> Session
    Session --> Agent
    Session --> SessionManager
    Agent --> Loop
    Loop --> StreamFn
    StreamFn --> ModelRuntime
    Mode --> Runtime

关键对象:

对象 生命周期 核心职责
AgentSessionServices 与 cwd 绑定 Settings、Models、Resources
AgentSessionRuntime 当前宿主持有 管理当前 Session 及 Session 替换
AgentSession 一次 coding session 产品级编排
Agent 一次 Agent 状态实例 消息、工具、队列、事件
SessionManager 持久化或内存会话 JSONL、分支、上下文重建
InteractiveMode 一次 TUI 生命周期 输入与事件展示

源码导读:Agent 与 AgentSession 的区别

Section titled “源码导读:Agent 与 AgentSession 的区别”

只记住“Agent 是执行引擎,AgentSession 是产品编排层”还不够。下面用一次真实请求说明两者如何协作。

先区分三个容易混淆的概念:

概念 源码位置 保存什么 是否理解 coding-agent 产品
Agent packages/agent/src/agent.ts 当前模型、System Prompt、工具、消息、流式状态、消息队列 否
AgentSession packages/coding-agent/src/core/agent-session.ts 对 Agent 的产品级控制,以及扩展、重试、压缩、工具和资源状态 是
SessionManager packages/coding-agent/src/core/session-manager.ts JSONL Session Tree、当前 leaf、分支和历史恢复 是,但只负责持久化

这里最容易误解的一点是:

Agent.state.messages 是当前进程中供 Agent Loop 使用的消息状态;SessionManager 保存的是能够退出后恢复、分支和回放的持久化 Session。AgentSession 负责让两者保持一致。

打开 packages/agent/src/agent.ts,先看 Agent 类的字段和公开方法。

它持有的核心状态是:

Agent
├─ state
│ ├─ systemPrompt(从 system messages 重放的只读视图)
│ ├─ model / thinkingLevel
│ ├─ tools
│ ├─ messages
│ ├─ isStreaming / streamingMessage
│ └─ pendingToolCalls / errorMessage
├─ steeringQueue
├─ followUpQueue
├─ activeRun / AbortController
└─ lifecycle listeners

它提供的核心动作是:

  • prompt():加入新消息并启动 Agent Loop;
  • continue():从已有上下文继续执行;
  • steer():当前执行过程中,在下一次合适的轮次插入消息;
  • followUp():Agent 原本准备结束时,再启动后续请求;
  • abort():终止当前运行;
  • waitForIdle():等待 Loop 和异步事件监听器全部完成;
  • subscribe():订阅 Agent 生命周期事件。

Agent.prompt() 不会读取项目文件,也不会保存 JSONL。它最终只做一件核心工作:

规范化输入
→ 创建本次运行的 Context Snapshot
→ 调用 runAgentLoop()
→ 处理模型与工具产生的事件
→ 更新内存中的 AgentState

因此,单独使用 Agent 时,宿主程序必须自己决定:

  • System Prompt 从哪里来;
  • 提供哪些工具;
  • API Key 如何获取;
  • 消息如何持久化;
  • Context 过长时怎么办;
  • UI 如何展示事件。

这正是它能够被其他产品复用的原因。

再打开 packages/coding-agent/src/core/agent-session.ts。构造函数直接接收一个已经创建好的 Agent:

AgentSession
├─ agent
├─ sessionManager
├─ settingsManager
├─ modelRuntime
├─ resourceLoader
├─ extensionRunner
├─ tool registry
├─ retry / compaction state
└─ bash / branch / product event state

ModelRuntime 是 coding-agent 的模型运行服务。它在 pi-ai 的 Provider 能力之上,组织认证、模型目录、 动态 Provider、重试配置和 streamSimple() 调用。它不是 Agent 自己创建的。

创建链是:

main()
→ createAgentSessionServices()
→ ModelRuntime.create()
→ createAgentSessionFromServices()
→ createAgentSession()
→ new Agent({ streamFn })

createAgentSession() 在 sdk.ts 中构造一个 streamFn closure:

new Agent({
streamFn: async (model, context, options) => {
return modelRuntime.streamSimple(model, context, options);
},
});

上面是简化代码。真实 closure 还会合并 timeout、retry、Provider headers 和 Extension hooks。

因此 Agent 只依赖一个“给定 model/context,返回流式事件”的函数契约, 它不需要理解 API Key、Provider 注册或 coding-agent Settings。 这是依赖注入:产品层决定怎样调模型,通用 Agent Loop 只调用被注入的能力。

它不重新实现模型与工具循环,而是在 Agent 的前后增加 coding-agent 产品策略。

调用 AgentSession.prompt("修复这个 bug") 时,源码依次做:

AgentSession.prompt()
├─ 判断是否为 Extension Command
├─ 触发 Extension input hook
├─ 展开 Skill Command 和 Prompt Template
├─ 若 Agent 正在运行,则转成 steer / followUp
├─ 合并待注入的 Bash 和 Custom 消息
├─ 检查 Model 与认证
├─ 必要时先做 Compaction
├─ 构造 user/custom messages
├─ 触发 before_agent_start
├─ 更新本轮 System Prompt
└─ _runAgentPrompt()
└─ Agent.prompt(messages)

进入 Agent.prompt() 后,控制权才交给通用运行时:

Agent.prompt()
→ runAgentLoop()
→ 调用模型
→ 收到 Tool Call
→ 校验并执行 Tool
→ 写入 Tool Result
→ 再次调用模型
→ 发出 agent_end

AgentSession 在构造时通过下面这行订阅 Agent:

this._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);

所以 Loop 每产生一个事件,AgentSession._handleAgentEvent() 都会收到。它会:

  1. 把事件先发送给 Extension;
  2. 把事件转发给 Interactive、Print、JSON 或 RPC 等消费者;
  3. 在 message_end 时调用 SessionManager 持久化消息;
  4. 记录最后一条 Assistant Message,供重试和自动压缩判断使用。

当 Agent 发出 agent_end 后,AgentSession 仍可能继续工作:

Agent 已结束一次运行
→ 是否遇到可重试错误?
→ 是否需要自动 Compaction?
→ agent_end hook 是否又加入了消息?
→ 如果是,调用 Agent.continue()
→ 全部结束后发出 agent_settled

因此:

  • agent_end 表示通用 Agent Loop 的一次运行结束;
  • agent_settled 表示产品层的重试、压缩和后续 continuation 也全部处理完毕。

这也是为什么 UI 等待“Pi 完全空闲”时,不能只看 agent_end。

可以用一个判断标准区分某项能力属于哪一层:

把 coding-agent 换成客服 Agent、数据分析 Agent 或后台服务后,这项能力是否仍然成立?

仍然普遍成立的机制放在 Agent:

  • 模型调用;
  • Tool Loop;
  • Tool 参数校验和执行;
  • streaming;
  • steering / follow-up;
  • abort;
  • 生命周期事件。

只属于 Pi coding-agent 产品的策略放在 AgentSession:

  • 加载项目 AGENTS.md;
  • 展开 Skills 和 Prompt Templates;
  • Extension hooks;
  • 文件、Shell 等 coding tools 的组合;
  • Provider 认证和模型切换;
  • JSONL Session Tree;
  • Retry 和 Compaction;
  • Branch Summary;
  • 面向 TUI、Print、JSON、RPC 的产品事件。

持久化操作则进一步委托给 SessionManager。因此不是简单的两层,而是:

AgentSession:决定产品应该怎么运行
├─ Agent:真正执行模型与工具循环
└─ SessionManager:保存和恢复会话树

如果 Agent 直接加载 AGENTS.md、写 JSONL、处理 TUI 和 Compaction:

  • 通用 Agent Runtime 会绑定 coding-agent 的目录结构和产品策略;
  • SDK 或 Server 无法只复用执行循环;
  • Loop 测试会被文件系统、认证和 UI 状态干扰;
  • 更换持久化方式或宿主产品会变得困难。

分层之后,Agent 可以独立测试概率性执行过程,AgentSession 可以测试确定性的产品编排,两者的变化原因也不同。

第一次阅读不需要通读两个大文件,按这条路径即可:

  1. packages/agent/src/agent.ts
  • Agent 的字段;
  • constructor();
  • prompt();
  • runPromptMessages();
  • createContextSnapshot()。
  1. packages/coding-agent/src/core/agent-session.ts
  • AgentSession 的字段;
  • constructor() 中的 agent.subscribe(...);
  • prompt();
  • _runAgentPrompt();
  • _handlePostAgentRun();
  • _handleAgentEvent()。
  1. packages/coding-agent/src/core/session-manager.ts
  • appendMessage();
  • buildSessionContext()。

读完后,用下面三个问题自测:

  1. 删除 SessionManager 后,Agent 能否完成一次模型与工具循环?能,但不能持久化和恢复。
  2. 删除 AgentSession 后,能否直接调用 Agent.prompt()?能,但要由新宿主自己提供 Prompt、工具、认证、持久化和恢复策略。
  3. 删除 Agent 后,AgentSession 能否工作?不能,因为它自身不实现 Agent Loop。

第一阶段只需要理解启动骨架,不深入每个函数。

入口:

packages/coding-agent/src/cli.ts
→ main(process.argv.slice(2))

主链路:

main()
→ 解析 CLI 参数
→ 运行 migrations
→ 选择或创建 SessionManager
→ 确定最终 session cwd
→ 解析 project trust
→ createAgentSessionServices()
├─ SettingsManager
├─ ModelRuntime
└─ DefaultResourceLoader.reload()
→ createAgentSessionFromServices()
→ createAgentSession()
├─ 恢复 model/thinking/messages
├─ new Agent()
└─ new AgentSession()
→ createAgentSessionRuntime()
→ 选择运行模式
├─ InteractiveMode
├─ PrintMode / JSON
└─ RpcMode

Session 可以来自另一个项目。以下内容都与 cwd 绑定:

  • .pi/settings.json
  • .pi/extensions
  • .pi/skills
  • .pi/prompts
  • 项目 AGENTS.md
  • Project Trust

因此不能先按启动目录加载资源,再切换到其他项目的 Session。Pi 会先确定最终 cwd,然后创建一组 coherent cwd-bound services。 Session 保存目录有默认值,但可由 CLI、环境变量或 Settings 覆盖,不能简化为始终与 cwd 固定绑定。

用户执行 /new、/resume、/fork 或 import 时,可能需要:

  • 关闭旧 Extension;
  • 释放旧 Session;
  • 切换 cwd;
  • 重新加载 Settings、Models 和 Resources;
  • 重建 AgentSession;
  • 让 TUI 重新绑定到新 Session。

AgentSessionRuntime 专门负责这种“整个运行时替换”,避免把切换逻辑塞进 AgentSession。

Pi 核心只保留普遍适用的机制,不内建存在大量策略分歧的工作流。

当前必须区分“通用 Agent Core”与“coding-agent 随包提供的产品能力”。CLI 已内置 mcp、codemode、tool-search 等 Extension;不能再把“不内建 MCP”作为 Pi 当前的产品结论。

// extensions/index.ts 的缩写:省略 llama.cpp 与类型。
const builtInExtensions = [
{ name: "codemode", factory: codemodeExtension, replaceable: true, builtin: true },
{ name: "tool-search", factory: toolSearchExtension, replaceable: true, builtin: true },
{ name: "mcp", factory: mcpExtension, replaceable: true, builtin: true },
];

这些能力复用 Extension 的加载、生命周期和工具接口,没有要求裸 agentLoop() 理解 MCP transport。 可替换内置扩展与第三方扩展的工具、命令或 flag 冲突时,可由后者接管。具体审批与执行环境策略仍需 宿主选择;pi-durable 的任务所有权与子会话能力也不能等同于 CLI 默认带一个子 Agent 工具。

例如 Agent Core 提供:

  • beforeToolCall
  • afterToolCall
  • Tool registry
  • 生命周期事件

但不规定:

  • 哪些命令危险;
  • 是否需要用户确认;
  • 是否在容器中执行;
  • 是否允许访问网络。

这些属于宿主环境的 policy。

与其把所有功能加入核心,Pi 当前提供广泛的扩展面:

  • 注册 Tool
  • 注册 Command
  • 注册 Provider
  • 拦截 Context
  • 修改 Provider Request
  • 自定义 Compaction
  • 注入 TUI
  • 发现额外资源

目标是“适配用户工作流”,而不是要求用户适配固定产品流程。

4. Prompt 只承担模型需要理解的内容

Section titled “4. Prompt 只承担模型需要理解的内容”

可以由程序保证的约束,不只依靠 Prompt:

  • Tool 参数由 schema 校验;
  • Tool 的 parallel/sequential 执行语义由 Loop 控制;parallel 模式下完成事件按实际完成顺序,Tool Result 按模型源顺序回写;
  • Session 由持久化层保存;
  • Context Overflow 由 Compaction 处理;
  • pi-ai 提供统一上层协议,同时保留必要的 provider-specific compatibility;
  • Project Trust 由启动流程控制。

AgentEvent 包含下列事件类型。这是类型集合,不是一次调用的严格时序:

agent_start
turn_start
message_start
message_update
tool_execution_start
tool_execution_update
tool_execution_end
message_end
turn_end
agent_end

Interactive、JSON 和 RPC 会订阅 AgentSession 事件。Print 的 JSON 模式输出事件,普通文本模式则在运行后读取最终 Session State。

好处:

  • Agent Core 不依赖 TUI;
  • 流式输出天然可观察;
  • RPC 和测试复用同一生命周期;
  • UI 更换不会改变 Agent Loop。

需要精确表述的是:

packages/tui 只负责渲染机制;InteractiveMode 既把用户输入提交给 AgentSession,也订阅 AgentSession 事件更新组件。TUI 不直接控制 Agent Loop。

当前 coding-agent 不把对话只保存成线性 message 数组,而是通过 SessionManager 保存为 JSONL Session Tree。

这为后续能力提供基础:

  • resume
  • fork
  • clone
  • tree navigation
  • compaction
  • branch summary
  • session export

7. 供应链安全是工程设计的一部分

Section titled “7. 供应链安全是工程设计的一部分”

根 README 和 AGENTS.md 强调:

  • 外部依赖锁定精确版本;
  • 安装时默认 --ignore-scripts;
  • lockfile 和 shrinkwrap 需要显式审核;
  • 发布前从仓库外进行隔离 smoke test;
  • npm 发布使用 CI OIDC;
  • 不降级代码来绕过过期依赖引起的类型错误。

这与 Agent 项目尤其相关,因为:

  • Extension 能执行任意代码;
  • Tool 会调用本地程序;
  • Agent 会读取凭据和项目文件;
  • 自动化发布扩大供应链风险。

七、产品理念与开发规范不能混淆

Section titled “七、产品理念与开发规范不能混淆”

新版 packages/coding-agent/README.md 已精简,重点是 minimal/extensible terminal agent、多种运行模式,以及让用户创建或安装 Prompt、Skill、Extension、Theme。旧版“不内建 MCP”等清单已不适用;当前产品能力要同时核对 builtInExtensions 与入口装配。

本文关于主循环、工具、Session、扩展和权限边界的判断分别以 src/core、sdk.ts、tools/index.ts 及 docs/security.md 为依据。产品方向可以解释源码,但不能替代实际装配与调用证据。

AGENTS.md:

  • TypeScript 代码质量规则
  • 测试命令
  • Git 并发安全
  • 依赖与 lockfile 规则
  • Issue、PR、Changelog 和 Release 流程

AGENTS.md 同时也是阶段 5 的一个实例:Pi 会把它作为 project context 加载到 System Prompt。

为什么 coding-agent 直接依赖 ai,而不只依赖 agent

Section titled “为什么 coding-agent 直接依赖 ai,而不只依赖 agent”

因为 coding-agent 还需要直接使用:

  • ModelRuntime
  • Provider 注册
  • Auth
  • 模型查询和切换
  • Compaction 的模型调用
  • Provider 请求 hook

这些不是 Agent Loop 独占的能力。

  • 可以独立测试终端渲染;
  • 可用于非 Agent 程序;
  • Agent Core 不需要依赖终端环境;
  • coding-agent 负责把业务事件适配成通用组件。

server 不依赖 coding-agent。它围绕 PiServerService + protocol 组织 Session Server, 由宿主应用提供 Session 列表、模型列表、创建和打开 Session 的实现。 因此它是一条实验性远程协议链的基础包,不是当前 CLI 主路径的上层入口。

避免 Agent Core 强制依赖:

  • Node 内建 SQLite;
  • 原生模块;
  • 特定数据库运行时。

这体现 dependency inversion:Core 定义接口,Storage package 提供实现。

client → protocol
ai → telemetry
agent → ai + telemetry
server → ai + protocol
session-backends/sqlite-node → agent + ai
coding-agent → agent + ai + client + protocol + tui
tui → 无 Pi workspace 依赖
Mode
→ AgentSessionRuntime
→ AgentSession
→ Agent
→ agentLoop
→ 注入的 streamFunction
→ ModelRuntime.streamSimple()
→ pi-ai
→ Provider
Settings + Project Trust
→ ResourceLoader
├─ Extensions
├─ Skills
├─ Prompt Templates
├─ Themes
└─ AGENTS.md / System Prompt
→ AgentSession

Pi 是一个 minimal terminal coding harness,核心特征是分层和可扩展。 packages/ai 将不同 Provider 转成统一的模型、消息和流式协议; packages/agent 使用这套协议实现 Agent State、Tool Loop、队列、abort 和生命周期事件; packages/coding-agent 通过 AgentSession 加入项目资源、coding tools、Extensions、认证、重试、Compaction 和 JSONL Session Tree; packages/tui 只提供终端渲染机制,不理解 Agent 业务。

一次请求的主链是:

Mode
→ AgentSession.prompt()
→ Agent.prompt()
→ runAgentLoop()
→ streamFunction
→ ModelRuntime.streamSimple()
→ pi-ai Provider

Agent 事件会回到 AgentSession,先进入 Extension hooks,再通知 UI/RPC 等消费者, 并在 message_end 时交给 SessionManager 持久化。 agent_end 只是底层 Loop 结束,产品层仍可能重试、压缩或继续队列消息,直到 agent_settled 才表示真正空闲。

Pi 的 minimal core 不是功能少,而是将普遍成立的 mechanism 留在核心, CLI 已随包提供 MCP、codemode 和工具搜索扩展;通用 Loop 仍通过工具与 hooks 工作。权限策略及产品工作流由 Extension 或宿主组织。

  1. 为什么 AgentSession 不等于 Agent?请从 prompt 前处理、Loop 和 post-run 三段回答。
  2. 为什么 agent_end 之后 Pi 仍可能没有完全空闲?
  3. 当前 coding-agent 的 JSONL SessionManager 与新 AgentHarness 的 Session Storage 是同一套实现吗?
  4. server 为什么不能画成 server → coding-agent?它要求宿主注入什么接口?
  5. Agent 到 Provider 的真实调用链里,ModelRuntime 是由谁注入的?

packages/agent/src/harness 的 AgentHarness 与 packages/durable/src/harness 的 Harness 是不同实现。 最新 pi-durable 已提供 Harness.open → root/submit → pi.generation → pi.tool 的可运行链、恢复调度、 compaction、扩展注册表和每会话 Agent 配置。CLI 的 createAgentSession() 主路径仍使用 AgentSession, 不能因为仓库出现新 Harness 就说 CLI 已迁移。第十章以新 pi-durable 为主线,单列旧实现边界。