Skip to content
预计 1 分钟右侧目录可快速定位

代码修改如何成为可验证动作:Shell、Patch 与 Command Lifecycle ​

前置:Coding Agent 的工作环境是什么:Workspace 与 Filesystem State
核心问题:一次 shell/patch 执行怎样从“模型意图”变成有 identity、timeout、输出和退出状态的可验证动作?

pytest 可在 workspace 内执行,但 curl 外网或删除父目录可被 sandbox/policy 阻断。Agent 对函数附近生成 unified diff;若原文件已变化导致 context mismatch,返回 conflict 让其重新读取。

Shell Tool ​

Shell 是 Coding Agent 最强也最危险的 Tool 之一,因为一条命令同时拥有文件、进程、网络和环境变量能力。

一个可控的 Shell Tool 至少要明确:

text
cwd / user / env
allowed network/filesystem scope
timeout + cancellation
stdout/stderr size limit
exit code / signal
approval requirement

例如 pytest 超时后,不能只让上层停止等待而留下测试进程继续运行;Tool 必须能把 cancellation 传播到 child process,并记录最终 exit/signal。PTY 只有交互程序真正需要时再引入,否则会额外增加 session state。

Apply Patch / File Editing ​

编辑最好生成可审查 patch,apply 后读取 diff 并运行 targeted test;“工具返回成功”不是修改正确的证据。Patch 编辑应以明确 base state 为前提,最好保留 old/new diff、目标路径和 apply result。修改后必须重新读取关键片段并运行 formatter/test;并发修改时要检测 base hash/mtime 冲突,避免悄悄覆盖用户或其他 Agent 的变化。

Patch 接口应基于明确文件版本/上下文应用最小变更,并返回 diff/冲突。比“重写整个文件”更易审计和避免覆盖并发修改。

Command Lifecycle ​

命令从 created→running→exited/cancelled/timeout,有 stdout/stderr stream 和 process id。长命令需要异步观察、终止子进程树,并在 Agent disconnect 时定义是否继续。

🔍 源码对照:长命令如何在重连后继续被观察 ​

精确定位

ts
async function pollCommand(id, isCancelled, settle) {
  while (!isCancelled()) {
    const box = await ensureBoxReady()
    const snapshot = await readTerminalSnapshot(box, id)
    const footer = parseTerminalFooter(snapshot.content)

    if (footer.isComplete) {
      settle(footer.exitCode === 0 ? "success" : "error")
      return
    }
    await delay(pollInterval)
  }
}

对照理解

  • Command completion 不是“调用 spawn 返回了”或“上层不再等待”,而是 Runtime 持续读取外部 execution artifact,直到看到可验证的 terminal footer。
  • pollShellTerminalFile() 还处理 output file 丢失、读取权限被撤销、超长等待和 cancellation;这些都必须收敛成明确 outcome。
  • 这说明长命令需要稳定 execution id + 可重新定位的 output artifact。Host 重启后可以重新 watch,而不是把“进程仍在跑”误判成任务丢失。

Shadow Harness 对照

CommandExecution 至少保存 execution_id / status / output_ref / exit_code / timeout_or_cancel_reason;Resume 时先 reconciliation 外部 process/artifact,再决定状态。

Failure Modes ​

Shell 输出和进程生命周期无上限 ​

症状: command 没 timeout/output cap,stdout/stderr 无限进入 Context。

为什么危险: 内存/context 被拖垮,cancel 后进程仍可能运行。

处理: 记录 PID/exit/timeout,限制 buffer,完整日志写 artifact,取消时终止 process tree。

Patch 成功就认为代码任务完成 ​

症状: apply patch 成功后不跑 formatter/static/tests。

为什么危险: 文件写入成功不代表行为正确。

处理: patch 后执行 diff review + targeted/static/full tests,并保存结果。

如何验证 ​

Case断言
Shell 输出和进程生命周期无上限持续输出且不退出命令在 timeout 后 process tree 被清理。
Patch 成功就认为代码任务完成可应用但破坏测试的 patch 不能让 Run 进入 SUCCEEDED。

关联源码 ​

自测 ​

  1. 模型生成了一条 shell command 后,从“准备执行”到“结果可作为 Observation”中间要记录哪些 lifecycle 状态?
  2. Patch 命令返回 0,但目标文件内容与预期不符。为什么 exit code 成功不能替代 change verification?

Sources ​

AI Engineering · Agent · Harness · Backend Systems