Skip to content

Commit 9ffa4d6

Browse files
feat: bindings and bindings overwrites support (#4)
1 parent 605fa59 commit 9ffa4d6

23 files changed

Lines changed: 387 additions & 493 deletions

File tree

src/uipath_lowcode/_cli/cli_run.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import asyncio
22
import os
3+
from pathlib import Path
34
from typing import Optional
45

56
from openinference.instrumentation.langchain import (
@@ -28,7 +29,10 @@
2829
_instrument_traceable_attributes,
2930
)
3031

31-
from ..lowcode_agent_graph_builder import build_lowcode_agent_graph
32+
from ..agent_graph_builder import build_agent_graph
33+
from .constants import AGENT_FILENAME
34+
from .input_loader import load_agent_configuration
35+
from .runtime import AgentLangGraphRuntime
3236

3337

3438
def lowcode_run_middleware(
@@ -51,9 +55,13 @@ def lowcode_run_middleware(
5155

5256
def generate_runtime(ctx: LangGraphRuntimeContext) -> LangGraphRuntime:
5357
async def graph_builder():
54-
return await build_lowcode_agent_graph(input_data=ctx.input)
58+
agent_json_path = Path.cwd() / AGENT_FILENAME
59+
agent_definition = load_agent_configuration(agent_json_path)
60+
61+
return await build_agent_graph(agent_definition, input_data=ctx.input)
62+
63+
runtime = AgentLangGraphRuntime(ctx, graph_builder)
5564

56-
runtime = LangGraphRuntime(ctx, graph_builder)
5765
# If not resuming and no job id, delete the previous state file
5866
if not ctx.resume and ctx.job_id is None:
5967
if os.path.exists(runtime.state_file_path):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
AGENT_FILENAME = "agent.json"

src/uipath_lowcode/lowcode_agent_graph_builder/exceptions.py renamed to src/uipath_lowcode/_cli/exceptions.py

File renamed without changes.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from pathlib import Path
2+
3+
from pydantic import ValidationError
4+
from uipath.agent.models.agent import LowCodeAgentDefinition
5+
6+
from .constants import (
7+
AGENT_FILENAME,
8+
)
9+
from .exceptions import (
10+
ConfigurationError,
11+
InputValidationError,
12+
)
13+
14+
15+
def load_agent_configuration(file_path: Path) -> LowCodeAgentDefinition:
16+
"""Load and validate agent.json configuration.
17+
18+
Raises:
19+
ConfigurationError: If file missing or has invalid structure
20+
InputValidationError: If validation against schema fails
21+
"""
22+
if not file_path.exists():
23+
raise ConfigurationError(f"{AGENT_FILENAME} not found at {file_path}")
24+
25+
try:
26+
return LowCodeAgentDefinition.model_validate_json(file_path.read_text())
27+
except ValidationError as e:
28+
raise InputValidationError(
29+
f"{AGENT_FILENAME} failed schema validation. Error: {e}",
30+
validation_errors=e.errors(),
31+
) from e
32+
except (ValueError, TypeError) as e:
33+
raise ConfigurationError(
34+
f"Invalid {AGENT_FILENAME} structure. Error: {e}"
35+
) from e

src/uipath_lowcode/_cli/runtime.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from uipath_langchain._cli._runtime._runtime import (
2+
LangGraphRuntime,
3+
)
4+
5+
6+
class AgentLangGraphRuntime(LangGraphRuntime):
7+
pass
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"""Agent Graph Builder - Translates agent.json to LangGraph StateGraph."""
2+
3+
from .graph import build_agent_graph
4+
5+
__all__ = ["build_agent_graph"]
6+
7+
__version__ = "0.1.0"

src/uipath_lowcode/lowcode_agent_graph_builder/graph.py renamed to src/uipath_lowcode/agent_graph_builder/graph.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
"""LowCode Agent graph construction - wrapper delegating to uipath_langchain.agent.graph."""
1+
"""Agent graph construction - wrapper delegating to uipath_langchain.agent.graph."""
22

3-
from pathlib import Path
43
from typing import Any, Optional, Union
54

65
from langgraph.graph import StateGraph
6+
from uipath.agent.models.agent import LowCodeAgentDefinition
77
from uipath_langchain.agent.react import (
88
AgentGraphConfig,
99
AgentGraphState,
@@ -12,25 +12,20 @@
1212
)
1313
from uipath_langchain.agent.tools import create_tools_from_resources
1414

15-
from .constants import (
16-
AGENT_CONFIG_FILENAME,
17-
AGENT_LOOP_RECURSION_LIMIT,
18-
)
19-
from .input_loader import load_agent_configuration, load_input_arguments
15+
from .input_utils import validate_input_data
2016
from .llm_utils import create_llm
2117
from .message_utils import build_agent_messages
2218

19+
AGENT_LOOP_RECURSION_LIMIT = 50
20+
2321

24-
async def build_lowcode_agent_graph(
22+
async def build_agent_graph(
23+
agent_definition: LowCodeAgentDefinition,
2524
input_data: Optional[Union[str, dict[str, Any]]] = None,
2625
) -> StateGraph[AgentGraphState]:
2726
"""Build LangGraph agent from agent.json configuration and optional input data."""
2827

29-
agent_json_path = Path.cwd() / AGENT_CONFIG_FILENAME
30-
agent_definition = load_agent_configuration(agent_json_path)
31-
input_arguments = load_input_arguments(
32-
agent_definition.input_schema, input_data=input_data
33-
)
28+
input_arguments = validate_input_data(agent_definition.input_schema, input_data)
3429

3530
tools = await create_tools_from_resources(agent_definition)
3631
llm = create_llm(
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from typing import Any, Optional, Union
2+
3+
from jsonschema_pydantic import jsonschema_to_pydantic
4+
5+
6+
def validate_input_data(
7+
input_schema: dict[str, Any],
8+
input_data: Optional[Union[str, dict[str, Any]]] = None,
9+
) -> dict[str, Any]:
10+
"""Load and validate input arguments against schema.
11+
12+
Raises:
13+
InputValidationError: If input doesn't match schema
14+
ConfigurationError: If input has invalid structure
15+
"""
16+
try:
17+
if input_data is None or input_data == "":
18+
return {}
19+
20+
pydantic_input_model = jsonschema_to_pydantic(input_schema)
21+
22+
if isinstance(input_data, str):
23+
parsed_data = pydantic_input_model.model_validate_json(input_data)
24+
else:
25+
parsed_data = pydantic_input_model.model_validate(input_data)
26+
27+
return parsed_data.model_dump()
28+
29+
except Exception as e:
30+
raise Exception(
31+
"Agent input failed schema validation",
32+
validation_errors=e.errors(),
33+
) from e

src/uipath_lowcode/lowcode_agent_graph_builder/llm_utils.py renamed to src/uipath_lowcode/agent_graph_builder/llm_utils.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from uipath_langchain.chat.models import UiPathChat
22

3-
# LLM configuration defaults
43
LLM_TIMEOUT_SECONDS = 300
54
LLM_MAX_RETRIES = 2
65

src/uipath_lowcode/lowcode_agent_graph_builder/message_utils.py renamed to src/uipath_lowcode/agent_graph_builder/message_utils.py

File renamed without changes.

0 commit comments

Comments
 (0)