Peri 把模型协议、会话执行、能力装配、协议出口和终端呈现拆成不同边界。本文回答三个问题:一项状态由谁持有,一项决策由谁执行,一个事件在哪里被协议化。
内容整理自主仓库 docs/design/architecture.md(状态:现行设计);演进状态按根 CLAUDE.md 的阶段目标校对。跨模块不变量以 docs/standards/architecture-contracts.md 为准;具体符号与代码入口查 docs/code-index/。
边界地图
从端点向下进入
事件 ↑从执行层向上返回
能力供给 ↑供给层为上方各层提供能力
能力供给自下而上;请求向下进入,事件向上返回。
peri-tuiprintTUI、CLI、IDE 与 print 都经 ACP;stdio 只是本地 transport
peri-acpACP 适配、事件协议化与 caps 门控;不承载业务
peri-controller组合 Resources 与 Runtime;取消目标链路中只定位与转发;观测走旁路
peri-runtime只持有 session_id → SessionHandle 映射,不持有 session 状态
peri-agentSession 聚合根、RCRA 循环、冻结上下文与 cancel 终态判定(目标)
peri-modelOpenAI / Anthropic 协议、ModelMessage / ModelStream;无业务语义
能力供给与共享底座
peri-middlewaresperi-resourcesperi-processperi-configperi-acp-types连接与工具切面、外部数据、子进程、配置权威面、共享契约
三问定层
判断一项职责归哪一层,按以下顺序回答:
- 生命周期:状态跟着 session 活,归 Agent;跟着进程或多 session 活,归 Runtime;单次调用即结束的,不跨层。
- 来源:LLM 协议形态归 Model;ACP 协议形态归 ACP;外部系统数据的访问通道归 Resources,持有者按生命周期决定。
- 消费:界面呈现归 TUI;组合多源决策归 Controller;旁路观测走独立通道,不参与业务链路。
发生争议时,通道与持有分离,生命周期优先于消费;协议适配归 Model,业务切面归 Middleware,界面归 TUI,接口契约归 peri-acp-types。
两条协议边界
这两条边界都是协议边界,不是进程边界。MCP 按能力消费方向定义,与部署位置无关;MCP 能力边界也不强制对应独立进程,部署隔离按信任边界和生命周期确定。模型可见性与调用授权分别校验,宿主专用控制工具不进入模型工具目录。
在这个方向上,文件系统依赖尽量下沉到 mcp-packages 层以下,业务层不直接外溢;网络依赖优先于本地文件依赖。工作区与工具环境可独立于计算实例驻留是服务化目标,不是当前已完成的承诺。
职责边界
按四个长期能力面阅读,最后单独看 Model 的协议边界。每个面都落在主链的一段上,不是独立进程。
Sessions:状态跟着会话活
peri-agent 是 Session 聚合根。Session 的创建、运行和销毁,消息队列、RCRA 循环、冻结上下文、Session 级 hook 与 cancel 终态都归这一层。Session 创建时从 Resources 拉取项目指引、Skills 摘要和日期并冻结;SubAgent 创建时复制同一份冻结数据,因此会话内不会漂移。存储中 Session 就是 Thread,SubAgent 通过 parent_thread_id 形成父子链。
peri-runtime 只维护 session_id → SessionHandle 映射,负责多 Session 的事件聚合补打与请求转发。它不持有 Session 状态、持久态或业务配置;其余能力全部注入,状态留在各 Session 内。它也不是消息激活或执行准入的第二权威。
历史与执行分开。Thread/transcript、配置与 frozen/inherited 是历史事实源;Store 不保存 Agent 执行恢复账本。进程重启后可以加载历史会话并继续对话,但不会重建旧 mailbox、任务 owner 或旧执行;外部副作用未知时如实报告,不伪造完成、取消或跨进程恢复。
Resources:能力接入与外部数据
peri-middlewares 承载业务切面:Goal、SubAgent、Permission、AskUser 等通过 Hook 挂载,并声明工具与 prompt 贡献;生产链顺序属于行为契约,不能按名称排序或为局部方便重排。文件系统与终端工具由 builtin Workspace MCP 实例提供;Skills、Cron 等能力同样经 MCP Middleware 接入,业务层不直接持有这些实现。MCP 客户端连接池、连接生命周期与工具桥接也在 Middleware 层。
peri-resources 是外部系统门面:会话持久化(本地 SQLite 与远端 Turso adapter)、Workspace 级 OAuth 凭据。adapter 负责保存与适配状态,共用领域 reducer,不维护第二份业务规则;它不拥有 MCP 连接,也不承担交互 broker。配置来源 I/O 由独立 peri-mcp-config bootstrap 提供文件正文、具名环境与字节 CAS,不由 peri-resources 实现;有效配置规则归 peri-config,也不归输入 provider。peri-process 提供 OS 子进程能力,不拥有 session、数据库 lease、协议或 UI;Bash、MCP 与 JavaScript 的 owner 各自持有并负责清理。
这里的关键规则是通道与持有分离:外部数据的访问通道归 Resources,持有者按生命周期决定。工作区与工具环境可独立于计算实例驻留是服务化目标,不是当前已完成的承诺。
Orchestration:同构 Agent 的任务关系
peri-controller 是控制面:用 lite params(session 标识、agent 定义引用、cwd、初始输入)选择 Resources 与 Runtime,运行 Session 并消费事件;其余上下文由 Controller 组装注入。事件聚合与过滤、cancel 的定位与转发也在这一层;它只定位和转发,不解释取消语义。观测是横切旁路,不参与业务结果。
peri-agent 以 AgentGroup 组织平等 Agent,SubAgent 通过 SessionFactory::spawn_subagent 创建;Task 与 Thread 分工不同:Thread 是持久化实体,Task 是当前进程的运行投影。任务归属、调用关联和交付只存在于当前进程,不持久化 owner 声明、任务绑定或交付账本,也不提供跨实例恢复。
Subagent、Multitask 与 Workflow 都建立在同构 Agent 上,管理任务关系、协调与当前运行期等待,不恢复旧执行。
编排的长期边界是任务关系、协调与当前运行期等待,不绑定某个活跃 Harness 实例;当前实现仍以进程内 Runtime/Controller 为主,跨实例协调属于未完成的服务化目标。结果到达不是复活已取消 turn 的授权;当前运行、暂停和关闭状态都要参与判断。
Endpoint:所有客户端经 ACP
peri-acp 是纯协议实现:ACP 适配、事件协议化映射与 caps 门控,不承载业务。配置的 typed 结果由 peri-config 提供,ACP 不复制 typed 解析和来源规则;宿主把同一 scoped snapshot 注入新建 MCP pool。
所有客户端一律经 ACP:TUI、CLI、IDE、print 以及 stdio 路径共用同一套业务语义。stdio 是本地 transport,不是另一条业务链;TUI 只把 ACP 传来的数据映射成界面,print 是同层轻量渲染。peri-tui 可以在启动和配置层复用类型与初始化能力,但 Agent 执行入口仍在 ACP 会话路径。
Model:只做协议适配
peri-model 是最底层:OpenAI 与 Anthropic 双协议 adapter,统一的 ModelMessage / ModelStream 只表达协议形态,不含业务语义;流式输出经 ModelStreamEvent 统一。它不解释 Agent 会话语义;取消的最终判定在 Agent,Model 只负责执行中止。
peri-config 是内部配置权威面,向 ACP、Middleware、Controller 与 TUI 提供 typed 结果;peri-acp-types 是跨层共享契约;peri-process 是 OS 子进程能力。三者都不拥有 Session 生命周期。
关键链路
方向是调用与传递方向,不是 crate 依赖。
Receive→
Compact→
Reason→
ActReceive 是唯一退出口
Agentemit →
Runtime聚合 →
Controller过滤 →
ACP协议化 →
TUITUI→
ACP→
Controller定位 →
Runtime查映射 →
Agent终态判定 →
Model中止
RCRA
RCRA 是 Receive → Compact → Reason → Act。Receive 是消息消费与退出判断的唯一入口,也是 cancel 检查点;Reason 调用模型;Act 执行工具并原子提交 AI 消息与工具结果。Compact 属于 Agent 阶段,token 计数经 Model。上层不直接驱动这个循环。
事件链
Agent 发射业务事件,Runtime 按 Session 维度聚合与路由并补 session_id,Controller 过滤,ACP 做穷尽协议映射与 caps 门控,TUI 只消费协议化路径。同一业务事件不能沿两条链到达 TUI;否则会出现重复、乱序或身份字段不同。
事件携带 turn_id + agent_id;session_id 由 Runtime 补打,同 Session 事件带单调 session_seq。跨层消息统一携带 (session_id, session_epoch, turn_id, attempt_id),epoch/attempt_id 不可复用,防止迟到消息命中新 Session。终止事件必须使客户端离开 loading 状态;主 turn 返回终态前要等待 root EventBus forwarder 完成,保证最终 LlmCallEnd / UsageUpdate 先于 AgentDone / TurnDone。
取消
下图与本节描述的是目标链路:TUI → ACP → Controller(定位)→ Runtime(查映射)→ Agent(终态判定)→ Model(中止)。目标接线尚未全部落地;当前取消仍由 ACP 的 SessionManager::cancel_session 与 SessionState.cancel_token 过渡承载。
目标契约中,Controller 只定位与转发,Runtime 查映射,Agent 做最终判定并中止 Model 执行。取消按 (session_id, turn_id, attempt_id) 幂等,turn 终态唯一(Completed 或 Interrupted);优先级为 cancel > 续跑 > promote > retry。
cancel 不等于清空待办:MQ 未消费消息保留,随下次循环作为新 attempt 输入;请求可带 clear_queue,默认 false。
生命周期与持久真相
Session 销毁按固定顺序收束:停收新输入 → 取消 owned tasks → join(带 deadline)→ 超时 abort → 持久化事务收束 → drain 事件 → 移除映射。
异步完成的路径是:当前任务完成 → 明确收件会话的内存 MQ → 当前运行资格与取消检查 → RCRA 处理并写入 canonical history。结果到达不是复活已取消 turn 的授权;当前运行、暂停和关闭状态都要参与判断。
持久真相只有 Thread/transcript、配置与 frozen/inherited。持久 Work、任务恢复绑定、处理义务与 control 回执目标已撤销,不建立替代执行账本。TaskManager、运行句柄、MQ 和 callback 是当前进程能力,不因加载历史复活旧 execution。进程重启只加载历史并允许续聊,不重建旧 mailbox、不接管旧任务,也不保证外部后台结果再次送达。
外部副作用未知时如实报告,不伪造完成、取消或跨进程恢复保证。
错误模型按边界分层:跨层边界用类型化错误并逐层包 context,层内用 anyhow 穿透。只有终止类、可重试类和协议错误必须类型化;TurnError 语义保留在 Agent 层。
HITL 与 secret 的边界:宿主把 broker 经装配端口注入 Middleware,审批由 PermissionMiddleware、提问由 HumanInTheLoopMiddleware 消费同一 UserInteractionBroker 契约。权限审批只决定工具执行前是否询问,不替代操作系统、容器或凭据策略提供的隔离。
演进状态
三个阶段的目标范围不同,不能互相替代:
- 单机本地:已完成。 本地 Agent、会话与工具形成可用闭环。
- 单机服务化:未完成。 目标是由 TS SDK 负责入口、进程与跨主 Agent 管理,Peri 负责 ACP 后端、Agent 执行、Store 直连与 MCP Client。重启后保留历史会话加载与续聊,不恢复旧执行。
- 集群化 / Serverless:未完成。 目标是多实例协调与接管、工具环境独立驻留、云端部署,以及计算核心减重、实例替换和决策/推理/工具执行分开部署。
判断某项能力是否已经具备,先看代码、契约测试与 active spec;阶段标签只表达目标完成度。设计文档里的“现行设计”和“已批准目标”也必须分开读。
事实源与维护
- 总体设计:主仓库
docs/design/architecture.md,状态为现行设计。 - 跨模块不变量:
docs/standards/architecture-contracts.md。 - 代码入口:
docs/code-index/。 - 进度与验收:
spec/issues/。 - 设计索引与状态语义:主仓库
docs/design/README.md;本站设计入口。
冲突时按代码与契约测试、docs/standards/、模块指引、docs/design/、active spec、历史记录的顺序判断。本页只做面向贡献者的整理,删去实现清单;需要精确符号时查代码索引。