Skip to content

feat(advanced): download tool-produced attachments into the workspace - #1105

Draft
robert-ursu wants to merge 2 commits into
mainfrom
feat/advanced-tool-attachments
Draft

robert-ursu wants to merge 2 commits into
mainfrom
feat/advanced-tool-attachments

Conversation

@robert-ursu

@robert-ursu robert-ursu commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • adds ToolAttachmentsMiddleware, a wrap_tool_call / awrap_tool_call hook that finds JobAttachment tickets in a tool result, downloads them to <workspace>/<ID>_<name> (the layout input attachments already use) and writes a FilePath onto each ticket in the tool message
  • wires it into create_advanced_agent for a FilesystemBackend, on the main agent and on every subagent, which share the workspace
  • handles content-block results (MCP tools) and Command results (a subagent's task answer); error results and create_output_file results pass through untouched

Why

An advanced agent only had a file on disk when the ticket arrived through the input schema or the chat window. A ticket a tool returned mid-run (a process tool's output file, a batch transform result, a child agent's output) stayed as JSON, and the meta prompt promised a FilePath that was not there. The standard agent's job-attachment wrapper covers this, but it runs only in UiPathToolNode; on this path tools run through deepagents' tool node.

Tracks PC-5029.

Design notes for review

  • Detection is structural (a dict with a UUID ID and a non-empty FullName) rather than schema-driven, so MCP tools, the code interpreter and a child agent's free-form output are covered too. A ticket's own Metadata is not searched.
  • A failed download leaves the ticket without a FilePath instead of failing the tool call, mirroring resolve_message_attachments; the agent still holds a reference it can hand to other tools. A stale FilePath on such a ticket is dropped.
  • create_output_file is skipped: the agent wrote and named that file itself, so the ticket points back at a copy of what is already in the workspace.
  • The sync wrap_tool_call downloads through asyncio.run when no loop is running and otherwise leaves the result alone with a warning.

Follow-ups, deliberately not in this PR

  • Link downloaded child-job tickets to the current job, so a parent agent can pass a child's file through as its own output file (the verification node checks against the current job's attachments) and the file shows on the parent job page. WorkspaceHydrator.link_attachment already exists for this.
  • Record downloads in the hydration registry so dehydrate does not re-upload them as .uipath-workspace/ snapshot files. Needs a small uipath-runtime API.

Test plan

  • tests/agent/advanced/test_tool_attachments.py: detection, string and content-block rewrite, Command rewrite, skip rules, file already present, failed download, sync path, and two end-to-end runs on a real deep agent (main agent and general-purpose subagent)
  • tests/agent/advanced, tests/agent/attachments and the circular import test green; ruff and mypy clean
  • manual: an advanced agent calling an agent tool whose output schema has a file field, then read_file on the returned FilePath

Companion prompt change: UiPath/uipath-agents-python#762

🤖 Generated with Claude Code

https://claude.ai/code/session_01QQVAR7BZ5CZbRMMZcb9RGf

robert-ursu and others added 2 commits September 21, 2026 16:58
An advanced agent only had a file on disk when its ticket arrived through
the input schema or the chat window. A ticket a tool returned mid-run, such
as a process tool's output file, a batch transform result or a child
agent's output, stayed as JSON in the tool message, so the agent had no path
to open. The standard agent's job-attachment wrapper covers this but runs
only in UiPathToolNode; on this path tools run through deepagents' tool
node.

ToolAttachmentsMiddleware wraps every tool call, finds JobAttachment-shaped
objects in the result, downloads them to <workspace>/<ID>_<name>, the
layout input attachments use, and writes a FilePath onto each ticket. It is
installed for a FilesystemBackend on the main agent and on every subagent,
which share the workspace. Content-block results and Command results are
handled; error results and create_output_file results pass through, and a
failed download leaves the ticket without a path rather than failing the
call.

Tracks PC-5029.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QQVAR7BZ5CZbRMMZcb9RGf
CI type-checks the tests too. Narrow the content block and the Command
update before indexing, and type the failing-download set as a frozenset.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QQVAR7BZ5CZbRMMZcb9RGf
@sonarqubecloud

Copy link
Copy Markdown

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant