-
Notifications
You must be signed in to change notification settings - Fork 29
feat: add a new internal analyze_files tool with supporting infrastructure for file attachment handling #368
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
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
8a8ad0e
feat: add jsonchema pydantic converter
cristian-groza fb8cda8
fix: tool args
cristian-groza 39ce271
fix: refactor code
cristian-groza a2fb69c
fix: update uipath and jsonschema-pydantic-converter versions
cristian-groza 62ca99d
fix: refactored code
cristian-groza 8738ab4
fix: linting issues
cristian-groza c4d7c54
fix: linting issues
cristian-groza 9ca88f0
fix: linting issues
cristian-groza a3165a9
fix: ruff format issues
cristian-groza c9e633a
fix: address PR comments
cristian-groza 23a8548
fix: pr comments
cristian-groza 5fe66f5
fix: increment package version
cristian-groza f41e418
feat: resolve job attachments and call llm with files
cristian-groza 48551df
fix: add unit tests
cristian-groza daa8b8a
fix: linting errors
cristian-groza File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| """Job attachment utilities for ReAct Agent.""" | ||
|
|
||
| import copy | ||
| import uuid | ||
| from typing import Any | ||
|
|
||
| from jsonpath_ng import parse # type: ignore[import-untyped] | ||
| from pydantic import BaseModel | ||
| from uipath.platform.attachments import Attachment | ||
|
|
||
| from .json_utils import extract_values_by_paths, get_json_paths_by_type | ||
|
|
||
|
|
||
| def get_job_attachments( | ||
| schema: type[BaseModel], | ||
| data: dict[str, Any] | BaseModel, | ||
| ) -> list[Attachment]: | ||
| """Extract job attachments from data based on schema and convert to Attachment objects. | ||
|
|
||
| Args: | ||
| schema: The Pydantic model class defining the data structure | ||
| data: The data object (dict or Pydantic model) to extract attachments from | ||
|
|
||
| Returns: | ||
| List of Attachment objects | ||
| """ | ||
| job_attachment_paths = get_job_attachment_paths(schema) | ||
| job_attachments = extract_values_by_paths(data, job_attachment_paths) | ||
|
|
||
| result = [] | ||
| for attachment in job_attachments: | ||
| result.append(Attachment.model_validate(attachment, from_attributes=True)) | ||
|
|
||
| return result | ||
|
|
||
|
|
||
| def get_job_attachment_paths(model: type[BaseModel]) -> list[str]: | ||
| """Get JSONPath expressions for all job attachment fields in a Pydantic model. | ||
|
|
||
| Args: | ||
| model: The Pydantic model class to analyze | ||
|
|
||
| Returns: | ||
| List of JSONPath expressions pointing to job attachment fields | ||
| """ | ||
| return get_json_paths_by_type(model, "Job_attachment") | ||
|
|
||
|
|
||
| def replace_job_attachment_ids( | ||
| json_paths: list[str], | ||
| tool_args: dict[str, Any], | ||
| state: dict[str, Attachment], | ||
| errors: list[str], | ||
| ) -> dict[str, Any]: | ||
| """Replace job attachment IDs in tool_args with full attachment objects from state. | ||
|
|
||
| For each JSON path, this function finds matching objects in tool_args and | ||
| replaces them with corresponding attachment objects from state. The matching | ||
| is done by looking up the object's 'ID' field in the state dictionary. | ||
|
|
||
| If an ID is not a valid UUID or is not present in state, an error message | ||
| is added to the errors list. | ||
|
|
||
| Args: | ||
| json_paths: List of JSONPath expressions (e.g., ["$.attachment", "$.attachments[*]"]) | ||
| tool_args: The dictionary containing tool arguments to modify | ||
| state: Dictionary mapping attachment UUID strings to Attachment objects | ||
| errors: List to collect error messages for invalid or missing IDs | ||
|
|
||
| Returns: | ||
| Modified copy of tool_args with attachment IDs replaced by full objects | ||
|
|
||
| Example: | ||
| >>> state = { | ||
| ... "123e4567-e89b-12d3-a456-426614174000": Attachment(id="123e4567-e89b-12d3-a456-426614174000", name="file1.pdf"), | ||
| ... "223e4567-e89b-12d3-a456-426614174001": Attachment(id="223e4567-e89b-12d3-a456-426614174001", name="file2.pdf") | ||
| ... } | ||
| >>> tool_args = { | ||
| ... "attachment": {"ID": "123"}, | ||
| ... "other_field": "value" | ||
| ... } | ||
| >>> paths = ['$.attachment'] | ||
| >>> errors = [] | ||
| >>> replace_job_attachment_ids(paths, tool_args, state, errors) | ||
| {'attachment': {'ID': '123', 'name': 'file1.pdf', ...}, 'other_field': 'value'} | ||
| """ | ||
| result = copy.deepcopy(tool_args) | ||
|
|
||
| for json_path in json_paths: | ||
| expr = parse(json_path) | ||
| matches = expr.find(result) | ||
|
|
||
| for match in matches: | ||
| current_value = match.value | ||
|
|
||
| if isinstance(current_value, dict) and "ID" in current_value: | ||
| attachment_id_str = str(current_value["ID"]) | ||
|
|
||
| try: | ||
| uuid.UUID(attachment_id_str) | ||
| except (ValueError, AttributeError): | ||
| errors.append( | ||
| _create_job_attachment_error_message(attachment_id_str) | ||
| ) | ||
| continue | ||
|
|
||
| if attachment_id_str in state: | ||
| replacement_value = state[attachment_id_str] | ||
| match.full_path.update( | ||
| result, replacement_value.model_dump(by_alias=True, mode="json") | ||
| ) | ||
| else: | ||
| errors.append( | ||
| _create_job_attachment_error_message(attachment_id_str) | ||
| ) | ||
|
|
||
| return result | ||
|
|
||
|
|
||
| def _create_job_attachment_error_message(attachment_id_str: str) -> str: | ||
| return ( | ||
| f"Could not find JobAttachment with ID='{attachment_id_str}'. " | ||
| f"Try invoking the tool again and please make sure that you pass " | ||
| f"valid JobAttachment IDs associated with existing JobAttachments in the current context." | ||
| ) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.