保存 Runner、prompt、schema 与只读 fixture 模板。fixture 实验不会在这里创建 .git,也不会修改这里的源码。
算法可视化与交互学习平台
Coding Agent Engineering:让 Agent 在真实仓库中工作Coding Agents: Repository Understanding, Editing and Verification
No.17 建立 Action → Observation 控制循环,No.18 让 Agent 能规划与 Replan,No.19 让任务可以 checkpoint / resume;No.20 把这些能力放进真实 Git repository。用户下载完整示例包和本地 Qwen2.5-Coder-1.5B-Instruct,浏览器直连 127.0.0.1:4891 的 Mini Coding Agent Runner:模型提出搜索、计划、诊断与交付候选,确定性 Runtime 负责路径授权、真实文件修改、Git、build、lint、test 和 receipts。六个递进实验共用一次模型加载,在隔离 Todo CLI 仓库中真实经历定位、首轮失败、重规划、修复、验证与 diff 审查,也可在明确批准后切换到自选仓库;全程不使用预填成功 trace。
Module runtime · real local repository
No.20 统一 Coding Agent 运行环境
六张实验卡共享同一 Runner、代码模型、workspace 配置与人工批准状态。fixture 的每个 run 都会复制出独立 Git 工作副本,卡片之间不继承文件或 receipts; 不会修改解压后的 Runner 示例包;custom 只在你明确填写绝对路径后启用,其中 Patch / Mission 写入要求 clean Git baseline。默认不批准写文件或运行命令。
fixture 的真实仓库在 %TEMP%\algolab-coding-agent-runs\<run-id>\workspace,隐藏 Git 目录在 workspace\.git,Diff 与 Git 状态分别在同一 run 的 artifacts\git.diff 和 artifacts\git-status.txt。
custom 使用你填写的目录,但选择模式或点击运行都不会自动 git init;写入任务要求它事先是 clean Git repository。
首次准备:下载完整包,再由用户明确下载本地模型
ZIP 不含模型权重。解压后任选下面一组命令;下载器默认保存 Qwen2.5-Coder-1.5B-Instruct,写入权重来源与逐文件 SHA-256,Runner 启动后保持离线加载。
py -3.12 -m venv .venv
& .\.venv\Scripts\python.exe -m pip install -r .\requirements.txt
& .\.venv\Scripts\python.exe .\download_model.py
.\run.ps1 -PythonPath .\.venv\Scripts\python.exepython3 -m venv .venv
./.venv/bin/python -m pip install -r ./requirements.txt
./.venv/bin/python ./download_model.py
chmod +x run.sh && ./run.sh ./.venv/bin/python内存不足时,可在下载命令后加 --model Qwen/Qwen2.5-Coder-0.5B-Instruct。模型加载一次后,六张实验卡共享同一进程。
Workspace scope
页面不会扫描磁盘或自动选择仓库;实际 canonical path、Git root 与 writable scope 由本地 Runner 再次校验。
fixture:工作副本位于 %TEMP%\algolab-coding-agent-runs\<run-id>\workspace,解压目录只提供 Runner 与不可变模板。
custom:选择模式或点击实验按钮都不会自动执行 git init。Patch / Mission 写入要求目录已经初始化 Git、有 baseline commit 且工作树干净。
本次运行的人工批准
运行后到哪里找工作仓库、Diff 与 Git 状态?
ZIP 解压目录、fixture 工作仓库和 run artifacts 是三个不同位置。每张实验卡都会创建新的 run;完成后请在该卡片的“本次 run 的本地文件位置”中复制精确绝对路径。
git.diff 和 git-status.txt 是审查快照;真正的代码变化位于同一 run 的 workspace。Windows 资源管理器需开启“隐藏的项目”才能看到 .git。
custom 不会复制仓库,也不会自动初始化、commit、reset 或清理改动。Patch / Mission 遇到非 Git 仓库会以 not_git_repository 停止,baseline 不干净则以 dirty_baseline 停止;artifacts 仍保存在独立 run 临时目录,不写进 custom 仓库。
只创建或填写一个空文件夹不等于配置了代码仓库。它默认也不是 ZIP 解压目录;请另选包含真实源码/测试的任务仓库,不要把 Runner 自己的 coding_agent_local 目录当作修改目标。
A. 使用自己的真实项目
不需要复制示例文件。直接把上方 custom 路径指向项目的 Git 根目录。已有 Git 仓库不要重新初始化;先按项目自己的流程提交或妥善处理现有改动,再确认 git status --short 没有输出。不要在不理解内容时直接执行 git add -A。
- 目录中应有真实源码、测试和项目自己的依赖/构建配置。
- Patch / Mission 写入前必须有
.git、至少一个 HEAD commit 和 clean baseline。 - 需要修改时开启“允许受限写入”;需要 test / lint / build 时再开启“允许白名单命令”。
B. 使用 No.20 教学项目
从 ZIP 解压目录中只复制 fixture/ 里面的内容到一个新的空 TEMP_REPO。其中 todo/exporter.py 保留 NotImplementedError,tests/test_csv_export.py 保留测试入口;这是预期的任务 baseline,等待 Agent 补全实现和验收测试。
TEMP_REPO/
├─ README.md
├─ todo/
│ ├─ __init__.py
│ ├─ cli.py
│ ├─ storage.py
│ └─ exporter.py
└─ tests/
├─ __init__.py
└─ test_csv_export.py不要复制:runner/、prompts/、schemas/、models/、run.ps1、requirements.txt 或 algolab_local_runner.py;这些属于执行器,不是目标仓库代码。
Windows:复制教学 fixture 并初始化 Git baseline
下面命令应在 ZIP 解压后的 coding_agent_local 目录执行,并会在复制前拒绝非空目标。若 Git 提示缺少提交身份,请先按 Git 提示配置您自己的 user.name 与 user.email,再重新执行 commit。
# 请先在 PowerShell 进入 ZIP 解压后的 coding_agent_local 目录
$customRepo = Join-Path $env:USERPROFILE "AlgoLab\TEMP_REPO"
# 只允许复制到不存在或完全为空的目录,避免覆盖用户文件
if (Test-Path -LiteralPath $customRepo) {
if (Get-ChildItem -LiteralPath $customRepo -Force) {
throw "TEMP_REPO 必须为空;请换一个新目录,避免覆盖已有文件。"
}
} else {
New-Item -ItemType Directory -Path $customRepo | Out-Null
}
Copy-Item -Path ".\fixture\*" -Destination $customRepo -Recurse
# 建立可审查的 Git baseline
git -C $customRepo init
git -C $customRepo status --short
git -C $customRepo add README.md todo tests
git -C $customRepo diff --cached --stat
git -C $customRepo commit -m "baseline: G-TODO-CSV fixture"
# 两项验收:HEAD 必须存在;最后一条命令必须没有输出
git -C $customRepo rev-parse --verify HEAD
git -C $customRepo status --shortrev-parse --verify HEAD 返回 commit;最后一次 git status --short 完全没有输出。Windows 资源管理器可能隐藏 .git,请以这两条 Git 命令为准。git init、commit、reset、stash 或清理工作树。完整示例包:Runner、Mini Coding Agent、fixture 仓库与测试
下载后在本机运行,网页只连接 127.0.0.1:4891
ZIP 包包含可审计源码、隔离 fixture、真实 Git/patch/build/lint/test 流程和启动脚本。Runner 不会自动下载模型,也不会把仓库上传到 AlgoLab 服务端。
一套让本地模型在真实 Git 仓库里工作的完整工程,而不是一段自动改代码的演示
根目录负责准备模型与启动 4891,runner/ 把 HTTP Job、LLM Decision 和可信执行层连接起来,agent.py 提供受限文件、Patch、命令与 Checkpoint 原语,fixture/ 提供可复制的真实 Git 任务,tests/ 则在不下载模型时验证同一条安全与修复闭环。
模型只提议
本地 Qwen 只返回受 schema 约束的 plan、搜索目标、候选 Patch、diagnosis 和 review;它拿不到文件句柄,也不能提交 shell 文本。
Runtime 控制副作用
CodingAgentRuntime 校验 Decision、检查写入与命令批准,再调用 WorkspaceAdapter 和 CommandRunner;路径、命令、时间、输出与 artifact 都有确定性边界。
仓库证据决定下一步
文件清单、搜索命中、读取片段、精确 Patch receipt、真实进程退出码、git status 与 git diff 才是可审计事实;模型的文字不能替代执行结果。
验证形成因果闭环
mission 必须先让真实 unittest 因三类 CSV escaping 缺陷失败,再把 receipt 交给模型诊断与重规划;修复后重跑同一测试,并通过 tabnanny、内存 compile 和最终 Git diff 审查。
文档结构:六个文件角色共同组成可运行、可验证的 Coding Agent
每个标签都对应 ZIP 与 manifest 中的真实文件;点击后会在下方同步打开完整内容和逐文件解释。
根目录 · 准备、发布与启动
从包级说明、依赖与模型溯源,到 Windows/POSIX 启动脚本及两个等价的 Python 服务入口。
公开 API 与仓库工程原语
顶层 API、受限文件/Patch/Checkpoint/命令原语、确定性 Mini Agent CLI,以及把 fixture 复制为临时 Git 仓库的工厂。
runner/ · 六阶段控制器
实现严格 Decision、真实/测试模型策略、六模式编排、异步 Job 与 4891 HTTP 协议,把模型提议接到可信仓库原语。
prompts/ + schemas/ · 模型与请求契约
三份提示词约束常规 Decision、mission 因果链与一次格式修复;两份 JSON Schema 公开模型输出和页面请求的机器可读边界。
fixture/ · 可复制的真实 Git 教学仓库
一个尚未完成 CSV export 的最小 Python 项目:已有存储与 list CLI,缺失 exporter 实现和验收测试,供 Agent 真实修改并产生可重复的失败。
tests/ · 不下载模型也能运行的工程回归
分别验证底层 workspace/patch/command 原语,以及六模式 Runtime、FakeModelPolicy、Job、API helper、批准与 artifact 边界。
文件调用关系:模型候选如何变成仓库证据
箭头表示一次 run 中的控制或数据推进;不同泳道刻意区分模型建议、确定性执行、仓库事实和最终验收。横向内容可滚动查看。
模型由用户显式下载;指定的 Python 启动 loopback 服务,浏览器以 HTTP 创建异步 run,并按 trace seq 增量读取状态或协作式取消。
准备可复查环境
安装固定推理依赖,下载允许的 Qwen,并记录 revision、逐文件大小与 SHA-256。
使用明确的 Python
Windows 或 POSIX 脚本不猜虚拟环境,只转交用户给出的解释器和 4891 参数。
Loopback HTTP
检查本地模型文件,创建/查询/取消 run,并只开放五类固定 artifact。
异步 Job 生命周期
维护 queued/running/terminal、增量 trace、取消事件、路径脱敏和进程内模型复用。
边界:HTTP 服务默认只监听 127.0.0.1:4891;模型路径和 custom workspace 路径只以名称或 SHA-256 出现在公共快照中。
Runtime 只提供当前 stage 所需的公开仓库证据、批准状态与 schema;模型返回候选计划、定位、Patch、诊断或审查意见,随后再次接受严格校验。
Stage-specific context
scope、inspect、patch、verify、review、mission 各自获得有界上下文和候选约束。
本地模型适配
LLM只从本地目录加载 Qwen,按 path/device/dtype 缓存,串行生成并响应 deadline/cancel。
严格 Decision
必须是唯一 JSON 对象,字段、candidate、Patch 数量、诊断和 review 均受固定协议限制。
一次有界修复
若第一次输出非法,Runtime 用验证错误和同一 schema 请求一次替换 JSON;再次失败即停止。
边界:模型永远不接收 WorkspaceAdapter、subprocess 或任意 shell 能力;即使 JSON 合法,批准门和 Runtime 的阶段规则仍可拒绝它。
所有仓库动作都通过 canonical workspace adapter;写入前建立 Checkpoint,全部 old-text 唯一命中后才进行原子事务,最终由 Git 展示真实变化。
创建隔离 fixture 或锁定 custom root
fixture 被复制并初始化为临时 Git 仓库;custom 写入要求用户指定路径且 baseline clean。
搜索与读取
只遍历 workspace 内普通 UTF-8 文件,拒绝绝对路径、父级穿越、symlink 逃逸和超限读取。
Checkpoint + 多文件事务
记录写前快照,校验每个精确 preimage,原子写入四个文件;中途失败会反向回滚。
git status + git diff
Runtime 使用固定 command ID 获取工作树状态与未暂存 diff,并保存为最终 artifacts。
边界:custom 仓库不会继承 fixture 的预审代码:模型必须先读真实文件并给出 exact old→new;Runtime 仍拒绝脏基线、重复目标和范围外路径。
mission 的第一版手写 CSV 拼接必须产生非零测试 receipt;模型只能依据该输出诊断,Runtime 应用 csv.writer 修复后重跑,并补齐 lint、build 和 Git 审查。
Plan-v1 修改四个文件
CLI、exporter、五项验收测试与 README 作为一个事务落盘,exporter 暂用有缺陷的手写拼接。
真实 unittest 失败
EXIT 1逗号、双引号和嵌入换行三个测试真实失败;exit code 与受限输出成为诊断 receipt。
Diagnosis + Plan-v2
本地模型引用失败证据并提议 csv.writer 候选;Runtime 只替换已诊断的 exporter 缺陷。
同测通过 + 扩展验收
1 → 0 → 0 → 0同一 unittest 变为五项通过,随后 tabnanny 与不写产物的内存 compile 都必须为零退出。
Git 与模型双重 review
Runtime 先取得 status/diff;模型只能基于测试 receipts 和 diff 给出 approve/revise/blocked。
边界:verify 模式会故意保留失败仓库用于教学诊断;只有 mission 才要求修复、复测、lint/build 和最终 approve 全部完成。
测试双替身只替代文本生成,不绕过 CodingAgentRuntime、WorkspaceAdapter、CommandRunner、真实 Git 或真实 unittest,因此无需模型权重也能稳定验证工程边界。
确定性候选 Decision
FakeModelPolicy 按 stage 返回与真实 Qwen 相同 schema,可选择非法首包以测试一次 repair。
底层原语回归
验证路径逃逸、精确 diff、事务回滚、Checkpoint 批准、命令 allowlist、超时与输出上限。
六模式与闭环回归
真实临时 Git fixture 跑 scope 到 mission,并断言 first test 三项失败、second test 五项通过和最终 diff。
Job/API/artifact 回归
验证增量 seq、异步 Job、请求体上限、模型预检不加载权重、路径脱敏和 artifact allowlist。
边界:FakeModelPolicy 证明控制面与真实仓库动作;它不证明某台机器上的 Qwen 权重、显存或生成质量,真实模型仍需用户显式下载后单独运行。
No.17–19 让 Agent 会行动、规划和恢复,No.20 让它对真实仓库负责
No.17 的 Runtime 能把模型候选动作变成可验证的 Action 与 Observation;No.18 用 Goal、Plan、Ledger 和 Replan 对完整任务负责;No.19 又让这些状态可以压缩、checkpoint 与 resume。但如果工具只会查知识、算数字或操作一份虚构状态,系统还没有跨进 Coding Agent 最关键的边界:读取用户已有代码,在有限范围内产生真实文件和命令副作用,并用仓库自己的验证系统证明修改成立。
本章不是浏览器动画。先下载页面提供的完整 ZIP,用 download_model.py 把 Qwen/Qwen2.5-Coder-1.5B-Instruct 保存到本机,再启动 127.0.0.1:4891。六张实验卡共用同一个模型进程;浏览器只发送目标和审批,所有源码、模型、Git 与终端输出都留在用户电脑。模型负责提出可审查的计划、诊断和总结,Runtime 才拥有路径检查、Patch、命令与验收的执行权。
贯穿任务是下载包中的 G-TODO-CSV:一个真实 Python Todo CLI 已能读取并列出待办,现在要新增 python -m todo.cli export-csv --db todos.json --output todos.csv。修改准确落到 todo/cli.py、todo/exporter.py、tests/test_csv_export.py 与 README.md;第一版故意用朴素字符串拼接,普通行和空列表测试通过,而逗号、双引号和内嵌换行三个独立断言真实失败。Agent 必须把真实 unittest 输出交给本地模型诊断,再由 Runtime 验证最小修复。
Repository Task Contract 同时约束目标、验收、范围与副作用
一个可执行仓库任务不是一句需求,而是 Goal、Acceptance Criteria、Workspace、Constraints、允许的 Side Effects 与 Permission Policy 的联合契约。
G-TODO-CSV 的验收
AC1:CLI 接受 export-csv、--db 与 --output;AC2:普通与空列表输出稳定表头;AC3:逗号、双引号和换行按 CSV 规则转义;AC4:unittest、tabnanny lint 与内存 compile build 全部通过,README 与行为一致。
范围不是建议
Workspace 和允许副作用在模型提出动作之前由 Runtime 固定。模型可以建议增加文件,但不能自行扩大 root、开启网络或批准 destructive command。
完成条件来自外部证据
Final Answer 只能总结已经存在的 receipts;一句“测试应该能过”不能替代 exit_code=0,也不能把未运行写成已通过。
实验一:先固定 Workspace、Git baseline 与允许路径,再让 Agent 看代码
点击运行后,浏览器把目标发送给本机 4891 Runner。本地 Qwen2.5-Coder-1.5B-Instruct 先生成公开的 scope / inspect 建议,确定性 Runtime 再创建真实的临时 Todo CLI Git 仓库,解析 repository root 与 canonical paths,执行 git status,计算文件 hash、baseline tree、tracked / untracked 与 protected paths,并把模型建议与 policy receipt 并列展示。此阶段保持 read-only:allow_write 与 allow_commands 均不需要开启。路径越界、symlink 逃逸或 dirty baseline 的结论必须来自本机文件系统和 Git,模型不能自行授权,页面也没有预填成功结果。
每次点击都会创建真实异步 run;没有连接或模型时保持 not_run,不执行浏览器 fallback。
请先在模块顶部下载示例包和模型,启动 4891,依次完成“检查 Runner”和“检查本地模型”。
phase = not_run
events = 0 · receipts = 0
stop_reason = —
workspace = fixture · %TEMP%\algolab-coding-agent-runs\<run-id>\workspace
model = ./models/Qwen2.5-Coder-1.5B-Instruct
approvals = write:false / commands:false
fixture 每次复制到独立临时 Git 工作区;六张卡共享配置,但不共享仓库或上一张卡的 receipts。下载的 Runner 包与原始 fixture 不会被修改。
模型候选与 Runtime 证据分开记录
Workspace root、Git root 与可写范围是三条不同边界
Workspace 是用户交给 Agent 的可见环境;repository root 是 Git 元数据定义的版本边界;writable scope 是本次任务允许修改的最小子集。三者常常重合,但不能依靠“通常如此”授权。Monorepo 可能只有一个 Git root,却只允许修改一个 package;submodule 有独立历史;symlink 的文本路径在 root 内,真实目标却可能越界。
| 对象 | 本章真实实例 | Runtime 判断 |
|---|---|---|
| Workspace root | 每个 run 的临时 workspace/;custom 时为用户填写的绝对目录 | 先 resolve 为 canonical base,不能用 .. 或 symlink 逃逸 |
| Git baseline | Runner 复制 fixture 后真实执行 git init/add/commit | 用真实 git status --short 区分 clean baseline 与已有修改 |
| Writable paths | todo/**、tests/**、README.md | .git/**、模型目录、run artifacts 与越界路径默认拒绝 |
| Command cwd | canonical repository root | 每个稳定 command ID 单独绑定 cwd,模型不能用隐式 cd |
Inspect 阶段先记录 dirty baseline。custom workspace 一旦有未提交改动,写模式直接以 dirty_baseline 安全停止,不猜测哪些内容属于用户,也不覆盖或 reset;scope / inspect 仍保留只读能力。
路径授权发生在 canonicalize 之后,而不是字符串前缀比较之后
只有真实路径位于动作对应的授权 roots 内、动作在 allowlist 中且目标不受保护时,Runtime 才能分派。
先解析再比较
必须处理 ..、大小写规则、junction / symlink 与路径分隔符;字符串 startsWith 不能证明真实目标仍在 root 内。
读写策略分离
依赖源码或 lockfile 可以被读取以理解项目,但若不在 writable set 中,patch 仍应得到 scope_denied receipt。
拒绝也进入 trace
拒绝事件至少记录 normalized path、action、policy version 与 reason;敏感绝对路径在导出前脱敏。
项目结构要从入口、依赖与验证配置共同推断,不能只看目录名
文件树只能回答“有什么”,不能回答“运行时谁调用谁”。Inspect Repository 应先找到入口、依赖声明、语言与构建配置、测试发现规则和相邻实现,再画出与任务有关的最小依赖图。本章下载包刻意使用零第三方运行时依赖的 Python fixture:todo/cli.py 解析参数,todo/storage.py 读取 JSON,todo/exporter.py 定义待实现接口,tests/test_csv_export.py 承载可执行验收,README 是用户接口。
| 证据 | 回答的问题 | 本章真实读取 |
|---|---|---|
| 入口与 imports | CLI、storage 与 formatter 的调用边 | todo/cli.py、todo/__init__.py |
| 相邻实现 | Todo 字段、JSON 读法、返回值与换行约定 | todo/storage.py、todo/exporter.py |
| 测试发现 | 怎样证明普通、空与三个 escaping 边界 | python -m unittest discover -s tests -p test_*.py -v |
| 静态验证 | 怎样在零下载条件下 lint / build | 标准库 tabnanny 与逐文件内存 compile() |
实验二:从结构与依赖出发,用 Search → Read 建立可引用的修改证据
本地模型读取 Runtime 提供的真实文件清单与目标后,输出结构化 Search → Read 候选;Runner 只执行 allowlist 内的搜索和精确读取,从 todo/cli.py、todo/exporter.py、todo/storage.py、tests/test_csv_export.py 与 README 当前字节构建 evidence。trace 分别显示 model.decision、search.completed、read.completed、path 与 excerpt,使用户能检查“模型为什么想看”与“仓库实际返回什么”。fixture 是隔离的真实目录,不是 JavaScript 内存文件表;custom workspace 仍先只读,任何越界路径由 Runtime 拒绝。
每次点击都会创建真实异步 run;没有连接或模型时保持 not_run,不执行浏览器 fallback。
请先在模块顶部下载示例包和模型,启动 4891,依次完成“检查 Runner”和“检查本地模型”。
phase = not_run
events = 0 · receipts = 0
stop_reason = —
workspace = fixture · %TEMP%\algolab-coding-agent-runs\<run-id>\workspace
model = ./models/Qwen2.5-Coder-1.5B-Instruct
approvals = write:false / commands:false
fixture 每次复制到独立临时 Git 工作区;六张卡共享配置,但不共享仓库或上一张卡的 receipts。下载的 Runner 包与原始 fixture 不会被修改。
模型候选与 Runtime 证据分开记录
搜索负责缩小候选,精确读取负责把候选变成可修改证据
高效定位通常是逐层收窄:先用真实文件列表确认语言与 package 边界,再搜索用户术语和未实现 marker,随后读取命中点附近的完整函数、调用者和测试。Agent 不应从第一个字符串命中直接开始编辑,也不应为了“理解完整项目”把所有文件读一遍。
- File list:确认
todo/*.py、tests/test_csv_export.py与 README,跳过.git、__pycache__和模型目录。 - Text search:默认搜索
NotImplementedError与CSV_EXPORT_TESTS,把实现 seam 和测试 seam 同时定位出来。 - Focused read:模型选择目标文件,Runtime 返回当前精确字节的 UTF-8 文本、大小和受限 excerpt;CRLF/LF 不被读取层偷偷归一化。
- Cross-reference:沿
from .storage import load_todos、export_csv与测试调用确认传播范围。
每条 evidence 都能回到具体 trace seq、path、search hit 或 read receipt。Plan 的每个 edit step必须引用这些事实;如果“需要改 README”只是模型经验而不是验收或仓库证据,它应被标记为待确认。
修改计划必须把每个文件变化连接到证据和验证命令
No.18 已经说明 Plan step 要产生可验收状态变化;在仓库里还要增加两类坐标:evidence refs 说明为什么改这里,verification refs 说明怎样证明这一步没有破坏项目。G-TODO-CSV 的初始计划不是“写 CSV、跑测试”,而是一个可以被执行器逐项拒绝或完成的文件级计划。
| Step | 预期变化 | 真实证据 | 验证 |
|---|---|---|---|
| S1 | todo/exporter.py 从 NotImplementedError 变为可测 export_csv | exporter read + Todo dict fields | 五个独立 unittest cases |
| S2 | todo/cli.py 接入 export-csv --db --output | argparse dispatch + storage import | CLI 写文件断言 |
| S3 | tests/test_csv_export.py 补普通、空、逗号、引号、换行与 CLI cases | 测试 marker + AC2/AC3 | Plan v1 真实出现三项 escaping failure |
| S4 | README 记录可复制命令 | 用户交付契约 | 最终 diff review |
Plan 还要声明修改顺序、允许路径、预计稳定 command IDs 和停止条件。新证据可以改变计划:真实测试证明手写拼接不满足 CSV quoting 后,Plan v2 保留 CLI、tests 与文档,只把 formatter 换为标准库 csv.writer。
Patch 只有在 preimage 与 hunk 上下文仍匹配时才能安全应用
Runtime 在修改前同时检查文件 preimage hash 和每个 hunk 的上下文;任一不匹配都拒绝整项修改并要求重新读取。
拒绝 stale edit
读取后若用户或另一进程修改了文件,旧 patch 不能靠模糊匹配强行落盘;应重新 read、更新证据并重算 diff。
多文件原子边界
教学 Runtime 先验证全部目标,再提交 workspace snapshot;生产实现可使用临时文件、transaction 或 Git worktree 避免半套修改。
Patch receipt
记录 before/after hash、applied hunks、changed lines、policy decision 和 patch ID;不记录含 secret 的完整文件副本。
实验三:把计划变成多文件 Patch,并从 baseline 计算真实 diff
本地模型根据真实 evidence 生成文件级 Plan 与候选 ID;只有用户开启 allow_write 后,Runner 才在本次隔离 Git fixture 中检查 canonical scope,并以 exact old → new transaction 真实修改 todo/cli.py、todo/exporter.py、tests/test_csv_export.py 与 README.md。四个目标先全部验证,任一 preimage 不匹配就整组拒绝;成功后逐文件返回 before/after SHA-256、unified diff 与 checkpoint receipt。Plan v1 故意使用手写 f-string + join,同时写入五个独立测试,为下一实验产生普通/空通过、comma/quote/newline 三项真实失败;关闭批准时只返回 approval_required。
每次点击都会创建真实异步 run;没有连接或模型时保持 not_run,不执行浏览器 fallback。
批准由你显式勾选,只用于之后新建的 run;被截停的旧 run 不能原地续跑。
请先在模块顶部下载示例包和模型,启动 4891,依次完成“检查 Runner”和“检查本地模型”。
phase = not_run
events = 0 · receipts = 0
stop_reason = —
workspace = fixture · %TEMP%\algolab-coding-agent-runs\<run-id>\workspace
model = ./models/Qwen2.5-Coder-1.5B-Instruct
approvals = write:false / commands:false
fixture 每次复制到独立临时 Git 工作区;六张卡共享配置,但不共享仓库或上一张卡的 receipts。下载的 Runner 包与原始 fixture 不会被修改。
模型候选与 Runtime 证据分开记录
精确修改不是少改几行,而是让所有受影响契约同步变化
“最小 diff”不等于“只改一个文件”。新增 CSV export 同时改变 formatter API、CLI route、测试真值和用户文档;如果只在 todo/exporter.py 写函数却不接入 CLI,局部代码可能正确,任务仍然失败。相反,顺手格式化全仓库会扩大审查面,并可能覆盖用户无关改动。
| 文件 | 精确变化 | 不应发生 |
|---|---|---|
todo/exporter.py | 实现 export_csv;Plan v2 只替换失败 formatter | 重写 storage 或让模型直接写任意源码 |
todo/cli.py | 新增一个 argparse 子命令并写 UTF-8 输出 | 更换整个参数解析框架 |
tests/test_csv_export.py | 独立期望覆盖普通、空、comma、quote、newline 与 CLI | 调用实现函数计算 expected |
README.md | 记录真实 export-csv --db --output 命令 | 宣称尚未验证的行为 |
Runner 的 transaction 先准备全部目标,再用同目录临时文件、flush、fsync 与原子 replace 写入;中途失败会按保存的原始字节回滚。读取和 Patch 都保留 CRLF/LF 精确字节,避免 Windows 上“模型看到 LF、校验器看到 CRLF”的 stale edit 假冲突。
终端命令必须显式声明 cwd、参数、超时、环境与副作用级别
Shell 是 Coding Agent 最强也最危险的工具。模型不能提交一整段 shell 文本;它只能选择 Runtime 注册的稳定 command ID。Runtime 再绑定固定 argv、canonical cwd、最小环境、timeout 与 64 KiB 输出上限,并以 subprocess.Popen(..., shell=False) 执行。
| 稳定 ID | 真实 argv / 作用 | 本章策略 |
|---|---|---|
tests | python -m unittest discover -s tests -p test_*.py -v | 真实执行 fixture 测试;保留 exit 1 与 exit 0 两次 receipt |
python_lint | python -m tabnanny todo tests | 标准库缩进 lint,不下载工具 |
python_build | 逐个读取 Python 文件并在内存 compile(..., 'exec') | 真实语法 build,不写 pyc 或生成目录 |
git_status / git_diff | 固定只读 Git argv | 只用于 baseline 与最终审查 |
| install、reset、push | 不在 registry | 即使模型请求或通用批准开启也无法执行 |
每次命令返回真实 argv、exit code、合并后的 stdout/stderr、duration、timeout 与 truncation。custom JavaScript 仓库只从已有 package scripts 中选择安全的 lint/test/build ID,先拒绝包含下载、安装、删除等明显危险 marker 的 script。
Command Receipt 把一次终端执行变成可恢复、可审查的 Observation
命令收据同时记录执行环境、时间边界、退出状态、输出与文件状态变化,后续诊断不能只看一段自然语言摘要。
exit code 优先
日志中出现 PASS 不代表命令成功;Runtime 以进程状态和测试结构化结果为准。
环境失败不冒充代码失败
缺少依赖、命令不存在、权限拒绝与断言失败使用不同 error code,决定下一步是请求批准、修环境还是改代码。
文件 delta 揭示隐藏副作用
lint/build 即使 exit_code=0,也要检查是否意外改写源码、lockfile 或越界生成文件。
实验四:让第一版在真实边界测试中失败,再从 stderr 与断言定位原因
开启 allow_write 与 allow_commands 后,Runner 在真实 fixture 中应用 Plan v1,并用固定 argv 启动 unittest 子进程。五个测试中,普通/空列表与 plain CLI case 通过,comma、quote、embedded newline 三项独立断言失败,整个命令真实返回 exit_code=1;stdout/stderr、duration、timeout 与 truncation 都来自本机。Runner 随后把失败 receipt 交给同一个本地模型进行第二次结构化调用,输出 cause/evidence/repair;实验以“成功捕获并诊断真实失败”完成,但仓库仍保持红色,绝不把 diagnosis 写成测试通过。
每次点击都会创建真实异步 run;没有连接或模型时保持 not_run,不执行浏览器 fallback。
批准由你显式勾选,只用于之后新建的 run;被截停的旧 run 不能原地续跑。
请先在模块顶部下载示例包和模型,启动 4891,依次完成“检查 Runner”和“检查本地模型”。
phase = not_run
events = 0 · receipts = 0
stop_reason = —
workspace = fixture · %TEMP%\algolab-coding-agent-runs\<run-id>\workspace
model = ./models/Qwen2.5-Coder-1.5B-Instruct
approvals = write:false / commands:false
fixture 每次复制到独立临时 Git 工作区;六张卡共享配置,但不共享仓库或上一张卡的 receipts。下载的 Runner 包与原始 fixture 不会被修改。
模型候选与 Runtime 证据分开记录
测试失败先分类,再决定重试、修环境、改代码还是 Replan
失败日志是 Observation,不是自动要求“再生成一版代码”。相同的非零 exit code 可能来自解析错误、lint、断言差异、环境缺失、timeout 或 flaky case;不同类别需要不同证据和恢复路径。
| 层 | 示例 | 正确下一步 |
|---|---|---|
| Environment | Python、Git 或 test discovery 不可用 | 核对 health、manifest 与 argv;不改业务代码 |
| Build | todo.cli import / 语法失败 | 读取 compiler location 与当前文件,修接线 |
| Lint | tabnanny 报缩进歧义 | 按当前文件最小修改,不全仓格式化 |
| Test assertion | comma 字段缺少外层双引号 | 比较失败 expected/actual 与当前 formatter,建立可证伪假设 |
| Timeout | 子进程超过上限被 kill | 检查阻塞原因,不把 timeout 当实现错误 |
| Regression | escaping 通过但 CLI 写文件失败 | 扩大到 CLI case 并 Replan,不能只保留局部绿色 |
本章首轮是结构性实现缺口:手写 f-string 与 join 不执行 RFC 风格 quoting。真实输出中三个测试名分别指向 comma、quote、embedded newline;Runtime 把 receipt 交给模型形成 diagnosis,Plan v2 保留已经有效的 CLI route、tests 和文档,只把 todo/exporter.py 换为标准库 csv.writer。
Diagnosis 用可证伪假设连接失败 Observation 与下一次最小动作
在与当前 Observation 一致的候选原因中,优先选择单位成本能排除最多假设的安全动作,而不是直接生成最大 patch。
本章的三个假设
H1:整行需要统一包裹;H2:只有含特殊字符的 cell 需要包裹并双写内部引号;H3:测试期望错误。读取断言与 CSV 契约即可排除 H1/H3。
Replan 保留有效产物
CLI route、普通 case 与 README 结构仍有效;Plan v2 只替换 escaping step,并增加回归验证,不重新检查整仓库。
失败指纹防止盲重试
command、case IDs、error code 与 relevant diff hash 相同且无新证据时视为同一失败;达到阈值后停止或请求人工判断。
验证从最便宜的 targeted check 逐层扩展到仓库级验收
修复后立刻只看最终绿色会丢掉因果链,只重跑一个 case 又可能漏回归。Coding Agent 使用从便宜到完整的 verification ladder;每一层都形成独立 command receipt,失败决定回到 Read、Edit 或 Replan。
- Static sanity:重新读取 changed regions,确认 import、argparse route、精确换行与 preimage。
- 同一完整 unittest:先在 Plan v1 得到 exit 1 和三个命名失败;修复后用完全相同的 argv 得到 5 tests、exit 0,避免换命令逃避失败。
- Lint:运行标准库
tabnanny检查todo与tests,保存真实 exit code。 - Build:逐文件读取并调用内存
compile(),输出实际编译文件数,不产生 pyc 副作用。 - Repository review:最后执行 Git status/diff,确认 verifier 没有额外生成文件。
custom workspace 根据真实 manifest 选择已有 npm lint/test/build;缺少某层时写 not_run,而不是套用 fixture 命令。测试返回 0 但发现 0 个 tests 时仍不能满足 AC。
完成是验收、验证、范围与变更审查的合取,不是某个测试的绿色图标
只有验收条件、build、lint、tests、diff review 全部满足且没有 scope violation 时,任务才能标记 completed。
三态而非布尔
每项 verifier 使用 passed / failed / not_run;not_run 不能在聚合时变成 true 或 0 failures。
测试与验收分开
测试通过可以证明行为样例,但 README、允许范围、用户已有改动和最终交付字段仍需独立检查。
正确停止也是结果
权限被拒、环境缺失或 baseline 冲突时,Runtime 可以安全 stopped;这不等于任务成功,但优于越权完成。
实验五:应用 Plan v2,重跑验证并审查真实 Git status / diff
本卡让本地模型在同一个全新 fixture run 内完成真实闭环,不读取实验四的临时仓库:review.inspect 先 search/read,review.initial 形成四文件 csv-naive Plan v1;获得写入与命令批准后,Runtime 应用它并运行 unittest 得到 exit 1 与三个 escaping failures。本地模型再依次产生 review.diagnosis 和 review.replan,Plan v2 保留 CLI、tests、README,只把 todo/exporter.py 替换为 csv.writer。随后同一 unittest 必须报告 5 tests / exit 0,tabnanny lint 与内存 compile build 也必须 exit 0;Runtime 再运行 git status --short、git diff,并把真实 diff 交给 review.final 形成公开 verdict/findings。
每次点击都会创建真实异步 run;没有连接或模型时保持 not_run,不执行浏览器 fallback。
批准由你显式勾选,只用于之后新建的 run;被截停的旧 run 不能原地续跑。
请先在模块顶部下载示例包和模型,启动 4891,依次完成“检查 Runner”和“检查本地模型”。
phase = not_run
events = 0 · receipts = 0
stop_reason = —
workspace = fixture · %TEMP%\algolab-coding-agent-runs\<run-id>\workspace
model = ./models/Qwen2.5-Coder-1.5B-Instruct
approvals = write:false / commands:false
fixture 每次复制到独立临时 Git 工作区;六张卡共享配置,但不共享仓库或上一张卡的 receipts。下载的 Runner 包与原始 fixture 不会被修改。
模型候选与 Runtime 证据分开记录
Git status 与 diff 是最终审查入口,不是 Agent 记忆的装饰
验证通过后仍要回到仓库状态。真实 git status --short 回答哪些 tracked/untracked paths 改变,完整 git diff --no-ext-diff -- 检查语义、秘密、调试残留、生成文件和测试质量。只展示 Agent 保存的候选 patch 会漏掉命令副作用,也无法发现运行期间的新改动。
| 审查问题 | G-TODO-CSV 的真实期望 | 异常信号 |
|---|---|---|
| 范围 | 仅 todo/cli.py、todo/exporter.py、一个测试文件与 README | __pycache__、模型、artifact 或凭据文件出现 |
| 必要性 | 每个 hunk 对应 S1–S4 / AC | 无关重命名、全文件格式化 |
| 正确性 | csv.writer、CLI 接线、独立 expected | 测试复用实现函数计算 expected |
| 可交付性 | 5 tests、lint、build receipts 都通过 | skip、弱化断言或把 expected failure 隐去 |
custom baseline 必须 clean 才允许写;无法区分用户改动时直接 dirty_baseline,不会 restore、checkout 或 reset。最终 artifacts 固定为 summary.json、trace.json、git.diff、git-status.txt 与 workspace-manifest.json,路由不能读取其他文件。
Checkpoint 保存的是可继续工作的仓库协议,不是一句“做到测试了”
No.19 的 checkpoint 在 Coding Agent 中必须绑定仓库身份和精确副作用。至少保存 task/goal hash、workspace policy version、baseline tree、current tree、Plan version/cursor、evidence IDs、patch receipts、command receipts、approval receipts、verification matrix 与未解决失败。大 diff 和日志作为带 hash 的 artifacts 引用,不塞进摘要。
- 保存:在 patch 或 command 到达终态后,先持久化 receipts 与 artifacts,再推进 cursor。
- 中断:丢弃进程内模型上下文不影响 Git snapshot 与 checkpoint manifest。
- 恢复校验:重新 canonicalize root,核对 repository identity、baseline/current hashes、policy 与 artifact hashes。
- 重建:从 receipts 归约 changed files、passed checks、remaining plan 和 approval state。
- 继续:只从 next safe action 分派,避免重复 patch、重复安装或重复外部写入。
如果恢复时 workspace 被用户修改,Runtime 不猜测如何合并。它生成 checkpoint/current diff,保留只读诊断能力,并要求重新 inspect、Replan 或人工决定。对可重复测试可安全重跑;对发布、删除、提交等副作用必须检查 idempotency key 或明确重新批准。
Resume 只有在仓库、状态、策略与副作用收据共同一致时成立
仓库身份、baseline/current hashes、policy version、artifact receipts 与 side-effect receipts 必须全部通过校验。
current tree 不是 baseline
baseline 说明任务开始前状态,current tree 说明 checkpoint 时已完成修改;二者都需要,才能发现外部漂移并避免重复工作。
审批不会永久继承
批准应绑定 action fingerprint、scope 与有效期;Resume 后命令或目标改变时必须重新判断。
恢复后的第一步
先生成恢复报告并重建 verification matrix,再决定重跑失败测试或继续 diff review,不能直接让模型猜 next step。
本地 Runner 承载真实能力,Sandbox、权限与人工批准决定动作能否发生
真实 Coding Agent 不能只放在浏览器中:网页没有权限读取任意仓库、调用 Git 或启动测试进程。因此本章采用与 No.16、No.17 相同的本地边界,但把工具扩大到 repository engineering。AlgoLab Backend 只发布页面与完整示例 ZIP;浏览器直接连接用户电脑上的 127.0.0.1:4891;模型权重、仓库文件、命令输出和 artifacts 不经过部署服务器。
| 组件 | 职责 | 明确不做 |
|---|---|---|
| 课程页面 | 配置目标、模型路径、workspace mode 与批准;展示 trace | 不伪造文件、diff 或 exit code |
| 本地模型 | 提出结构化 inspect、plan、diagnosis、review 与 summary | 不直接打开文件、不执行命令、不授予自己权限 |
| 确定性 Runtime | canonicalize、policy、Git、Patch、subprocess、receipts、checkpoint | 不把模型文本当成功证据 |
| 隔离 fixture | 每次 run 建立真实临时 Git 仓库,安全复现实验 | 不修改 AlgoLab 主仓库 |
首次使用依次完成四步:下载并解压 ZIP;在虚拟环境安装 requirements.txt;运行 download_model.py 将 Qwen/Qwen2.5-Coder-1.5B-Instruct 保存到用户指定目录;用 run.ps1 或 run.sh 启动服务并在页面检查 health 与 model inspect。模型只加载一次,六个实验共用该进程。权重不会被打进 ZIP,也不会在点击实验时静默下载。
Sandbox 是执行边界,permission policy 是决策规则,human approval 是特定动作的临时授权,三者不能合并成一个“安全模式”开关。
| 等级 | 示例 | 默认处理 |
|---|---|---|
| Read-only | list/search/read、git status/diff | 授权 root 内自动执行并记录 |
| Workspace write | 对计划文件应用已验证 patch | 用户开启 allow_write,且路径、preimage、writable set 均通过 |
| Execute repository code | test/lint/build | 用户开启 allow_commands;Runtime 校验 argv、cwd、timeout 与脚本 |
| Network / install | npm install、下载工具 | 实验 run 中默认拒绝;模型下载是用户在启动前显式执行的独立步骤 |
| Destructive / external | 删除、reset、commit、push、发布 | 示例 Runtime 默认拒绝,不因通用写入批准而放行 |
审批请求应绑定 exact argv、cwd、目标 paths、preimage、policy version 与预计副作用。用户拒绝后,Agent 可以保留只读诊断并报告 not_run;不能换一种拼写重复请求同一动作。
动作分派必须同时通过能力、范围、风险与审批四道门
工具存在、作用域允许、风险未超过当前自动执行阈值且所需审批有效,动作才进入执行器。
动作指纹
approval 应绑定 tool、normalized args、cwd、target hashes 与 policy version;参数改变后旧批准失效。
风险和模型置信度无关
即使模型确信 reset 能修复问题,destructive risk 也不会下降;审批门由 Runtime 计算。
拒绝后的可用路径
系统保留 read-only inspect、diff 和报告能力,并把 blocked verifier 写入 Final Summary。
完整示例包让实验可复现,危险操作控制让副作用可停止、可恢复
页面提供的 ZIP 不是一段演示脚本,而是一套可以离开 AlgoLab 仓库独立运行的最小工程:README 与 manifest 解释协议,模型下载脚本固定本地保存流程,HTTP server 与 job store 提供异步运行和取消,model policy 约束结构化输出,workspace policy 负责路径与命令安全,prompts / schemas 固定公开决策契约,fixture 是带测试的真实小仓库,tests 使用 FakeModelPolicy 验证安全规则而不下载权重。页面还能按 manifest 浏览每个源码文件并核对 SHA-256。
| 运行模式 | 适用场景 | 副作用边界 |
|---|---|---|
| fixture(默认) | 学习六阶段闭环、复现真实失败 | 复制到临时目录并初始化 Git;结束后可由系统清理 |
| custom + read-only | 在自己的仓库练习定位、计划与 review | 只能 list/search/read/status/diff |
| custom + approvals | 进阶多文件修改与验证 | 写入和命令分别批准;baseline dirty 状态会进入交付报告 |
危险不只等于删除。覆盖未提交文件、递归移动目录、运行未知 postinstall、修改数据库、推送分支、发布包和长时间占用资源都可能难以恢复。Runtime 在执行前识别 side-effect class,在执行中支持 timeout / cancellation,在执行后记录 receipt 与真实文件 delta。
- 删除与覆盖:拒绝 workspace root、home、通配 broad target;示例 Agent 不提供任意删除工具。
- 版本控制:不以 reset/checkout 清理用户改动;fixture 通过新建临时 Git 仓库获得干净 baseline。
- 依赖与脚本:先读 manifest 与 script;run 中拒绝安装、网络和 shell 拼接,只执行允许的结构化 argv。
- 外部系统:commit、push、PR、部署与消息发送不在本章 capability set 中,通用批准不能凭空增加工具。
- Secrets:搜索、日志、diff、artifact 与 Final Summary 都需过滤敏感路径和环境值。
核心实验:让 Mini Coding Agent 在同一真实 fixture 中完成完整仓库闭环
核心实验把前五个阶段串成一个异步本地 run:同一个已加载的 Qwen2.5-Coder-1.5B-Instruct 依次产生 mission.inspect、mission.initial、mission.diagnosis、mission.replan 与 mission.review 五次结构化决策;确定性 Runtime 先在真实临时 Git 仓库中 search/read,再创建 checkpoint、应用四文件 Plan v1、运行 unittest 得到 exit 1 与三个 escaping failures、应用只替换 exporter 的 Plan v2、用同一 unittest 得到 5 tests / exit 0,最后运行 tabnanny lint、内存 compile build 与 Git review。每个事件有递增 seq、公开 summary、工具参数、path/hash 与 receipt,可取消并下载五个 artifacts。页面只轮询 4891,不播放固定动画;custom workspace 必须显式路径、clean baseline 和两项批准。
每次点击都会创建真实异步 run;没有连接或模型时保持 not_run,不执行浏览器 fallback。
批准由你显式勾选,只用于之后新建的 run;被截停的旧 run 不能原地续跑。
请先在模块顶部下载示例包和模型,启动 4891,依次完成“检查 Runner”和“检查本地模型”。
phase = not_run
events = 0 · receipts = 0
stop_reason = —
workspace = fixture · %TEMP%\algolab-coding-agent-runs\<run-id>\workspace
model = ./models/Qwen2.5-Coder-1.5B-Instruct
approvals = write:false / commands:false
fixture 每次复制到独立临时 Git 工作区;六张卡共享配置,但不共享仓库或上一张卡的 receipts。下载的 Runner 包与原始 fixture 不会被修改。
模型候选与 Runtime 证据分开记录
逐项读核心 trace,并把已验证事实写成最终交付说明
默认 mission 的增量 trace 能重建完整因果链:repository.baseline 与 workspace.scoped 固定真实 Git/root 边界;mission.inspect 产生 search/read events;mission.initial 给出基于本次读取的 Plan v1;checkpoint.created 先于任何写入;plan-v1 的四文件 patch receipts 证明改动落盘;第一次 tests receipt 以 exit 1 暴露 comma / quote / newline 三项失败;mission.diagnosis 引用真实输出;mission.replan 保留有效 CLI、tests、README,只替换 exporter;同一 tests argv 随后报告 5 tests / exit 0,python_lint 与 python_build 也各自 exit 0;最后 git.reviewed 与 mission.review 共同约束交付。
| Final 字段 | 必须来自 | 本章真实内容 |
|---|---|---|
| Goal / result | Task Contract + terminal state | export-csv --db --output implemented,completed |
| Changed files | 真实 git status / diff | CLI、exporter、一个独立测试文件、README |
| Behavior | 5 个 unittest 方法 | 普通 + 空列表、逗号、引号、换行与 CLI 写文件五组断言均被覆盖 |
| Verification | 4 张 command receipts | tests exit 1 → tests exit 0 → lint exit 0 → build exit 0 |
| Failure and repair | 五次 model decisions + patch receipts | 手写 join 失败,最小替换为 csv.writer |
| Scope / approvals | policy.approval + safety | 写入/命令批准;shell/network/destructive=false |
| Artifacts | artifact allowlist + SHA-256 | summary、trace、diff、status、workspace manifest |
| Checkpoint | checkpoint manifest | 写前快照文件数与 restore_requires_approval;精确内容留在本地 run 内 |
Final Summary 不粘贴整段日志,也不用“应该”“看起来”。模型可以组织语言,但 Runtime 只交付 receipt 支撑的字段。fixture 小模型连续两次违反结构化契约时,Runtime 只允许审计候选并公开记录 contract normalization;custom 仍严格停止。审批被拒、用户取消、测试仍失败或 custom baseline 漂移时,明确返回 stop_reason 和已有证据。
Coding Agent 评测必须同时覆盖定位、修改、验证、安全、恢复与交付
单一 Task Success 无法解释失败发生在定位、patch、验证、权限、恢复还是最终报告;各指标必须从同一 trace 独立计算。
分母为零显示 N/A
没有请求高风险动作时 Approval Correctness 可能是 N/A;没有 checkpoint 场景时 Resume Success 也不能伪装成 100%。
效率单独报告
Steps、search/read bytes、patch attempts、commands、wall-time proxy 与 Context tokens 描述成本,但不能覆盖安全和正确性。
默认 mission 的预期
首轮 Task Success 为失败但 Diagnosis 有效;Plan v2 后 AC 全通过、scope violations=0、verification coverage=100%,Final claims 均能回到 receipts。
安全停止不是任务成功
越界注入时 Scope gate 正确拒绝可提高安全指标,但 Task Success 仍为 false;两者必须同时呈现。
精炼 typed controller:让证据、Patch、测试与权限收据驱动同一个循环
python这段 typed controller 是下载包中真实 Runner 的最小抽象:本地模型只经 propose 返回候选,文件系统、Git、Patch 和 subprocess 全部经 authorize / execute;Observation 与 receipts 才能推进状态。完整可运行实现、fixture、启动脚本与无模型单测请在本模块顶部下载 ZIP 并逐文件浏览。
按执行顺序理解与检查
from __future__ import annotations
from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Literal, Protocol
class Phase(str, Enum):
INSPECT = 'inspect'
PLAN = 'plan'
EDIT = 'edit'
VERIFY = 'verify'
DIAGNOSE = 'diagnose'
REVIEW = 'review'
DELIVER = 'deliver'
STOPPED = 'stopped'
@dataclass(frozen=True)
class ToolCall:
name: Literal['list', 'search', 'read', 'patch', 'command', 'status', 'diff']
args: dict[str, Any]
reason: str
@dataclass(frozen=True)
class PolicyDecision:
allowed: bool
risk: Literal['read', 'write', 'execute', 'network', 'destructive']
approval_id: str | None = None
reason: str = ''
@dataclass(frozen=True)
class Receipt:
kind: str
ok: bool
data: dict[str, Any]
error_code: str | None = None
@dataclass
class AgentState:
goal: dict[str, Any]
workspace: dict[str, Any]
phase: Phase = Phase.INSPECT
plan_version: int = 0
evidence: dict[str, Receipt] = field(default_factory=dict)
patches: list[Receipt] = field(default_factory=list)
commands: list[Receipt] = field(default_factory=list)
approvals: list[PolicyDecision] = field(default_factory=list)
failures: list[Receipt] = field(default_factory=list)
acceptance: dict[str, Literal['passed', 'failed', 'not_run']] = field(default_factory=dict)
blockers: list[str] = field(default_factory=list)
last_failure_fingerprint: str | None = None
repeated_failure_count: int = 0
class Runtime(Protocol):
def propose(self, state: AgentState) -> ToolCall: ...
def authorize(self, state: AgentState, call: ToolCall) -> PolicyDecision: ...
def execute(self, state: AgentState, call: ToolCall) -> Receipt: ...
def reduce(self, state: AgentState, call: ToolCall, receipt: Receipt) -> None: ...
def checkpoint(self, state: AgentState) -> Receipt: ...
def final_report(self, state: AgentState) -> dict[str, Any]: ...
def run_agent(runtime: Runtime, state: AgentState, max_steps: int = 40) -> dict[str, Any]:
for _ in range(max_steps):
if state.phase is Phase.DELIVER:
return runtime.final_report(state)
if state.phase is Phase.STOPPED:
return runtime.final_report(state)
call = runtime.propose(state)
policy = runtime.authorize(state, call)
state.approvals.append(policy)
if not policy.allowed:
state.blockers.append(f'{call.name}: {policy.reason}')
state.phase = Phase.STOPPED
continue
receipt = runtime.execute(state, call)
runtime.reduce(state, call, receipt)
if call.name == 'patch':
state.patches.append(receipt)
if call.name == 'command':
state.commands.append(receipt)
if not receipt.ok:
state.failures.append(receipt)
checkpoint = runtime.checkpoint(state)
if not checkpoint.ok:
state.blockers.append('checkpoint validation failed')
state.phase = Phase.STOPPED
state.blockers.append('max_steps reached before verified delivery')
state.phase = Phase.STOPPED
return runtime.final_report(state)
正在检查登录状态与模型配置…