Skip to content

Commit 9ad7715

Browse files
committed
feat: add context agent tools
1 parent 316002d commit 9ad7715

File tree

6 files changed

+497
-8
lines changed

6 files changed

+497
-8
lines changed

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
[project]
22
name = "uipath-langchain"
3-
version = "0.1.44"
3+
version = "0.1.45"
44
description = "Python SDK that enables developers to build and deploy LangGraph agents to the UiPath Cloud Platform"
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.11"
77
dependencies = [
8-
"uipath>=2.2.44, <2.3.0",
8+
"uipath>=2.2.45,<2.3.0",
99
"langgraph>=1.0.0, <2.0.0",
1010
"langchain-core>=1.0.0, <2.0.0",
1111
"aiosqlite==0.21.0",

src/uipath_langchain/agent/react/agent.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def create_agent(
7777
llm_tools: list[BaseTool] = [*agent_tools, *flow_control_tools]
7878

7979
init_node = create_init_node(messages, input_schema)
80+
8081
tool_nodes = create_tool_node(agent_tools)
8182
tool_nodes_with_guardrails = create_tools_guardrails_subgraph(
8283
tool_nodes, guardrails

src/uipath_langchain/agent/tools/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Tool creation and management for LowCode agents."""
22

33
from .context_tool import create_context_tool
4+
from .escalation_tool import create_escalation_tool
45
from .integration_tool import create_integration_tool
56
from .mcp_tool import create_mcp_tools
67
from .process_tool import create_process_tool
@@ -15,6 +16,7 @@
1516
"create_context_tool",
1617
"create_process_tool",
1718
"create_integration_tool",
19+
"create_escalation_tool",
1820
"create_mcp_tools",
1921
"UiPathToolNode",
2022
"ToolWrapperMixin",

src/uipath_langchain/agent/tools/context_tool.py

Lines changed: 150 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
"""Context tool creation for semantic index retrieval."""
22

3+
import uuid
34
from typing import Any
45

56
from langchain_core.documents import Document
67
from langchain_core.tools import StructuredTool
8+
from langgraph.types import interrupt
79
from pydantic import BaseModel, Field
8-
from uipath.agent.models.agent import AgentContextResourceConfig
10+
from uipath.agent.models.agent import (
11+
AgentContextResourceConfig,
12+
AgentContextRetrievalMode,
13+
)
914
from uipath.eval.mocks import mockable
15+
from uipath.platform.common import CreateBatchTransform, CreateDeepRag
16+
from uipath.platform.context_grounding import (
17+
BatchTransformOutputColumn,
18+
BatchTransformResponse,
19+
CitationMode,
20+
DeepRagResponse,
21+
)
1022

1123
from uipath_langchain.retrievers import ContextGroundingRetriever
1224

@@ -16,6 +28,18 @@
1628

1729
def create_context_tool(resource: AgentContextResourceConfig) -> StructuredTool:
1830
tool_name = sanitize_tool_name(resource.name)
31+
retrieval_mode = resource.settings.retrieval_mode.lower()
32+
if retrieval_mode == AgentContextRetrievalMode.DEEP_RAG.value.lower():
33+
return handle_deep_rag(tool_name, resource)
34+
elif retrieval_mode == AgentContextRetrievalMode.BATCH_TRANSFORM.value.lower():
35+
return handle_batch_transform(tool_name, resource)
36+
else:
37+
return handle_semantic_search(tool_name, resource)
38+
39+
40+
def handle_semantic_search(
41+
tool_name: str, resource: AgentContextResourceConfig
42+
) -> StructuredTool:
1943
retriever = ContextGroundingRetriever(
2044
index_name=resource.index_name,
2145
folder_path=resource.folder_path,
@@ -52,3 +76,128 @@ async def context_tool_fn(query: str) -> dict[str, Any]:
5276
coroutine=context_tool_fn,
5377
output_type=output_model,
5478
)
79+
80+
81+
def handle_deep_rag(
82+
tool_name: str, resource: AgentContextResourceConfig
83+
) -> StructuredTool:
84+
ensure_valid_fields(resource)
85+
# needed for type checking
86+
assert resource.settings.query is not None
87+
assert resource.settings.query.value is not None
88+
89+
index_name = resource.index_name
90+
prompt = resource.settings.query.value
91+
if not resource.settings.citation_mode:
92+
raise ValueError("Citation mode is required for Deep RAG")
93+
citation_mode = CitationMode(resource.settings.citation_mode.value)
94+
95+
input_model = None
96+
output_model = DeepRagResponse
97+
98+
@mockable(
99+
name=resource.name,
100+
description=resource.description,
101+
input_schema=input_model,
102+
output_schema=output_model.model_json_schema(),
103+
example_calls=[], # Examples cannot be provided for context.
104+
)
105+
async def context_tool_fn() -> dict[str, Any]:
106+
# TODO: add glob pattern support
107+
return interrupt(
108+
CreateDeepRag(
109+
name=f"task-{uuid.uuid4()}",
110+
index_name=index_name,
111+
prompt=prompt,
112+
citation_mode=citation_mode,
113+
)
114+
)
115+
116+
return StructuredToolWithOutputType(
117+
name=tool_name,
118+
description=resource.description,
119+
args_schema=input_model,
120+
coroutine=context_tool_fn,
121+
output_type=output_model,
122+
)
123+
124+
125+
def handle_batch_transform(
126+
tool_name: str, resource: AgentContextResourceConfig
127+
) -> StructuredTool:
128+
ensure_valid_fields(resource)
129+
130+
# needed for type checking
131+
assert resource.settings.query is not None
132+
assert resource.settings.query.value is not None
133+
134+
index_name = resource.index_name
135+
prompt = resource.settings.query.value
136+
137+
index_folder_path = resource.folder_path
138+
if not resource.settings.web_search_grounding:
139+
raise ValueError("Web search grounding field is required for Batch Transform")
140+
enable_web_search_grounding = (
141+
resource.settings.web_search_grounding.value.lower() == "enabled"
142+
)
143+
144+
batch_transform_output_columns: list[BatchTransformOutputColumn] = []
145+
if (output_columns := resource.settings.output_columns) is None or not len(
146+
output_columns
147+
):
148+
raise ValueError(
149+
"Batch transform requires at least one output column to be specified in settings.output_columns"
150+
)
151+
152+
for column in output_columns:
153+
batch_transform_output_columns.append(
154+
BatchTransformOutputColumn(
155+
name=column.name,
156+
description=column.description,
157+
)
158+
)
159+
160+
class BatchTransformSchemaModel(BaseModel):
161+
destination_path: str = Field(
162+
...,
163+
description="The relative file path destination for the modified csv file",
164+
)
165+
166+
input_model = BatchTransformSchemaModel
167+
output_model = BatchTransformResponse
168+
169+
@mockable(
170+
name=resource.name,
171+
description=resource.description,
172+
input_schema=input_model.model_json_schema(),
173+
output_schema=output_model.model_json_schema(),
174+
example_calls=[], # Examples cannot be provided for context.
175+
)
176+
async def context_tool_fn(destination_path: str) -> dict[str, Any]:
177+
# TODO: storage_bucket_folder_path_prefix support
178+
return interrupt(
179+
CreateBatchTransform(
180+
name=f"task-{uuid.uuid4()}",
181+
index_name=index_name,
182+
prompt=prompt,
183+
destination_path=destination_path,
184+
index_folder_path=index_folder_path,
185+
enable_web_search_grounding=enable_web_search_grounding,
186+
output_columns=batch_transform_output_columns,
187+
)
188+
)
189+
190+
return StructuredToolWithOutputType(
191+
name=tool_name,
192+
description=resource.description,
193+
args_schema=input_model,
194+
coroutine=context_tool_fn,
195+
output_type=output_model,
196+
)
197+
198+
199+
def ensure_valid_fields(resource_config: AgentContextResourceConfig):
200+
if not resource_config.settings.query:
201+
raise ValueError("Query object is required")
202+
if not resource_config.settings.query.value:
203+
raise ValueError("Query prompt is required")

0 commit comments

Comments
 (0)