-
Notifications
You must be signed in to change notification settings - Fork 2.8k
fix: create parent directories early in write_to_file to prevent ENOENT errors #9640
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
…NT errors Fixes #9634 When creating a file in a non-existent subdirectory, the write_to_file tool would fail with ENOENT errors because directories were only created later when diffViewProvider.open() was called. Changes: - Add createDirectoriesForFile import from utils/fs - Create directories immediately after determining file doesn't exist in both execute() and handlePartial() methods - Add comprehensive tests for directory creation behavior This ensures parent directories are created before any subsequent file operations that depend on them.
Contributor
Review completed. No issues found - this PR correctly fixes the ENOENT error by creating parent directories early in the write_to_file tool. The implementation is clean, well-tested, and addresses the root cause described in issue #9634. Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues. |
mrubens
approved these changes
Nov 27, 2025
mini2s
added a commit
to zgsm-ai/costrict
that referenced
this pull request
Nov 27, 2025
* fix: include mcpServers in getState() for auto-approval (RooCodeInc#9199) * fix: replace rate-limited badges with badgen.net (RooCodeInc#9200) * Batch settings updates from the webview to the extension host (RooCodeInc#9165) Co-authored-by: Roo Code <[email protected]> * fix: Apply updated API profile settings when provider/model unchanged (RooCodeInc#9208) (RooCodeInc#9210) fix: apply updated API profile settings when provider/model unchanged (RooCodeInc#9208) * fix: migrate Issue Fixer to REST + ProjectsV2 (RooCodeInc#9207) * fix(issue-fixer): migrate to REST for issue/comments and add ProjectsV2; remove Projects Classic mentions * Update .roo/rules-issue-fixer/4_github_cli_usage.xml Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> * Update .roo/rules-issue-fixer/4_github_cli_usage.xml Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> --------- Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> * Migrate conversation continuity to plugin-side encrypted reasoning items (Responses API) (RooCodeInc#9203) * Migrate conversation continuity to plugin-side encrypted reasoning items (Responses API) Summary We moved continuity off OpenAI servers and now maintain conversation state locally by persisting and replaying encrypted reasoning items. Requests are stateless (store=false) while retaining the performance/caching benefits of the Responses API. Why This aligns with how Roo manages context and simplifies our Responses API implementation while keeping all the benefits of continuity, caching, and latency improvements. What changed - All OpenAI models now use the Responses API; system instructions are passed via the top-level instructions field; requests include store=false and include=["reasoning.encrypted_content"]. - We persist encrypted reasoning items (type: "reasoning", encrypted_content, optional id) into API history and replay them on subsequent turns. - Reasoning summaries default to summary: "auto" when supported; text.verbosity only when supported. - Atomic persistence via safeWriteJson. Removed - previous_response_id flows, suppressPreviousResponseId/skipPrevResponseIdOnce, persistGpt5Metadata(), and GPT‑5 response ID metadata in UI messages. Kept - taskId and mode metadata for cross-provider features. Result - ZDR-friendly, stateless continuity with equal or better performance and a simpler codepath. * fix(webview): remove unused metadata prop from ReasoningBlock render * Responses API: retain response id for troubleshooting (not continuity) Continuity is stateless via encrypted reasoning items that we persist and replay. We now capture the top-level response id in OpenAiNativeHandler and persist the assistant message id into api_conversation_history.json solely for debugging/correlation with provider logs; it is not used for continuity or control flow. Also: silence request-body debug logging to avoid leaking prompts. * remove DEPRECATED tests * chore: remove unused Task types file to satisfy knip CI * fix(task): properly type cleanConversationHistory and createMessage args in Task to address Dan's review * chore: add changeset for v3.31.2 (RooCodeInc#9216) * Changeset version bump (RooCodeInc#9217) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <[email protected]> * rename: sliding-window -> context-management; truncateConversationIfNeeded -> manageContext (RooCodeInc#9206) * Fix: Roo Anthropic input token normalization (avoid double-count) (RooCodeInc#9224) * OpenAI Native: gate encrypted_content include; remove gpt-5-chat-latest verbosity flag (fixes RooCodeInc#9225) (RooCodeInc#9231) openai-native: include reasoning.encrypted_content only when reasoningEffort is set; prevent Responses API error on non-reasoning models. types: remove supportsVerbosity from gpt-5-chat-latest to avoid invalid verbosity error. Fixes RooCodeInc#9225 * docs: remove Contributors section from README files (RooCodeInc#9198) Co-authored-by: Roo Code <[email protected]> * Release v3.31.3 (RooCodeInc#9232) * Changeset version bump (RooCodeInc#9233) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <[email protected]> * Add native tool call support (RooCodeInc#9159) Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> * Consistently use Package.name for better support of the nightly app (RooCodeInc#9240) * fix: resolve 400 error with native tools on OpenRouter (RooCodeInc#9238) * fix: change tool_choice from required to auto for native protocol (RooCodeInc#9242) * docs: include PR numbers in release guide (RooCodeInc#9236) * Add enum support to configuration schema (RooCodeInc#9247) * refactor(task): switch to <feedback> wrapper to prevent focus drift after context-management event (condense/truncate) (RooCodeInc#9237) * refactor(task): wrap initial user message in <feedback> instead of <task> to prevent focus drift after context-management Rationale: After a successful context-management event, framing the next user block as feedback reduces model focus drift. Mentions parsing already supports <feedback>, and tool flows (attemptCompletion, responses) are aligned. No change to loop/persistence. * refactor(mentions): drop <task> parsing; standardize on <feedback>; update tests * fix: Filter native tools by mode restrictions (RooCodeInc#9246) * fix: filter native tools by mode restrictions Native tools are now filtered based on mode restrictions before being sent to the API, matching the behavior of XML tools. Previously, all native tools were sent to the API regardless of mode, causing the model to attempt using disallowed tools. Changes: - Created filterNativeToolsForMode() and filterMcpToolsForMode() utility functions - Extracted filtering logic from Task.ts into dedicated module - Applied same filtering approach used for XML tools in system prompt - Added comprehensive test coverage (10 tests) Impact: - Model only sees tools allowed by current mode - No more failed tool attempts due to mode restrictions - Consistent behavior between XML and Native protocols - Better UX with appropriate tool suggestions per mode * refactor: eliminate repetitive tool checking using group-based approach - Add getAvailableToolsInGroup() helper to check tools by group instead of individually - Refactor filterNativeToolsForMode() to reuse getToolsForMode() instead of duplicating logic - Simplify capabilities.ts by using group-based checks (60% reduction) - Refactor rules.ts to use group helper (56% reduction) - Remove debug console.log statements - Update tests and snapshots Benefits: - Eliminates code duplication - Leverages existing TOOL_GROUPS structure - More maintainable - new tools in groups work automatically - All tests passing (26/26) * fix: add fallback to default mode when mode config not found Ensures the agent always has functional tools even if: - A custom mode is deleted while tasks still reference it - Mode configuration becomes corrupted - An invalid mode slug is provided Without this fallback, the agent would have zero tools (not even ask_followup_question or attempt_completion), completely breaking it. * Fix broken share button (RooCodeInc#9253) fix(webview-ui): make Share button popover work by forwarding ref in LucideIconButton - Convert LucideIconButton to forwardRef so Radix PopoverTrigger(asChild) receives a focusable element - Enables Share popover and shareCurrentTask flow - Verified with ShareButton/TaskActions Vitest suites * Add GPT-5.1 models and clean up reasoning effort logic (RooCodeInc#9252) * Reasoning effort: capability-driven; add disable/none/minimal; remove GPT-5 minimal special-casing; document UI semantics; remove temporary logs * Remove Unused supportsReasoningNone * Roo reasoning: omit field on 'disable'; UI: do not flip enableReasoningEffort when selecting 'disable' * Update packages/types/src/model.ts Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> * Update webview-ui/src/components/settings/SimpleThinkingBudget.tsx Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> --------- Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> * fix: make line_ranges optional in read_file tool schema (RooCodeInc#9254) The OpenAI tool schema required both 'path' and 'line_ranges' in FileEntry, but the TypeScript type definition marks lineRanges as optional. This caused the AI to fail when trying to read files without specifying line_ranges. Changes: - Updated read_file tool schema to only require 'path' parameter - line_ranges remains available but optional, matching TypeScript types - Aligns with implementation which treats lineRanges as optional throughout Fixes issue where read_file tool kept failing with missing parameters. * fix: prevent consecutive user messages on streaming retry (RooCodeInc#9249) * feat(openai): OpenAI Responses: model-driven prompt caching and generic reasoning options refactor (RooCodeInc#9259) * revert out of scope changes from RooCodeInc#9252 (RooCodeInc#9258) * Revert "refactor(task): switch to <feedback> wrapper to prevent focus drift after context-management event (condense/truncate)" (RooCodeInc#9261) * Release v3.32.0 (RooCodeInc#9264) * Changeset version bump (RooCodeInc#9265) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <[email protected]> * [FIX] Fix OpenAI Native handling of encrypted reasoning blocks to prevent error when condensing (RooCodeInc#9263) * fix: prevent duplicate tool_result blocks in native protocol mode for read_file (RooCodeInc#9272) When read_file encountered errors (e.g., file not found), it would call handleError() which internally calls pushToolResult(), then continue to call pushToolResult() again with the final XML. In native protocol mode, this created two tool_result blocks with the same tool_call_id, causing 400 errors on subsequent API calls. This fix replaces handleError() with task.say() for error notifications. The agent still receives error details through the XML in the single final pushToolResult() call. This change works for both protocols: - Native: Only one tool_result per tool_call_id (fixes duplicate issue) - XML: Only one text block with complete XML (cleaner than before) Agent visibility preserved: Errors are included in the XML response sent to the agent via pushToolResult(). Tests: All 44 tests passing. Updated test to verify say() is called. * Fix duplicate tool blocks causing 'tool has already been used' error (RooCodeInc#9275) * feat(openai-native): add abort controller for request cancellation (RooCodeInc#9276) * Disable XML parser for native tool protocol (RooCodeInc#9277) * Release v3.32.1 (RooCodeInc#9278) * Changeset version bump (RooCodeInc#9280) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <[email protected]> * refactor: centralize toolProtocol configuration checks (RooCodeInc#9279) * refactor: centralize toolProtocol configuration checks - Created src/utils/toolProtocol.ts with getToolProtocolFromSettings() utility - Replaced all direct vscode.workspace.getConfiguration() calls with centralized utility - Updated 6 files to use the new utility function - All tests pass and TypeScript compilation succeeds * refactor: use isNativeProtocol function from types package * fix: format tool responses for native protocol (RooCodeInc#9270) * fix: format tool responses for native protocol - Add toolResultFormatting utilities for protocol detection - ReadFileTool now builds both XML and native formats - Native format returns clean, readable text without XML tags - Legacy conversation history conversion is protocol-aware - All tests passing (55 total) * refactor: use isNativeProtocol from @roo-code/types Remove duplicate implementation and import from types package instead * fix: prevent duplicate tool_result blocks in native tool protocol (RooCodeInc#9248) * Merge remote-tracking branch 'upstream/main' into roo-to-main * Fix duplicate import (RooCodeInc#9281) * chore(core): remove unused TelemetryEventName import * feat: implement dynamic tool protocol resolution with proper precedence hierarchy (RooCodeInc#9286) Co-authored-by: Roo Code <[email protected]> * web: Roo Code Cloud Provider pricing page and changes elsewhere (RooCodeInc#9195) Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <[email protected]> * feat(zgsm): add abort signal handling for streaming responses * Move the native tool call toggle to experimental settings (RooCodeInc#9297) Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> Co-authored-by: daniel-lxs <[email protected]> * fix: Replace broken badgen.net badges with shields.io (RooCodeInc#9318) Co-authored-by: Roo Code <[email protected]> * fix: preserve tool blocks for native protocol in conversation history (RooCodeInc#9319) * feat: add git status to environment details (RooCodeInc#9310) * feat: Move Import/Export to Modes view toolbar (RooCodeInc#8686) Cleanup of Mode Edit view (RooCodeInc#9077) * Add max git status files to evals settings (RooCodeInc#9322) * Release: v1.86.0 (RooCodeInc#9323) * fix: prevent infinite loop when attempt_completion succeeds (RooCodeInc#9325) * feat: add tool protocol selector to advanced settings (RooCodeInc#9324) Co-authored-by: Roo Code <[email protected]> Co-authored-by: Matt Rubens <[email protected]> * Remove experimental setting for native tool calls (RooCodeInc#9333) * Fix the type of the list files recursive parameter (RooCodeInc#9337) * fix: use VSCode theme color for outline button borders (RooCodeInc#9336) Co-authored-by: Roo Code <[email protected]> Co-authored-by: Bruno Bergher <[email protected]> * feat: update cloud agent CTA to point to setup page (RooCodeInc#9338) Co-authored-by: Roo Code <[email protected]> * Improve Google Gemini defaults, temperature, and cost reporting (RooCodeInc#9327) * fix: sync parser state with profile/model changes (RooCodeInc#9355) * feat: enable native tool calling for openai-native provider (RooCodeInc#9348) Co-authored-by: daniel-lxs <[email protected]> * Add Gemini 3 Pro Preview model (RooCodeInc#9357) * fix: pass tool protocol parameter to lineCountTruncationError (RooCodeInc#9358) * Remove the Roo model defaults (RooCodeInc#9340) * chore: add changeset and announcement for v3.33.0 (RooCodeInc#9360) * Changeset version bump (RooCodeInc#9362) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <[email protected]> * fix: resolve native tool protocol race condition causing 400 errors (RooCodeInc#9363) * Retry eval tasks if API instability detected (RooCodeInc#9365) * fix: exclude XML tool examples from MODES section when native protocol enabled (RooCodeInc#9367) * Add native tool calling support to OpenAI-compatible (RooCodeInc#9369) * Add native tool calling support to OpenAI-compatible * Fix OpenAI strict mode schema validation by adding converter methods to BaseProvider - Add convertToolsForOpenAI() and convertToolSchemaForOpenAI() methods to BaseProvider - These methods ensure all properties are in required array and convert nullable types - Remove line_ranges from required array in read_file tool (converter handles it) - Update OpenAiHandler and BaseOpenAiCompatibleProvider to use helper methods - Elimi
Problem
Fixes #9634
When creating a file in a non-existent subdirectory, the
write_to_filetool would fail with ENOENT errors because directories were only created later whendiffViewProvider.open()was called.Root Cause
execute()andhandlePartial()methods check if a file exists and seteditTypediffViewProvider.open()ordiffViewProvider.saveDirectly()diffViewProvider.isEditingwas already true from a previous operation,open()would be skipped and directories would never be createdSolution
Create parent directories immediately after determining a file doesn't exist, before any other operations that might depend on them:
createDirectoriesForFileimport fromutils/fsexecute()method: Create directories when!fileExistsbefore file operationshandlePartial()method: Same fix to prevent ENOENT during partial streamingTesting
Test Scenarios Covered
Important
Fixes ENOENT errors in
WriteToFileTool.tsby creating parent directories early, with comprehensive tests added.execute()andhandlePartial()inWriteToFileTool.ts.createDirectoriesForFilefromutils/fsto ensure directories exist before file operations.writeToFileTool.spec.tsto verify early directory creation for non-existent files in bothexecuteandpartialmodes.editTypeis cached as modify.This description was created by
for e0e38d8. You can customize this summary. It will automatically update as commits are pushed.