You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
PR feat: expose MCP and HTTP Tool Errors to the LLM #408 introduced forward_tool_error_message on fallback strategies, which forwards the real error text to the LLM instead of only the generic fallback instructions. The gate lives in compose_tool_error_fallback_message (src/quickapp/common/tool_fallback/utils.py:10): the real message is forwarded only when the escaping exception is a ToolErrorException subclass.
ToolErrorException subclasses exist only for MCP tools (MCPToolErrorException) and REST tools (RestApiToolErrorException). The internal file tools (src/quickapp/dial_files_tooling/) never raise one.
Instead, the file tools let raw DialExceptions escape their tool bodies: _check_permission_denied handles only 403, and every except DialException site ends in a bare raise (e.g. _base_file_tool.py:128-130 in _list_folder_entries, _copy_file_tool.py:42-44, and the same pattern in the write/edit/delete/move tools).
Additionally, _DialFileTool._download_text (_base_file_tool.py:65-67) wraps any non-404 DialException — including Core 5xx server errors — into InvalidToolCallParameterException("path", ...).
How it got this way (if known): the file tools predate feat: expose MCP and HTTP Tool Errors to the LLM #408's ToolErrorException forwarding contract; their error handling was written around the parameter-retry path only.
Why is this debt?
Impact today: forward_tool_error_message=True is a silent no-op for all nine internal file tools — a raw DialException is not a ToolErrorException, so compose_tool_error_fallback_message drops the real error text and the LLM receives only the generic fallback instructions. The model then reports vague failures like "the backend tool is failing", which is exactly the symptom observed in Quick app 2.0 with switched on Files tools can not perform actions with pdf Context files from Organization or Shared with me #447 (copy of a shared/organization context file fails with no actionable detail surfaced to the model or the user).
Misleading retry semantics: _download_text labels Core server errors (5xx) as InvalidToolCallParameterException, which routes them into the hardcoded "fix the parameter and retry" branch of StagedBaseTool.__run_tool_body — the model is told to fix a parameter that is not broken, and the tool's configured fallback strategies are bypassed entirely.
Risk if left unaddressed: every file-tool failure that is not a 404/403/etag conflict stays undiagnosable from the conversation; support has to reproduce with server logs.
Approach: make every failure escaping a file tool one of exactly two standardized shapes — no raw DialException leaks:
InvalidToolCallParameterException for parameter-shaped failures the model can fix and retry (not found 404, access denied 403, etag conflict, bad range/pattern) — handled today by the dedicated branch in StagedBaseTool.__run_tool_body (src/quickapp/common/staged_base_tool.py:129).
A new FileToolErrorException(ToolErrorException) for genuine tool/server failures (e.g. Core 5xx), mirroring src/quickapp/mcp_tooling/_mcp_tool_error_exception.py. Being a ToolErrorException, it makes compose_tool_error_fallback_message forward the real text when forward_tool_error_message=True — zero changes to the fallback machinery.
Affected modules: src/quickapp/dial_files_tooling/_base_file_tool.py (a translation helper replacing _check_permission_denied, applied at every except DialException site), the write/edit/delete/copy/move tools, and _tool_configs.py (ship forward_tool_error_message=True defaults for all nine file tools).
Migration / rollout considerations: none — the file-tool configs are hardcoded (not overridable from app manifests), and the change only improves the message the LLM sees.
A design doc under docs/designs/ will follow in a separate PR.
Alternatives considered
Loosening compose_tool_error_fallback_message to forward the text of any exception: rejected — the ToolErrorException gate is deliberate (feat: expose MCP and HTTP Tool Errors to the LLM #408); arbitrary exception reprs may leak internals and noisy stack context.
Wrapping every DialException into InvalidToolCallParameterException (extending the current _download_text pattern): rejected — server errors are not parameter errors; "fix the parameter and retry" is misleading and bypasses configured fallback strategies.
QuickApps version
latest
Area
Toolsets (REST / DIAL deployment / MCP / internal)
What is the current state?
src/quickapp/dial_files_tooling/(internal file tools),src/quickapp/common/tool_fallback/utils.pyforward_tool_error_messageon fallback strategies, which forwards the real error text to the LLM instead of only the generic fallback instructions. The gate lives incompose_tool_error_fallback_message(src/quickapp/common/tool_fallback/utils.py:10): the real message is forwarded only when the escaping exception is aToolErrorExceptionsubclass.ToolErrorExceptionsubclasses exist only for MCP tools (MCPToolErrorException) and REST tools (RestApiToolErrorException). The internal file tools (src/quickapp/dial_files_tooling/) never raise one.DialExceptions escape their tool bodies:_check_permission_deniedhandles only 403, and everyexcept DialExceptionsite ends in a bareraise(e.g._base_file_tool.py:128-130in_list_folder_entries,_copy_file_tool.py:42-44, and the same pattern in the write/edit/delete/move tools)._DialFileTool._download_text(_base_file_tool.py:65-67) wraps any non-404DialException— including Core 5xx server errors — intoInvalidToolCallParameterException("path", ...).ToolErrorExceptionforwarding contract; their error handling was written around the parameter-retry path only.Why is this debt?
forward_tool_error_message=Trueis a silent no-op for all nine internal file tools — a rawDialExceptionis not aToolErrorException, socompose_tool_error_fallback_messagedrops the real error text and the LLM receives only the generic fallback instructions. The model then reports vague failures like "the backend tool is failing", which is exactly the symptom observed in Quick app 2.0 with switched on Files tools can not perform actions with pdf Context files from Organization or Shared with me #447 (copy of a shared/organization context file fails with no actionable detail surfaced to the model or the user)._download_textlabels Core server errors (5xx) asInvalidToolCallParameterException, which routes them into the hardcoded "fix the parameter and retry" branch ofStagedBaseTool.__run_tool_body— the model is told to fix a parameter that is not broken, and the tool's configured fallback strategies are bypassed entirely.Proposed remediation
DialExceptionleaks:InvalidToolCallParameterExceptionfor parameter-shaped failures the model can fix and retry (not found 404, access denied 403, etag conflict, bad range/pattern) — handled today by the dedicated branch inStagedBaseTool.__run_tool_body(src/quickapp/common/staged_base_tool.py:129).FileToolErrorException(ToolErrorException)for genuine tool/server failures (e.g. Core 5xx), mirroringsrc/quickapp/mcp_tooling/_mcp_tool_error_exception.py. Being aToolErrorException, it makescompose_tool_error_fallback_messageforward the real text whenforward_tool_error_message=True— zero changes to the fallback machinery.src/quickapp/dial_files_tooling/_base_file_tool.py(a translation helper replacing_check_permission_denied, applied at everyexcept DialExceptionsite), the write/edit/delete/copy/move tools, and_tool_configs.py(shipforward_tool_error_message=Truedefaults for all nine file tools).A design doc under
docs/designs/will follow in a separate PR.Alternatives considered
compose_tool_error_fallback_messageto forward the text of any exception: rejected — theToolErrorExceptiongate is deliberate (feat: expose MCP and HTTP Tool Errors to the LLM #408); arbitrary exception reprs may leak internals and noisy stack context.DialExceptionintoInvalidToolCallParameterException(extending the current_download_textpattern): rejected — server errors are not parameter errors; "fix the parameter and retry" is misleading and bypasses configured fallback strategies.Additional information