diff --git a/.agents/notes/implemented/feature/2026-09-28-apply-patch-file-editing.i18n.yaml b/.agents/notes/implemented/feature/2026-09-28-apply-patch-file-editing.i18n.yaml new file mode 100644 index 0000000000..8f0d29bfeb --- /dev/null +++ b/.agents/notes/implemented/feature/2026-09-28-apply-patch-file-editing.i18n.yaml @@ -0,0 +1,25 @@ +# Bilingual-pair consistency record for 2026-09-28-apply-patch-file-editing.md (docs/i18n/README.md): per heading +# section, a hash of its English and Chinese blocks outside code blocks and generated regions. +# After editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-09-28-apply-patch-file-editing.md +/agent-note-apply-patch-file-editing: + en: 2ff887cb8deab0eb + zh: b503b00d8690955c +/agent-note-apply-patch-file-editing/problem: + en: de9b76d89795ccec + zh: 588d45b7d9ca9582 +/agent-note-apply-patch-file-editing/decision: + en: e80fb1fafd5cf065 + zh: 7fdd3c29f8f7a3b6 +/agent-note-apply-patch-file-editing/alternatives-considered: + en: 8807fd9b985dad25 + zh: 2f0c415e8d8e2f7f +/agent-note-apply-patch-file-editing/consequences: + en: 6b1b596aa0cebdb6 + zh: 5e6ab9bb40e81b78 +/agent-note-apply-patch-file-editing/testing: + en: 82ae0a96fbae53bc + zh: 9a8194bdb134ae8c +/agent-note-apply-patch-file-editing/deferred: + en: db33b4cfe1943a3a + zh: d69bb3a0f7fc376c diff --git a/.agents/notes/implemented/feature/2026-09-28-apply-patch-file-editing.md b/.agents/notes/implemented/feature/2026-09-28-apply-patch-file-editing.md new file mode 100644 index 0000000000..a1775d510b --- /dev/null +++ b/.agents/notes/implemented/feature/2026-09-28-apply-patch-file-editing.md @@ -0,0 +1,45 @@ +# Agent Note: Apply patch file editing + +Status: implemented + +English | [中文](2026-09-28-apply-patch-file-editing.zh.md) + +## Problem + +A model editing several files or separated regions needs multiple literal-edit calls or a shell script. Shell and Python edits do not expose filesystem mutation intents, so a working directory without Git cannot reliably present those edits in the turn Review tab. A patch tool expresses related edits in one call while retaining guarded filesystem operations. #5121 asks for the capability and its effectiveness evaluation; #4556 supplies the broader motivation for efficient file editing. + +## Decision + +`apply_patch` accepts one Codex-style patch for add, update, delete, and move operations, including multiple files and hunks. The pure [dsh-fs-patch library](../../../../packages/fs/fs-patch/README.md) follows Codex `rust-v0.158.0` parsing, sequential matching, whitespace tolerance, and `NormalizeToLf` reconstruction. The matcher receives LF text only; Codex `PreserveLineEndings` is not implemented. The pinned reference and compatibility fixtures distinguish syntax and matching behavior from Harness observation and sandbox policy. + +The [filesystem service](../../../../packages/fs/fs/README.md) exposes `patchText`, `deleteFile`, and `moveFile`; local, sandboxed, and SSH providers implement them. `fs/delete-intent` requires the same present observation as `fs/edit-intent`, while move destinations use `fs/write-intent`. Internal reads do not grant model observations. Version guards and sandbox enforcement remain with the provider. There is no transaction across paths: a move publishes its destination before deleting its source, and `sourceDeleted` distinguishes a completed move from a published destination whose source could not be removed. + +The [tool executor](../../../../packages/fs/tool-fs/README.md) resolves paths and simulates expected state during whole-patch preflight, including repeated paths and moves, without writing files. A rejected preflight commits nothing. Commit reobtains observation guards for each operation and stops at the first failure or cancellation without rollback. After an I/O or cancellation failure with uncertain effects, an independent `stat` comparison checks whether every affected target retains its prior version; changed state or a failed comparison produces `unknown` and requires rereading before retry. Reports retain completed, failed, unknown, and skipped operations, including a partially published move. + +Commit reports return `isError: false` so completed diff metadata survives a stopped patch; their operation statuses and stopped flag still expose failure. Syntax and preflight rejection produce tool errors. Successful move summaries use `M `. Applied diff paths use canonical absolute `processPath` for client navigation, while operation records retain display paths and unresolved failures retain original patch paths. + +[Review capture](../../../../packages/deliverables/workspace-changes/README.md) uses filesystem intent listeners, not argument parsing. `tools/pre-execute` associates the execution with its turn recorder; prepended write, edit, and delete listeners first await the policy decision, then await capture before provider mutation. Moves capture both endpoints. Each turn retains its first admitted baseline and compares actual final bytes, so repeated edits yield one net diff and reverted changes disappear. Denied intents create no capture or observation. Existing size, count, time, location, and Session-lifetime limits remain; a commit failure does not discard earlier real changes. + +`tool-fs.enableApplyPatch` defaults to `false`. An explicit overlay registers its schema, guidance, native/PTC execution, and tool presentation while retaining existing file tools. Registration uses plugin effects, and the agent loop is unchanged. + +## Alternatives considered + +**Keep using shell or Python for patches.** This leaves non-Git changes without filesystem intent capture and does not provide the requested model-facing editing tool. + +**Reuse Codex markers with an independently strict matcher.** This reduces initial implementation work but makes familiar patches fail differently. A pinned Codex parser and matcher make deviations reviewable; Harness policies stay explicit. + +**Make the whole patch transactional.** Cross-file rollback adds recovery state and can overwrite concurrent external edits. Preflight and ordered commits reject known failures early and expose partial results without promising rollback. + +**Expand Review while adding the tool.** Rename presentation, persistent storage, SSH capture, and capture-failure policy are independent product decisions. Existing whole-file capture and rendering cover this integration. + +## Consequences + +One call can express related edits, but lower tool-call counts do not establish better task outcomes or lower total token cost. Preflight cannot prevent a later conflict, cancellation, or storage failure; callers must inspect operation statuses and actual files before retrying. Permissive upstream matching remains pinned and tested rather than silently tightened. Provider implementations and external subclasses must support three additional operations, and partial moves require handling both endpoints. + +## Testing + +Parser and matcher fixtures cover the pinned syntax, whitespace, repeated contexts, and EOF behavior. Provider and executor tests cover observation, version and sandbox refusals, repeated paths, partial moves, cancellation, and uncertain outcomes. The real-tool Review matrix runs with no repository and with Git unavailable, checking all operation kinds, first-to-last baselines, rejected edits, partial publication, reverted changes, capture ordering, malformed syntax, and path aliases. Real model Session recordings cover successful updates, read-policy rejection and retry, and partial execution; deterministic cancellation stays in executor tests. + +## Deferred + +Default activation awaits the controlled editing-task evaluation in step eight: compare final-file correctness, task success, prompt and completion tokens, model steps, tool calls, retries, latency, and Review coverage on identical initial states. SSH Review, closing-prose file references for `apply_patch`, and Codex `PreserveLineEndings` remain outside this implementation. diff --git a/.agents/notes/implemented/feature/2026-09-28-apply-patch-file-editing.zh.md b/.agents/notes/implemented/feature/2026-09-28-apply-patch-file-editing.zh.md new file mode 100644 index 0000000000..60cb453259 --- /dev/null +++ b/.agents/notes/implemented/feature/2026-09-28-apply-patch-file-editing.zh.md @@ -0,0 +1,45 @@ +# Agent Note: apply_patch 文件编辑 + +Status: implemented + +[English](2026-09-28-apply-patch-file-editing.md) | 中文 + +## 问题 + +模型编辑多个文件或分离区域时,需要多次字面量编辑调用或 shell 脚本。shell 和 Python 编辑不发出文件系统修改 intent,因此没有 Git 的工作目录无法在轮次 Review tab 中可靠呈现这些修改。补丁工具用一次调用表达相关编辑,同时保留受保护的文件系统操作。#5121 要求实现能力并评测效果;#4556 提供高效文件编辑的更广泛动机。 + +## 决策 + +`apply_patch` 接收一份 Codex 风格补丁,支持新增、更新、删除和移动,以及多个文件和 hunk。[dsh-fs-patch 纯库](../../../../packages/fs/fs-patch/README.zh.md)遵循 Codex `rust-v0.158.0` 的解析、顺序匹配、空白容忍和 `NormalizeToLf` 重建。匹配器只接收 LF 文本;尚未实现 Codex `PreserveLineEndings`。固定版本参考与兼容性 fixture(测试前置数据)将语法和匹配行为同 Harness 观察及沙箱策略区分开来。 + +[文件系统服务](../../../../packages/fs/fs/README.zh.md)提供 `patchText`、`deleteFile` 和 `moveFile`;本地、沙箱和 SSH 提供方均实现它们。`fs/delete-intent` 与 `fs/edit-intent` 要求相同的存在观察,移动目标使用 `fs/write-intent`。内部读取不授予模型观察。版本防护和沙箱约束仍由提供方负责。不存在跨路径事务:移动先发布目标,再删除源;`sourceDeleted` 区分已完成的移动与目标已发布但源未能删除的情况。 + +[工具执行器](../../../../packages/fs/tool-fs/README.zh.md)在整份补丁预检时解析路径并模拟预期状态,包括重复路径和移动,不写入文件。预检拒绝时没有提交。提交时为每条操作重新获取观察防护,在首次失败或取消时停止,不回滚。I/O 或取消失败导致效果不确定时,独立的 `stat` 比较检查所有受影响目标是否仍保持先前版本;状态变化或比较失败会产生 `unknown`,要求重试前重新读取。报告保留已完成、失败、未知和跳过的操作,包括部分发布的移动。 + +提交报告返回 `isError: false`,让已完成的 diff 元数据在补丁中止后仍被保留;操作状态和 stopped 标记继续暴露失败。语法和预检拒绝产生工具错误。成功移动的摘要使用 `M `。已应用 diff 的路径采用规范绝对 `processPath`,供客户端导航使用;操作记录保留显示路径,解析失败则保留补丁原始路径。 + +[Review 采集](../../../../packages/deliverables/workspace-changes/README.zh.md)使用文件系统 intent 监听器,不解析参数。`tools/pre-execute` 将执行关联到轮次记录器;前置的 write、edit 和 delete 监听器先等待策略决策,再等待捕获完成,然后提供方才修改文件。移动捕获两端。每轮保留首次准入时的基线,比较实际最终字节,因此重复编辑形成一份净 diff,还原的变化不再显示。被拒绝的 intent 不产生副本或观察。现有大小、数量、时间、位置和 Session 生命周期限制保持适用;提交失败不会丢弃先前真实变化。 + +`tool-fs.enableApplyPatch` 默认为 `false`。显式 overlay 注册 schema、指导文本、native/PTC 执行与调用展示,同时保留已有文件工具。注册使用插件 effect,不修改 agent loop(智能体循环)。 + +## 考虑过的替代方案 + +**继续使用 shell 或 Python 打补丁。** 这使非 Git 修改缺少文件系统 intent 采集,也不能提供所需的模型文件编辑工具。 + +**复用 Codex 标记但采用独立的严格匹配器。** 这能减少初期实现工作,但会让熟悉的补丁以不同方式失败。固定 Codex 解析器和匹配器使偏差可审查;Harness 策略继续显式存在。 + +**将整份补丁做成事务。** 跨文件回滚增加恢复状态,还可能覆盖并发外部修改。预检和顺序提交可以提早拒绝已知失败,并公开部分结果,而不承诺回滚。 + +**加入工具时同时扩展 Review。** 重命名展示、持久存储、SSH 采集和捕获失败策略是独立产品决策。既有整文件采集和展示覆盖本次接入。 + +## 后果 + +一次调用可以表达相关编辑,但工具调用次数减少并不证明任务效果更好或总 token 成本更低。预检不能阻止之后的冲突、取消或存储失败;调用方必须在重试前检查操作状态和实际文件。上游宽松匹配保持固定版本并受到测试约束,不会被悄悄收紧。提供方实现和外部子类必须支持三个新增操作,部分移动要求处理两端状态。 + +## 测试 + +解析器和匹配器 fixture 覆盖固定版本的语法、空白、重复上下文与 EOF 行为。提供方和执行器测试覆盖观察、版本和沙箱拒绝、重复路径、部分移动、取消和未知结果。真实工具 Review 矩阵分别在无仓库和 Git 不可用环境运行,检查所有操作类型、首末基线、被拒编辑、部分发布、还原变化、采集顺序、无效语法与路径别名。真实模型 Session 录制覆盖成功更新、读取策略拒绝后重试与部分执行;确定性取消保留在执行器测试中。 + +## 延期工作 + +默认启用等待第八步受控编辑任务评测:在相同初始状态下比较最终文件正确性、任务成功率、提示词及完成 token、模型步数、工具调用、重试、延迟和 Review 覆盖。SSH Review、`apply_patch` 的收尾文案文件引用,以及 Codex `PreserveLineEndings` 不在本次实现内。 diff --git a/.agents/notes/proposed/feature/2026-09-28-apply-patch-file-editing.i18n.yaml b/.agents/notes/proposed/feature/2026-09-28-apply-patch-file-editing.i18n.yaml deleted file mode 100644 index f0a3f4b270..0000000000 --- a/.agents/notes/proposed/feature/2026-09-28-apply-patch-file-editing.i18n.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# Bilingual-pair consistency record for 2026-09-28-apply-patch-file-editing.md (docs/i18n/README.md): per heading -# section, a hash of its English and Chinese blocks outside code blocks and generated regions. -# After editing either side, bring the other along and re-record with: -# pnpm run verify-translation-pairing --write .agents/notes/proposed/feature/2026-09-28-apply-patch-file-editing.md -/agent-note-apply-patch-file-editing: - en: 76281e6919445c05 - zh: 22c855a840d5e98c -/agent-note-apply-patch-file-editing/problem: - en: 631d9a311ab996a9 - zh: 5d248a4690caa635 -/agent-note-apply-patch-file-editing/proposal: - en: aa5d52ca643f37df - zh: 835b59c07bc8401d -/agent-note-apply-patch-file-editing/proposal/confirmed-design-choices: - en: 8c339c6d47231562 - zh: 6e1ce7388e1719ee -/agent-note-apply-patch-file-editing/proposal/development-plan: - en: 3d2cbf824e81faa9 - zh: 3c2b8ccc764f102b -/agent-note-apply-patch-file-editing/proposal/review-acceptance-boundary: - en: 2cf837328ca3d83b - zh: 2ec94cc07a1d7ee5 -/agent-note-apply-patch-file-editing/alternatives-considered: - en: 4afded3298d7eb9c - zh: f397a2338787ca81 -/agent-note-apply-patch-file-editing/acceptance-criteria: - en: 837dc9f292c43ced - zh: 4666e89322ce6baf -/agent-note-apply-patch-file-editing/risks: - en: 089b7b5b89ce4588 - zh: baa6648e5410d033 diff --git a/.agents/notes/proposed/feature/2026-09-28-apply-patch-file-editing.md b/.agents/notes/proposed/feature/2026-09-28-apply-patch-file-editing.md deleted file mode 100644 index ba1ac07fa5..0000000000 --- a/.agents/notes/proposed/feature/2026-09-28-apply-patch-file-editing.md +++ /dev/null @@ -1,88 +0,0 @@ -# Agent Note: Apply patch file editing - -Status: proposed - -English | [中文](2026-09-28-apply-patch-file-editing.zh.md) - -## Problem - -A model editing several files or separated regions needs multiple literal-edit calls or a shell script. Shell and Python edits do not expose their affected paths to the existing file-tool capture path, so a working directory without Git cannot reliably present those edits in the turn Review tab. A patch tool can express related edits in one call and identify every affected path before mutation. Implementation precedes the effectiveness evaluation in #5121; #4556 supplies the broader motivation for efficient use of file tools. - -## Proposal - -Add an `apply_patch` tool for text-file creation, updates, deletion, and moves, with multiple files and hunks per call. Use Codex patch syntax and the existing filesystem capability, observation policy, sandbox policy, and tool execution lifecycle. Keep parsing and path extraction in a shared pure module so execution and Review capture interpret the same patch. - -Review work is limited to collecting the tool's affected paths before mutation and adding necessary composition or configuration entries. Reuse the existing [workspace change recorder](../../../../packages/deliverables/workspace-changes/README.md) and [Review tab](../../../../packages/client/ui-deliverables/README.md), including their diff types and display logic. Moves may appear as deletion plus creation. Rename-specific presentation, durable Review storage, remote capture, and changes to capture limits or failure policy are outside this proposal. - -### Confirmed design choices - -The choices below are approved. The complete tool remains proposed; the pure parser and text matcher are implemented in [dsh-fs-patch](../../../../packages/fs/fs-patch/README.md), with Codex `rust-v0.158.0` as their syntax and matching reference, and guarded filesystem operations are implemented in [dsh-fs](../../../../packages/fs/fs/README.md) and its providers. The preflight and sequential executor are implemented in [dsh-tool-fs](../../../../packages/fs/tool-fs/README.md). Package READMEs own supported behavior and exclusions; tool registration and presentation remain proposed. - -| Topic | Confirmed choice | Implementation specification | -|---|---|---| -| Input | A JSON argument with a `patch` string; reuse filesystem permission fields when applicable. | Final argument schema, activation method, and bounded result fields. | -| Syntax | `*** Begin Patch`, `*** End Patch`, `*** Add File:`, `*** Update File:`, `*** Delete File:`, `*** Move to:`, hunk markers, and `*** End of File`. | Select an upstream Codex version and enumerate supported forms, malformed input, and any exclusions. | -| Matching | Follow the parser and matcher of a pinned Codex version. | Verify the reference behavior for exact matching, whitespace tolerance, Unicode normalization, repeated contexts, search order, empty hunks, and EOF handling; record an expected output or error for each. | -| Filesystem policy | Preserve the mounted observation and sandbox policies; an internal preflight read does not count as a model observation. | Specify update/delete/move guards and destination collisions under these policies, plus path aliases, repeated paths, cross-provider moves, and line-ending preservation. | -| Failure | Preflight the whole patch, then commit in order; stop at the first failure and report actual completed, failed, and unexecuted operations; no whole-patch rollback. | Per-operation commit points, cancellation, and partial moves are reported. Syntax/preflight throw; commit values retain `isError: false` so known partial diff metadata is recorded. | -| Activation | Enable through composition for implementation and evaluation while retaining existing file tools. | `tool-fs.enableApplyPatch` defaults to false; an evaluation overlay enables registration and guidance without changing shipped profile defaults. | -| Review | Reuse existing whole-file capture and diff presentation without changing bounds or lifetime. | `workspace-changes.mutationPaths` uses `parsePatch` and `collectMutationPaths`; one ordered pre-execute queue captures both move endpoints before writing, deduplicates canonical paths, and retains each turn’s first baseline. Invalid syntax captures nothing; reads do not emit `fs/observed`. Turn-end comparison lists only actual net changes. | - -The selected Codex version defines patch syntax and text matching. Read-before-edit, freshness checks, and sandbox restrictions remain Harness deployment policies. The compatibility matrix records these policy differences and the verified reference behavior; it is an implementation specification, not a pending choice between matching strategies. - -### Development plan - -We implement and verify the steps in order. The parser supplies the shared records for matching, execution, and capture. Steps 1–6 precede integrated acceptance in step 7; evaluation in step 8 follows acceptance. - -1. **Implement patch parsing and affected-path collection.** Add `packages/fs/fs-patch` as a pure library without tool, Session, or filesystem-provider dependencies. Pin the Codex syntax reference and retain applicable license notices. Define serializable operations and hunks; implement `parsePatch(patch)` with original-input line errors and `collectMutationPaths(operations)` with both move endpoints. Preserve operation order and repeated operations; deduplicate only collected path strings. Cover single/multiple files and hunks, moves, malformed input, and reference syntax cases without filesystem I/O. - -2. **Implement hunk matching and text updates.** Apply the parsed hunks to caller-supplied text in the same pure library. Follow the pinned Codex matcher for exact matching, whitespace tolerance, Unicode normalization, repeated contexts, search order, and EOF behavior. Cover LF/CRLF, missing final newline, empty files, and unmatched hunks; document deliberate differences and expected results. Keep file reads, permission checks, and commits outside this step. - -3. **Provide guarded filesystem operations.** The current [filesystem service](../../../../packages/fs/fs/README.md) has text writes and literal edits, but no delete or move operation. Add only the primitives needed by the chosen patch design, preserving provider-owned freshness checks and atomic publication of a single file. Update local, sandboxed, and [SSH filesystem](../../../../packages/ssh/fs-ssh/README.md) implementations and any affected RPC helper/schema consumers together. A move spans two paths: define locking, source and destination guards, and failure outcomes explicitly. Exit when stale versions, denied paths, collisions, and interrupted operations leave the documented disk state; do not claim a multi-file transaction. - -4. **Implement patch execution.** Resolve and deduplicate canonical targets, obtain policy intents, and preflight syntax, permissions, matching, and destination rules before mutation. Recheck freshness at each provider commit; preflight does not prevent a later race or I/O failure. Execute in order, update observations after actual mutations, and retain completed-operation facts through cancellation or later failure. Exit when result metadata and concise model output agree with disk state, including partial moves, and the executor never bypasses the filesystem provider with shell or direct host writes. - -5. **Expose and present the tool.** Register `apply_patch` through normal plugin effects and the existing tool/PTC paths; keep the agent loop unchanged. Put parameter rules in the schema, teach when to choose the tool, and provide short corrective errors. Design the Host presenter and Web tool-call presentation using existing result metadata and presentation mechanisms. Add the selected activation/configuration entries and fail clearly on missing dependencies. Exit when the intended profiles advertise and execute the tool, disabled profiles remain coherent, and model-visible output is reconstructable from the Session log. - -6. **Connect existing Review capture.** The recorder's [mutation-path extraction](../../../../packages/deliverables/workspace-changes/src/capture.ts) currently recognizes a fixed set of tools and returns one path. Add the smallest producer-side adaptation for `apply_patch` to enumerate every affected path, including both move endpoints, from the shared parser. Await baseline capture before any write and retain the first capture of each path in the turn. Reuse turn-end capture and comparison of actual bytes. Exit when a non-Git directory shows every supported file with a net change, repeated edits produce a first-to-last diff, failed/unexecuted operations add no fictitious change, and Review display code is unchanged. This requires a small path-extraction change; configuration alone cannot provide it today. - -7. **Verify the composed capability and document it.** Combine focused parser/provider/tool tests with a recorded Session snapshot through a shipped profile and an existing Review flow in a non-Git directory. Cover successful edits, preflight rejection, partial execution, cancellation, and existing-tool regression. If the snapshot harness cannot express a required path, add that support in the same implementation. Update affected bilingual READMEs, JSDoc, subsystem references, and generated catalogs; acknowledge any declared persistence-type changes. Follow [testing policy](../../../../docs/testing.md) and [scope-based checks](../../../skills/dsh-pre-push-checks/SKILL.md). Exit when the acceptance matrix below passes and any unavailable real-provider evidence is explicitly reported. - -8. **Evaluate after implementation.** Run the same representative editing tasks with existing file tools and with `apply_patch`, controlling model, repository state, and task instructions. Measure correct final files, task success, request/prompt/output tokens, model steps, tool calls, retries, latency, and existing Review coverage. Report failures as well as gains, including the first-request prompt cost. Exit with a reproducible comparison and a recommendation on default activation; do not assume improvement or build a general benchmarking platform as part of this feature. - -### Review acceptance boundary - -Review uses whole-file captures before the first mutation and at turn end; tool-call hunks and patch text are not substitutes for these bytes. Test without a Git repository and with Git unavailable so Git coverage cannot conceal missing tool-path capture. A create followed by deletion, or an edit fully reverted in the same turn, has no net change and need not produce a row. - -The [existing Review decision](../../../../packages/deliverables/workspace-changes/README.md) owns size/count/time limits, capture-error behavior, session lifetime, and supported locations. This feature inherits them. Acceptance covers supported Host files while their Session is available; it does not promise persistent or SSH Review. Adding operations to the SSH filesystem provider keeps the filesystem API complete and does not imply remote Review support. - -## Alternatives considered - -**Keep using shell or Python for patches.** This leaves non-Git file changes without a predictable pre-mutation path list and does not provide the requested model-facing editing tool. - -**Reuse Codex markers with an independently strict matcher.** This can reduce initial implementation work but makes familiar patches fail differently. The confirmed design follows a pinned Codex parser and matcher, with Harness filesystem-policy differences explicitly recorded. - -**Make the whole patch transactional.** Cross-file rollback adds recovery state and can overwrite concurrent external edits. Preflight plus ordered commits gives earlier rejection and explicit partial results without promising rollback. - -**Expand Review while adding the tool.** Rename UI, persistent storage, remote capture, and a new capture-failure policy are independent product decisions. Existing capture and diff rendering suffice for the scoped tool integration. - -## Acceptance criteria - -| Area | Required evidence | -|---|---| -| Text operations | Add, update, delete, move, multiple files, and multiple hunks produce the expected final bytes; syntax and matching differences are recorded. | -| Guarded mutation | Unobserved or stale sources, protected paths, and destination conflicts follow the chosen policies; rejected preflight performs no writes. | -| Failure and cancellation | A failure after an earlier commit reports every completed mutation and every pending operation; disk state and output agree. | -| Non-Git Review | Existing Review shows supported net changes at turn end, including both move endpoints as existing file entries; no display-logic change. | -| Tool experience | Normal calls and PTC use the registered tool; concise output, errors, tool-call presentation, and Session snapshots agree. | -| Adoption evidence | The post-implementation comparison reports correctness and total work before recommending broader activation. | - -## Risks - -Upstream matching may be permissive or change between versions. Pin the reference and verify its behavior with compatibility fixtures; fix unintended mismatches against that reference. Any proposed matching-policy change must be recorded as a change to the confirmed design. Copying upstream code also requires license and dependency review. - -Preflight can succeed before a later version conflict, cancellation, or storage failure. Provider guards and accurate partial outcomes must survive these failures, especially for moves; a test failure here blocks tool acceptance. - -Path extraction can drift from execution or omit a move endpoint. Sharing the parsed operations and testing the complete non-Git path is required before enabling the tool in a profile with Review. - -This proposal preserves the rationale of the [filesystem split](../../../../packages/fs/fs/README.md), [observation event policy](../../../../packages/fs/fs-observation-policy/README.md), [filesystem sandbox](../../../../packages/fs/fs-sandbox/README.md), and [turn changed-files card](../../../../packages/deliverables/workspace-changes/README.md). It adds an editing capability without superseding those decisions. diff --git a/.agents/notes/proposed/feature/2026-09-28-apply-patch-file-editing.zh.md b/.agents/notes/proposed/feature/2026-09-28-apply-patch-file-editing.zh.md deleted file mode 100644 index 0e89c3ec4a..0000000000 --- a/.agents/notes/proposed/feature/2026-09-28-apply-patch-file-editing.zh.md +++ /dev/null @@ -1,88 +0,0 @@ -# Agent Note: Apply patch 文件编辑 - -Status: proposed - -[English](2026-09-28-apply-patch-file-editing.md) | 中文 - -## 问题 - -模型编辑多个文件或相隔较远的区域时,需要多次字面量编辑调用或一段 shell 脚本。Shell 和 Python 编辑不会向现有文件工具采集路径暴露受影响文件,因此没有 Git 的工作目录无法可靠地在轮次 Review tab 中展示这些修改。补丁工具可以在一次调用中表达相关编辑,并在修改前识别所有受影响路径。#5121 先实现工具再评测效果;#4556 提供了高效使用文件工具的更广泛动机。 - -## 提案 - -新增 `apply_patch` 工具,支持文本文件的创建、更新、删除和移动,以及一次调用中的多文件、多 hunk 修改。采用 Codex 补丁语法,复用现有文件系统能力、观察策略、沙箱策略和工具执行生命周期。将解析与路径提取放在共享的纯模块中,使执行与 Review 采集对同一补丁保持一致理解。 - -Review 工作仅限于在修改前采集工具涉及的路径,以及添加必要的组合或配置项。复用现有[工作区变更记录器](../../../../packages/deliverables/workspace-changes/README.zh.md)和 [Review tab](../../../../packages/client/ui-deliverables/README.zh.md),包括其 diff 类型和展示逻辑。移动可以显示为删除加创建。重命名专用展示、Review 持久化存储、远程采集,以及采集限制或失败策略的调整均不在本提案范围内。 - -### 已确认的设计选择 - -以下设计选择已获确认。完整工具仍处于提案阶段;纯解析器和文本匹配器已在 [dsh-fs-patch](../../../../packages/fs/fs-patch/README.zh.md) 中实现,以 Codex `rust-v0.158.0` 为语法和匹配参照;受保护的文件系统操作已在 [dsh-fs](../../../../packages/fs/fs/README.zh.md) 及其提供方实现。预检与顺序执行器已在 [dsh-tool-fs](../../../../packages/fs/tool-fs/README.zh.md) 中实现。包 README 维护支持行为与排除项;工具注册与呈现仍处于提案阶段。 - -| 主题 | 已确认方案 | 实现规范 | -|---|---|---| -| 输入 | 使用包含 `patch` 字符串的 JSON 参数;适用时复用文件系统权限字段。 | 最终参数 schema、启用方式,以及有输出上限的结果字段。 | -| 语法 | `*** Begin Patch`、`*** End Patch`、`*** Add File:`、`*** Update File:`、`*** Delete File:`、`*** Move to:`、hunk 标记和 `*** End of File`。 | 选择上游 Codex 版本,列出支持形式、非法输入及排除项。 | -| 匹配 | 遵循固定版本 Codex 的解析器和匹配器。 | 核对参照实现的精确匹配、空白容错、Unicode 归一化、重复上下文、搜索顺序、空 hunk 和 EOF 行为;每项记录预期输出或错误。 | -| 文件系统策略 | 保留已挂载的观察与沙箱策略;内部预检读取不算模型观察。 | 在这些策略下细化更新、删除和移动的保护条件与目标冲突,以及路径别名、重复路径、跨提供方移动和换行符保留规则。 | -| 失败 | 先预检整个补丁,再按顺序提交;首次失败即停止,报告实际完成、失败和未执行的操作;不提供整个补丁回滚。 | 报告各操作提交点、取消与部分移动。语法/预检抛错;提交值保留 `isError: false`,确保已知部分 diff 元数据被记录。 | -| 启用 | 通过组合配置启用以进行实现和评测,同时保留现有文件工具。 | `tool-fs.enableApplyPatch` 默认为 false;评测 overlay 启用注册与提示,默认 profile 保持关闭。 | -| Review | 复用现有整文件采集和 diff 展示,不改变限制与生命周期。 | `workspace-changes.mutationPaths` 使用 `parsePatch` 与 `collectMutationPaths`;同一有序 pre-execute 队列在写入前采集移动两端,按规范化路径去重并保留每轮首次基线。语法无效时不采集;读取不发出 `fs/observed`。轮次结束比较只列实际净变化。 | - -补丁语法与文本匹配遵循选定的 Codex 版本。先读后改、版本新鲜度检查和沙箱限制仍属于 Harness 部署策略。兼容性矩阵记录这些策略差异和已核实的参照行为,是实现规范,不再将匹配策略列为待选择项。 - -### 开发计划 - -我们按顺序实现并验证各步骤。解析器提供匹配、执行与采集共用的记录。步骤 1–6 完成后进行步骤 7 的集成验收;步骤 8 的评测在验收后开始。 - -1. **实现补丁解析与受影响路径收集。** 新增 `packages/fs/fs-patch` 纯库,不依赖工具、Session 或文件系统提供方。固定 Codex 语法参照并保留适用的许可声明。定义可序列化的操作和 hunk;实现携带原始输入行号错误的 `parsePatch(patch)`,以及包含移动两端的 `collectMutationPaths(operations)`。保留操作顺序和重复操作,只对收集的路径字符串去重。不进行文件系统 I/O,覆盖单文件、多文件、多 hunk、移动、非法输入及参照语法用例。 - -2. **实现 hunk 匹配与文本更新。** 在同一纯库中将解析出的 hunk 应用于调用方提供的文本。精确匹配、空白容错、Unicode 归一化、重复上下文、搜索顺序及 EOF 行为遵循固定版本的 Codex 匹配器。覆盖 LF/CRLF、缺少末尾换行、空文件与无法匹配的 hunk;记录有意差异和预期结果。文件读取、权限检查和提交不属于此步骤。 - -3. **补齐受保护的文件系统操作。** 当前[文件系统服务](../../../../packages/fs/fs/README.zh.md)提供文本写入和字面量编辑,没有删除或移动操作。只添加选定补丁设计需要的原语,保留提供方负责的版本新鲜度检查和单文件原子发布。同时更新本地、沙箱和 [SSH 文件系统](../../../../packages/ssh/fs-ssh/README.zh.md)实现,以及受影响的 RPC helper/schema 消费方。移动涉及两个路径,必须明确定义锁、源与目标保护条件及失败结果。退出条件:旧版本、受限路径、目标冲突和中断操作都留下约定的磁盘状态;不宣称多文件事务。 - -4. **实现补丁执行。** 解析并去重规范化目标,获取策略意图,在修改前预检语法、权限、匹配及目标规则。每次由提供方提交时重新检查版本新鲜度;预检不能消除后续竞态或 I/O 失败。按顺序执行,在实际修改后更新观察状态,并在取消或后续失败时保留已完成操作的事实。退出条件:结果元数据和精简模型输出与磁盘状态一致,包括部分完成的移动;执行器不通过 shell 或直接写 Host 文件绕过文件系统提供方。 - -5. **暴露并呈现工具。** 通过常规插件 effect 和现有工具/PTC 路径注册 `apply_patch`,保持 agent loop 不变。将参数规则放入 schema,说明何时选用工具,并提供简短的纠错信息。使用现有结果元数据和呈现机制设计 Host presenter 与 Web 工具调用展示。添加选定的启用/配置项,对缺失依赖给出明确错误。退出条件:目标 profile 能声明并执行工具,未启用的 profile 保持一致,所有模型可见输出均可由 Session 日志重建。 - -6. **接入现有 Review 采集。** 记录器的[修改路径提取](../../../../packages/deliverables/workspace-changes/src/capture.ts)目前只识别固定工具,并返回单一路径。为 `apply_patch` 增加最小的生产端适配,从共享解析器枚举全部受影响路径,包括移动的源与目标。在任何写入前等待基线采集完成,并保留每个路径在轮次中的首次采集。复用轮次结束时对实际字节的采集与比较。退出条件:无 Git 目录能展示所有支持范围内存在净变化的文件,重复编辑形成从首次修改前到最终状态的 diff,失败或未执行操作不产生虚假变更,Review 展示代码不变。这里需要小幅修改路径提取;当前仅靠配置不能实现。 - -7. **验证组合能力并补齐文档。** 将定向解析器、提供方和工具测试,与通过已发布 profile 的录制 Session 快照、无 Git 目录中的现有 Review 流程结合。覆盖成功修改、预检拒绝、部分执行、取消及现有工具回归。如果快照测试框架无法表达必要路径,在同一实现中补齐支持。更新受影响的双语 README、JSDoc、子系统参考和生成目录;确认声明的持久化类型变更。遵循[测试策略](../../../../docs/testing.zh.md)和[按范围选择检查的规则](../../../skills/dsh-pre-push-checks/SKILL.md)。退出条件:下方验收矩阵通过,无法获得的真实提供方验证证据明确列出。 - -8. **实现后评测。** 使用现有文件工具与 `apply_patch` 分别执行同一组典型编辑任务,控制模型、仓库状态和任务指令。测量最终文件正确性、任务成功率、请求/prompt/输出 token、模型步骤、工具调用、重试、延迟和现有 Review 覆盖情况。报告失败及收益,包含首个请求的 prompt 成本。退出条件:形成可复现的比较与默认启用建议;不预设改进,也不在本功能中建设通用评测平台。 - -### Review 验收范围 - -Review 使用首次修改前与轮次结束时的完整文件采集;工具调用的 hunk 和补丁文本不能代替这些字节。测试应同时覆盖无 Git 仓库及 Git 不可用的环境,避免 Git 覆盖掩盖工具路径漏采集。文件在同一轮次中先创建后删除,或修改后完全还原,没有净变化,可以不产生文件行。 - -[现有 Review 决策](../../../../packages/deliverables/workspace-changes/README.zh.md)负责大小、数量、时间限制、采集错误行为、会话生命周期及支持位置。本功能沿用这些规则。验收覆盖 Session 可用期间支持范围内的 Host 文件,不承诺持久化或 SSH Review。补齐 SSH 文件系统提供方的操作是为了保持文件系统 API 完整,不代表支持远程 Review。 - -## 考虑过的替代方案 - -**继续通过 shell 或 Python 应用补丁。** 无 Git 文件变更仍然缺少可预先确定的修改路径列表,也无法提供所需的模型文件编辑工具。 - -**复用 Codex 标记,自行实现严格匹配器。** 这可以减少初期实现工作,但会让熟悉的补丁以不同方式失败。已确认设计遵循固定版本 Codex 的解析器和匹配器,并明确记录 Harness 文件系统策略的差异。 - -**让整个补丁具备事务性。** 跨文件回滚需要恢复状态,并可能覆盖并发的外部编辑。预检加顺序提交可以提前拒绝错误,并提供明确的部分结果,无需承诺回滚。 - -**添加工具时同时扩展 Review。** 重命名 UI、持久化存储、远程采集和新采集失败策略是独立的产品决策。现有采集与 diff 渲染足以支持本次范围内的工具接入。 - -## 验收标准 - -| 领域 | 必需证据 | -|---|---| -| 文本操作 | 新增、更新、删除、移动、多文件和多 hunk 产生预期最终字节;语法与匹配差异有记录。 | -| 受保护的修改 | 未观察或已过期的源文件、受限路径及目标冲突遵循选定策略;预检拒绝不发生写入。 | -| 失败与取消 | 前序提交后的失败报告全部已完成修改和待执行操作;磁盘状态与输出一致。 | -| 无 Git Review | 现有 Review 在轮次结束时展示支持范围内的净变化,包含移动两端对应的现有文件条目;不改变展示逻辑。 | -| 工具体验 | 普通调用和 PTC 使用注册工具;精简输出、错误、工具调用展示与 Session 快照一致。 | -| 启用依据 | 实现后的比较先报告正确性和总工作量,再建议扩大启用范围。 | - -## 风险 - -上游匹配可能较宽松,也可能随版本变化。固定参照版本,并用兼容性 fixture 核对其行为;修复与参照实现不一致的意外差异。任何匹配策略调整都必须记录为已确认设计的变更。复制上游代码还需要审查许可证和依赖。 - -预检成功后仍可能发生版本冲突、取消或存储失败。提供方保护条件和准确的部分结果必须在这些失败下得到保留,尤其是移动;此处测试失败会阻止工具验收。 - -路径提取可能偏离执行行为或遗漏移动的一端。在支持 Review 的 profile 中启用工具前,必须共享解析结果并验证完整的无 Git 路径。 - -本提案保留[文件系统拆分](../../../../packages/fs/fs/README.zh.md)、[观察事件策略](../../../../packages/fs/fs-observation-policy/README.zh.md)、[文件系统沙箱](../../../../packages/fs/fs-sandbox/README.zh.md)和[轮次变更文件卡片](../../../../packages/deliverables/workspace-changes/README.zh.md)的决策依据。它新增编辑能力,不替代上述决策。 diff --git a/packages/fs/fs-patch/README.i18n.yaml b/packages/fs/fs-patch/README.i18n.yaml index 3f5366ec21..3d99efd4cb 100644 --- a/packages/fs/fs-patch/README.i18n.yaml +++ b/packages/fs/fs-patch/README.i18n.yaml @@ -30,8 +30,8 @@ en: c843cf32d16ab46f zh: a2cabd9293705cc6 /dsh-fs-patch/further-exploration: - en: e454a5069195a7ac - zh: dcab5cbc4a6f78f1 + en: 95d956173414da4e + zh: 29c6d0306a4af646 /dsh-fs-patch/known-limitations-and-deferred-work: en: fcc76944c497c7c7 zh: 307ad5bd3afe8e6f diff --git a/packages/fs/fs-patch/README.md b/packages/fs/fs-patch/README.md index d0919f1c56..b8c7f7ea10 100644 --- a/packages/fs/fs-patch/README.md +++ b/packages/fs/fs-patch/README.md @@ -95,7 +95,7 @@ The batch parser builds syntax records without a Session or provider dependency. ## Further Exploration - [Filesystem package group](../README.md) — providers, policies, and file tools. -- [Apply patch proposal](../../../.agents/notes/proposed/feature/2026-09-28-apply-patch-file-editing.md) — implementation sequence and Review scope. +- [Apply patch proposal](../../../.agents/notes/implemented/feature/2026-09-28-apply-patch-file-editing.md) — implementation sequence and Review scope. ## Known Limitations and Deferred Work diff --git a/packages/fs/fs-patch/README.zh.md b/packages/fs/fs-patch/README.zh.md index 897d3b33ab..c4bd2e2258 100644 --- a/packages/fs/fs-patch/README.zh.md +++ b/packages/fs/fs-patch/README.zh.md @@ -95,7 +95,7 @@ if (operation?.kind === 'update') { ## 进一步探索 - [文件系统包组](../README.zh.md)——提供方、策略和文件工具。 -- [Apply patch 提案](../../../.agents/notes/proposed/feature/2026-09-28-apply-patch-file-editing.zh.md)——实现顺序与 Review 范围。 +- [Apply patch 提案](../../../.agents/notes/implemented/feature/2026-09-28-apply-patch-file-editing.zh.md)——实现顺序与 Review 范围。 ## 已知限制与后续工作