uipath-langchain 0.0.112__py3-none-any.whl → 0.1.24__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.
Files changed (82) hide show
  1. uipath_langchain/_cli/_templates/main.py.template +12 -13
  2. uipath_langchain/_cli/cli_init.py +127 -156
  3. uipath_langchain/_cli/cli_new.py +2 -6
  4. uipath_langchain/_resources/AGENTS.md +21 -0
  5. uipath_langchain/_resources/REQUIRED_STRUCTURE.md +92 -0
  6. uipath_langchain/{tracers → _tracing}/__init__.py +0 -2
  7. uipath_langchain/_tracing/_instrument_traceable.py +134 -0
  8. uipath_langchain/_utils/__init__.py +1 -2
  9. uipath_langchain/_utils/_request_mixin.py +351 -54
  10. uipath_langchain/_utils/_settings.py +2 -11
  11. uipath_langchain/agent/exceptions/__init__.py +6 -0
  12. uipath_langchain/agent/exceptions/exceptions.py +11 -0
  13. uipath_langchain/agent/guardrails/__init__.py +21 -0
  14. uipath_langchain/agent/guardrails/actions/__init__.py +11 -0
  15. uipath_langchain/agent/guardrails/actions/base_action.py +23 -0
  16. uipath_langchain/agent/guardrails/actions/block_action.py +41 -0
  17. uipath_langchain/agent/guardrails/actions/escalate_action.py +274 -0
  18. uipath_langchain/agent/guardrails/actions/log_action.py +57 -0
  19. uipath_langchain/agent/guardrails/guardrail_nodes.py +125 -0
  20. uipath_langchain/agent/guardrails/guardrails_factory.py +70 -0
  21. uipath_langchain/agent/guardrails/guardrails_subgraph.py +247 -0
  22. uipath_langchain/agent/guardrails/types.py +20 -0
  23. uipath_langchain/agent/react/__init__.py +14 -0
  24. uipath_langchain/agent/react/agent.py +113 -0
  25. uipath_langchain/agent/react/constants.py +2 -0
  26. uipath_langchain/agent/react/init_node.py +20 -0
  27. uipath_langchain/agent/react/llm_node.py +43 -0
  28. uipath_langchain/agent/react/router.py +97 -0
  29. uipath_langchain/agent/react/terminate_node.py +82 -0
  30. uipath_langchain/agent/react/tools/__init__.py +7 -0
  31. uipath_langchain/agent/react/tools/tools.py +50 -0
  32. uipath_langchain/agent/react/types.py +39 -0
  33. uipath_langchain/agent/react/utils.py +49 -0
  34. uipath_langchain/agent/tools/__init__.py +17 -0
  35. uipath_langchain/agent/tools/context_tool.py +53 -0
  36. uipath_langchain/agent/tools/escalation_tool.py +111 -0
  37. uipath_langchain/agent/tools/integration_tool.py +181 -0
  38. uipath_langchain/agent/tools/process_tool.py +49 -0
  39. uipath_langchain/agent/tools/static_args.py +138 -0
  40. uipath_langchain/agent/tools/structured_tool_with_output_type.py +14 -0
  41. uipath_langchain/agent/tools/tool_factory.py +45 -0
  42. uipath_langchain/agent/tools/tool_node.py +22 -0
  43. uipath_langchain/agent/tools/utils.py +11 -0
  44. uipath_langchain/chat/__init__.py +4 -0
  45. uipath_langchain/chat/bedrock.py +187 -0
  46. uipath_langchain/chat/gemini.py +330 -0
  47. uipath_langchain/chat/mapper.py +309 -0
  48. uipath_langchain/chat/models.py +261 -38
  49. uipath_langchain/chat/openai.py +132 -0
  50. uipath_langchain/chat/supported_models.py +42 -0
  51. uipath_langchain/embeddings/embeddings.py +136 -36
  52. uipath_langchain/middlewares.py +0 -2
  53. uipath_langchain/py.typed +0 -0
  54. uipath_langchain/retrievers/context_grounding_retriever.py +7 -9
  55. uipath_langchain/runtime/__init__.py +36 -0
  56. uipath_langchain/runtime/_serialize.py +46 -0
  57. uipath_langchain/runtime/config.py +61 -0
  58. uipath_langchain/runtime/errors.py +43 -0
  59. uipath_langchain/runtime/factory.py +315 -0
  60. uipath_langchain/runtime/graph.py +159 -0
  61. uipath_langchain/runtime/runtime.py +453 -0
  62. uipath_langchain/runtime/schema.py +349 -0
  63. uipath_langchain/runtime/storage.py +115 -0
  64. uipath_langchain/vectorstores/context_grounding_vectorstore.py +90 -110
  65. {uipath_langchain-0.0.112.dist-info → uipath_langchain-0.1.24.dist-info}/METADATA +42 -20
  66. uipath_langchain-0.1.24.dist-info/RECORD +76 -0
  67. {uipath_langchain-0.0.112.dist-info → uipath_langchain-0.1.24.dist-info}/WHEEL +1 -1
  68. uipath_langchain-0.1.24.dist-info/entry_points.txt +5 -0
  69. uipath_langchain/_cli/_runtime/_context.py +0 -21
  70. uipath_langchain/_cli/_runtime/_exception.py +0 -17
  71. uipath_langchain/_cli/_runtime/_input.py +0 -136
  72. uipath_langchain/_cli/_runtime/_output.py +0 -234
  73. uipath_langchain/_cli/_runtime/_runtime.py +0 -371
  74. uipath_langchain/_cli/_utils/_graph.py +0 -202
  75. uipath_langchain/_cli/cli_run.py +0 -80
  76. uipath_langchain/tracers/AsyncUiPathTracer.py +0 -274
  77. uipath_langchain/tracers/_events.py +0 -33
  78. uipath_langchain/tracers/_instrument_traceable.py +0 -416
  79. uipath_langchain/tracers/_utils.py +0 -52
  80. uipath_langchain-0.0.112.dist-info/RECORD +0 -36
  81. uipath_langchain-0.0.112.dist-info/entry_points.txt +0 -2
  82. {uipath_langchain-0.0.112.dist-info → uipath_langchain-0.1.24.dist-info}/licenses/LICENSE +0 -0
