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
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[project]
name = "uipath-langchain"
version = "0.11.4"
version = "0.11.5"
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"
dependencies = [
"uipath>=2.10.69, <2.11.0",
"uipath>=2.10.70, <2.11.0",
"uipath-core>=0.5.15, <0.6.0",
"uipath-platform>=0.1.45, <0.2.0",
"uipath-runtime>=0.10.0, <0.11.0",
Expand Down
85 changes: 76 additions & 9 deletions src/uipath_langchain/agent/tools/static_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import copy
import logging
import re
from typing import Any, Iterator, Mapping, Sequence, TypeVar

from jsonpath_ng import parse # type: ignore[import-untyped]
Expand All @@ -12,6 +13,7 @@
from uipath.agent.models.agent import (
AgentToolArgumentArgumentProperties,
AgentToolArgumentProperties,
AgentToolArrayBuilderArgumentProperties,
AgentToolStaticArgumentProperties,
AgentToolTextBuilderArgumentProperties,
)
Expand All @@ -37,10 +39,16 @@
"""Tool static argument model."""

value: Any
display_value: Any
is_sensitive: bool


_INDEX_AND_REST_REGEX = re.compile(r"^\[(\d+)\](.*)$")

_SENSITIVE_ITEM_PLACEHOLDER = "<hidden>"


def _resolve_argument_properties(

Check failure on line 51 in src/uipath_langchain/agent/tools/static_args.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 38 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=UiPath_uipath-langchain-python&issues=AZ5K0GxNVpekpcmFrUgv&open=AZ5K0GxNVpekpcmFrUgv&pullRequest=871
argument_properties: Mapping[str, AgentToolArgumentProperties],
agent_input: dict[str, Any],
) -> dict[str, ToolStaticArgument]:
Expand All @@ -48,12 +56,15 @@

def resolve_to_static(
props: AgentToolArgumentProperties,
json_path: str,
) -> ToolStaticArgument | None:
"""Resolves argument and textBuilder variants to static."""
"""Resolves argument, textBuilder, and arrayBuilder variants to static."""
match props:
case AgentToolStaticArgumentProperties():
return ToolStaticArgument(
value=props.value, is_sensitive=props.is_sensitive
value=props.value,
display_value=props.value,
is_sensitive=props.is_sensitive,
)
case AgentToolArgumentArgumentProperties():
agent_argument = parse(props.argument_path).find(agent_input)
Expand All @@ -62,30 +73,86 @@
else:
argument_value = agent_argument[0].value
return ToolStaticArgument(
value=argument_value, is_sensitive=props.is_sensitive
value=argument_value,
display_value=argument_value,
is_sensitive=props.is_sensitive,
)
case AgentToolTextBuilderArgumentProperties():
text_value = build_string_from_tokens(props.tokens, agent_input)
return ToolStaticArgument(
value=text_value, is_sensitive=props.is_sensitive
value=text_value,
display_value=text_value,
is_sensitive=props.is_sensitive,
)
case AgentToolArrayBuilderArgumentProperties():
return resolve_arraybuilder(json_path, argument_properties)
case _:
raise ValueError(f"Unsupported argument property type: {type(props)}")

def resolve_arraybuilder(
base_path: str,
argument_properties: Mapping[str, AgentToolArgumentProperties],
) -> ToolStaticArgument:
"""Build an array value from arrayBuilder indexed children.

Only direct indexed children ``base_path[N]`` are considered; entries
with other nested properties are out of scope and silently skipped."""

base_with_bracket = base_path + "["
direct_children: dict[int, AgentToolArgumentProperties] = {}
max_index = -1

for path, props in argument_properties.items():
if not path.startswith(base_with_bracket):
continue
match = _INDEX_AND_REST_REGEX.match(path[len(base_path) :])
if not match or match.group(2) != "":
continue
idx = int(match.group(1))
direct_children[idx] = props
if idx > max_index:
max_index = idx

runtime_items: list[Any] = []
display_items: list[Any] = []
for i in range(max_index + 1):
item_props = direct_children.get(i)
if item_props is None:
runtime_items.append(None)
display_items.append(None)
continue
resolved = resolve_to_static(item_props, f"{base_path}[{i}]")
if resolved is None:
runtime_items.append(None)
display_items.append(None)
else:
runtime_items.append(resolved.value)
display_value = (
_SENSITIVE_ITEM_PLACEHOLDER
if resolved.is_sensitive
else resolved.display_value
)
display_items.append(display_value)

return ToolStaticArgument(
value=runtime_items, display_value=display_items, is_sensitive=False
)

def deduplicate_argument_properties(
properties: Mapping[str, AgentToolArgumentProperties],
) -> Iterator[tuple[str, AgentToolArgumentProperties]]:
"""Skips more specific argument properties. In effect, prioritizes parent paths over child paths."""

sorted_paths = sorted(properties.keys())
for i, json_path in enumerate(sorted_paths):
if i > 0 and json_path.startswith(sorted_paths[i - 1]):
last_yielded: str | None = None
for json_path in sorted(properties.keys()):
if last_yielded is not None and json_path.startswith(last_yielded):
continue
yield json_path, properties[json_path]
last_yielded = json_path

static_args: dict[str, ToolStaticArgument] = {}
for json_path, props in deduplicate_argument_properties(argument_properties):
static_arg = resolve_to_static(props)
static_arg = resolve_to_static(props, json_path)
if static_arg is not None:
static_args[json_path] = static_arg
return static_args
Expand Down Expand Up @@ -119,7 +186,7 @@
apply_static_value_to_schema(
modified_json_schema,
json_path,
static_arg.value,
static_arg.display_value,
static_arg.is_sensitive,
)
except SchemaModificationError as e:
Expand Down
Loading
Loading