uipath-langchain 0.0.131__py3-none-any.whl → 0.0.132__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,7 +2,6 @@ import logging
2
2
  from typing import Any, Optional, cast
3
3
 
4
4
  from langgraph.types import Command
5
- from uipath import UiPath
6
5
  from uipath._cli._runtime._contracts import (
7
6
  UiPathApiTrigger,
8
7
  UiPathErrorCategory,
@@ -32,7 +31,6 @@ class LangGraphInputProcessor:
32
31
  context: The runtime context for the graph execution.
33
32
  """
34
33
  self.context = context
35
- self.uipath = UiPath()
36
34
 
37
35
  async def process(self) -> Any:
38
36
  """
@@ -6,7 +6,6 @@ from typing import Any, Dict, List, Optional, Tuple, Union
6
6
  from langchain_core.callbacks.base import BaseCallbackHandler
7
7
  from langchain_core.messages import BaseMessage
8
8
  from langchain_core.runnables.config import RunnableConfig
9
- from langchain_core.tracers.langchain import wait_for_all_tracers
10
9
  from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
11
10
  from langgraph.errors import EmptyInputError, GraphRecursionError, InvalidUpdateError
12
11
  from langgraph.graph.state import CompiledStateGraph
@@ -16,8 +15,6 @@ from uipath._cli._runtime._contracts import (
16
15
  UiPathRuntimeResult,
17
16
  )
18
17
 
19
- from ..._utils import _instrument_traceable_attributes
20
- from ...tracers import AsyncUiPathTracer
21
18
  from .._utils._graph import LangGraphConfig
22
19
  from ._context import LangGraphRuntimeContext
23
20
  from ._conversation import map_message
@@ -48,13 +45,10 @@ class LangGraphRuntime(UiPathBaseRuntime):
48
45
  Raises:
49
46
  LangGraphRuntimeError: If execution fails
50
47
  """
51
- _instrument_traceable_attributes()
52
48
 
53
49
  if self.context.state_graph is None:
54
50
  return None
55
51
 
56
- tracer = None
57
-
58
52
  try:
59
53
  async with AsyncSqliteSaver.from_conn_string(
60
54
  self.state_file_path
@@ -71,13 +65,8 @@ class LangGraphRuntime(UiPathBaseRuntime):
71
65
 
72
66
  processed_input = await input_processor.process()
73
67
 
74
- # Set up tracing if available
75
68
  callbacks: List[BaseCallbackHandler] = []
76
69
 
77
- if self.context.job_id and self.context.tracing_enabled:
78
- tracer = AsyncUiPathTracer(context=self.context.trace_context)
79
- callbacks = [tracer]
80
-
81
70
  graph_config: RunnableConfig = {
82
71
  "configurable": {
83
72
  "thread_id": (
@@ -185,11 +174,7 @@ class LangGraphRuntime(UiPathBaseRuntime):
185
174
  UiPathErrorCategory.USER,
186
175
  ) from e
187
176
  finally:
188
- if tracer is not None:
189
- await tracer.wait_for_all_tracers()
190
-
191
- if self.context.langsmith_tracing_enabled:
192
- wait_for_all_tracers()
177
+ pass
193
178
 
194
179
  async def validate(self) -> None:
195
180
  """Validate runtime inputs."""
@@ -10,6 +10,7 @@ from uipath._cli._runtime._contracts import UiPathRuntimeFactory
10
10
  from uipath._cli._utils._console import ConsoleLogger
11
11
  from uipath._cli.middlewares import MiddlewareResult
12
12
 
13
+ from .._tracing import _instrument_traceable_attributes
13
14
  from ._runtime._context import LangGraphRuntimeContext
14
15
  from ._runtime._runtime import LangGraphRuntime
15
16
 
@@ -24,6 +25,8 @@ def langgraph_dev_middleware(interface: Optional[str]) -> MiddlewareResult:
24
25
  runtime_factory = UiPathRuntimeFactory(
25
26
  LangGraphRuntime, LangGraphRuntimeContext
26
27
  )
28
+
29
+ _instrument_traceable_attributes()
27
30
  runtime_factory.add_instrumentor(LangChainInstrumentor, get_current_span)
28
31
  app = UiPathDevTerminal(runtime_factory)
29
32
  asyncio.run(app.run_async())
@@ -1,7 +1,10 @@
1
1
  import asyncio
2
- from os import environ as env
3
2
  from typing import List, Optional
4
3
 
4
+ from openinference.instrumentation.langchain import (
5
+ LangChainInstrumentor,
6
+ get_current_span,
7
+ )
5
8
  from uipath._cli._evals._runtime import UiPathEvalContext, UiPathEvalRuntime
6
9
  from uipath._cli._runtime._contracts import (
7
10
  UiPathRuntimeFactory,
@@ -13,15 +16,15 @@ from uipath.eval._helpers import auto_discover_entrypoint
13
16
  from uipath_langchain._cli._runtime._context import LangGraphRuntimeContext
14
17
  from uipath_langchain._cli._runtime._runtime import LangGraphRuntime
15
18
  from uipath_langchain._cli._utils._graph import LangGraphConfig
19
+ from uipath_langchain._tracing import (
20
+ LangChainExporter,
21
+ _instrument_traceable_attributes,
22
+ )
16
23
 
17
24
 
18
25
  def langgraph_eval_middleware(
19
26
  entrypoint: Optional[str], eval_set: Optional[str], eval_ids: List[str], **kwargs
20
27
  ) -> MiddlewareResult:
21
- # Add default env variables
22
- env["UIPATH_REQUESTING_PRODUCT"] = "uipath-python-sdk"
23
- env["UIPATH_REQUESTING_FEATURE"] = "langgraph-agent"
24
-
25
28
  config = LangGraphConfig()
26
29
  if not config.exists:
27
30
  return MiddlewareResult(
@@ -33,6 +36,8 @@ def langgraph_eval_middleware(
33
36
  eval_context.eval_ids = eval_ids
34
37
 
35
38
  try:
39
+ _instrument_traceable_attributes()
40
+
36
41
  runtime_entrypoint = entrypoint or auto_discover_entrypoint()
37
42
 
38
43
  def generate_runtime_context(
@@ -53,6 +58,11 @@ def langgraph_eval_middleware(
53
58
  ),
54
59
  )
55
60
 
61
+ if eval_context.job_id:
62
+ runtime_factory.add_span_exporter(LangChainExporter())
63
+
64
+ runtime_factory.add_instrumentor(LangChainInstrumentor, get_current_span)
65
+
56
66
  async def execute():
57
67
  async with UiPathEvalRuntime.from_eval_context(
58
68
  factory=runtime_factory, context=eval_context
@@ -1,10 +1,17 @@
1
1
  import asyncio
2
2
  import os
3
- from os import environ as env
4
3
  from typing import Optional
5
4
 
5
+ from openinference.instrumentation.langchain import (
6
+ LangChainInstrumentor,
7
+ get_current_span,
8
+ )
9
+ from uipath._cli._runtime._contracts import (
10
+ UiPathRuntimeFactory,
11
+ )
6
12
  from uipath._cli.middlewares import MiddlewareResult
7
13
 
14
+ from .._tracing import LangChainExporter, _instrument_traceable_attributes
8
15
  from ._runtime._exception import LangGraphRuntimeError
9
16
  from ._runtime._runtime import ( # type: ignore[attr-defined]
10
17
  LangGraphRuntime,
@@ -24,23 +31,35 @@ def langgraph_run_middleware(
24
31
  ) # Continue with normal flow if no langgraph.json
25
32
 
26
33
  try:
27
- # Add default env variables
28
- env["UIPATH_REQUESTING_PRODUCT"] = "uipath-python-sdk"
29
- env["UIPATH_REQUESTING_FEATURE"] = "langgraph-agent"
30
-
31
34
  context = LangGraphRuntimeContext.with_defaults(**kwargs)
32
35
  context.langgraph_config = config
33
36
  context.entrypoint = entrypoint
34
37
  context.input = input
35
38
  context.resume = resume
36
39
 
40
+ _instrument_traceable_attributes()
41
+
42
+ def generate_runtime(ctx: LangGraphRuntimeContext) -> LangGraphRuntime:
43
+ runtime = LangGraphRuntime(ctx)
44
+ # If not resuming and no job id, delete the previous state file
45
+ if not ctx.resume and ctx.job_id is None:
46
+ if os.path.exists(runtime.state_file_path):
47
+ os.remove(runtime.state_file_path)
48
+ return runtime
49
+
37
50
  async def execute():
38
- async with LangGraphRuntime.from_context(context) as runtime:
39
- if context.resume is False and context.job_id is None:
40
- # Delete the previous graph state file at debug time
41
- if os.path.exists(runtime.state_file_path):
42
- os.remove(runtime.state_file_path)
43
- await runtime.execute()
51
+ runtime_factory = UiPathRuntimeFactory(
52
+ LangGraphRuntime,
53
+ LangGraphRuntimeContext,
54
+ runtime_generator=generate_runtime,
55
+ )
56
+
57
+ if context.job_id:
58
+ runtime_factory.add_span_exporter(LangChainExporter())
59
+
60
+ runtime_factory.add_instrumentor(LangChainInstrumentor, get_current_span)
61
+
62
+ await runtime_factory.execute(context)
44
63
 
45
64
  asyncio.run(execute())
46
65
 
@@ -0,0 +1,4 @@
1
+ from ._instrument_traceable import _instrument_traceable_attributes
2
+ from ._oteladapter import LangChainExporter
3
+
4
+ __all__ = ["LangChainExporter", "_instrument_traceable_attributes"]
@@ -0,0 +1,135 @@
1
+ import importlib
2
+ import logging
3
+ import sys
4
+ from typing import Any, Callable, Dict, List, Optional
5
+
6
+ from uipath.tracing import traced
7
+
8
+ # Original module and traceable function references
9
+ original_langsmith: Any = None
10
+ original_traceable: Any = None
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ # Apply the patch
16
+ def _map_traceable_to_traced_args(
17
+ run_type: Optional[str] = None,
18
+ name: Optional[str] = None,
19
+ tags: Optional[List[str]] = None,
20
+ metadata: Optional[Dict[str, Any]] = None,
21
+ **kwargs: Any,
22
+ ) -> Dict[str, Any]:
23
+ """
24
+ Map LangSmith @traceable arguments to UiPath @traced() arguments.
25
+
26
+ Args:
27
+ run_type: Function type (tool, chain, llm, retriever, etc.)
28
+ name: Custom name for the traced function
29
+ tags: List of tags for categorization
30
+ metadata: Additional metadata dictionary
31
+ **kwargs: Additional arguments (ignored)
32
+
33
+ Returns:
34
+ Dict containing mapped arguments for @traced()
35
+ """
36
+ traced_args = {}
37
+
38
+ # Direct mappings
39
+ if name is not None:
40
+ traced_args["name"] = name
41
+
42
+ # Pass through run_type directly to UiPath @traced()
43
+ if run_type:
44
+ traced_args["run_type"] = run_type
45
+
46
+ # For span_type, we can derive from run_type or use a default
47
+ if run_type:
48
+ # Map run_type to appropriate span_type for OpenTelemetry
49
+ span_type_mapping = {
50
+ "tool": "tool_call",
51
+ "chain": "chain_execution",
52
+ "llm": "llm_call",
53
+ "retriever": "retrieval",
54
+ "embedding": "embedding",
55
+ "prompt": "prompt_template",
56
+ "parser": "output_parser",
57
+ }
58
+ traced_args["span_type"] = span_type_mapping.get(run_type, run_type)
59
+
60
+ # Note: UiPath @traced() doesn't support custom attributes directly
61
+ # Tags and metadata information is lost in the current mapping
62
+ # This could be enhanced in future versions
63
+
64
+ return traced_args
65
+
66
+
67
+ def otel_traceable_adapter(
68
+ func: Optional[Callable[..., Any]] = None,
69
+ *,
70
+ run_type: Optional[str] = None,
71
+ name: Optional[str] = None,
72
+ tags: Optional[List[str]] = None,
73
+ metadata: Optional[Dict[str, Any]] = None,
74
+ **kwargs: Any,
75
+ ):
76
+ """
77
+ OTEL-based adapter that converts LangSmith @traceable decorator calls to UiPath @traced().
78
+
79
+ This function maintains the same interface as LangSmith's @traceable but uses
80
+ UiPath's OpenTelemetry-based tracing system underneath.
81
+
82
+ Args:
83
+ func: Function to be decorated (when used without parentheses)
84
+ run_type: Type of function (tool, chain, llm, etc.)
85
+ name: Custom name for tracing
86
+ tags: List of tags for categorization
87
+ metadata: Additional metadata dictionary
88
+ **kwargs: Additional arguments (for future compatibility)
89
+
90
+ Returns:
91
+ Decorated function or decorator function
92
+ """
93
+
94
+ def decorator(f: Callable[..., Any]) -> Callable[..., Any]:
95
+ # Map arguments to @traced() format
96
+ traced_args = _map_traceable_to_traced_args(
97
+ run_type=run_type, name=name, tags=tags, metadata=metadata, **kwargs
98
+ )
99
+
100
+ # Apply UiPath @traced() decorator
101
+ return traced(**traced_args)(f)
102
+
103
+ # Handle both @traceable and @traceable(...) usage patterns
104
+ if func is None:
105
+ # Called as @traceable(...) - return decorator
106
+ return decorator
107
+ else:
108
+ # Called as @traceable - apply decorator directly
109
+ return decorator(func)
110
+
111
+
112
+ def _instrument_traceable_attributes():
113
+ """Apply the patch to langsmith module at import time."""
114
+ global original_langsmith, original_traceable
115
+
116
+ # Import the original module if not already done
117
+ if original_langsmith is None:
118
+ # Temporarily remove our custom module from sys.modules
119
+ if "langsmith" in sys.modules:
120
+ original_langsmith = sys.modules["langsmith"]
121
+ del sys.modules["langsmith"]
122
+
123
+ # Import the original module
124
+ original_langsmith = importlib.import_module("langsmith")
125
+
126
+ # Store the original traceable
127
+ original_traceable = original_langsmith.traceable
128
+
129
+ # Replace the traceable function with our patched version
130
+ original_langsmith.traceable = otel_traceable_adapter
131
+
132
+ # Put our modified module back
133
+ sys.modules["langsmith"] = original_langsmith
134
+
135
+ return original_langsmith
@@ -0,0 +1,222 @@
1
+ import json
2
+ import logging
3
+ from typing import Any, Dict, List
4
+
5
+ from opentelemetry.sdk.trace.export import (
6
+ SpanExportResult,
7
+ )
8
+ from uipath.tracing import LlmOpsHttpExporter
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ def _safe_parse_json(s: Any) -> Any:
14
+ """Safely parse a JSON string, returning the original if not a string or on error."""
15
+ if not isinstance(s, str):
16
+ return s
17
+ try:
18
+ return json.loads(s)
19
+ except (json.JSONDecodeError, TypeError):
20
+ return s
21
+
22
+
23
+ def _get_llm_messages(attributes: Dict[str, Any], prefix: str) -> List[Dict[str, Any]]:
24
+ """Extracts and reconstructs LLM messages from flattened attributes."""
25
+ messages: dict[int, dict[str, Any]] = {}
26
+ message_prefix = f"{prefix}."
27
+
28
+ for key, value in attributes.items():
29
+ if key.startswith(message_prefix):
30
+ parts = key[len(message_prefix) :].split(".")
31
+ if len(parts) >= 2 and parts[0].isdigit():
32
+ index = int(parts[0])
33
+ if index not in messages:
34
+ messages[index] = {}
35
+ current: Any = messages[index]
36
+
37
+ for i, part in enumerate(parts[1:-1]):
38
+ key_part: str | int = part
39
+ if part.isdigit() and (
40
+ i + 2 < len(parts) and parts[i + 2].isdigit()
41
+ ):
42
+ key_part = int(part)
43
+
44
+ if isinstance(current, dict):
45
+ if key_part not in current:
46
+ current[key_part] = {}
47
+ current = current[key_part]
48
+ elif isinstance(current, list) and isinstance(key_part, int):
49
+ if key_part >= len(current):
50
+ current.append({})
51
+ current = current[key_part]
52
+
53
+ current[parts[-1]] = value
54
+
55
+ # Convert dict to list, ordered by index
56
+ return [messages[i] for i in sorted(messages.keys())]
57
+
58
+
59
+ class LangChainExporter(LlmOpsHttpExporter):
60
+ # Mapping of old attribute names to new attribute names or (new name, function)
61
+ ATTRIBUTE_MAPPING: dict[str, str | tuple[str, Any]] = {
62
+ "input.value": ("input", _safe_parse_json),
63
+ "output.value": ("output", _safe_parse_json),
64
+ "llm.model_name": "model",
65
+ }
66
+
67
+ # Mapping of span types
68
+ SPAN_TYPE_MAPPING: dict[str, str] = {
69
+ "LLM": "completion",
70
+ "TOOL": "toolCall",
71
+ # Add more mappings as needed
72
+ }
73
+
74
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
75
+ super().__init__(*args, **kwargs)
76
+
77
+ def _map_llm_call_attributes(self, attributes: Dict[str, Any]) -> Dict[str, Any]:
78
+ """Maps attributes for LLM calls, handling flattened keys."""
79
+ result = attributes.copy() # Keep original attributes including basic mappings
80
+
81
+ # Token Usage
82
+ token_keys = {
83
+ "llm.token_count.prompt": "promptTokens",
84
+ "llm.token_count.completion": "completionTokens",
85
+ "llm.token_count.total": "totalTokens",
86
+ }
87
+ usage = {
88
+ new_key: attributes.get(old_key)
89
+ for old_key, new_key in token_keys.items()
90
+ if old_key in attributes
91
+ }
92
+ if usage:
93
+ result["usage"] = usage
94
+
95
+ # Input/Output Messages
96
+ result["input"] = _get_llm_messages(attributes, "llm.input_messages")
97
+ output_messages = _get_llm_messages(attributes, "llm.output_messages")
98
+ result["output"] = output_messages
99
+
100
+ # Invocation Parameters
101
+ invocation_params = _safe_parse_json(
102
+ attributes.get("llm.invocation_parameters", "{}")
103
+ )
104
+ if isinstance(invocation_params, dict):
105
+ result["model"] = invocation_params.get("model", result.get("model"))
106
+ settings: dict[str, Any] = {}
107
+ if "max_tokens" in invocation_params:
108
+ settings["maxTokens"] = invocation_params["max_tokens"]
109
+ if "temperature" in invocation_params:
110
+ settings["temperature"] = invocation_params["temperature"]
111
+ if settings:
112
+ result["settings"] = settings
113
+
114
+ # Tool Calls
115
+ tool_calls: list[dict[str, Any]] = []
116
+ for msg in output_messages:
117
+ # Ensure msg is a dictionary before proceeding
118
+ if not isinstance(msg, dict):
119
+ continue
120
+ msg_tool_calls = msg.get("message", {}).get("tool_calls", [])
121
+
122
+ # Ensure msg_tool_calls is a list
123
+ if not isinstance(msg_tool_calls, list):
124
+ continue
125
+
126
+ for tc in msg_tool_calls:
127
+ if not isinstance(tc, dict):
128
+ continue
129
+ tool_call_data = tc.get("tool_call", {})
130
+ if not isinstance(tool_call_data, dict):
131
+ continue
132
+ tool_calls.append(
133
+ {
134
+ "id": tool_call_data.get("id"),
135
+ "name": tool_call_data.get("function", {}).get("name"),
136
+ "arguments": _safe_parse_json(
137
+ tool_call_data.get("function", {}).get("arguments", "{}")
138
+ ),
139
+ }
140
+ )
141
+ if tool_calls:
142
+ result["toolCalls"] = tool_calls
143
+
144
+ return result
145
+
146
+ def _map_tool_call_attributes(self, attributes: Dict[str, Any]) -> Dict[str, Any]:
147
+ """Maps attributes for tool calls."""
148
+ result = attributes.copy() # Keep original attributes
149
+
150
+ result["type"] = "toolCall"
151
+ result["callId"] = attributes.get("call_id") or attributes.get("id")
152
+ result["toolName"] = attributes.get("tool.name")
153
+ result["arguments"] = _safe_parse_json(
154
+ attributes.get("input", attributes.get("input.value", "{}"))
155
+ )
156
+ result["toolType"] = "Integration"
157
+ result["result"] = _safe_parse_json(
158
+ attributes.get("output", attributes.get("output.value"))
159
+ )
160
+ result["error"] = None
161
+
162
+ return result
163
+
164
+ def _process_span_attributes(self, span_data: Dict[str, Any]) -> Dict[str, Any]:
165
+ """Extracts, transforms, and maps attributes for a span."""
166
+ if "Attributes" not in span_data:
167
+ return span_data
168
+
169
+ logger.info(f"Processing span: {span_data}")
170
+
171
+ attributes_val = span_data["Attributes"]
172
+ if isinstance(attributes_val, str):
173
+ try:
174
+ attributes: Dict[str, Any] = json.loads(attributes_val)
175
+ except json.JSONDecodeError as e:
176
+ logger.warning(f"Failed to parse attributes JSON: {e}")
177
+ return span_data
178
+ elif isinstance(attributes_val, dict):
179
+ attributes = attributes_val
180
+ else:
181
+ return span_data
182
+
183
+ # Determine SpanType
184
+ if "openinference.span.kind" in attributes:
185
+ span_type = attributes["openinference.span.kind"]
186
+ span_data["SpanType"] = self.SPAN_TYPE_MAPPING.get(span_type, span_type)
187
+
188
+ # Apply basic attribute mapping
189
+ for old_key, mapping in self.ATTRIBUTE_MAPPING.items():
190
+ if old_key in attributes:
191
+ if isinstance(mapping, tuple):
192
+ new_key, func = mapping
193
+ attributes[new_key] = func(attributes[old_key])
194
+ else:
195
+ new_key = mapping
196
+ attributes[new_key] = attributes[old_key]
197
+
198
+ # Apply detailed mapping based on SpanType
199
+ span_type = span_data.get("SpanType")
200
+ if span_type == "completion":
201
+ processed_attributes = self._map_llm_call_attributes(attributes)
202
+ elif span_type == "toolCall":
203
+ processed_attributes = self._map_tool_call_attributes(attributes)
204
+ else:
205
+ processed_attributes = attributes.copy()
206
+
207
+ span_data["Attributes"] = json.dumps(processed_attributes)
208
+
209
+ logger.info(f"Transformed span: {span_data}")
210
+ return span_data
211
+
212
+ def _send_with_retries(
213
+ self, url: str, payload: List[Dict[str, Any]], max_retries: int = 4
214
+ ) -> SpanExportResult:
215
+ # Transform attributes in each span's payload before sending
216
+ transformed_payload = [self._process_span_attributes(span) for span in payload]
217
+
218
+ return super()._send_with_retries(
219
+ url=url,
220
+ payload=transformed_payload,
221
+ max_retries=max_retries,
222
+ )
@@ -1,6 +1,4 @@
1
- import datetime
2
1
  import logging
3
- from zoneinfo import ZoneInfo
4
2
 
5
3
 
6
4
  class IgnoreSpecificUrl(logging.Filter):
@@ -28,25 +26,3 @@ def _setup_tracer_httpx_logging(url: str):
28
26
  # Create a custom logger for httpx
29
27
  # Add the custom filter to the root logger
30
28
  logging.getLogger("httpx").addFilter(IgnoreSpecificUrl(url))
31
-
32
-
33
- def _simple_serialize_defaults(obj):
34
- if hasattr(obj, "model_dump"):
35
- return obj.model_dump(exclude_none=True, mode="json")
36
- if hasattr(obj, "dict"):
37
- return obj.dict()
38
- if hasattr(obj, "to_dict"):
39
- return obj.to_dict()
40
-
41
- if isinstance(obj, (set, tuple)):
42
- if hasattr(obj, "_asdict") and callable(obj._asdict):
43
- return obj._asdict()
44
- return list(obj)
45
-
46
- if isinstance(obj, datetime.datetime):
47
- return obj.isoformat()
48
-
49
- if isinstance(obj, (datetime.timezone, ZoneInfo)):
50
- return obj.tzname(None)
51
-
52
- return str(obj)
@@ -1,4 +1,3 @@
1
- from ..tracers._instrument_traceable import _instrument_traceable_attributes
2
1
  from ._request_mixin import UiPathRequestMixin
3
2
 
4
- __all__ = ["UiPathRequestMixin", "_instrument_traceable_attributes"]
3
+ __all__ = ["UiPathRequestMixin"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uipath-langchain
3
- Version: 0.0.131
3
+ Version: 0.0.132
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
@@ -25,7 +25,7 @@ Requires-Dist: openai>=1.65.5
25
25
  Requires-Dist: openinference-instrumentation-langchain>=0.1.50
26
26
  Requires-Dist: pydantic-settings>=2.6.0
27
27
  Requires-Dist: python-dotenv>=1.0.1
28
- Requires-Dist: uipath<2.2.0,>=2.1.54
28
+ Requires-Dist: uipath<2.2.0,>=2.1.56
29
29
  Provides-Extra: langchain
30
30
  Description-Content-Type: text/markdown
31
31