@@ -1,274 +0,0 @@
1
- import asyncio
2
- import json
3
- import logging
4
- import queue
5
- import uuid
6
- import warnings
7
- from os import environ as env
8
- from typing import Any, Dict, Optional
9
-
10
- import httpx
11
- from langchain_core.tracers.base import AsyncBaseTracer
12
- from langchain_core.tracers.schemas import Run
13
- from pydantic import PydanticDeprecationWarning
14
- from uipath._cli._runtime._contracts import UiPathTraceContext
15
-
16
- from ._events import CustomTraceEvents, FunctionCallEventData
17
- from ._utils import _setup_tracer_httpx_logging, _simple_serialize_defaults
18
-
19
- logger = logging.getLogger(__name__)
20
-
21
- _setup_tracer_httpx_logging("/llmops_/api/Agent/trace/")
22
-
23
-
24
- class Status:
25
- SUCCESS = 1
26
- ERROR = 2
27
- INTERRUPTED = 3
28
-
29
-
30
- class AsyncUiPathTracer(AsyncBaseTracer):
31
- def __init__(
32
- self,
33
- context: Optional[UiPathTraceContext] = None,
34
- client: Optional[httpx.AsyncClient] = None,
35
- **kwargs,
36
- ):
37
- super().__init__(**kwargs)
38
-
39
- self.client = client or httpx.AsyncClient()
40
- self.retries = 3
41
- self.log_queue: queue.Queue[dict[str, Any]] = queue.Queue()
42
-
43
- self.context = context or UiPathTraceContext()
44
-
45
- self.base_url = self._get_base_url()
46
-
47
- auth_token = env.get("UNATTENDED_USER_ACCESS_TOKEN") or env.get(
48
- "UIPATH_ACCESS_TOKEN"
49
- )
50
-
51
- self.headers = {"Authorization": f"Bearer {auth_token}"}
52
-
53
- self.running = True
54
- self.worker_task = asyncio.create_task(self._worker())
55
- self.function_call_run_map: Dict[str, Run] = {}
56
-
57
- async def on_custom_event(
58
- self,
59
- name: str,
60
- data: Any,
61
- *,
62
- run_id: uuid.UUID,
63
- tags=None,
64
- metadata=None,
65
- **kwargs: Any,
66
- ) -> None:
67
- if name == CustomTraceEvents.UIPATH_TRACE_FUNCTION_CALL:
68
- # only handle the function call event
69
-
70
- if not isinstance(data, FunctionCallEventData):
71
- logger.warning(
72
- f"Received unexpected data type for function call event: {type(data)}"
73
- )
74
- return
75
-
76
- if data.event_type == "call":
77
- run = self.run_map[str(run_id)]
78
- child_run = run.create_child(
79
- name=data.function_name,
80
- run_type=data.run_type,
81
- tags=data.tags,
82
- inputs=data.inputs,
83
- )
84
-
85
- if data.metadata is not None:
86
- run.add_metadata(data.metadata)
87
-
88
- call_uuid = data.call_uuid
89
- self.function_call_run_map[call_uuid] = child_run
90
-
91
- self._send_span(run)
92
-
93
- if data.event_type == "completion":
94
- call_uuid = data.call_uuid
95
- previous_run = self.function_call_run_map.pop(call_uuid, None)
96
-
97
- if previous_run:
98
- previous_run.end(
99
- outputs=self._safe_dict_dump(data.output), error=data.error
100
- )
101
- self._send_span(previous_run)
102
-
103
- async def wait_for_all_tracers(self) -> None:
104
- """
105
- Wait for all pending log requests to complete
106
- """
107
- self.running = False
108
- if self.worker_task:
109
- await self.worker_task
110
-
111
- async def _worker(self):
112
- """Worker loop that processes logs from the queue."""
113
- while self.running:
114
- try:
115
- if self.log_queue.empty():
116
- await asyncio.sleep(1)
117
- continue
118
-
119
- span_data = self.log_queue.get_nowait()
120
-
121
- url = self._build_url(self.context.trace_id)
122
-
123
- for attempt in range(self.retries):
124
- response = await self.client.post(
125
- url,
126
- headers=self.headers,
127
- json=[span_data], # api expects a list of spans
128
- timeout=10,
129
- )
130
-
131
- if response.is_success:
132
- break
133
-
134
- await asyncio.sleep(0.5 * (2**attempt)) # Exponential backoff
135
-
136
- if 400 <= response.status_code < 600:
137
- logger.warning(
138
- f"Error when sending trace: {response}. Body is: {response.text}"
139
- )
140
- except Exception as e:
141
- logger.warning(f"Exception when sending trace: {e}", exc_info=e)
142
-
143
- # wait for a bit to ensure all logs are sent
144
- await asyncio.sleep(1)
145
-
146
- # try to send any remaining logs in the queue
147
- while True:
148
- try:
149
- if self.log_queue.empty():
150
- break
151
-
152
- span_data = self.log_queue.get_nowait()
153
- url = self._build_url(self.context.trace_id)
154
-
155
- response = await self.client.post(
156
- url,
157
- headers=self.headers,
158
- json=[span_data], # api expects a list of spans
159
- timeout=10,
160
- )
161
- except Exception as e:
162
- logger.warning(f"Exception when sending trace: {e}", exc_info=e)
163
-
164
- async def _persist_run(self, run: Run) -> None:
165
- # Determine if this is a start or end trace based on whether end_time is set
166
- self._send_span(run)
167
-
168
- def _send_span(self, run: Run) -> None:
169
- """Send span data for a run to the API"""
170
- run_id = str(run.id)
171
-
172
- try:
173
- start_time = (
174
- run.start_time.isoformat() if run.start_time is not None else None
175
- )
176
- end_time = (
177
- run.end_time.isoformat() if run.end_time is not None else start_time
178
- )
179
-
180
- parent_id = (
181
- str(run.parent_run_id)
182
- if run.parent_run_id is not None
183
- else self.context.parent_span_id
184
- )
185
- attributes = self._safe_jsons_dump(self._run_to_dict(run))
186
- status = self._determine_status(run.error)
187
-
188
- span_data = {
189
- "id": run_id,
190
- "parentId": parent_id,
191
- "traceId": self.context.trace_id,
192
- "name": run.name,
193
- "startTime": start_time,
194
- "endTime": end_time,
195
- "referenceId": self.context.reference_id,
196
- "attributes": attributes,
197
- "organizationId": self.context.org_id,
198
- "tenantId": self.context.tenant_id,
199
- "spanType": "LangGraphRun",
200
- "status": status,
201
- "jobKey": self.context.job_id,
202
- "folderKey": self.context.folder_key,
203
- "processKey": self.context.folder_key,
204
- "expiryTimeUtc": None,
205
- }
206
-
207
- self.log_queue.put(span_data)
208
- except Exception as e:
209
- logger.warning(f"Exception when adding trace to queue: {e}.")
210
-
211
- async def _start_trace(self, run: Run) -> None:
212
- await super()._start_trace(run)
213
- await self._persist_run(run)
214
-
215
- async def _end_trace(self, run: Run) -> None:
216
- await super()._end_trace(run)
217
- await self._persist_run(run)
218
-
219
- def _determine_status(self, error: Optional[str]):
220
- if error:
221
- if error.startswith("GraphInterrupt("):
222
- return Status.INTERRUPTED
223
-
224
- return Status.ERROR
225
-
226
- return Status.SUCCESS
227
-
228
- def _safe_jsons_dump(self, obj) -> str:
229
- try:
230
- json_str = json.dumps(obj, default=_simple_serialize_defaults)
231
- return json_str
232
- except Exception as e:
233
- logger.warning(f"Error serializing object to JSON: {e}")
234
- return "{ }"
235
-
236
- def _safe_dict_dump(self, obj) -> Dict[str, Any]:
237
- try:
238
- serialized = json.loads(json.dumps(obj, default=_simple_serialize_defaults))
239
- return serialized
240
- except Exception as e:
241
- # Last resort - string representation
242
- logger.warning(f"Error serializing object to JSON: {e}")
243
- return {"raw": str(obj)}
244
-
245
- def _run_to_dict(self, run: Run):
246
- with warnings.catch_warnings():
247
- warnings.simplefilter("ignore", category=PydanticDeprecationWarning)
248
-
249
- # Helper function to safely copy values
250
- def safe_copy(value):
251
- if value is None:
252
- return None
253
- if hasattr(value, "copy") and callable(value.copy):
254
- return value.copy()
255
- return value
256
-
257
- return {
258
- **run.dict(exclude={"child_runs", "inputs", "outputs", "serialized"}),
259
- "inputs": safe_copy(run.inputs),
260
- "outputs": safe_copy(run.outputs),
261
- }
262
-
263
- def _get_base_url(self) -> str:
264
- uipath_url = (
265
- env.get("UIPATH_URL") or "https://cloud.uipath.com/dummyOrg/dummyTennant/"
266
- )
267
-
268
- uipath_url = uipath_url.rstrip("/")
269
-
270
- return uipath_url
271
-
272
- def _build_url(self, trace_id: Optional[str]) -> str:
273
- """Construct the URL for the API request."""
274
- return f"{self.base_url}/llmopstenant_/api/Traces/spans?traceId={trace_id}&source=Robots"
@@ -1,33 +0,0 @@
1
- from typing import Any, Dict, List, Literal, Optional
2
-
3
- RUN_TYPE_T = Literal[
4
- "tool", "chain", "llm", "retriever", "embedding", "prompt", "parser"
5
- ]
6
-
7
-
8
- class CustomTraceEvents:
9
- UIPATH_TRACE_FUNCTION_CALL = "__uipath_trace_function_call"
10
-
11
-
12
- class FunctionCallEventData:
13
- def __init__(
14
- self,
15
- function_name: str,
16
- event_type: str,
17
- inputs: Dict[str, Any],
18
- call_uuid: str,
19
- output: Any,
20
- error: Optional[str] = None,
21
- run_type: Optional[RUN_TYPE_T] = None,
22
- tags: Optional[List[str]] = None,
23
- metadata: Optional[Dict[str, Any]] = None,
24
- ):
25
- self.function_name = function_name
26
- self.event_type = event_type
27
- self.inputs = inputs
28
- self.call_uuid = call_uuid
29
- self.output = output
30
- self.error = error
31
- self.run_type = run_type or "chain"
32
- self.tags = tags
33
- self.metadata = metadata