Repository navigation
feat(chat): 为 Pi 启用原生引导 —— pi-acp 已可满足 promptRequired 安全门控(附端到端实测) #872
Description
摘要
Pi 目前被 registry.rs 的 steering_prompt_required_min_version() 排除在原生引导之外(_ => None),同时 pull 通道对它也不可用,导致 Pi 用户在 codeg 里完全没有中途干预手段。
但现状已经变了:pi-acp 社区已有一个实现完整安全契约的 PR(svkozak/pi-acp#115),我按同一契约独立实现并做了端到端验证——三个 outcome 全部按 codeg 要求的行为,且不产生 #934 那类"游离回合"。
因此建议:待 pi-acp 上游合并后,把 Pi 加入门控;或先落地与 #796 相同的通用能力门控机制。
一、现状(codeg v0.32.4,与上游 main 一致)
Pi 会话的 session/new 快照(实测):
{
"connection_id": "ff933fd2-680a-42e1-b536-d63d7947b056",
"status": "connected",
"feedback_tool_available": false,
"native_steering_available": false
}两条通道都是 false,UI 上运行回合时输入区只剩「取消」按钮,没有任何插话入口。
即使适配器主动宣称能力,codeg 仍然拒绝启用——补丁后日志:
[ACP][Pi] steering: advertised=true, agent_version=Some("0.0.34"), native=false
↑ 适配器已宣称 ↑ 被策略表拦下
策略表(registry.rs,含 steering_prompt_required_min_version_gates_claude_only 测试锁定):
match agent_type {
AgentType::ClaudeCode => Some("0.65.0"),
_ => None, // ← Pi / Codex / 其它
}二、pull 通道对 Pi 同样不可用
codeg 的降级方案是注入 codeg-mcp 反馈工具(check_user_feedback),但 pi-acp 接收后直接丢弃 mcpServers:
constructor(opts) {
this.mcpServers = opts.mcpServers; // 第 855 行赋值
// ...整个 3102 行文件里再无任何引用
}所以 feedback_tool_available: false。这不是 codeg 的问题(上游 PR svkozak/pi-acp#145 正在修),但结果是:Pi 用户既没有 native 也没有 pull,只能等回合跑完。
三、Pi 已经能满足 codeg 的安全契约
registry.rs 的注释列了两个条件,pi-acp 侧都能满足:
条件 1:尊重 _meta.steering.idleBehavior = "promptRequired" opt-in
svkozak/pi-acp#115(davidhs26, 2026-08-20, open)实现的正是这个契约:
initialize()上报_meta.steering.supported = true_session/steering三种 outcome:injected/promptRequired/startedNewTurn- 空闲 + opt-in →
promptRequired,不消费内容
条件 2(注释里的 ACTIVE 顾虑):steered work 期间保持 owning session/prompt in flight
这一点 _session/steering 形态天然满足,而且比 #91 的方案更稳妥:
| 方案 | 机制 | 与 codeg 回合生命周期的关系 |
|---|---|---|
| #91 | 把并发 session/prompt 路由到 steer |
需要对齐 concurrent prompt 的 resolve 时机——正是 #934 出问题的地方 |
#115 / _session/steering |
独立扩展请求,立即返回 {outcome:"injected"} |
完全不参与 prompt 生命周期;原 session/prompt 照常等到 agent_settled,不会被 steer 提前 settle |
也就是说:steer 请求立即返回、不产生新回合、不影响原 prompt 的终端事件——不存在"宿主请求不拥有的游离回合"。这正是 codeg 想避免的场景。
四、本地端到端验证
我按上述契约做了一份等价实现(pi-acp 0.0.34 + 该补丁),用原生 ACP stdio 驱动,结果:
空闲态(带 opt-in)
→ _session/steering { sessionId, prompt:[...], _meta:{steering:{idleBehavior:"promptRequired"}} }
← { "outcome": "promptRequired", "reason": "noRunningTurn" }
→ 不偷开新回合 ✅
运行中(prompt 强制跑 sleep 30 的 bash 调用,在它执行期间插入)
← { "outcome": "injected", "disposition": "queued" }
并且 agent 在同一回合内确实收到了注入内容——它在后续回复里输出了我要求的标记词。这是硬证据:消息进了模型上下文,不只是协议层回了句话。
未破坏原有行为
→ _session/nonexistent
← -32601 "Method not found"
methodNotFound 语义保留 ✅
验证方法可复现:起一个 pi-acp 子进程 → ACP initialize(检查 _meta.steering.supported)→ session/new → 发一个带 sleep 的 prompt → 中途发 _session/steering → 断言返回 injected 且 agent 回复含注入内容。无需 LLM 也可验证前两项(idle + methodNotFound)。
五、请求
- 待
svkozak/pi-acp#115上游合并后,把 Pi 加入steering_prompt_required_min_version(版本取首个带该契约的发布版)。 - 或者,如果 【胡淇华】feat(chat): enable native Codex steering when ACP advertises a safe idle contract #796 的通用能力门控机制先落地("live adapter 宣称 + 版本证明"而非静态白名单),Pi 应能随之自动生效——建议门控判定里显式包含 Pi 的适配器版本证明路径。
- 在适配器尚未就绪期间,是否可以在 UI 上把 Pi 的中途发送语义说明得明确一些?现在用户看到的是"发了没反应",容易误判为 bug(对比 ACP "redirect" fabricates empty ~1ms turn_completes when the agent advertises steering=false, wedging the conversation (cancelled/pending_review) and swallowing the send #590 那类"看起来卡死"的体验)。
六、补充说明
- 本机环境:codeg v0.32.4(= 上游最新稳定版)、pi-acp 0.0.34、pi 0.99.2、Windows Server。
- 我的 pi-acp 补丁是本地临时验证用的,已经回滚,不是要提交给上游的补丁(
#115已覆盖同等功能,避免制造#150说的重复 PR)。 - 上游
svkozak/pi-acp目前有 feat(chat): arrow-key send history in MessageInput #7 / 修复一下,执行的时候突然中断。 #91 / 太赞了,好丝滑的编辑器 #115 三个 steering 相关 PR,[Bug] 生产环境中 npx ACP 智能体实际已安装,但对话页提示未安装 #150 把它们归为重复簇并建议保留 修复一下,执行的时候突然中断。 #91。但从 codeg 的角度,只有 太赞了,好丝滑的编辑器 #115(扩展方法形态)才会让适配器上报_meta.steering.supported——修复一下,执行的时候突然中断。 #91 只改内部路由,codeg 看不到能力信号。如果最终合并的是 修复一下,执行的时候突然中断。 #91,Pi 在 codeg 里仍然会是native=false。这点建议在 pi-acp 那边也同步一下。
Activity