Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "uipath-langchain"
version = "0.7.11"
version = "0.7.12"
description = "Python SDK that enables developers to build and deploy LangGraph agents to the UiPath Cloud Platform"
readme = { file = "README.md", content-type = "text/markdown" }
requires-python = ">=3.11"
Expand Down
2 changes: 1 addition & 1 deletion samples/chat-hitl-agent/graph.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from langchain_anthropic import ChatAnthropic
from langchain_tavily import TavilySearch
from langchain.agents import create_agent
from uipath_langchain.chat import requires_approval
from uipath_langchain.chat.tools import requires_approval

tavily_tool = TavilySearch(max_results=5)

Expand Down
3 changes: 3 additions & 0 deletions samples/file-attachments-chat-agent/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
UIPATH_ACCESS_TOKEN=YOUR TOKEN HERE
UIPATH_URL=https://alpha.uipath.com/<organization>/<tenant>
OPENAI_API_KEY=your_openai_api_key
42 changes: 42 additions & 0 deletions samples/file-attachments-chat-agent/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# File Attachments Chat Agent

An AI assistant that reads and analyzes file attachments shared in the conversation.

## Requirements

- Python 3.11+
- OpenAI API key

## Installation

```bash
uv venv -p 3.11 .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
uv sync
```

Set your API key as an environment variable in .env

```bash
OPENAI_API_KEY=your_openai_api_key
```

## Usage

**1.** Upload the file to Orchestrator using the [attachments API](https://uipath.github.io/uipath-python/core/attachments/).

**2.** Run the agent, passing the attachment ID and file metadata returned by the upload:

```bash
uipath run agent '{
"messages": [
{
"type": "human",
"content": [
{ "type": "text", "text": "Summarize this document." },
{ "type": "text", "text": "<uip:attachments>[{\"id\": \"{orchestrator_attachment_id}\", \"full_name\": \"{file_name}\", \"mime_type\": \"{file_mime_type}\"}]</uip:attachments>" }
]
}
]
}'
```
9 changes: 9 additions & 0 deletions samples/file-attachments-chat-agent/agent.mermaid
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
flowchart TB
__start__(__start__)
model(model)
tools(tools)
__end__(__end__)
__start__ --> model
model --> __end__
model --> tools
tools --> model
5 changes: 5 additions & 0 deletions samples/file-attachments-chat-agent/langgraph.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"graphs": {
"agent": "./main.py:graph"
}
}
32 changes: 32 additions & 0 deletions samples/file-attachments-chat-agent/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI

from uipath_langchain.chat.tools import AnalyzeAttachmentsTool

system_prompt = """
You are an AI assistant specialized in analyzing user-provided files using the available file analysis tool.
Always use the provided tool to read and analyze any uploaded or referenced file. Never guess or fabricate file contents. If a file is missing or inaccessible, ask the user to upload it again.

When a file is received:
1.Identify the file type.
2.Provide a clear, concise summary.
3.Extract key information relevant to the user’s request.
4.Highlight important patterns, issues, or insights when applicable.
5.If the user’s request is unclear, ask a focused clarification question before proceeding.

For follow-up questions:
1.Base all answers strictly on the file contents.
2.Maintain context across the conversation.
3.Perform deeper analysis, comparisons, transformations, or extractions as requested.
4.Clearly distinguish between observed facts and inferred insights. If something cannot be determined from the file, state that explicitly.

Keep responses structured, concise, and professional. Treat all file data as sensitive and do not retain or reuse it outside the current conversation.
"""

llm = ChatOpenAI(model="gpt-4.1")

graph = create_agent(
llm,
tools=[AnalyzeAttachmentsTool(llm=llm)],
system_prompt=system_prompt,
)
10 changes: 10 additions & 0 deletions samples/file-attachments-chat-agent/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[project]
name = "file-attachments-chat-agent"
version = "0.0.1"
description = "file-attachments-chat-agent"
authors = [{ name = "John Doe", email = "john.doe@myemail.com" }]
dependencies = [
"langchain-openai>=1.1.9",
"uipath-langchain",
]
requires-python = ">=3.11"
14 changes: 14 additions & 0 deletions samples/file-attachments-chat-agent/uipath.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"$schema": "https://cloud.uipath.com/draft/2024-12/uipath",
"runtimeOptions": {
"isConversational": true
},
"packOptions": {
"fileExtensionsIncluded": [],
"filesIncluded": [],
"filesExcluded": [],
"directoriesExcluded": [],
"includeUvLock": true
},
"functions": {}
}
8 changes: 7 additions & 1 deletion src/uipath_langchain/chat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@ def __getattr__(name):

