feat: let agents produce output files as job attachments - #1061
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds first-class support for agent-produced output files by introducing an internal create_output_file tool (returning a job-attachment ticket) and adding pre-termination verification that required file outputs are present and linked to the current job. This extends the agent orchestration layer to safely support output schemas that include job-attachment fields, including advanced-agent and conversational-advanced flows.
Changes:
- Introduce
create_output_fileinternal tool and sharedJOB_ATTACHMENT_DEFINITIONschema for job-attachment fields. - Add output-file field discovery + verification (including retry gating) and wire a new
VERIFY_OUTPUT_FILESnode into the ReAct and advanced-agent graphs. - Refactor conversational structured-output extraction into a reusable extractor and enable conversational advanced agents to declare additional output fields.
File summaries
| File | Description |
|---|---|
| uv.lock | Updates lock metadata and bumps package version to 0.16.14. |
| pyproject.toml | Bumps project version to 0.16.14. |
| src/uipath_langchain/agent/tools/internal_tools/schema_utils.py | Extracts reusable JOB_ATTACHMENT_DEFINITION for job-attachment schemas. |
| src/uipath_langchain/agent/tools/internal_tools/output_file_tool.py | Adds the create_output_file internal tool to publish job attachments. |
| src/uipath_langchain/agent/attachments/output_files.py | Adds output-file field discovery, prompt builder, and attachment-link verification helpers. |
| src/uipath_langchain/agent/react/types.py | Adds output-file verification state fields and a new graph node enum value. |
| src/uipath_langchain/agent/react/router.py | Routes end_execution through output-file verification when enabled. |
| src/uipath_langchain/agent/react/output_files_node.py | Adds a verification gate node that can bounce control back to the agent with corrective feedback. |
| src/uipath_langchain/agent/react/conversational_output_node.py | Refactors conversational extraction into create_conversational_output_extractor() and rewraps it as a node. |
| src/uipath_langchain/agent/react/agent.py | Wires the verification node into the standard ReAct graph when file outputs are expected. |
| src/uipath_langchain/agent/advanced/agent.py | Adds output-file verification to advanced agents and output-field extraction for conversational advanced agents. |
| tests/agent/tools/internal_tools/test_output_file_tool.py | Adds unit tests for tool schema, MIME guessing, and attachment creation behavior. |
| tests/agent/attachments/test_output_files.py | Adds tests for output-file field discovery, prompt text, and verification logic. |
| tests/agent/react/test_output_files_node.py | Adds tests for verification node behavior and graph wiring. |
| tests/agent/advanced/test_create_advanced_agent_graph.py | Adds tests asserting verification node/state wiring in advanced agent graphs. |
| tests/agent/advanced/test_conversational_advanced_agent_graph.py | Adds tests for conversational output extraction node insertion and output merging. |
Review details
- Files reviewed: 15/16 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
57a0a8b to
9e14466
Compare
An output schema could declare a file field, but nothing could fill it: the agent had no way to create an attachment, and the termination path only validated whatever the model claimed. Add a create_output_file tool that publishes agent-authored content as a job attachment and returns the attachment ticket, plus a verification gate that runs just before termination. The gate routes with Command, sending the agent back with a corrective message and faulting only once the retries are spent. Reaching it without an end_execution call raises rather than passing the output through, since the router is the only route in and letting it past would skip verification silently. Whether to verify is the caller's decision, carried by output_files_enabled rather than inferred from the tools present: a process tool or coded function can return a real ticket too, so an agent without create_output_file still needs its output checked. The gate has to catch everything the output schema would reject, or termination hard-fails on validation and the agent never gets its corrective turn. Three ways that could happen, each covered: - A field is matched by its JSON key, which is the alias when the converter assigned one. A property named `schema` becomes `schema_` with that alias, so matching model-field names alone silently made it optional. - A filled field is shape-checked against Attachment itself rather than by hand, so a half-filled reference (an id with no name) is corrected rather than faulted. - A complete reference is checked against the attachments linked to this job, so an invented id cannot pass. An optional file field is offered but never demanded: the prompt states the obligation per declared kind, and only a required field left empty counts as missing. A field the agent does fill is verified either way. The tool takes inline content everywhere, and a workspace path as well when the backend exposes a root, so an advanced agent does not re-emit a file body through the model. Paths resolve against deepagents' public `cwd`, the same seam the input-attachment path writes through, with traversal and containment checked here rather than delegated to a private resolver whose disappearance would silently drop the argument. The tool's output schema reuses single_attachment_schema, which batch transform already needed for the same shape.
A conversational agent's loop produces messages, so nothing in it fills the fields its output schema declares. The standard path already solves this with a focused extraction call after the loop, forced onto the set_conversational_output tool. The advanced path had no equivalent and returned messages only. Split that extraction out of the react node into create_conversational_output_extractor, which is graph agnostic, and build a node over it in the conversational advanced wrapper graph. The react node keeps its behavior and now delegates. The extraction receives the whole transcript, as the standard path passes: a declared field's answer often lives in the user's message or an earlier exchange, not in what the agent just produced.
9e14466 to
124f05d
Compare
|



Summary
create_output_filetool that publishes its content as a job attachment and returns the reference to put in that fieldWhy
files were input-only. the output schema could declare a file, and the product even nudged you toward it, but nothing could produce one: the agent had no way to create an attachment and the termination path only validated whatever the model claimed, so the field was unfillable.
Advanced agent with file output
Standard agent with file output