Skip to content

fix(write-to-file): address partial filesystem error review - #1066

Open
easonLiangWorldedtech wants to merge 6 commits into
Zoo-Code-Org:mainfrom
easonLiangWorldedtech:fix/pr-727-review
Open

fix(write-to-file): address partial filesystem error review#1066
easonLiangWorldedtech wants to merge 6 commits into
Zoo-Code-Org:mainfrom
easonLiangWorldedtech:fix/pr-727-review

Conversation

@easonLiangWorldedtech

@easonLiangWorldedtech easonLiangWorldedtech commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR addresses all review comments from PR #727 regarding the write_to_file filesystem error handling fix.

Closes: #703 #727

Changes

1. Task.ts — finalizePartialToolAsk() improvements

  • Search by type, not just position: Instead of only using at(-1) to find the last message, now searches for any partial tool ask matching the expected pattern (type === "ask", ask === "tool", partial === true). This prevents issues where async gaps between task.ask("tool", ...) and the catch block could insert new messages.
  • Text matching support: Added text comparison to further ensure we're finalizing the correct message, not just any recent tool ask.
  • Persistence: Now persists partial=false through the proper persistence path (not just webview update), ensuring state survives reload/resume — addressing CodeRabbit's actionable comment.
  • Error resilience: Wrapped the updateClineMessage call in try/catch so if it fails, we don't interrupt the error flow.

