Skip to content

Commit 3a36a91

Browse files
authored
Merge pull request #237 from UiPath/fix/set_breakpoints
fix: set breakpoints for debug
2 parents c58ecc5 + c7108e7 commit 3a36a91

File tree

9 files changed

+77
-44
lines changed

9 files changed

+77
-44
lines changed

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "uipath-langchain"
3-
version = "0.0.143"
3+
version = "0.0.144"
44
description = "UiPath Langchain"
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.10"
@@ -111,4 +111,4 @@ asyncio_mode = "auto"
111111
name = "testpypi"
112112
url = "https://test.pypi.org/simple/"
113113
publish-url = "https://test.pypi.org/legacy/"
114-
explicit = true
114+
explicit = true
Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,43 @@
1-
from typing import Optional
1+
from enum import Enum
2+
from typing import Optional, Union
23

3-
from uipath._cli._runtime._contracts import UiPathErrorCategory, UiPathRuntimeError
4+
from uipath._cli._runtime._contracts import (
5+
UiPathBaseRuntimeError,
6+
UiPathErrorCategory,
7+
UiPathErrorCode,
8+
)
49

510

6-
class LangGraphRuntimeError(UiPathRuntimeError):
11+
class LangGraphErrorCode(Enum):
12+
CONFIG_MISSING = "CONFIG_MISSING"
13+
CONFIG_INVALID = "CONFIG_INVALID"
14+
15+
GRAPH_NOT_FOUND = "GRAPH_NOT_FOUND"
16+
GRAPH_IMPORT_ERROR = "GRAPH_IMPORT_ERROR"
17+
GRAPH_TYPE_ERROR = "GRAPH_TYPE_ERROR"
18+
GRAPH_VALUE_ERROR = "GRAPH_VALUE_ERROR"
19+
GRAPH_LOAD_ERROR = "GRAPH_LOAD_ERROR"
20+
GRAPH_INVALID_UPDATE = "GRAPH_INVALID_UPDATE"
21+
GRAPH_EMPTY_INPUT = "GRAPH_EMPTY_INPUT"
22+
23+
DB_QUERY_FAILED = "DB_QUERY_FAILED"
24+
DB_TABLE_CREATION_FAILED = "DB_TABLE_CREATION_FAILED"
25+
HITL_EVENT_CREATION_FAILED = "HITL_EVENT_CREATION_FAILED"
26+
DB_INSERT_FAILED = "DB_INSERT_FAILED"
27+
LICENSE_NOT_AVAILABLE = "LICENSE_NOT_AVAILABLE"
28+
29+
30+
class LangGraphRuntimeError(UiPathBaseRuntimeError):
731
"""Custom exception for LangGraph runtime errors with structured error information."""
832

933
def __init__(
1034
self,
11-
code: str,
35+
code: Union[LangGraphErrorCode, UiPathErrorCode],
1236
title: str,
1337
detail: str,
1438
category: UiPathErrorCategory = UiPathErrorCategory.UNKNOWN,
1539
status: Optional[int] = None,
1640
):
17-
super().__init__(code, title, detail, category, status, prefix="LANGGRAPH")
41+
super().__init__(
42+
code.value, title, detail, category, status, prefix="LANGGRAPH"
43+
)

src/uipath_langchain/_cli/_runtime/_graph_resolver.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@
22
from typing import Any, Awaitable, Callable, Optional
33

44
from langgraph.graph.state import CompiledStateGraph, StateGraph
5-
from uipath._cli._runtime._contracts import (
6-
UiPathErrorCategory,
7-
)
5+
from uipath._cli._runtime._contracts import UiPathErrorCategory, UiPathErrorCode
86

97
from .._utils._graph import GraphConfig, LangGraphConfig
10-
from ._exception import LangGraphRuntimeError
8+
from ._exception import LangGraphErrorCode, LangGraphRuntimeError
119

1210

