Repository navigation
🧭 fix: Explain Missing Workspace Paths to the Model - #16700
Conversation
Attached workspace file tools now append a short, specific explanation when the worker rejects a path with 422: - NOT_FOUND from a current worker, or INVALID_PATH carrying its "Workspace path does not exist" message through an older Code API, says the path does not exist: wait for a command still writing it, or list the directory to find the right path. For create_file it names the missing parent directory. - An older worker's bare INVALID_PATH on read_file, create_file or edit_file, which it also returns for a missing file, lists the possible causes: not written yet, a directory or symlink, or a missing parent directory for create_file. Other rejections are unchanged.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Some generated guidance is inaccurate for edit operations and genuine legacy path-safety rejections.
Review effort: Balanced
Findings: 1
What changed in this PR
Improves model guidance for attached-workspace path failures across worker versions.
Changes:
- Classifies missing and legacy ambiguous path rejections.
- Adds contextual guidance to five workspace tools.
- Tests current, mapped, legacy, and unrelated rejections.
| File | Description |
|---|---|
packages/api/src/code/paths.ts |
Classifies and explains path failures. |
packages/api/src/agents/handlers.ts |
Applies explanations to workspace tools. |
packages/api/src/agents/handlers.spec.ts |
Covers worker-version rejection behavior. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if (operation === 'search' || operation === 'list') { | ||
| return `${quoted} does not exist. List a parent directory to find the right path.`; | ||
| } | ||
| return `${quoted} does not exist. If a command is still writing it, wait for that command to finish before reading it again; otherwise list its directory to find the right path.`; |
|
Codex Review: Didn't find any major issues. Chef's kiss. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
Codex Review: Didn't find any major issues. Swish! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
Codex Review: Didn't find any major issues. Keep them coming! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |

Pull Request
Summary
When an attached worker rejects a workspace path, the model gets the raw worker error,
Workspace tool request rejected (upstreamStatus: 422); upstreamBody: "{"error":"Invalid workspace path","code":"INVALID_PATH"}". Current workers return that same response for a file that does not exist yet. The message suggests the path format is wrong, butworkspace/{relativePath}is the form the tools ask for.Over 7 days on demo.librechat.ai, 57 workspace file-tool calls failed with 422
INVALID_PATH. 54 of them used a correctly prefixedworkspace/path to a file that was simply not there. About 30 wereread_filecalls on log files a background command had not written yet, for exampleworkspace/.worktrees/<lane>/.checks/tests.log. Several of those succeeded when the agent read the same path again later. Most of the rest were guessed paths, and 5 werecreate_filecalls into a directory that did not exist yet.The worker side is fixed in LibreChat-AI/code-interpreter#301. Workers built from it return
NOT_FOUND("Workspace path does not exist") for an absent path, keepINVALID_PATHfor real path-safety rejections, and create missing parent directories forcreate_fileon held roots. That PR also covers a Code API that predates the new code. There, the worker sendsINVALID_PATHinstead but keeps the "Workspace path does not exist" message.This PR makes LibreChat append a short, specific explanation to these rejections in the attached
read_file,create_file,edit_file,list_workspace_filesandsearch_workspacetools. It handles both worker generations:NOT_FOUND, orINVALID_PATHwith the "Workspace path does not exist" message through an older Code API. The model is told the path does not exist, and that it should wait for a command still writing the file or list the directory to find the right path. Forcreate_file, it is told which parent directory is missing and to create it first.INVALID_PATHonread_file,create_fileoredit_fileis ambiguous, because it also covers a missing file. The model gets the possible causes: the file is not written yet, the path is a directory or symlink, or (forcreate_file) the parent directory is missing. The same bare rejection onlist_workspace_filesandsearch_workspaceis left unchanged, so a real path-safety error is never presented as a missing file.Every other rejection is unchanged. The raw upstream status and body remain in the message and in the logs.
Related to LibreChat-AI/code-interpreter#301. No dependency in either direction: this PR handles both old and new workers, and #301 works with current LibreChat.
How it works
packages/api/src/code/paths.tsclassifies the rejection from the upstream status and body, then appends static text. No worker-supplied text is echoed. Each attached tool's error path calls it once:Example of what the model now sees for a log a background command has not written yet, from a current worker:
Type of change
Testing
Tested environments/configuration:
packages/apiJest.Automated tests:
attached path rejectionscases topackages/api/src/agents/handlers.spec.ts. They run throughcreateToolExecuteHandlerwith the worker call rejecting the way each worker generation does:create_fileandedit_file, for three cases: a current worker (NOT_FOUND), a current worker behind an older Code API (INVALID_PATH+ the "does not exist" message), and an older worker (bareINVALID_PATH). Other 422 rejections (INVALID_REQUEST) stay unexplained.read_filefor the same three cases.list_workspace_filesandsearch_workspaceforNOT_FOUND, the mapped message and the bare legacy rejection. The bare rejection is left unexplained.npx jest src/agents/handlers.spec.ts -t "path rejection": 17 pass.npx jest src/agents/handlers.spec.ts src/code: the new tests pass.handlers.spec.tshas 54 failures in skill and sandbox edit tests that fail identically on unmodifieddevon this Windows machine. They are unrelated to these code paths.npx tsc --noEmitinpackages/api: clean.npm run build:api: succeeds. ESLint and the pre-commit static checks: clean.Screenshots / recordings
No user-facing change.
Risk / compatibility
Text is only appended to existing tool error messages; no tool result shapes or request payloads change. Detection of a mapped
NOT_FOUNDdepends on the worker's exact "Workspace path does not exist" message from LibreChat-AI/code-interpreter#301. If that message changes, those responses fall back to the legacy explanation, which still covers a missing file.Checklist