uipath-langchain 0.0.125__py3-none-any.whl → 0.0.126__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.
- uipath_langchain/_cli/_runtime/_conversation.py +256 -0
- uipath_langchain/_cli/_runtime/_runtime.py +21 -1
- {uipath_langchain-0.0.125.dist-info → uipath_langchain-0.0.126.dist-info}/METADATA +2 -2
- {uipath_langchain-0.0.125.dist-info → uipath_langchain-0.0.126.dist-info}/RECORD +7 -6
- {uipath_langchain-0.0.125.dist-info → uipath_langchain-0.0.126.dist-info}/WHEEL +0 -0
- {uipath_langchain-0.0.125.dist-info → uipath_langchain-0.0.126.dist-info}/entry_points.txt +0 -0
- {uipath_langchain-0.0.125.dist-info → uipath_langchain-0.0.126.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from langchain_core.messages import (
|
|
6
|
+
AIMessage,
|
|
7
|
+
AIMessageChunk,
|
|
8
|
+
BaseMessage,
|
|
9
|
+
HumanMessage,
|
|
10
|
+
ToolMessage,
|
|
11
|
+
)
|
|
12
|
+
from uipath.agent.conversation import (
|
|
13
|
+
UiPathConversationContentPartChunkEvent,
|
|
14
|
+
UiPathConversationContentPartEndEvent,
|
|
15
|
+
UiPathConversationContentPartEvent,
|
|
16
|
+
UiPathConversationContentPartStartEvent,
|
|
17
|
+
UiPathConversationEvent,
|
|
18
|
+
UiPathConversationExchangeEvent,
|
|
19
|
+
UiPathConversationMessageEndEvent,
|
|
20
|
+
UiPathConversationMessageEvent,
|
|
21
|
+
UiPathConversationMessageStartEvent,
|
|
22
|
+
UiPathConversationToolCallEndEvent,
|
|
23
|
+
UiPathConversationToolCallEvent,
|
|
24
|
+
UiPathConversationToolCallStartEvent,
|
|
25
|
+
UiPathInlineValue,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _new_id() -> str:
|
|
30
|
+
return str(uuid.uuid4())
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _wrap_in_conversation_event(
|
|
34
|
+
msg_event: UiPathConversationMessageEvent,
|
|
35
|
+
exchange_id: Optional[str] = None,
|
|
36
|
+
conversation_id: Optional[str] = None,
|
|
37
|
+
) -> UiPathConversationEvent:
|
|
38
|
+
"""Helper to wrap a message event into a conversation-level event."""
|
|
39
|
+
return UiPathConversationEvent(
|
|
40
|
+
conversation_id=conversation_id or _new_id(),
|
|
41
|
+
exchange=UiPathConversationExchangeEvent(
|
|
42
|
+
exchange_id=exchange_id or _new_id(),
|
|
43
|
+
message=msg_event,
|
|
44
|
+
),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _extract_text(content) -> str:
|
|
49
|
+
"""Normalize LangGraph message.content to plain text."""
|
|
50
|
+
if isinstance(content, str):
|
|
51
|
+
return content
|
|
52
|
+
if isinstance(content, list):
|
|
53
|
+
return "".join(
|
|
54
|
+
part.get("text", "")
|
|
55
|
+
for part in content
|
|
56
|
+
if isinstance(part, dict) and part.get("type") == "text"
|
|
57
|
+
)
|
|
58
|
+
return str(content or "")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def map_message(
|
|
62
|
+
message: BaseMessage,
|
|
63
|
+
exchange_id: Optional[str] = None,
|
|
64
|
+
conversation_id: Optional[str] = None,
|
|
65
|
+
) -> Optional[UiPathConversationEvent]:
|
|
66
|
+
"""Convert LangGraph BaseMessage (chunk or full) into a UiPathConversationEvent."""
|
|
67
|
+
message_id = getattr(message, "id", None) or _new_id()
|
|
68
|
+
timestamp = datetime.now().isoformat()
|
|
69
|
+
|
|
70
|
+
# --- Streaming AIMessageChunk ---
|
|
71
|
+
if isinstance(message, AIMessageChunk):
|
|
72
|
+
msg_event = UiPathConversationMessageEvent(
|
|
73
|
+
message_id=message.id or _new_id(),
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
if message.content == []:
|
|
77
|
+
msg_event.start = UiPathConversationMessageStartEvent(
|
|
78
|
+
role="assistant", timestamp=timestamp
|
|
79
|
+
)
|
|
80
|
+
msg_event.content_part = UiPathConversationContentPartEvent(
|
|
81
|
+
content_part_id=f"chunk-{message.id}-{0}",
|
|
82
|
+
start=UiPathConversationContentPartStartEvent(mime_type="text/plain"),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
elif isinstance(message.content, list) and message.content:
|
|
86
|
+
for chunk in message.content:
|
|
87
|
+
if not isinstance(chunk, dict):
|
|
88
|
+
continue
|
|
89
|
+
idx = chunk.get("index", 0)
|
|
90
|
+
ctype = chunk.get("type")
|
|
91
|
+
id = chunk.get("id", f"chunk-{message.id}-{idx}")
|
|
92
|
+
|
|
93
|
+
# Start of a tool call
|
|
94
|
+
if ctype == "tool_use":
|
|
95
|
+
msg_event.tool_call = UiPathConversationToolCallEvent(
|
|
96
|
+
tool_call_id=id,
|
|
97
|
+
start=UiPathConversationToolCallStartEvent(
|
|
98
|
+
tool_name=chunk.get("name") or "",
|
|
99
|
+
arguments=UiPathInlineValue(inline=""),
|
|
100
|
+
timestamp=timestamp,
|
|
101
|
+
),
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# JSON args streaming (content part for tool args)
|
|
105
|
+
elif ctype == "input_json_delta":
|
|
106
|
+
text = chunk.get("partial_json", "")
|
|
107
|
+
# first delta: emit content part start + first chunk
|
|
108
|
+
if text == "":
|
|
109
|
+
msg_event.content_part = UiPathConversationContentPartEvent(
|
|
110
|
+
content_part_id=id,
|
|
111
|
+
start=UiPathConversationContentPartStartEvent(
|
|
112
|
+
mime_type="application/json"
|
|
113
|
+
),
|
|
114
|
+
)
|
|
115
|
+
else:
|
|
116
|
+
msg_event.content_part = UiPathConversationContentPartEvent(
|
|
117
|
+
content_part_id=id,
|
|
118
|
+
chunk=UiPathConversationContentPartChunkEvent(
|
|
119
|
+
data=text,
|
|
120
|
+
content_part_sequence=idx,
|
|
121
|
+
),
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# Plain text from assistant
|
|
125
|
+
elif ctype == "text":
|
|
126
|
+
text = chunk.get("text", "")
|
|
127
|
+
msg_event.content_part = UiPathConversationContentPartEvent(
|
|
128
|
+
content_part_id=id,
|
|
129
|
+
chunk=UiPathConversationContentPartChunkEvent(
|
|
130
|
+
data=text,
|
|
131
|
+
content_part_sequence=idx,
|
|
132
|
+
),
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
stop_reason = message.response_metadata.get("stop_reason")
|
|
136
|
+
if not message.content and stop_reason in ("tool_use", "end_turn"):
|
|
137
|
+
msg_event.end = UiPathConversationMessageEndEvent(timestamp=timestamp)
|
|
138
|
+
|
|
139
|
+
if (
|
|
140
|
+
msg_event.start
|
|
141
|
+
or msg_event.content_part
|
|
142
|
+
or msg_event.tool_call
|
|
143
|
+
or msg_event.end
|
|
144
|
+
):
|
|
145
|
+
return _wrap_in_conversation_event(msg_event, exchange_id, conversation_id)
|
|
146
|
+
|
|
147
|
+
return None
|
|
148
|
+
|
|
149
|
+
text_content = _extract_text(message.content)
|
|
150
|
+
|
|
151
|
+
# --- HumanMessage ---
|
|
152
|
+
if isinstance(message, HumanMessage):
|
|
153
|
+
return _wrap_in_conversation_event(
|
|
154
|
+
UiPathConversationMessageEvent(
|
|
155
|
+
message_id=message_id,
|
|
156
|
+
start=UiPathConversationMessageStartEvent(
|
|
157
|
+
role="user", timestamp=timestamp
|
|
158
|
+
),
|
|
159
|
+
content_part=UiPathConversationContentPartEvent(
|
|
160
|
+
content_part_id=f"cp-{message_id}",
|
|
161
|
+
start=UiPathConversationContentPartStartEvent(
|
|
162
|
+
mime_type="text/plain"
|
|
163
|
+
),
|
|
164
|
+
chunk=UiPathConversationContentPartChunkEvent(data=text_content),
|
|
165
|
+
end=UiPathConversationContentPartEndEvent(),
|
|
166
|
+
),
|
|
167
|
+
end=UiPathConversationMessageEndEvent(),
|
|
168
|
+
),
|
|
169
|
+
exchange_id,
|
|
170
|
+
conversation_id,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# --- AIMessage ---
|
|
174
|
+
if isinstance(message, AIMessage):
|
|
175
|
+
# Extract first tool call if present
|
|
176
|
+
tool_calls = getattr(message, "tool_calls", []) or []
|
|
177
|
+
first_tc = tool_calls[0] if tool_calls else None
|
|
178
|
+
|
|
179
|
+
return _wrap_in_conversation_event(
|
|
180
|
+
UiPathConversationMessageEvent(
|
|
181
|
+
message_id=message_id,
|
|
182
|
+
start=UiPathConversationMessageStartEvent(
|
|
183
|
+
role="assistant", timestamp=timestamp
|
|
184
|
+
),
|
|
185
|
+
content_part=(
|
|
186
|
+
UiPathConversationContentPartEvent(
|
|
187
|
+
content_part_id=f"cp-{message_id}",
|
|
188
|
+
start=UiPathConversationContentPartStartEvent(
|
|
189
|
+
mime_type="text/plain"
|
|
190
|
+
),
|
|
191
|
+
chunk=UiPathConversationContentPartChunkEvent(
|
|
192
|
+
data=text_content
|
|
193
|
+
),
|
|
194
|
+
end=UiPathConversationContentPartEndEvent(),
|
|
195
|
+
)
|
|
196
|
+
if text_content
|
|
197
|
+
else None
|
|
198
|
+
),
|
|
199
|
+
tool_call=(
|
|
200
|
+
UiPathConversationToolCallEvent(
|
|
201
|
+
tool_call_id=first_tc.get("id") or _new_id(),
|
|
202
|
+
start=UiPathConversationToolCallStartEvent(
|
|
203
|
+
tool_name=first_tc.get("name"),
|
|
204
|
+
arguments=UiPathInlineValue(
|
|
205
|
+
inline=str(first_tc.get("args", ""))
|
|
206
|
+
),
|
|
207
|
+
timestamp=timestamp,
|
|
208
|
+
),
|
|
209
|
+
)
|
|
210
|
+
if first_tc
|
|
211
|
+
else None
|
|
212
|
+
),
|
|
213
|
+
end=UiPathConversationMessageEndEvent(),
|
|
214
|
+
),
|
|
215
|
+
exchange_id,
|
|
216
|
+
conversation_id,
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
# --- ToolMessage ---
|
|
220
|
+
if isinstance(message, ToolMessage):
|
|
221
|
+
return _wrap_in_conversation_event(
|
|
222
|
+
UiPathConversationMessageEvent(
|
|
223
|
+
message_id=message_id,
|
|
224
|
+
tool_call=UiPathConversationToolCallEvent(
|
|
225
|
+
tool_call_id=message.tool_call_id,
|
|
226
|
+
start=UiPathConversationToolCallStartEvent(
|
|
227
|
+
tool_name=message.name or "",
|
|
228
|
+
arguments=UiPathInlineValue(inline=""),
|
|
229
|
+
timestamp=timestamp,
|
|
230
|
+
),
|
|
231
|
+
end=UiPathConversationToolCallEndEvent(
|
|
232
|
+
timestamp=timestamp,
|
|
233
|
+
result=UiPathInlineValue(inline=message.content),
|
|
234
|
+
),
|
|
235
|
+
),
|
|
236
|
+
),
|
|
237
|
+
exchange_id,
|
|
238
|
+
conversation_id,
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
# --- Fallback ---
|
|
242
|
+
return _wrap_in_conversation_event(
|
|
243
|
+
UiPathConversationMessageEvent(
|
|
244
|
+
message_id=message_id,
|
|
245
|
+
start=UiPathConversationMessageStartEvent(
|
|
246
|
+
role="assistant", timestamp=timestamp
|
|
247
|
+
),
|
|
248
|
+
content_part=UiPathConversationContentPartEvent(
|
|
249
|
+
content_part_id=f"cp-{message_id}",
|
|
250
|
+
chunk=UiPathConversationContentPartChunkEvent(data=text_content),
|
|
251
|
+
),
|
|
252
|
+
end=UiPathConversationMessageEndEvent(),
|
|
253
|
+
),
|
|
254
|
+
exchange_id,
|
|
255
|
+
conversation_id,
|
|
256
|
+
)
|
|
@@ -20,6 +20,7 @@ from ..._utils import _instrument_traceable_attributes
|
|
|
20
20
|
from ...tracers import AsyncUiPathTracer
|
|
21
21
|
from .._utils._graph import LangGraphConfig
|
|
22
22
|
from ._context import LangGraphRuntimeContext
|
|
23
|
+
from ._conversation import map_message
|
|
23
24
|
from ._exception import LangGraphRuntimeError
|
|
24
25
|
from ._input import LangGraphInputProcessor
|
|
25
26
|
from ._output import LangGraphOutputProcessor
|
|
@@ -98,8 +99,27 @@ class LangGraphRuntime(UiPathBaseRuntime):
|
|
|
98
99
|
if max_concurrency is not None:
|
|
99
100
|
graph_config["max_concurrency"] = int(max_concurrency)
|
|
100
101
|
|
|
102
|
+
if self.context.chat_handler:
|
|
103
|
+
async for stream_chunk in graph.astream(
|
|
104
|
+
processed_input,
|
|
105
|
+
graph_config,
|
|
106
|
+
stream_mode="messages",
|
|
107
|
+
subgraphs=True,
|
|
108
|
+
):
|
|
109
|
+
if not isinstance(stream_chunk, tuple) or len(stream_chunk) < 2:
|
|
110
|
+
continue
|
|
111
|
+
|
|
112
|
+
_, (message, _) = stream_chunk
|
|
113
|
+
event = map_message(
|
|
114
|
+
message=message,
|
|
115
|
+
conversation_id=self.context.execution_id,
|
|
116
|
+
exchange_id=self.context.execution_id,
|
|
117
|
+
)
|
|
118
|
+
if event:
|
|
119
|
+
self.context.chat_handler.on_event(event)
|
|
120
|
+
|
|
101
121
|
# Stream the output at debug time
|
|
102
|
-
|
|
122
|
+
elif self.is_debug_run():
|
|
103
123
|
# Get final chunk while streaming
|
|
104
124
|
final_chunk = None
|
|
105
125
|
async for stream_chunk in graph.astream(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: uipath-langchain
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.126
|
|
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.
|
|
28
|
+
Requires-Dist: uipath<2.2.0,>=2.1.38
|
|
29
29
|
Provides-Extra: langchain
|
|
30
30
|
Description-Content-Type: text/markdown
|
|
31
31
|
|
|
@@ -6,10 +6,11 @@ uipath_langchain/_cli/cli_init.py,sha256=xhxJ8tuMSrVUNHvltgyPpOrvgMA-wq9shHeYYwv
|
|
|
6
6
|
uipath_langchain/_cli/cli_new.py,sha256=dL8-Rri6u67ZZdbb4nT38A5xD_Q3fVnG0UK9VSeKaqg,2563
|
|
7
7
|
uipath_langchain/_cli/cli_run.py,sha256=R-cUi3lO3Qd4ysTXD7PW4sa1RsB427v_Y6xUQxWijfQ,3725
|
|
8
8
|
uipath_langchain/_cli/_runtime/_context.py,sha256=yyzYJDmk2fkH4T5gm4cLGRyXtjLESrpzHBT9euqluTA,817
|
|
9
|
+
uipath_langchain/_cli/_runtime/_conversation.py,sha256=qobBjb3PEDRQVhrcy8vUXXuzBneELqwphDAU7xEUOqA,9683
|
|
9
10
|
uipath_langchain/_cli/_runtime/_exception.py,sha256=USKkLYkG-dzjX3fEiMMOHnVUpiXJs_xF0OQXCCOvbYM,546
|
|
10
11
|
uipath_langchain/_cli/_runtime/_input.py,sha256=vZ8vfVxvPSaPWmIPghvNx1VRKzbalHsKUMBPiKDvJWM,5492
|
|
11
12
|
uipath_langchain/_cli/_runtime/_output.py,sha256=yJOZPWv2FRUJWv1NRs9JmpB4QMTDXu8jrxoaKrfJvzw,9078
|
|
12
|
-
uipath_langchain/_cli/_runtime/_runtime.py,sha256=
|
|
13
|
+
uipath_langchain/_cli/_runtime/_runtime.py,sha256=9X_8YEny238V1sTb4cjkpd6J69DYQWo6eYVH9kA9gEQ,15383
|
|
13
14
|
uipath_langchain/_cli/_templates/langgraph.json.template,sha256=eeh391Gta_hoRgaNaZ58nW1LNvCVXA7hlAH6l7Veous,107
|
|
14
15
|
uipath_langchain/_cli/_templates/main.py.template,sha256=nMJQIYPlRk90iANfNVpkJ2EQX20Dxsyq92-BucEz_UM,1189
|
|
15
16
|
uipath_langchain/_cli/_utils/_graph.py,sha256=JPShHNl0UQvl4AdjLIqLpNt_JAjpWH9WWF22Gs47Xew,7445
|
|
@@ -31,8 +32,8 @@ uipath_langchain/tracers/_instrument_traceable.py,sha256=0e841zVzcPWjOGtmBx0GeHb
|
|
|
31
32
|
uipath_langchain/tracers/_utils.py,sha256=JOT1tKMdvqjMDtj2WbmbOWMeMlTXBWavxWpogX7KlRA,1543
|
|
32
33
|
uipath_langchain/vectorstores/__init__.py,sha256=w8qs1P548ud1aIcVA_QhBgf_jZDrRMK5Lono78yA8cs,114
|
|
33
34
|
uipath_langchain/vectorstores/context_grounding_vectorstore.py,sha256=TncIXG-YsUlO0R5ZYzWsM-Dj1SVCZbzmo2LraVxXelc,9559
|
|
34
|
-
uipath_langchain-0.0.
|
|
35
|
-
uipath_langchain-0.0.
|
|
36
|
-
uipath_langchain-0.0.
|
|
37
|
-
uipath_langchain-0.0.
|
|
38
|
-
uipath_langchain-0.0.
|
|
35
|
+
uipath_langchain-0.0.126.dist-info/METADATA,sha256=rzCwILV0ipPfMnQks58Uh3J2KVNeb9F7FmymzJG0plo,4235
|
|
36
|
+
uipath_langchain-0.0.126.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
37
|
+
uipath_langchain-0.0.126.dist-info/entry_points.txt,sha256=FUtzqGOEntlJKMJIXhQUfT7ZTbQmGhke1iCmDWZaQZI,81
|
|
38
|
+
uipath_langchain-0.0.126.dist-info/licenses/LICENSE,sha256=JDpt-uotAkHFmxpwxi6gwx6HQ25e-lG4U_Gzcvgp7JY,1063
|
|
39
|
+
uipath_langchain-0.0.126.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|