uipath-langchain 0.0.144__py3-none-any.whl → 0.0.146__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of uipath-langchain might be problematic. Click here for more details.

@@ -2,12 +2,14 @@ import logging
2
2
  import os
3
3
  from contextlib import asynccontextmanager
4
4
  from typing import Any, AsyncGenerator, AsyncIterator, Optional, Sequence
5
+ from uuid import uuid4
5
6
 
6
7
  from langchain_core.runnables.config import RunnableConfig
7
8
  from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
8
9
  from langgraph.errors import EmptyInputError, GraphRecursionError, InvalidUpdateError
9
10
  from langgraph.graph.state import CompiledStateGraph, StateGraph
10
11
  from langgraph.types import Interrupt, StateSnapshot
12
+ from typing_extensions import override
11
13
  from uipath._cli._runtime._contracts import (
12
14
  UiPathBaseRuntime,
13
15
  UiPathBreakpointResult,
@@ -17,12 +19,14 @@ from uipath._cli._runtime._contracts import (
17
19
  UiPathRuntimeResult,
18
20
  UiPathRuntimeStatus,
19
21
  )
22
+ from uipath._cli.models.runtime_schema import Entrypoint
20
23
  from uipath._events._events import (
21
24
  UiPathAgentMessageEvent,
22
25
  UiPathAgentStateEvent,
23
26
  UiPathRuntimeEvent,
24
27
  )
25
28
 
29
+ from .._utils._schema import generate_schema_from_graph
26
30
  from ._context import LangGraphRuntimeContext
27
31
  from ._exception import LangGraphErrorCode, LangGraphRuntimeError
28
32
  from ._graph_resolver import AsyncResolver, LangGraphJsonResolver
@@ -481,6 +485,21 @@ class LangGraphScriptRuntime(LangGraphRuntime):
481
485
  self.resolver = LangGraphJsonResolver(entrypoint=entrypoint)
482
486
  super().__init__(context, self.resolver)
483
487
 
488
+ @override
489
+ async def get_entrypoint(self) -> Entrypoint:
490
+ """Get entrypoint for this LangGraph runtime."""
491
+ graph = await self.resolver()
492
+ compiled_graph = graph.compile()
493
+ schema_details = generate_schema_from_graph(compiled_graph)
494
+
495
+ return Entrypoint(
496
+ file_path=self.context.entrypoint, # type: ignore[call-arg]
497
+ unique_id=str(uuid4()),
498
+ type="agent",
499
+ input=schema_details.schema["input"],
500
+ output=schema_details.schema["output"],
501
+ )
502
+
484
503
  async def cleanup(self) -> None:
485
504
  """Cleanup runtime resources including resolver."""
486
505
  await super().cleanup()
@@ -0,0 +1,137 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any, Dict
3
+
4
+ from langgraph.graph.state import CompiledStateGraph
5
+
6
+
7
+ @dataclass
8
+ class SchemaDetails:
9
+ schema: dict[str, Any]
10
+ has_input_circular_dependency: bool
11
+ has_output_circular_dependency: bool
12
+
13
+
14
+ def resolve_refs(schema, root=None, visited=None):
15
+ """Recursively resolves $ref references in a JSON schema, handling circular references.
16
+
17
+ Returns:
18
+ tuple: (resolved_schema, has_circular_dependency)
19
+ """
20
+ if root is None:
21
+ root = schema
22
+
23
+ if visited is None:
24
+ visited = set()
25
+
26
+ has_circular = False
27
+
28
+ if isinstance(schema, dict):
29
+ if "$ref" in schema:
30
+ ref_path = schema["$ref"]
31
+
32
+ if ref_path in visited:
33
+ # Circular dependency detected
34
+ return {
35
+ "type": "object",
36
+ "description": f"Circular reference to {ref_path}",
37
+ }, True
38
+
39
+ visited.add(ref_path)
40
+
41
+ # Resolve the reference
42
+ ref_parts = ref_path.lstrip("#/").split("/")
43
+ ref_schema = root
44
+ for part in ref_parts:
45
+ ref_schema = ref_schema.get(part, {})
46
+
47
+ result, circular = resolve_refs(ref_schema, root, visited)
48
+ has_circular = has_circular or circular
49
+
50
+ # Remove from visited after resolution (allows the same ref in different branches)
51
+ visited.discard(ref_path)
52
+
53
+ return result, has_circular
54
+
55
+ resolved_dict = {}
56
+ for k, v in schema.items():
57
+ resolved_value, circular = resolve_refs(v, root, visited)
58
+ resolved_dict[k] = resolved_value
59
+ has_circular = has_circular or circular
60
+ return resolved_dict, has_circular
61
+
62
+ elif isinstance(schema, list):
63
+ resolved_list = []
64
+ for item in schema:
65
+ resolved_item, circular = resolve_refs(item, root, visited)
66
+ resolved_list.append(resolved_item)
67
+ has_circular = has_circular or circular
68
+ return resolved_list, has_circular
69
+
70
+ return schema, False
71
+
72
+
73
+ def process_nullable_types(
74
+ schema: Dict[str, Any] | list[Any] | Any,
75
+ ) -> Dict[str, Any] | list[Any]:
76
+ """Process the schema to handle nullable types by removing anyOf with null and keeping the base type."""
77
+ if isinstance(schema, dict):
78
+ if "anyOf" in schema and len(schema["anyOf"]) == 2:
79
+ types = [t.get("type") for t in schema["anyOf"]]
80
+ if "null" in types:
81
+ non_null_type = next(
82
+ t for t in schema["anyOf"] if t.get("type") != "null"
83
+ )
84
+ return non_null_type
85
+
86
+ return {k: process_nullable_types(v) for k, v in schema.items()}
87
+ elif isinstance(schema, list):
88
+ return [process_nullable_types(item) for item in schema]
89
+ return schema
90
+
91
+
92
+ def generate_schema_from_graph(
93
+ graph: CompiledStateGraph[Any, Any, Any],
94
+ ) -> SchemaDetails:
95
+ """Extract input/output schema from a LangGraph graph"""
96
+ input_circular_dependency = False
97
+ output_circular_dependency = False
98
+ schema = {
99
+ "input": {"type": "object", "properties": {}, "required": []},
100
+ "output": {"type": "object", "properties": {}, "required": []},
101
+ }
102
+
103
+ if hasattr(graph, "input_schema"):
104
+ if hasattr(graph.input_schema, "model_json_schema"):
105
+ input_schema = graph.input_schema.model_json_schema()
106
+ unpacked_ref_def_properties, input_circular_dependency = resolve_refs(
107
+ input_schema
108
+ )
109
+
110
+ # Process the schema to handle nullable types
111
+ processed_properties = process_nullable_types(
112
+ unpacked_ref_def_properties.get("properties", {})
113
+ )
114
+
115
+ schema["input"]["properties"] = processed_properties
116
+ schema["input"]["required"] = unpacked_ref_def_properties.get(
117
+ "required", []
118
+ )
119
+
120
+ if hasattr(graph, "output_schema"):
121
+ if hasattr(graph.output_schema, "model_json_schema"):
122
+ output_schema = graph.output_schema.model_json_schema()
123
+ unpacked_ref_def_properties, output_circular_dependency = resolve_refs(
124
+ output_schema
125
+ )
126
+
127
+ # Process the schema to handle nullable types
128
+ processed_properties = process_nullable_types(
129
+ unpacked_ref_def_properties.get("properties", {})
130
+ )
131
+
132
+ schema["output"]["properties"] = processed_properties
133
+ schema["output"]["required"] = unpacked_ref_def_properties.get(
134
+ "required", []
135
+ )
136
+
137
+ return SchemaDetails(schema, input_circular_dependency, output_circular_dependency)
@@ -6,8 +6,9 @@ from openinference.instrumentation.langchain import (
6
6
  get_current_span,
7
7
  )
8
8
  from uipath._cli._evals._console_progress_reporter import ConsoleProgressReporter
9
+ from uipath._cli._evals._evaluate import evaluate
9
10
  from uipath._cli._evals._progress_reporter import StudioWebProgressReporter
10
- from uipath._cli._evals._runtime import UiPathEvalContext, UiPathEvalRuntime
11
+ from uipath._cli._evals._runtime import UiPathEvalContext
11
12
  from uipath._cli._runtime._contracts import (
12
13
  UiPathRuntimeFactory,
13
14
  )
@@ -82,14 +83,7 @@ def langgraph_eval_middleware(
82
83
 
83
84
  runtime_factory.add_instrumentor(LangChainInstrumentor, get_current_span)
84
85
 
85
- async def execute():
86
- async with UiPathEvalRuntime.from_eval_context(
87
- factory=runtime_factory, context=eval_context, event_bus=event_bus
88
- ) as eval_runtime:
89
- await eval_runtime.execute()
90
- await event_bus.wait_for_all()
91
-
92
- asyncio.run(execute())
86
+ asyncio.run(evaluate(runtime_factory, eval_context, event_bus))
93
87
  return MiddlewareResult(should_continue=False)
94
88
 
95
89
  except Exception as e:
@@ -6,7 +6,7 @@ import shutil
6
6
  import uuid
7
7
  from collections.abc import Generator
8
8
  from enum import Enum
9
- from typing import Any, Callable, Dict, overload
9
+ from typing import Any, Callable, overload
10
10
 
11
11
  import click
12
12
  from langgraph.graph.state import CompiledStateGraph
@@ -14,6 +14,8 @@ from uipath._cli._utils._console import ConsoleLogger
14
14
  from uipath._cli._utils._parse_ast import generate_bindings_json # type: ignore
15
15
  from uipath._cli.middlewares import MiddlewareResult
16
16
 
17
+ from uipath_langchain._cli._utils._schema import generate_schema_from_graph
18
+
17
19
  from ._utils._graph import LangGraphConfig
18
20
 
19
21
  console = ConsoleLogger()
@@ -27,88 +29,6 @@ class FileOperationStatus(str, Enum):
27
29
  SKIPPED = "skipped"
28
30
 
29
31
 
30
- def resolve_refs(schema, root=None):
31
- """Recursively resolves $ref references in a JSON schema."""
32
- if root is None:
33
- root = schema # Store the root schema to resolve $refs
34
-
35
- if isinstance(schema, dict):
36
- if "$ref" in schema:
37
- ref_path = schema["$ref"].lstrip("#/").split("/")
38
- ref_schema = root
39
- for part in ref_path:
40
- ref_schema = ref_schema.get(part, {})
41
- return resolve_refs(ref_schema, root)
42
-
43
- return {k: resolve_refs(v, root) for k, v in schema.items()}
44
-
45
- elif isinstance(schema, list):
46
- return [resolve_refs(item, root) for item in schema]
47
-
48
- return schema
49
-
50
-
51
- def process_nullable_types(
52
- schema: Dict[str, Any] | list[Any] | Any,
53
- ) -> Dict[str, Any] | list[Any]:
54
- """Process the schema to handle nullable types by removing anyOf with null and keeping the base type."""
55
- if isinstance(schema, dict):
56
- if "anyOf" in schema and len(schema["anyOf"]) == 2:
57
- types = [t.get("type") for t in schema["anyOf"]]
58
- if "null" in types:
59
- non_null_type = next(
60
- t for t in schema["anyOf"] if t.get("type") != "null"
61
- )
62
- return non_null_type
63
-
64
- return {k: process_nullable_types(v) for k, v in schema.items()}
65
- elif isinstance(schema, list):
66
- return [process_nullable_types(item) for item in schema]
67
- return schema
68
-
69
-
70
- def generate_schema_from_graph(
71
- graph: CompiledStateGraph[Any, Any, Any],
72
- ) -> Dict[str, Any]:
73
- """Extract input/output schema from a LangGraph graph"""
74
- schema = {
75
- "input": {"type": "object", "properties": {}, "required": []},
76
- "output": {"type": "object", "properties": {}, "required": []},
77
- }
78
-
79
- if hasattr(graph, "input_schema"):
80
- if hasattr(graph.input_schema, "model_json_schema"):
81
- input_schema = graph.input_schema.model_json_schema()
82
- unpacked_ref_def_properties = resolve_refs(input_schema)
83
-
84
- # Process the schema to handle nullable types
85
- processed_properties = process_nullable_types(
86
- unpacked_ref_def_properties.get("properties", {})
87
- )
88
-
89
- schema["input"]["properties"] = processed_properties
90
- schema["input"]["required"] = unpacked_ref_def_properties.get(
91
- "required", []
92
- )
93
-
94
- if hasattr(graph, "output_schema"):
95
- if hasattr(graph.output_schema, "model_json_schema"):
96
- output_schema = graph.output_schema.model_json_schema()
97
- unpacked_ref_def_properties = resolve_refs(output_schema)
98
-
99
- # Process the schema to handle nullable types
100
- processed_properties = process_nullable_types(
101
- unpacked_ref_def_properties.get("properties", {})
102
- )
103
-
104
- schema["output"]["properties"] = processed_properties
105
- schema["output"]["required"] = unpacked_ref_def_properties.get(
106
- "required", []
107
- )
108
-
109
- return schema
110
-
111
-
112
32
  def generate_agent_md_file(
113
33
  target_directory: str,
114
34
  file_name: str,
@@ -255,7 +175,7 @@ async def langgraph_init_middleware_async(
255
175
  else loaded_graph
256
176
  )
257
177
  compiled_graph = state_graph.compile()
258
- graph_schema = generate_schema_from_graph(compiled_graph)
178
+ schema_details = generate_schema_from_graph(compiled_graph)
259
179
 
260
180
  mermaids[graph.name] = compiled_graph.get_graph(xray=1).draw_mermaid()
261
181
 
@@ -277,11 +197,17 @@ async def langgraph_init_middleware_async(
277
197
  "filePath": graph.name,
278
198
  "uniqueId": str(uuid.uuid4()),
279
199
  "type": "agent",
280
- "input": graph_schema["input"],
281
- "output": graph_schema["output"],
200
+ "input": schema_details.schema["input"],
201
+ "output": schema_details.schema["output"],
282
202
  }
283
203
  entrypoints.append(new_entrypoint)
284
204
 
205
+ warning_circular_deps = f" schema of graph '{graph.name}' contains circular dependencies. Some types might not be correctly inferred."
206
+ if schema_details.has_input_circular_dependency:
207
+ console.warning("Input" + warning_circular_deps)
208
+ if schema_details.has_output_circular_dependency:
209
+ console.warning("Output" + warning_circular_deps)
210
+
285
211
  except Exception as e:
286
212
  console.error(f"Error during graph load: {e}")
287
213
  return MiddlewareResult(
@@ -323,6 +249,7 @@ async def langgraph_init_middleware_async(
323
249
  should_continue=False,
324
250
  should_include_stacktrace=True,
325
251
  )
252
+
326
253
  console.success(f"Created {click.style(config_path, fg='cyan')} file.")
327
254
 
328
255
  generate_agents_md_files(options)
@@ -0,0 +1,21 @@
1
+ """Runtime factory for LangGraph projects."""
2
+
3
+ from uipath._cli._runtime._contracts import UiPathRuntimeFactory
4
+
5
+ from ._cli._runtime._context import LangGraphRuntimeContext
6
+ from ._cli._runtime._runtime import LangGraphScriptRuntime
7
+
8
+
9
+ class LangGraphRuntimeFactory(
10
+ UiPathRuntimeFactory[LangGraphScriptRuntime, LangGraphRuntimeContext]
11
+ ):
12
+ """Factory for LangGraph runtimes."""
13
+
14
+ def __init__(self):
15
+ super().__init__(
16
+ LangGraphScriptRuntime,
17
+ LangGraphRuntimeContext,
18
+ context_generator=lambda **kwargs: LangGraphRuntimeContext.with_defaults(
19
+ **kwargs
20
+ ),
21
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uipath-langchain
3
- Version: 0.0.144
3
+ Version: 0.0.146
4
4
  Summary: UiPath Langchain
5
5
  Project-URL: Homepage, https://uipath.com
6
6
  Project-URL: Repository, https://github.com/UiPath/uipath-langchain-python
@@ -26,7 +26,7 @@ Requires-Dist: openai>=1.65.5
26
26
  Requires-Dist: openinference-instrumentation-langchain>=0.1.50
27
27
  Requires-Dist: pydantic-settings>=2.6.0
28
28
  Requires-Dist: python-dotenv>=1.0.1
29
- Requires-Dist: uipath<2.2.0,>=2.1.103
29
+ Requires-Dist: uipath<2.2.0,>=2.1.110
30
30
  Provides-Extra: langchain
31
31
  Description-Content-Type: text/markdown
32
32
 
@@ -1,11 +1,12 @@
1
1
  uipath_langchain/__init__.py,sha256=VBrvQn7d3nuOdN7zEnV2_S-uhmkjgEIlXiFVeZxZakQ,80
2
2
  uipath_langchain/middlewares.py,sha256=x3U_tmDIyMXPLzq6n-oNRAnpAF6pKa9wfkPYwE-oUfo,848
3
3
  uipath_langchain/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ uipath_langchain/runtime_factories.py,sha256=NFmEuXCraEfb2Sr02KQretYyVrtABUwnx5M68T6Z9Xo,644
4
5
  uipath_langchain/_cli/__init__.py,sha256=juqd9PbXs4yg45zMJ7BHAOPQjb7sgEbWE9InBtGZhfo,24
5
6
  uipath_langchain/_cli/cli_debug.py,sha256=zaB-W3_29FsCqF-YZ3EsayyxC957tg4tOjdcdX8ew-M,3311
6
7
  uipath_langchain/_cli/cli_dev.py,sha256=l3XFHrh-0OUFJq3zLMKuzedJAluGQBIZQTHP1KWOmpw,1725
7
- uipath_langchain/_cli/cli_eval.py,sha256=yzxOz-JOMMl1fejZNVQYlBSo-yUIxArtfp2EW1Ow6j4,3753
8
- uipath_langchain/_cli/cli_init.py,sha256=B-Ht1lz4HNlpYELZU7DLNhSrhGJbsaCdU9UMO2iHUgM,12654
8
+ uipath_langchain/_cli/cli_eval.py,sha256=Z1EYFObD0n-lfXfvjq4ejnrWQJrRrNktSxNPDE7QqSc,3529
9
+ uipath_langchain/_cli/cli_init.py,sha256=RtX3NMLgHj2gKNRKv2HW7iBI5gMrl7ZpkG6uV_f_arg,10145
9
10
  uipath_langchain/_cli/cli_new.py,sha256=KKLxCzz7cDQ__rRr_a496IHWlSQXhmrBNgmKHnXAnTY,2336
10
11
  uipath_langchain/_cli/cli_run.py,sha256=DIsAKsbQ8gTRz44q9ZV3jBjrbM8bhS6lEQ3dd4joDFU,3712
11
12
  uipath_langchain/_cli/_runtime/_context.py,sha256=mjmGEogKiO8tUV878BgV9rFIeA9MCmEH6hgs5W_dm4g,328
@@ -14,10 +15,11 @@ uipath_langchain/_cli/_runtime/_exception.py,sha256=xHKeu8njByiMcObbggyZk0cXYXX5
14
15
  uipath_langchain/_cli/_runtime/_graph_resolver.py,sha256=c-JrsX7rx_CflDPfKhz9q-PgBrgI2IOBcYwiffwddh8,5457
15
16
  uipath_langchain/_cli/_runtime/_input.py,sha256=HAJUxjNmOg9q7l_ebF1AzIKL5_ysXyjk1bWXHsjhEPI,5761
16
17
  uipath_langchain/_cli/_runtime/_output.py,sha256=2VvdW4olv7Vd0c4grtTQazXxfBbcuocgSSP6V2P8uHE,4887
17
- uipath_langchain/_cli/_runtime/_runtime.py,sha256=HFWU2h864Ifq0gK9-_Jy6sbg0CMxmFExSdSEiUArChE,18548
18
+ uipath_langchain/_cli/_runtime/_runtime.py,sha256=Cur3WdbIkDs60peF57QzaKl2YHP8-WBfpLXhTVLU_3c,19267
18
19
  uipath_langchain/_cli/_templates/langgraph.json.template,sha256=eeh391Gta_hoRgaNaZ58nW1LNvCVXA7hlAH6l7Veous,107
19
20
  uipath_langchain/_cli/_templates/main.py.template,sha256=GpSblGH2hwS9ibqQmX2iB2nsmOA5zDfEEF4ChLiMxbQ,875
20
21
  uipath_langchain/_cli/_utils/_graph.py,sha256=nMJWy8FmaD9rqPUY2lHc5uVpUzbXD1RO12uJnhe0kdo,6803
22
+ uipath_langchain/_cli/_utils/_schema.py,sha256=y0w0fADLxeOO-AipkhLJ7AX7azY6vmEIyBDzwaxUAPk,4716
21
23
  uipath_langchain/_resources/AGENTS.md,sha256=5VmIfaQ6H91VxInnxFmJklURXeWIIQpGQTYBEmvvoVA,1060
22
24
  uipath_langchain/_resources/REQUIRED_STRUCTURE.md,sha256=BRmWWFtM0qNXj5uumALVxq9h6pifJDGh5NzuyctuH1Q,2569
23
25
  uipath_langchain/_tracing/__init__.py,sha256=C2dRvQ2ynxCmyICgE-rJHimWKEcFRME_o9gfX84Mb3Y,123
@@ -55,8 +57,8 @@ uipath_langchain/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
55
57
  uipath_langchain/tools/preconfigured.py,sha256=SyvrLrM1kezZxVVytgScVO8nBfVYfFGobWjY7erzsYU,7490
56
58
  uipath_langchain/vectorstores/__init__.py,sha256=w8qs1P548ud1aIcVA_QhBgf_jZDrRMK5Lono78yA8cs,114
57
59
  uipath_langchain/vectorstores/context_grounding_vectorstore.py,sha256=TncIXG-YsUlO0R5ZYzWsM-Dj1SVCZbzmo2LraVxXelc,9559
58
- uipath_langchain-0.0.144.dist-info/METADATA,sha256=fnn1iHs-_Q0lyubeoDFTb6c5LGZaWZbpxDnMytjjbRg,4276
59
- uipath_langchain-0.0.144.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
60
- uipath_langchain-0.0.144.dist-info/entry_points.txt,sha256=FUtzqGOEntlJKMJIXhQUfT7ZTbQmGhke1iCmDWZaQZI,81
61
- uipath_langchain-0.0.144.dist-info/licenses/LICENSE,sha256=JDpt-uotAkHFmxpwxi6gwx6HQ25e-lG4U_Gzcvgp7JY,1063
62
- uipath_langchain-0.0.144.dist-info/RECORD,,
60
+ uipath_langchain-0.0.146.dist-info/METADATA,sha256=7u2FwmZLCfShij8MzNjH3-B3pVxqerwV99nGRAwVGSM,4276
61
+ uipath_langchain-0.0.146.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
62
+ uipath_langchain-0.0.146.dist-info/entry_points.txt,sha256=FUtzqGOEntlJKMJIXhQUfT7ZTbQmGhke1iCmDWZaQZI,81
63
+ uipath_langchain-0.0.146.dist-info/licenses/LICENSE,sha256=JDpt-uotAkHFmxpwxi6gwx6HQ25e-lG4U_Gzcvgp7JY,1063
64
+ uipath_langchain-0.0.146.dist-info/RECORD,,