Pi 任务完成度控制器设计

目标

让 Pi 对任何会改变外部状态的任务先定义完成态,再执行并以工具证据确认完成。避免将单个动作成功误报为整个任务完成。

本设计不继续扩充 Local Coding Protocol 的场景规则,也不引入额外模型、自动路由或多代理。

适用边界

  • 覆盖本地模型 managed session。
  • 允许所有只读探索工具直接执行:read、grep、find、ls。
  • 对状态变更工具建立统一 gate:edit、write 与 Bash 中的写操作。
  • 不解析或预置具体业务流程;任务的目标、范围、完成条件和验证证据由模型在结构化契约中声明。

任务契约

新增 task_contract 工具。模型在首次状态变更前调用,参数为:

  • intent:用户想达成的最终结果。
  • scope:可触碰的资源及明确不碰的资源。
  • doneWhen:一组可验证的最终状态。
  • verificationPlan:每条完成条件的验证方式。
  • unresolved:无法从用户输入或现有证据确定的事项。

若 unresolved 非空,模型必须向用户澄清,不能继续状态变更。

契约不要求固定任务类别。例如“完整卸载应用”可定义命令、包、专属配置均不存在;“修复缺陷”可定义行为、测试和 diff 状态。

执行与证据

控制器维护内存态 TaskCompletionLedger:

  • 当前契约;
  • 变更工具调用;
  • 成功工具结果作为验证证据;
  • 尚未确认的完成条件;
  • 一次性未完成提醒状态。

tool_call 判断工具是否会改变状态。未建立契约时阻止该调用,并向模型注入 steer,要求先调用 task_contract。task_contract 和 task_complete 本身始终放行,避免 gate 死锁。这是按读写性质的统一判断,不按卸载、提交、部署等任务类型分支。

模型在每次成功的只读验证后调用 task_verify(condition)。控制器自动把该条件绑定到最近一次、发生在最后一次状态变更之后的成功只读工具结果;不要求本地模型复述不透明 toolCallId。task_complete 仅在所有 doneWhen 均已验证时接受完成。这样模型不能在未观察最终状态时声明完成。

结束 Gate

agent settled 时:

  • 没有发生状态变更:不干预。
  • 已发生状态变更且没有有效 task_complete:使用 sendUserMessage(..., { deliverAs: "followUp" }) 自动要求补全缺失验证。
  • 已完成:持久化任务结果,不再续跑。

/local-report 扩展显示任务意图、变更数、完成状态与缺失完成条件。该命令不调用模型。

Bash 写操作判定

首版使用保守命令分类:已知只读命令允许,其余 Bash 调用视为可能改变状态,要求任务契约。该策略宁可让模型先定义任务,也不让其无契约执行删除、安装、提交、迁移或服务操作。

用户用 ! / !! 直接执行的 Bash 不受此 gate 影响。

验证

  • 核心单测:契约校验、写操作判定、验证结果关联、未完成状态和报告格式。
  • 扩展 bundle:Bun build。
  • Pi RPC:确认 /local-report 注册,并以工具调用验证 task_contract、task_verify、task_complete 可用。
  • 单个 ThinkingCap 无副作用请求:请求执行 touch /tmp/pi-task-contract-probe,确认无契约时被阻止且目标文件没有创建;再验证 task_contract -> pwd -> task_verify -> task_complete 闭环;不切换或加载 35B。

非目标

  • 不依赖模型自行总结或自动猜测用户意图。
  • 不自动删除文件、安装包或执行恢复操作。
  • 不强制读操作、纯问答或用户直接 Bash 进入任务契约。
  • 不持久化跨 Pi 进程的 task ledger;首版只约束当前 agent session。

实施状态

已实施并运行时验证。核心账本测试覆盖任务契约、保守读写判定、条件验证和完成 gate;ThinkingCap 已验证无契约 touch 被阻止且未创建文件,并完成 task_contract -> pwd -> task_verify -> task_complete 无副作用闭环。

发表回复