fix(tools): treat no-op writes and edits as terminal tool-loop failures (fixes #96983)#97004
fix(tools): treat no-op writes and edits as terminal tool-loop failures (fixes #96983)#97004zw-xysk wants to merge 2 commits into
Conversation
When write is called with content identical to the existing file, or when an edit produces unchanged content, the tool now returns a structured no-op result instead of proceeding with the write or throwing an error. This prevents the agent from retrying the same no-op mutation indefinitely. Changes: - write.ts: after readOriginalWriteState detects 'same' content, return 'No changes made' result before writing - edit.ts: catch the 'No changes made' error from edit-diff.ts and return a terminal result instead of re-throwing - Both tools continue to work normally for real changes Fixes openclaw#96983 Signed-off-by: 赵旺0668001248 <[email protected]>
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
Codex review: needs real behavior proof before merge. Reviewed June 26, 2026, 7:00 AM ET / 11:00 UTC. Summary PR surface: Source +61, Tests +74. Total +135 across 4 files. Reproducibility: yes. Source inspection shows current main has no-op write/edit paths, and the loop contract requires an explicit Review metrics: 1 noteworthy metric.
Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest possible solution: Return the existing Do we have a high-confidence way to reproduce the issue? Yes. Source inspection shows current main has no-op write/edit paths, and the loop contract requires an explicit Is this the best way to solve the issue? No. The patch is in the plausible file-tool boundary, but the best fix must set the runtime’s terminal signal rather than only returning no-op text. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against c05d0d5bbfb0. Label changesLabel justifications:
Evidence reviewedPR surface: Source +61, Tests +74. Total +135 across 4 files. View PR surface stats
Acceptance criteria:
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
- Add explicit 'details: undefined' to no-op returns (AgentToolResult requires details) - Fix test type narrowing for 'text' property access on result.content[0] - Keep existing behavior for real changes Fixes openclaw#96983 Signed-off-by: 赵旺0668001248 <[email protected]>
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
What Problem This Solves
Fixes #96983.
When the
writetool is called with content identical to the existing file, or theedittool produces unchanged content, the agent loop treats these as progress or a recoverable failure and retries the same no-op mutation indefinitely. This wastes tokens and confuses users.Why This Change Was Made
writetool:readOriginalWriteStatealready detects identical content via size + content comparison. Previously, the tool wrote the file anyway and returned success. Now it returns a structuredNo changes maderesult before writing, giving the tool-loop a clear terminal signal.edittool:applyEditsToNormalizedContent(inedit-diff.ts) already throws an error when edits produce identical content. Throwing made the agent retry the same edit. Now the error is caught and converted to a no-op result.User Impact
Agents no longer get stuck in loops rewriting identical file content or retrying no-op edits. Real changes and new file creation continue to work normally.
Changes Made
src/agents/sessions/tools/write.ts: After precheck detects identical content, returnNo changes maderesult before attempting write.src/agents/sessions/tools/edit.ts: In the catch block, detect theNo changes madeerror fromedit-diff.tsand return a terminal no-op result instead of re-throwing.src/agents/sessions/tools/write.test.ts: Added 2 regression tests.src/agents/sessions/tools/edit.test.ts: Added 2 regression tests.Evidence
node scripts/run-vitest.mjs run src/agents/sessions/tools/write.test.ts src/agents/sessions/tools/edit.test.ts— 13/13 passednode scripts/run-vitest.mjs run src/agents/sessions/— 382/389 passed (7 pre-existing flaky failures unrelated to this change)Real behavior proof
Environment: Linux, OpenClaw 2026.6.10, Node 24.13.1
Write tool — identical content:
Write tool — different content (no false positive):
Edit tool — oldText === newText:
Edit tool — real change (no false positive):
What was not tested: E2E agent loop with LLM calling write/edit (requires real model inference).