1311
class LangGraphJsonResolver:
@@ -36,7 +34,7 @@ async def _resolve(self, entrypoint: Optional[str]) -> StateGraph[Any, Any, Any]
3634
config = LangGraphConfig()
3735
if not config.exists:
3836
raise LangGraphRuntimeError(
39-
"CONFIG_MISSING",
37+
LangGraphErrorCode.CONFIG_MISSING,
4038
"Invalid configuration",
4139
"Failed to load configuration",
4240
UiPathErrorCategory.DEPLOYMENT,
@@ -46,7 +44,7 @@ async def _resolve(self, entrypoint: Optional[str]) -> StateGraph[Any, Any, Any]
4644
config.load_config()
4745
except Exception as e:
4846
raise LangGraphRuntimeError(
49-
"CONFIG_INVALID",
47+
LangGraphErrorCode.CONFIG_INVALID,
5048
"Invalid configuration",
5149
f"Failed to load configuration: {str(e)}",
5250
UiPathErrorCategory.DEPLOYMENT,
@@ -59,7 +57,7 @@ async def _resolve(self, entrypoint: Optional[str]) -> StateGraph[Any, Any, Any]
5957
elif not entrypoint:
6058
graph_names = ", ".join(g.name for g in graphs)
6159
raise LangGraphRuntimeError(
62-
"ENTRYPOINT_MISSING",
60+
UiPathErrorCode.ENTRYPOINT_MISSING,
6361
"Entrypoint required",
6462
f"Multiple graphs available. Please specify one of: {graph_names}.",
6563
UiPathErrorCategory.DEPLOYMENT,
@@ -69,7 +67,7 @@ async def _resolve(self, entrypoint: Optional[str]) -> StateGraph[Any, Any, Any]
6967
self.graph_config = config.get_graph(entrypoint)
7068
if not self.graph_config:
7169
raise LangGraphRuntimeError(
72-
"GRAPH_NOT_FOUND",
70+
LangGraphErrorCode.GRAPH_NOT_FOUND,
7371
"Graph not found",
7472
f"Graph '{entrypoint}' not found.",
7573
UiPathErrorCategory.DEPLOYMENT,
@@ -83,28 +81,28 @@ async def _resolve(self, entrypoint: Optional[str]) -> StateGraph[Any, Any, Any]
8381
)
8482
except ImportError as e:
8583
raise LangGraphRuntimeError(
86-
"GRAPH_IMPORT_ERROR",
84+
LangGraphErrorCode.GRAPH_IMPORT_ERROR,
8785
"Graph import failed",
8886
f"Failed to import graph '{entrypoint}': {str(e)}",
8987
UiPathErrorCategory.USER,
9088
) from e
9189
except TypeError as e:
9290
raise LangGraphRuntimeError(
93-
"GRAPH_TYPE_ERROR",
91+
LangGraphErrorCode.GRAPH_TYPE_ERROR,
9492
"Invalid graph type",
9593
f"Graph '{entrypoint}' is not a valid StateGraph or CompiledStateGraph: {str(e)}",
9694
UiPathErrorCategory.USER,
9795
) from e
9896
except ValueError as e:
9997
raise LangGraphRuntimeError(
100-
"GRAPH_VALUE_ERROR",
98+
LangGraphErrorCode.GRAPH_VALUE_ERROR,
10199
"Invalid graph value",
102100
f"Invalid value in graph '{entrypoint}': {str(e)}",
103101
UiPathErrorCategory.USER,
104102
) from e
105103
except Exception as e:
106104
raise LangGraphRuntimeError(
107-
"GRAPH_LOAD_ERROR",
105+
LangGraphErrorCode.GRAPH_LOAD_ERROR,
108106
"Failed to load graph",
109107
f"Unexpected error loading graph '{entrypoint}': {str(e)}",
110108
UiPathErrorCategory.USER,

src/uipath_langchain/_cli/_runtime/_input.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
from ._context import LangGraphRuntimeContext
1515
from ._conversation import uipath_to_human_messages
16-
from ._exception import LangGraphRuntimeError
16+
from ._exception import LangGraphErrorCode, LangGraphRuntimeError
1717

1818
logger = logging.getLogger(__name__)
1919

@@ -140,7 +140,7 @@ async def _get_latest_trigger(
140140
return cast(tuple[str, str, str, str, str], tuple(result))
141141
except Exception as e:
142142
raise LangGraphRuntimeError(
143-
"DB_QUERY_FAILED",
143+
LangGraphErrorCode.DB_QUERY_FAILED,
144144
"Database query failed",
145145
f"Error querying resume trigger information: {str(e)}",
146146
UiPathErrorCategory.SYSTEM,

src/uipath_langchain/_cli/_runtime/_output.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,10 @@
33
from typing import Any
44

55
from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
6-
from uipath._cli._runtime._contracts import (
7-
UiPathErrorCategory,
8-
UiPathResumeTrigger,
9-
)
6+
from uipath._cli._runtime._contracts import UiPathErrorCategory, UiPathResumeTrigger
107
from uipath._cli._runtime._hitl import HitlProcessor
118

12-
from ._exception import LangGraphRuntimeError
9+
from ._exception import LangGraphErrorCode, LangGraphRuntimeError
1310

1411
logger = logging.getLogger(__name__)
1512

@@ -93,7 +90,7 @@ async def create_and_save_resume_trigger(
9390
""")
9491
except Exception as e:
9592
raise LangGraphRuntimeError(
96-
"DB_TABLE_CREATION_FAILED",
93+
LangGraphErrorCode.DB_TABLE_CREATION_FAILED,
9794
"Failed to create resume triggers table",
9895
f"Database error while creating table: {str(e)}",
9996
UiPathErrorCategory.SYSTEM,
@@ -104,7 +101,7 @@ async def create_and_save_resume_trigger(
104101
resume_trigger = await hitl_processor.create_resume_trigger()
105102
except Exception as e:
106103
raise LangGraphRuntimeError(
107-
"HITL_EVENT_CREATION_FAILED",
104+
LangGraphErrorCode.HITL_EVENT_CREATION_FAILED,
108105
"Failed to process HITL request",
109106
f"Error while trying to process HITL request: {str(e)}",
110107
UiPathErrorCategory.SYSTEM,
@@ -139,7 +136,7 @@ async def create_and_save_resume_trigger(
139136
await memory.conn.commit()
140137
except Exception as e:
141138
raise LangGraphRuntimeError(
142-
"DB_INSERT_FAILED",
139+
LangGraphErrorCode.DB_INSERT_FAILED,
143140
"Failed to save resume trigger",
144141
f"Database error while saving resume trigger: {str(e)}",
145142
UiPathErrorCategory.SYSTEM,

src/uipath_langchain/_cli/_runtime/_runtime.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
UiPathBaseRuntime,
1313
UiPathBreakpointResult,
1414
UiPathErrorCategory,
15+
UiPathErrorCode,
1516
UiPathResumeTrigger,
1617
UiPathRuntimeResult,
1718
UiPathRuntimeStatus,
@@ -23,7 +24,7 @@
2324
)
2425

2526
from ._context import LangGraphRuntimeContext
26-
from ._exception import LangGraphRuntimeError
27+
from ._exception import LangGraphErrorCode, LangGraphRuntimeError
2728
from ._graph_resolver import AsyncResolver, LangGraphJsonResolver
2829
from ._input import get_graph_input
2930
from ._output import create_and_save_resume_trigger, serialize_output
@@ -79,7 +80,11 @@ async def execute(self) -> Optional[UiPathRuntimeResult]:
7980
graph_config = self._get_graph_config()
8081

8182
# Execute without streaming
82-
graph_output = await compiled_graph.ainvoke(graph_input, graph_config)
83+
graph_output = await compiled_graph.ainvoke(
84+
graph_input,
85+
graph_config,
86+
interrupt_before=self.context.breakpoints,
87+
)
8388

8489
# Get final state and create result
8590
self.context.result = await self._create_runtime_result(
@@ -140,6 +145,7 @@ async def stream(
140145
async for stream_chunk in compiled_graph.astream(
141146
graph_input,
142147
graph_config,
148+
interrupt_before=self.context.breakpoints,
143149
stream_mode=["messages", "updates"],
144150
subgraphs=True,
145151
):
@@ -426,30 +432,30 @@ def _create_runtime_error(self, e: Exception) -> LangGraphRuntimeError:
426432

427433
if isinstance(e, GraphRecursionError):
428434
return LangGraphRuntimeError(
429-
"GRAPH_RECURSION_ERROR",
435+
LangGraphErrorCode.GRAPH_LOAD_ERROR,
430436
"Graph recursion limit exceeded",
431437
detail,
432438
UiPathErrorCategory.USER,
433439
)
434440

435441
if isinstance(e, InvalidUpdateError):
436442
return LangGraphRuntimeError(
437-
"GRAPH_INVALID_UPDATE",
443+
LangGraphErrorCode.GRAPH_INVALID_UPDATE,
438444
str(e),
439445
detail,
440446
UiPathErrorCategory.USER,
441447
)
442448

443449
if isinstance(e, EmptyInputError):
444450
return LangGraphRuntimeError(
445-
"GRAPH_EMPTY_INPUT",
451+
LangGraphErrorCode.GRAPH_EMPTY_INPUT,
446452
"The input data is empty",
447453
detail,
448454
UiPathErrorCategory.USER,
449455
)
450456

451457
return LangGraphRuntimeError(
452-
"EXECUTION_ERROR",
458+
UiPathErrorCode.EXECUTION_ERROR,
453459
"Graph execution failed",
454460
detail,
455461
UiPathErrorCategory.USER,

src/uipath_langchain/_utils/_request_mixin.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@
2020
from uipath._cli._runtime._contracts import UiPathErrorCategory, UiPathRuntimeError
2121
from uipath._utils._ssl_context import get_httpx_client_kwargs
2222

23-
from uipath_langchain._cli._runtime._exception import LangGraphRuntimeError
23+
from uipath_langchain._cli._runtime._exception import (
24+
LangGraphErrorCode,
25+
LangGraphRuntimeError,
26+
)
2427
from uipath_langchain._utils._settings import (
2528
UiPathClientFactorySettings,
2629
UiPathClientSettings,
@@ -371,7 +374,7 @@ def _make_status_error(
371374
title = body.get("title", "").lower()
372375
if title == "license not available":
373376
raise LangGraphRuntimeError(
374-
code="LICENSE_NOT_AVAILABLE",
377+
code=LangGraphErrorCode.LICENSE_NOT_AVAILABLE,
375378
title=body.get("title", "License Not Available"),
376379
detail=body.get(
377380
"detail", "License not available for this service"

src/uipath_langchain/agent/react/terminate_node.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from langchain_core.messages import AIMessage
66
from pydantic import BaseModel
7+
from uipath._cli._runtime._contracts import UiPathErrorCode
78
from uipath.agent.react import END_EXECUTION_TOOL, RAISE_ERROR_TOOL
89

910
from .exceptions import (
@@ -40,7 +41,9 @@ def terminate_node(state: AgentGraphState):
4041
)
4142
detail = tool_call["args"].get("details", "")
4243
raise AgentTerminationException(
43-
code="400", title=error_message, detail=detail
44+
code=UiPathErrorCode.EXECUTION_ERROR,
45+
title=error_message,
46+
detail=detail,
4447
)
4548

4649
raise AgentNodeRoutingException(

uv.lock

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

0 commit comments

Comments
 (0)