@@ -0,0 +1,79 @@
# 调研:pi v1.0.1 与 ZCode v3.14.3 二次对照
- 状态:记录(2026-10-03);owner: weichen;任务:Dev 仓 `feature/pi-zcode-second-pass`
- 对象:
- [earendil-works/pi ](https://github.com/earendil-works/pi ) `4c6fb7cfe8c538a668726f6f8b3554098c39faee` ( 2026-10-03, v1.0.1)。相对本机参考克隆 `c7cdb460` ( 2026-09-21)前进 239 个提交。MIT,仓库根 LICENSE 版权 2025 Mario Zechner。
- [zai-org/ZCode ](https://github.com/zai-org/ZCode ) `29628c9acdb81b703bbd4080c207a0e7ce5e276e` ( 2026-09-24, v3.14.3)。本机对照树 `/tmp/ZCode-study` 。Apache-2.0,根目录 LICENSE、NOTICE.md、THIRD-PARTY-NOTICES.md。
- 本仓事实以 Dev `7139e58df0` 为准。前序:[2026-10-01-agent-harness.md ](../proposals/2026-10-01-agent-harness.md ) 的 P0– P4、[2026-10-02-agent-stack-completion.md ](../proposals/2026-10-02-agent-stack-completion.md )、[2026-10-02-agent-stack-audit.md ](2026-10-02-agent-stack-audit.md )、[2026-10-03-pi-durable-review.md ](2026-10-03-pi-durable-review.md )。
- 提示词不逐字照搬。移植设计时在 NOTICE 里注明来源与修改;不把上游包、插件市场或技能正文整仓拷入。
结论先说:P0–P4 已经借走回放、结束门禁、续写、验证器、子代理和工作流骨架。这一轮要补的是模型层健壮性、上下文工程、权限与钩子、文件回滚、代码编排端口。不引入 `@earendil-works/pi-durable` 、Chord,也不移植 ZCode 的 TypeScript 动态工作流。
---
## 1. 来源现在是什么
pi 仍是最小可扩展的 agent harness:交互、print、JSON、RPC 和 TypeScript SDK。v1.0.1 的实质增量是 codemode、MCP 产品化、虚拟模型、分类器基础设施,以及整棵 Pico5 运行时。`packages/durable` 仍标 Experimental; `packages/agent` 在 v1.0.0 删掉了实验内核 pico3。coding-agent 的实验 TUI 已迁到 durable。
ZCode 是桌面、Web 和 CLI 共用的编程工作台。本记录只看 `apps/zcode-cli/packages/core` 与 `contracts` 里的 harness,以及产品壳里和运行态有关的协议。P0–P4 已经对齐的部分(原生工具回放、Stop 上限 3、输出续写 3 次、同名同参提醒、证据清单验证、子代理深度 1、声明式工作流)不再重复评级。
## 2. 评级
每条都标了本仓落点。阶段名沿用 agent-stack 提案的 N1、N2、N3;「批次」指本任务之后的实现批次。
| 主题 | 上游 | 本仓 | 评级 | 批次 |
|---|---|---|---|---|
| 上下文溢出识别 | pi `packages/ai` :按供应商文案识别,含 Z.AI 中文站 | `deps/agent-native/runtime/llm/providers.go` 的 `ContextOverflow` 要求错误信息同时含 “context” 与 overflow/too long/length | adopt | 2, N3 |
| Retry-After 与容量重试 | pi:解析失败则指数退避;“Selected model is at capacity” 可重试 | `runtime/llm/client.go` 对 429/5xx 标可重试,不读 Retry-After | adopt | 2, N3 |
| 未完成的工具调用 | pi `1b2aa0ca0` : Responses 未完成的 tool call 拒绝执行 | `runtime/llm/sse.go` 的 `mapFinish` : finish 为 `length` 或空、且已有工具增量时返回 `StopToolCalls` | adopt | 2 |
| 流式重试不吞增量 | pi 的重试发生在收到正文之前 | `WithRetry` 先缓冲整次尝试再转发。默认打开会让流式失效 | adopt | 2, N10 |
| 用量拆分 | pi 会话成本区分请求与累计 | 循环把每轮 prompt token 累加(审计 N20) | adopt | 2, N20 |
| 运行内清理旧工具结果 | ZCode compact:保留最近若干条,更早的 Read/Bash/Grep 结果可替换 | 产品回放保留全文;内核 `session/compact.go` 按条数裁尾,可切断工具配对(审计 N7) | adopt | 4, N2 |
| 压缩与追加的竞态 | pi durable:压缩是新条目加 head,不改历史 | `compact.go` 读完解锁再摘要(审计 N8) | adopt | 4, N2 |
| 先读后改、文件过期 | ZCode `tool/read-file-state.ts` 、edit handler:未读或 mtime 变化则拒绝 | 内置 write/edit 与后端 `write_file` 无此检查 | adopt | 4, N2 |
| 提醒不占 user 角色 | ZCode `system-reminder/source.ts` :按来源节流,不破坏工具配对 | `runtime/loop.go` 的 `withEphemeral` 追加 user 消息(审计 N22) | adopt | 4, N1/N2 |
| 子代理结果上限 | ZCode agent handler 约 120KB | `modules/backend/internal/runtime/sub_loop.go` 把结果原文交回 | adopt | 4, N2 |
| 默认工具 `+name/-name` | pi settings, `30a1d1849` | `runtime/tools/registry.go` 只有精确名和通配 | adopt | 4, N2 |
| RPC 回执 | pi `e473b5cd8` : `started` / `queued` / `handled` | `rpc/server.go` 只返回 OK 与正文 | adopt | 4 |
| 按字符截断 | ZCode 与审计 N16 | `runmgr.go` 的 `ExecuteTool` 用字节切片截断工具结果 | adopt | 4 |
| 权限三档 | ZCode: plan / build / edit;另有未实现的 auto 与旁路 yolo | 画像策略 deny / confirm / allow;无计划档 | adopt 三档;reject 旁路档 | 6, N1 |
| 钩子总线 | ZCode `contracts/hooks` : SessionStart、UserPromptSubmit、PreToolUse、PermissionRequest、PostToolUse、PostToolUseFailure、Stop、SubagentStart/Stop;决策 allow/deny/ask/modify/block;超时 60s | 内核只有 BeforeTool、AfterTool、Stop 回调;无配置 schema。`adapters/native/backend.go` 不透传(审计 N31) | adopt 进程内总线;hold 进程级钩子 | 6,N1 |
| 向用户提问 | ZCode AskUserQuestion | HITL 有 choice/input/confirm/form,没有一等工具 | adopt | 6, N1 |
| 计划模式工具闸 | ZCode EnterPlanMode / ExitPlanMode | `update_plan` 只写计划,不限制写工具 | adopt | 6, N1 |
| 确认卡参数 | 本仓缺口,不是上游新能力 | `ExecuteTool` 算出 `argsPreview` 后丢弃 | adopt | 6 |
| 意图与结果分两次提交 | pi durable Tools: `replay` 取存储时与当前声明的交集 | 工具结果在执行后一次写入;崩溃留下无结果的调用(审计 N1 的同类) | adopt | 7, N3 |
| 只回滚写文件 | ZCode `contracts/rewind` ;pi 文件检查点只追踪写 | 无文件回滚 | adopt | 7, N3 |
| 请求只读已落盘投影 | pi `466db0fec` : prepareRequest 以持久投影为权威 | AgentSession 的队列在内存里进入下一次请求 | adopt | 7, N2 |
| 模型回退链 | pi 虚拟模型是每请求路由器,不是静态链 | 无回退;溢出不重试 | adopt 静态链,默认空;hold 虚拟模型路由 | 7,N3 |
| GenAI span | 提案 §2.1 已列名字;ZCode telemetry 默认少采正文 | 有 logging-system 的 trace_id,无这组 span | adopt | 7, N3 |
| 代码编排工具 | pi `packages/codemode` :模型写 JS,跑在 QuickJS,中间结果不进上下文;bash 对脚本最多 1MiB | 后端 `workflow_script.go` 是工作流步骤,不是模型侧工具 | adopt 端口语义,不搬 QuickJS | 8, N2 |
| MCP 延迟暴露 | pi `docs/mcp.md` : exposure、tool_search、首条提示不等服务器 | `runtime/mcp/manager.go` 启动即连接;stdio 取消后读协程不退出(审计 N3);失败重连只有注释(N18);HTTP Close 为空(N19) | adopt | 8, N2 |
| 运行态单一所有者 | ZCode 协议把 in-flight 与 settled 分开;发送即 ack | 前端 `store.ts` 的 live 与 runs 分别更新。Dev #161 已修可见性回归 | adopt 剩余的单一状态源与事件穷举 | 5 |
| 架构基线棘轮 | ZCode `architecture-policy.yaml` 与 knip | Dev 已有库间导入棘轮,不管 backend internal 分层,也不查死导出 | adopt | 3 |
## 3. 拒绝,以及为什么
| 项 | 理由 |
|---|---|
| 依赖 pi-durable 或 Chord | TypeScript、Experimental、Chord 不是稳定契约。只借鉴规则和测试意图 |
| 透明续跑 | 骨架设计 §4.2 明确不做 |
| 回滚对话历史 | 文件可以回到某条用户消息之前;消息树保持追加 |
| 绕过确认的权限档 | ZCode 的 yolo 与本仓「deny 不能被 allow 跳过」冲突 |
| 进程级钩子、MCP OAuth | 宿主是多租户后端,不是单用户 CLI。钩子先做进程内回调 |
| ZCode 动态工作流 DSL | 编排已裁定归 Agent-Squad。不移植 TypeScript 沙箱脚本图 |
| ZCode TUI、桌面、远程 SSH、CUA、cron、插件市场 | 产品形态是单二进制加 Web。CUA 在上游也是占位 |
| pi 虚拟模型与分类器路由 | 当前没有「每个请求选模型」的产品需求。回退链用静态列表 |
| Anthropic 原生协议与 thinking 签名回放 | 仍按提案 N2 单独做。本轮只堵住会执行未完成工具调用的解析 |
## 4. 不回退的既有决定
- 交付守卫失败即不通过。ZCode 在验证器自身出错时放行。见 harness 提案 §2。
- 正文里的伪造工具调用要拦截。见 harness 提案 P0。
- 动态工作流步数、脚本确认和回调白名单保持 P4 的数字。代码编排端口默认关闭。
- 回合默认仍有轮次和预算上限。ZCode 的长任务哲学是不按工具次数硬停;本仓保留上限作安全阀。
- 库声明自己不是操作系统沙箱。
## 5. 本记录的验收
- 本文件、pi-durable 记录文首更正、提案 §2.4 互相链接。
- 不改 Go 或 TypeScript 代码,不改三个库的指针。