Skip to content

Commit 72ed309

Browse files
authored
Merge pull request #134 from UiPath/feat/return-middleware-result
pass input and output file to runtime executor
2 parents a0a551b + 0050ff6 commit 72ed309

8 files changed

Lines changed: 187 additions & 9 deletions

File tree

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.0.119"
3+
version = "0.0.120"
44
description = "UiPath Langchain"
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.10"
77
dependencies = [
8-
"uipath>=2.0.79, <2.1.0",
8+
"uipath>=2.1.0, <2.2.0",
99
"langgraph>=0.2.70",
1010
"langchain-core>=0.3.34",
1111
"langgraph-checkpoint-sqlite>=2.0.3",

src/uipath_langchain/_cli/cli_run.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616

1717
def langgraph_run_middleware(
18-
entrypoint: Optional[str], input: Optional[str], resume: bool
18+
entrypoint: Optional[str], input: Optional[str], resume: bool, **kwargs
1919
) -> MiddlewareResult:
2020
"""Middleware to handle langgraph execution"""
2121
config = LangGraphConfig()
@@ -38,10 +38,13 @@ async def execute():
3838
context.input = input
3939
context.resume = resume
4040
context.langgraph_config = config
41+
context.debug = kwargs.get("debug", False)
4142
context.logs_min_level = env.get("LOG_LEVEL", "INFO")
4243
context.job_id = env.get("UIPATH_JOB_KEY")
4344
context.trace_id = env.get("UIPATH_TRACE_ID")
4445
context.tracing_enabled = tracing
46+
context.input_file = kwargs.get("input_file", None)
47+
context.execution_output_file = kwargs.get("execution_output_file", None)
4548
context.trace_context = UiPathTraceContext(
4649
enabled=tracing,
4750
trace_id=env.get("UIPATH_TRACE_ID"),
@@ -64,7 +67,10 @@ async def execute():
6467

6568
asyncio.run(execute())
6669

67-
return MiddlewareResult(should_continue=False, error_message=None)
70+
return MiddlewareResult(
71+
should_continue=False,
72+
error_message=None,
73+
)
6874

6975
except LangGraphRuntimeError as e:
7076
return MiddlewareResult(

tests/cli/conftest.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import pytest
2+
3+
4+
@pytest.fixture
5+
def mock_env_vars():
6+
return {
7+
"UIPATH_URL": "http://example.com",
8+
"UIPATH_ACCESS_TOKEN": "***",
9+
}

tests/cli/mocks/langgraph.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"dependencies": ["."],
3+
"graphs": {
4+
"agent": "./main.py:graph"
5+
},
6+
"env": ".env"
7+
}

tests/cli/mocks/simple_agent.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from langgraph.graph import END, START, StateGraph
2+
from pydantic import BaseModel
3+
4+
5+
class GraphState(BaseModel):
6+
topic: str
7+
8+
9+
class GraphOutput(BaseModel):
10+
report: str
11+
12+
13+
async def generate_report(state: GraphState) -> GraphOutput:
14+
return GraphOutput(report=f" This is mock report for {state.topic}")
15+
16+
17+
builder = StateGraph(GraphState, output_schema=GraphOutput)
18+
19+
builder.add_node("generate_report", generate_report)
20+
21+
builder.add_edge(START, "generate_report")
22+
builder.add_edge("generate_report", END)
23+
24+
graph = builder.compile()

tests/cli/mocks/uipath.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"entryPoints": [
3+
{
4+
"filePath": "agent",
5+
"uniqueId": "3bbc70ec-e5b3-4c2a-ac2c-98e499a2c351",
6+
"type": "agent",
7+
"input": {
8+
"type": "object",
9+
"properties": {
10+
"topic": {
11+
"title": "Topic",
12+
"type": "string"
13+
}
14+
},
15+
"required": [
16+
"topic"
17+
]
18+
},
19+
"output": {
20+
"type": "object",
21+
"properties": {
22+
"report": {
23+
"default": null,
24+
"title": "Report",
25+
"type": "string"
26+
}
27+
},
28+
"required": []
29+
}
30+
}
31+
],
32+
"bindings": {
33+
"version": "2.0",
34+
"resources": []
35+
}
36+
}

tests/cli/test_run.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import json
2+
import os
3+
import tempfile
4+
5+
import pytest
6+
7+
from uipath_langchain._cli.cli_run import langgraph_run_middleware
8+
9+
10+
@pytest.fixture
11+
def simple_agent() -> str:
12+
if os.path.isfile("mocks/simple_agent.py"):
13+
with open("mocks/simple_agent.py", "r") as file:
14+
data = file.read()
15+
else:
16+
with open("tests/cli/mocks/simple_agent.py", "r") as file:
17+
data = file.read()
18+
return data
19+
20+
21+
@pytest.fixture
22+
def uipath_json() -> str:
23+
if os.path.isfile("mocks/uipath.json"):
24+
with open("mocks/uipath.json", "r") as file:
25+
data = file.read()
26+
else:
27+
with open("tests/cli/mocks/uipath.json", "r") as file:
28+
data = file.read()
29+
return data
30+
31+
32+
@pytest.fixture
33+
def langgraph_json() -> str:
34+
if os.path.isfile("mocks/langgraph.json"):
35+
with open("mocks/langgraph.json", "r") as file:
36+
data = file.read()
37+
else:
38+
with open("tests/cli/mocks/langgraph.json", "r") as file:
39+
data = file.read()
40+
return data
41+
42+
43+
class TestRun:
44+
def test_successful_execution(
45+
self,
46+
langgraph_json: str,
47+
uipath_json: str,
48+
simple_agent: str,
49+
mock_env_vars: dict[str, str],
50+
):
51+
os.environ.clear()
52+
os.environ.update(mock_env_vars)
53+
input_file_name = "input.json"
54+
output_file_name = "output.json"
55+
agent_file_name = "main.py"
56+
input_json_content = {"topic": "UiPath"}
57+
with tempfile.TemporaryDirectory() as temp_dir:
58+
current_dir = os.getcwd()
59+
os.chdir(temp_dir)
60+
# Create input and output files
61+
input_file_path = os.path.join(temp_dir, input_file_name)
62+
output_file_path = os.path.join(temp_dir, output_file_name)
63+
64+
with open(input_file_path, "w") as f:
65+
f.write(json.dumps(input_json_content))
66+
67+
# Create test script
68+
script_file_path = os.path.join(temp_dir, agent_file_name)
69+
with open(script_file_path, "w") as f:
70+
f.write(simple_agent)
71+
72+
# create uipath.json
73+
uipath_json_file_path = os.path.join(temp_dir, "uipath.json")
74+
with open(uipath_json_file_path, "w") as f:
75+
f.write(uipath_json)
76+
77+
# Create langgraph.json
78+
langgraph_json_file_path = os.path.join(temp_dir, "langgraph.json")
79+
with open(langgraph_json_file_path, "w") as f:
80+
f.write(langgraph_json)
81+
82+
result = langgraph_run_middleware(
83+
entrypoint="agent",
84+
input=None,
85+
resume=False,
86+
input_file=input_file_path,
87+
execution_output_file=output_file_path,
88+
)
89+
assert result.should_continue is False
90+
assert os.path.exists(output_file_path)
91+
with open(output_file_path, "r") as f:
92+
output = f.read()
93+
assert "This is mock report for" in output
94+
95+
os.chdir(current_dir)

uv.lock

Lines changed: 6 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)