2. WriteToFileTool.ts — Review fixes

  • Mistake counter order (edelauna feat: support OAuth 2.1 for streamable-http MCP servers #1): Moved consecutiveMistakeCount = 0 to after createDirectoriesForFile succeeds, preventing permanent read-only paths from zeroing the runaway-loop guard on every EROFS attempt.
  • Per-task partial stream failure (edelauna Roo to zoo upgrade #2): Changed partialStreamFailed from a singleton instance flag to a per-taskId map (Map<string, boolean>), preventing cross-task interference when multiple sessions run concurrently.
  • Precise finalize: Updated finalizePartialToolAsk() call in the catch block to use the improved search logic that finds the correct partial ask by type and text pattern.

3. writeToFileTool.spec.ts — New regression tests

4. Task.spec.ts — Thin layer test for finalizePartialToolAsk()

  • Directly tests that Task.finalizePartialToolAsk() correctly finds and finalizes partial tool asks even when they're not the last message in the array.
  • Verifies persistence through updateClineMessage is called.
  • Addresses edelauna feat(ci): add code coverage pipeline and E2E mocking with aimock #4 (mock replacement didn't verify actual mutation).

Review Comments Addressed

# Reviewer Comment Status
1 CodeRabbit Persist finalized tool-ask state in finalizePartialToolAsk ✅ Fixed — now persists via updateClineMessage
2 edelauna Mistake counter zeroed before call that can throw ✅ Fixed — moved after successful directory creation
3 edelauna Singleton partialStreamFailed has cross-task risk ✅ Fixed — changed to per-taskId Map
4 edelauna at(-1) could find wrong message in async gap ✅ Fixed — now searches by type + text pattern
5 edelauna Tests don't verify actual partial=false mutation ✅ Fixed — added thin layer test on Task.finalizePartialToolAsk()

Testing

  • Unit tests: 94 passed / 8 skipped (all existing + new regression tests)
  • Lint: All changed files pass ESLint with zero warnings
  • Commit hooks: Full repo lint passes

Related

Summary by CodeRabbit

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of live tool prompts when file streaming fails, including reliable finalization of matching partial prompts.
    • Reduced duplicate error notifications through more consistent cleanup and recovery.
    • Improved task-specific recovery for filesystem failures, including safer diff-view resets and directory handling.
  • Tests
    • Expanded regression coverage for partial prompt finalization, error handling, task isolation, and cleanup.
    • Silenced noisy test logging for cleaner test output.

…oo-Code-Org#703)

- Remove unguarded createDirectoriesForFile call from handlePartial; the call
  was a redundant optimization (execute() already creates dirs before open())
  and its unguarded throw caused the partial-block advancement gate in
  presentAssistantMessage to be skipped, permanently stalling the agent loop
- Move createDirectoriesForFile in execute() inside the try block so EROFS/
  EACCES errors route through handleError with diffViewProvider.reset() cleanup
  and consecutive-mistake counting, rather than escaping unhandled
- Add regression tests covering both failure paths
…_file filesystem failure

When write_to_file hits a filesystem error (EROFS/EACCES) the streaming
phase left the "Zoo wants to edit this file" spinner running, surfaced the
same error twice (handlePartial + execute), and spawned a new partial tool
message on every subsequent streaming delta.

- Add Task.finalizePartialToolAsk() to finalize a partial tool ask without
  blocking on user input, dismissing the spinner.
- handlePartial swallows streaming filesystem errors (after finalizing the
  spinner and resetting the diff view) so only the authoritative execute()
  error is reported, eliminating the duplicate error bubble.
- Track partialStreamFailed so later streaming deltas short-circuit instead
  of re-attempting and spawning repeated partial tool messages.
- Add regression tests for spinner finalization, single-error reporting, and
  no repeated partial messages.
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Task now finalizes matching partial tool asks by searching prior messages. WriteToFileTool tracks streaming failures per task instance, centralizes directory-creation errors, suppresses repeated updates, and cleans up partial asks and diff views.

Changes

Partial tool cleanup

Layer / File(s) Summary
Partial ask finalization
src/core/task/Task.ts, src/core/task/__tests__/Task.spec.ts
finalizePartialToolAsk searches backward for matching partial tool asks, persists completed messages, updates the webview, and tests matching and non-matching text.
Streaming failure handling
src/core/tools/WriteToFileTool.ts
Tracks failures and path state per task instance, moves directory creation into execute, prevents repeated partial updates, and finalizes and resets state after failures.
Failure regression coverage
src/core/tools/__tests__/writeToFileTool.spec.ts, src/core/task/__tests__/Task.throttle.test.ts
Tests deferred directory creation, partial cleanup, single error reporting, task isolation, filesystem errors, and console spy restoration.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant WriteToFileTool
  participant DiffViewProvider
  participant Task
  participant ErrorHandler
  WriteToFileTool->>DiffViewProvider: Stream diff open/update
  DiffViewProvider-->>WriteToFileTool: Filesystem failure
  WriteToFileTool->>Task: finalizePartialToolAsk(text?)
  WriteToFileTool->>DiffViewProvider: Reset diff view
  WriteToFileTool->>WriteToFileTool: Record task failure and skip later deltas
  WriteToFileTool->>ErrorHandler: Handle execute-phase error once
Loading

Possibly related PRs

Suggested reviewers: taltas

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary change: fixing partial filesystem error handling in write_to_file.
Description check ✅ Passed The description covers the linked issues, implementation changes, testing, and review feedback, though it does not reproduce every template heading.
Linked Issues check ✅ Passed The changes address issue #703 by recovering from filesystem failures, finalizing partial tool asks, and preventing the agent loop from stalling.
Out of Scope Changes check ✅ Passed The changes are focused on write_to_file error recovery, partial-task state handling, regression tests, and related test stability.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/core/tools/WriteToFileTool.ts`:
- Around line 276-300: Update the catch block in handlePartial so the
task.diffViewProvider.reset() cleanup is wrapped in a nested try/catch. Swallow
or log any reset failure while preserving the existing
partialStreamFailuresByTaskId marking and finalizePartialToolAsk cleanup,
ensuring no exception escapes handlePartial.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 468c8910-8760-4b70-9c62-a3381b90840b

📥 Commits

Reviewing files that changed from the base of the PR and between 569b43d and 0b837ea.

📒 Files selected for processing (4)
  • src/core/task/Task.ts
  • src/core/task/__tests__/Task.spec.ts
  • src/core/tools/WriteToFileTool.ts
  • src/core/tools/__tests__/writeToFileTool.spec.ts

Comment thread src/core/tools/WriteToFileTool.ts
@easonLiangWorldedtech

Copy link
Copy Markdown
Contributor Author

Updated the branch with commit 0966556d5 (fix(write-to-file): address partial filesystem error review) to address the remaining review/CI feedback.

Summary of fixes:

  • Finalized partial tool asks more safely in Task.finalizePartialToolAsk():

    • searches backward instead of relying on the last message
    • supports matching by partial ask text to avoid closing the wrong spinner
    • persists partial=false to task messages so reload/resume state is correct
    • awaits the webview update cleanup before returning to avoid pending async logging during test teardown
  • Hardened WriteToFileTool streaming state:

    • moved consecutiveMistakeCount = 0 until after parent directory creation succeeds
    • made partial stream failure tracking task-scoped
    • made path stabilization tracking task-scoped as well, so concurrent tasks with the same path no longer share singleton stabilization state
    • clears only the current task’s partial state on terminal success/error
    • wraps partial-failure diffViewProvider.reset() cleanup so reset errors are logged/swallowed and cannot escape handlePartial()
  • Added/updated regression coverage in writeToFileTool.spec.ts:

    • directory creation failure does not reset the mistake counter
    • stream failure state is isolated per task
    • same-path stabilization is isolated per task
    • reset failures during partial cleanup do not call handleError or escape partial handling
  • Added direct coverage for Task.finalizePartialToolAsk() in Task.spec.ts, including non-last partial ask persistence and text mismatch behavior.

  • Fixed the CI coverage unhandled rejection seen from Task.throttle.test.ts by mocking teardown console.log output from Task.dispose(), preventing Vitest worker teardown from closing while onUserConsoleLog is pending.

Validation run locally:

  • npx vitest run --coverage core/task/__tests__/Task.throttle.test.ts core/task/__tests__/Task.spec.ts core/tools/__tests__/writeToFileTool.spec.ts
    • 3 files passed
    • 115 passed / 8 skipped
    • no unhandled errors reproduced
  • pnpm --dir src exec eslint --prune-suppressions --max-warnings=0 core/task/Task.ts core/task/__tests__/Task.spec.ts core/task/__tests__/Task.throttle.test.ts core/tools/WriteToFileTool.ts core/tools/__tests__/writeToFileTool.spec.ts
  • full repo lint passed via the commit hook
  • git diff --check passed

@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.00000% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/core/tools/WriteToFileTool.ts 96.15% 0 Missing and 2 partials ⚠️
src/core/task/Task.ts 87.50% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/core/tools/WriteToFileTool.ts (1)

221-235: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Guarantee task-state cleanup when diff reset fails.

diffViewProvider.reset() can reject. On the success path that enters the outer catch and falsely reports a completed write as failed; on either path it prevents resetTaskPartialState(task), leaving failure/path entries behind. Suppress/log reset failures and move task-state cleanup into a finally; also clear it before the approval-declined returns.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/tools/WriteToFileTool.ts` around lines 221 - 235, The write handling
flow around diffViewProvider.reset and resetTaskPartialState must always clean
task state even when diff reset fails. Suppress or log reset errors, move
resetTaskPartialState(task) into a finally block, and ensure it runs before
approval-declined returns while preserving successful writes and existing error
handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/core/tools/WriteToFileTool.ts`:
- Around line 221-235: The write handling flow around diffViewProvider.reset and
resetTaskPartialState must always clean task state even when diff reset fails.
Suppress or log reset errors, move resetTaskPartialState(task) into a finally
block, and ensure it runs before approval-declined returns while preserving
successful writes and existing error handling.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d3ccf322-b3be-4471-9c3d-8c7d16c65256

📥 Commits

Reviewing files that changed from the base of the PR and between 0b837ea and 0966556.

📒 Files selected for processing (5)
  • src/core/task/Task.ts
  • src/core/task/__tests__/Task.spec.ts
  • src/core/task/__tests__/Task.throttle.test.ts
  • src/core/tools/WriteToFileTool.ts
  • src/core/tools/__tests__/writeToFileTool.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/core/tools/tests/writeToFileTool.spec.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/core/tools/WriteToFileTool.ts (1)

239-241: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant cleanup: the inner finally already runs before the catch body.

resetTaskPartialState(task) executes here on every path, including the throwing one, so the second call in the catch's finally (Line 252) is a no-op repeat. A single outer try { ... } catch { ... } finally { this.resetTaskPartialState(task) } expresses the same guarantee with one less nesting level.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/tools/WriteToFileTool.ts` around lines 239 - 241, Remove the
redundant inner finally cleanup around the WriteToFileTool operation and
restructure the surrounding try/catch so a single outer finally calls
resetTaskPartialState(task). Preserve the existing catch behavior while ensuring
resetTaskPartialState executes exactly once on every path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/core/tools/WriteToFileTool.ts`:
- Around line 247-253: Guard both Task.finalizePartialToolAsk calls in
src/core/tools/WriteToFileTool.ts at lines 247-253 and 335-336 with catch
handlers that log failures without rethrowing. Ensure the surrounding cleanup
continues to handle the original write error, reset the diff view via
resetDiffViewAfterWrite, and preserve handlePartial’s no-rethrow contract; apply
the same protection to the overload receiving partialMessage.

---

Nitpick comments:
In `@src/core/tools/WriteToFileTool.ts`:
- Around line 239-241: Remove the redundant inner finally cleanup around the
WriteToFileTool operation and restructure the surrounding try/catch so a single
outer finally calls resetTaskPartialState(task). Preserve the existing catch
behavior while ensuring resetTaskPartialState executes exactly once on every
path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a9ba64ca-936d-4cda-a1bd-549c328f5067

📥 Commits

Reviewing files that changed from the base of the PR and between 0966556 and 16c4d48.

📒 Files selected for processing (2)
  • src/core/tools/WriteToFileTool.ts
  • src/core/tools/__tests__/writeToFileTool.spec.ts

Comment thread src/core/tools/WriteToFileTool.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/core/tools/WriteToFileTool.ts (1)

29-58: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clean up per-task write_to_file partial state on task abort.

handlePartial() can populate partialStreamFailuresByTaskId and update path stabilization state before execute() completes. A cancelled task aborts before its finalize path, so the task-keyed entries can remain on the singleton tool and grow over a session. Add teardown for these task keys, for example from Task.dispose()/abort hooks or a matching abort handler, so abandoned write_to_file streams do not leak state.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/tools/WriteToFileTool.ts` around lines 29 - 58, Add abort/disposal
cleanup for the per-task state maintained by WriteToFileTool, invoking
resetTaskPartialState(task) when a task is cancelled before execute()
finalization. Ensure both partialStreamFailuresByTaskId and
lastSeenPartialPathByTaskId entries are removed for abandoned streams, while
preserving normal completion behavior.
🧹 Nitpick comments (1)
src/core/tools/__tests__/writeToFileTool.spec.ts (1)

613-631: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Restore console.error spy safely against assertion failures.

consoleErrorSpy.mockRestore() is only reached if every preceding expect(...) passes. If any assertion throws first, the spy leaks into later tests, silently swallowing console.error output and potentially masking unrelated failures for the rest of the run.

♻️ Suggested fix
 		it("continues execute error cleanup when finalizing partial ask fails", async () => {
 			const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {})
-			mockedCreateDirectoriesForFile.mockRejectedValue(
-				Object.assign(new Error("EACCES: permission denied, mkdir '/ro'"), { code: "EACCES" }),
-			)
-			mockCline.finalizePartialToolAsk.mockRejectedValue(new Error("finalize failed"))
-
-			await executeWriteFileTool({}, { fileExists: false })
-
-			expect(mockCline.finalizePartialToolAsk).toHaveBeenCalled()
-			expect(mockHandleError).toHaveBeenCalledWith("writing file", expect.any(Error))
-			expect(mockCline.diffViewProvider.reset).toHaveBeenCalled()
-			expect(consoleErrorSpy).toHaveBeenCalledWith(
-				"Error finalizing write_to_file partial tool ask:",
-				expect.any(Error),
-			)
-
-			consoleErrorSpy.mockRestore()
+			try {
+				mockedCreateDirectoriesForFile.mockRejectedValue(
+					Object.assign(new Error("EACCES: permission denied, mkdir '/ro'"), { code: "EACCES" }),
+				)
+				mockCline.finalizePartialToolAsk.mockRejectedValue(new Error("finalize failed"))
+
+				await executeWriteFileTool({}, { fileExists: false })
+
+				expect(mockCline.finalizePartialToolAsk).toHaveBeenCalled()
+				expect(mockHandleError).toHaveBeenCalledWith("writing file", expect.any(Error))
+				expect(mockCline.diffViewProvider.reset).toHaveBeenCalled()
+				expect(consoleErrorSpy).toHaveBeenCalledWith(
+					"Error finalizing write_to_file partial tool ask:",
+					expect.any(Error),
+				)
+			} finally {
+				consoleErrorSpy.mockRestore()
+			}
 		})

Alternatively, add a global afterEach(() => vi.restoreAllMocks()) if one doesn't already exist.

Also applies to: 675-694

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/tools/__tests__/writeToFileTool.spec.ts` around lines 613 - 631,
Ensure the console.error spy in the “continues execute error cleanup when
finalizing partial ask fails” test is restored even when an assertion fails by
using guaranteed cleanup such as a try/finally block. Apply the same safe
restoration to the related test around the second referenced section, or use an
existing suite-wide afterEach cleanup if appropriate.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/core/tools/WriteToFileTool.ts`:
- Around line 29-58: Add abort/disposal cleanup for the per-task state
maintained by WriteToFileTool, invoking resetTaskPartialState(task) when a task
is cancelled before execute() finalization. Ensure both
partialStreamFailuresByTaskId and lastSeenPartialPathByTaskId entries are
removed for abandoned streams, while preserving normal completion behavior.

---

Nitpick comments:
In `@src/core/tools/__tests__/writeToFileTool.spec.ts`:
- Around line 613-631: Ensure the console.error spy in the “continues execute
error cleanup when finalizing partial ask fails” test is restored even when an
assertion fails by using guaranteed cleanup such as a try/finally block. Apply
the same safe restoration to the related test around the second referenced
section, or use an existing suite-wide afterEach cleanup if appropriate.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a9a6f719-f4f2-455a-bc40-296111f9c54e

📥 Commits

Reviewing files that changed from the base of the PR and between 16c4d48 and be0e154.

📒 Files selected for processing (2)
  • src/core/tools/WriteToFileTool.ts
  • src/core/tools/__tests__/writeToFileTool.spec.ts

@github-actions github-actions Bot added the awaiting-review PR changes are ready and waiting for maintainer re-review label Jul 30, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/core/tools/WriteToFileTool.ts (1)

111-125: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Missing-param early returns bypass the new per-task cleanup and error-safe reset.

These two guard clauses return before the try block, so they skip both:

  • the new resetTaskPartialState(task) cleanup that the finally block otherwise always performs, leaving stale lastSeenPartialPathByTaskId/partialStreamFailuresByTaskId entries and a retained abort listener (and Task reference) for this task until it eventually aborts or a global resetPartialState() runs; and
  • the new resetDiffViewAfterWrite wrapper, calling the raw task.diffViewProvider.reset() instead — reintroducing the unguarded-reset risk fixed elsewhere in this PR.

If a prior partial delta already registered abort cleanup / seeded path-stabilization state for this task, a subsequent malformed block (missing path/content) leaves that state stale for the next write_to_file call in the same task.

🛠️ Proposed fix
 		if (!relPath) {
 			task.consecutiveMistakeCount++
 			task.recordToolError("write_to_file")
 			pushToolResult(await task.sayAndCreateMissingParamError("write_to_file", "path"))
-			await task.diffViewProvider.reset()
+			await this.resetDiffViewAfterWrite(task)
+			this.resetTaskPartialState(task)
 			return
 		}
 
 		if (newContent === undefined) {
 			task.consecutiveMistakeCount++
 			task.recordToolError("write_to_file")
 			pushToolResult(await task.sayAndCreateMissingParamError("write_to_file", "content"))
-			await task.diffViewProvider.reset()
+			await this.resetDiffViewAfterWrite(task)
+			this.resetTaskPartialState(task)
 			return
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/tools/WriteToFileTool.ts` around lines 111 - 125, Update the
missing-parameter guards in the write_to_file flow to perform the same per-task
cleanup as the try/finally path by invoking resetTaskPartialState(task), and
replace direct task.diffViewProvider.reset() calls with the
resetDiffViewAfterWrite wrapper. Preserve the existing error recording,
missing-parameter result, and early-return behavior for both relPath and
newContent validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/core/tools/WriteToFileTool.ts`:
- Around line 111-125: Update the missing-parameter guards in the write_to_file
flow to perform the same per-task cleanup as the try/finally path by invoking
resetTaskPartialState(task), and replace direct task.diffViewProvider.reset()
calls with the resetDiffViewAfterWrite wrapper. Preserve the existing error
recording, missing-parameter result, and early-return behavior for both relPath
and newContent validation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 57700e7d-e297-4257-a748-c7d81ed9ecde

📥 Commits

Reviewing files that changed from the base of the PR and between be0e154 and 224690b.

📒 Files selected for processing (2)
  • src/core/tools/WriteToFileTool.ts
  • src/core/tools/__tests__/writeToFileTool.spec.ts

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

Labels

awaiting-review PR changes are ready and waiting for maintainer re-review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Agent loop stalls permanently when write_to_file partial streaming hits a filesystem error (EROFS/EACCES)

3 participants