Skip to content

fix(tools): treat no-op writes and edits as terminal tool-loop failures (fixes #96983)#97004

Closed
zw-xysk wants to merge 2 commits into
openclaw:mainfrom
zw-xysk:fix/issue-96983-noop-write-edit
Closed

fix(tools): treat no-op writes and edits as terminal tool-loop failures (fixes #96983)#97004
zw-xysk wants to merge 2 commits into
openclaw:mainfrom
zw-xysk:fix/issue-96983-noop-write-edit

Conversation

@zw-xysk

@zw-xysk zw-xysk commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Fixes #96983.

When the write tool is called with content identical to the existing file, or the edit tool 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

  • write tool: readOriginalWriteState already detects identical content via size + content comparison. Previously, the tool wrote the file anyway and returned success. Now it returns a structured No changes made result before writing, giving the tool-loop a clear terminal signal.
  • edit tool: applyEditsToNormalizedContent (in edit-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, return No changes made result before attempting write.
  • src/agents/sessions/tools/edit.ts: In the catch block, detect the No changes made error from edit-diff.ts and 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

  • Unit tests: node scripts/run-vitest.mjs run src/agents/sessions/tools/write.test.ts src/agents/sessions/tools/edit.test.ts — 13/13 passed
  • Broader regression: node 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 SAME: No changes made to demo.txt. File content is identical.
  file unchanged: true

Write tool — different content (no false positive):

WRITE DIFFERENT: Successfully wrote 12 bytes to demo.txt
  file updated: true

Edit tool — oldText === newText:

EDIT NO-OP: No changes made to ... The replacement produced identical content.
  file unchanged: true

Edit tool — real change (no false positive):

EDIT REAL CHANGE: Successfully replaced 1 block(s) in ...
  file updated: true
  • ✅ Write to existing file with identical content → no-op, file unchanged
  • ✅ Write with different content → normal success
  • ✅ Write to new file → normal success
  • ✅ Edit with identical old/new text → no-op, file unchanged
  • ✅ Edit with real changes → normal replace success

What was not tested: E2E agent loop with LLM calling write/edit (requires real model inference).

  • AI-assisted

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]>
@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S labels Jun 26, 2026
@zw-xysk

zw-xysk commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper

clawsweeper Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed June 26, 2026, 7:00 AM ET / 11:00 UTC.

Summary
The PR changes the built-in write/edit agent tools and their tests so no-op file mutations return no-op text results instead of rewriting or throwing.

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 terminate: true result to stop another model turn.

Review metrics: 1 noteworthy metric.

  • Terminal no-op paths: 2 added, 0 set terminate. The PR adds no-op return paths for write and edit, but neither sets the field the agent loop uses to stop.

Stored data model
Persistent data-model change detected: serialized state: src/agents/sessions/tools/edit.test.ts, serialized state: src/agents/sessions/tools/edit.ts, serialized state: src/agents/sessions/tools/write.test.ts, serialized state: src/agents/sessions/tools/write.ts, unknown-data-model-change: src/agents/sessions/tools/edit.ts, unknown-data-model-change: src/agents/sessions/tools/write.ts. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #96983
Summary: This PR and the sibling open PR are candidate fixes for the same no-op file mutation loop issue.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🦪 silver shellfish
Patch quality: 🧂 unranked krab
Result: blocked until stronger real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Add terminate: true to the no-op write/edit results and assert it in tests.
  • [P1] Add or cite proof that the agent loop stops after the no-op result, with private paths and tokens redacted.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: The PR body includes copied live tool output, but it does not prove the agent loop received a terminal result and stopped retrying; add redacted terminal output/logs or a linked artifact and update the PR body for re-review.

Risk before merge

  • [P1] Merging as-is would change no-op write/edit output without actually making those no-op results terminal, so agents may still retry the same mutation.
  • [P1] The PR changes same-content write from an idempotent success-shaped result to a no-op result; maintainers should intentionally accept that compatibility change once the terminal signal is fixed.

Maintainer options:

  1. Add The Terminal Flag Before Merge (recommended)
    Set terminate: true on the no-op write/edit results and update tests to assert the machine-readable terminal signal.
  2. Accept Text-Only No-Op Results
    Maintainers could intentionally accept text-only no-op output, but that leaves the linked loop-stop bug unresolved and should not close the issue.

Next step before merge

  • [P1] The contributor needs to fix the terminal signal and add central-behavior proof before this external PR can be merge-ready; automation should not paper over the proof gate.

Security
Cleared: The diff only touches local agent tool runtime code and focused tests; it does not add dependencies, scripts, workflows, downloads, permissions, or secret handling.

Review findings

  • [P2] Set the terminal flag on no-op tool results — src/agents/sessions/tools/write.ts:407-419
Review details

Best possible solution:

Return the existing terminate: true signal for no-op write/edit results and assert it in focused tool tests or an agent-loop regression test before considering this PR merge-ready.

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 terminate: true result to stop another model turn.

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:

  • [P2] Set the terminal flag on no-op tool results — src/agents/sessions/tools/write.ts:407-419
    The agent loop only stops after a tool batch when every finalized result has result.terminate === true (packages/agent-core/src/agent-loop.ts). These new no-op write/edit returns only change the text content and omit terminate, so the model can still receive a normal successful tool result and retry the same no-op mutation.
    Confidence: 0.95

Overall correctness: patch is incorrect
Overall confidence: 0.95

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against c05d0d5bbfb0.

Label changes

Label justifications:

  • P2: The PR targets a normal-priority agent tool-loop bug with limited but real user impact.
  • merge-risk: 🚨 compatibility: The PR changes observable write/edit result semantics for no-op file mutations, which may affect callers that treated same-content writes as success.
  • merge-risk: 🚨 session-state: The patch affects the agent tool-loop state path where a non-terminal result can keep an agent retrying without progress.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🦪 silver shellfish and patch quality is 🧂 unranked krab.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR body includes copied live tool output, but it does not prove the agent loop received a terminal result and stopped retrying; add redacted terminal output/logs or a linked artifact and update the PR body for re-review.
Evidence reviewed

PR surface:

Source +61, Tests +74. Total +135 across 4 files.

View PR surface stats
Area Files Added Removed Net
Source 2 70 9 +61
Tests 2 75 1 +74
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 4 145 10 +135

Acceptance criteria:

  • [P1] node scripts/run-vitest.mjs src/agents/sessions/tools/write.test.ts src/agents/sessions/tools/edit.test.ts.

What I checked:

  • Repository policy read: Root AGENTS.md and scoped src/agents/AGENTS.md were read fully; their review guidance required checking the tool runtime path, caller/callee behavior, sibling fixes, and best-fix shape rather than reviewing the diff alone. (AGENTS.md:8, c05d0d5bbfb0)
  • Current main write no-op path: Current main computes readOriginalWriteState and can detect state: "same", but createWriteToolDefinition proceeds to ops.writeFile and returns Successfully wrote, so the linked bug is still real on main. (src/agents/sessions/tools/write.ts:395, c05d0d5bbfb0)
  • Terminal loop contract: The agent loop stops a tool batch only when every finalized tool result has result.terminate === true; plain text content is not a terminal signal. (packages/agent-core/src/agent-loop.ts:768, c05d0d5bbfb0)
  • Existing contract test: The existing agent-loop test asserts that the runtime avoids another model turn only when a finalized tool result explicitly terminates. (packages/agent-core/src/agent-loop.test.ts:726, c05d0d5bbfb0)
  • PR diff misses terminal field: The PR adds no-op write/edit returns with content and details: undefined, but no terminate: true, so the new paths do not satisfy the loop contract. (src/agents/sessions/tools/write.ts:407, 5265d8e32de6)
  • Sibling PR is related but not safe supersession: The sibling open PR targets the same canonical issue and adds terminate: true, but its current ClawSweeper review has unresolved findings, so it is related context rather than a safe replacement to close this PR against. (7caf70222b35)

Likely related people:

  • zhang-guiping: Blame and git log -S for the central write/edit/agent-loop symbols point to broad commit 5fccf06; confidence is low because the commit appears broad rather than a narrow feature introduction. (role: recent current-main file author; confidence: low; commits: 5fccf06b5f2b; files: src/agents/sessions/tools/write.ts, src/agents/sessions/tools/edit.ts, src/agents/sessions/tools/edit-diff.ts)
  • Ayaan Zaidi: git show -s lists Ayaan Zaidi as committer for broad commit 5fccf06 that carries the central lines in this checkout. (role: recent current-main committer; confidence: low; commits: 5fccf06b5f2b; files: src/agents/sessions/tools/write.ts, src/agents/sessions/tools/edit.ts, packages/agent-core/src/agent-loop.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. labels Jun 26, 2026
@clawsweeper clawsweeper Bot mentioned this pull request Jun 26, 2026
- 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]>
@zw-xysk

zw-xysk commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: S status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(tools): treat no-op edits and identical writes as terminal tool-loop failures

1 participant