return UiPathChatOpenAI
if name == "requires_approval":
from .hitl import requires_approval
from .tools.hitl import requires_approval

return requires_approval
if name == "AnalyzeAttachmentsTool":
from .tools.attachments import AnalyzeAttachmentsTool

return AnalyzeAttachmentsTool
if name in ("OpenAIModels", "BedrockModels", "GeminiModels"):
from . import supported_models

Expand All @@ -50,4 +54,6 @@ def __getattr__(name):
"requires_approval",
"LLMProvider",
"APIFlavor",
"requires_approval",
"AnalyzeAttachmentsTool",
]
16 changes: 16 additions & 0 deletions src/uipath_langchain/chat/tools/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
def __getattr__(name):
if name == "AnalyzeAttachmentsTool":
from .attachments import AnalyzeAttachmentsTool

return AnalyzeAttachmentsTool
if name == "requires_approval":
from .hitl import requires_approval

return requires_approval
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")


__all__ = [
"AnalyzeAttachmentsTool",
"requires_approval",
]
90 changes: 90 additions & 0 deletions src/uipath_langchain/chat/tools/attachments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
"""Attachment resolution for conversational agents."""

from typing import Any

from langchain_core.language_models import BaseChatModel
from langchain_core.tools import StructuredTool
from uipath.agent.models.agent import (
AgentInternalAnalyzeFilesToolProperties,
AgentInternalToolResourceConfig,
)

from uipath_langchain.agent.tools.internal_tools.analyze_files_tool import (
create_analyze_file_tool,
)

_ANALYZE_ATTACHMENTS_NAME = "analyze attachments"
_ANALYZE_ATTACHMENTS_DESCRIPTION = (
"Read and interpret the content of file attachments provided by the user. "
"Call this when you see a <uip:attachments> tag in a user message, passing "
"the attachment objects from inside the tag and a query describing what you "
"want to know about or do with the files."
)
_ANALYZE_ATTACHMENTS_INPUT_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {
"analysisTask": {
"type": "string",
"description": "What you want to know about or do with the files.",
},
"attachments": {
"type": "array",
"description": "The attachment objects from inside the <uip:attachments> tag.",
"items": {
"type": "object",
"properties": {
"ID": {
"type": "string",
"description": "The unique identifier of the attachment.",
},
"FullName": {
"type": "string",
"description": "The full name of the attachment file.",
},
"MimeType": {
"type": "string",
"description": "The MIME type of the attachment.",
},
},
"required": ["ID", "FullName", "MimeType"],
},
},
},
"required": ["analysisTask", "attachments"],
}
_ANALYZE_ATTACHMENTS_OUTPUT_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {
"analysisResult": {
"type": "string",
"description": "The result of analyzing the file attachments.",
},
},
"required": ["analysisResult"],
}


def AnalyzeAttachmentsTool(llm: BaseChatModel) -> StructuredTool:
"""Tool that reads and interprets file attachments using the provided LLM.

The tool downloads each attachment, passes the file content to a non-streaming
copy of the provided LLM for interpretation, and returns the result as text.
This keeps multimodal content out of the agent's message state — the original
``<uip:attachments>`` metadata in HumanMessages is never modified.

Example::

from langchain_openai import ChatOpenAI
from uipath_langchain.chat import AnalyzeAttachmentsTool

llm = ChatOpenAI(model="gpt-4.1")
tool = AnalyzeAttachmentsTool(llm=llm)
"""
resource = AgentInternalToolResourceConfig(
name=_ANALYZE_ATTACHMENTS_NAME,
description=_ANALYZE_ATTACHMENTS_DESCRIPTION,
input_schema=_ANALYZE_ATTACHMENTS_INPUT_SCHEMA,
output_schema=_ANALYZE_ATTACHMENTS_OUTPUT_SCHEMA,
properties=AgentInternalAnalyzeFilesToolProperties(),
)
return create_analyze_file_tool(resource, llm)
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.