agentscope-runtime 1.0.5.post1__py3-none-any.whl → 1.1.0b3__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.
- agentscope_runtime/__init__.py +3 -0
- agentscope_runtime/adapters/agentscope/message.py +85 -295
- agentscope_runtime/adapters/agentscope/stream.py +133 -3
- agentscope_runtime/adapters/agno/message.py +11 -2
- agentscope_runtime/adapters/agno/stream.py +1 -0
- agentscope_runtime/adapters/langgraph/__init__.py +1 -3
- agentscope_runtime/adapters/langgraph/message.py +11 -106
- agentscope_runtime/adapters/langgraph/stream.py +1 -0
- agentscope_runtime/adapters/ms_agent_framework/message.py +11 -1
- agentscope_runtime/adapters/ms_agent_framework/stream.py +1 -0
- agentscope_runtime/adapters/text/stream.py +1 -0
- agentscope_runtime/common/container_clients/agentrun_client.py +0 -3
- agentscope_runtime/common/container_clients/boxlite_client.py +26 -15
- agentscope_runtime/common/container_clients/fc_client.py +0 -11
- agentscope_runtime/common/utils/deprecation.py +14 -17
- agentscope_runtime/common/utils/logging.py +44 -0
- agentscope_runtime/engine/app/agent_app.py +5 -5
- agentscope_runtime/engine/app/celery_mixin.py +43 -4
- agentscope_runtime/engine/deployers/adapter/agui/__init__.py +8 -1
- agentscope_runtime/engine/deployers/adapter/agui/agui_adapter_utils.py +6 -1
- agentscope_runtime/engine/deployers/adapter/agui/agui_protocol_adapter.py +2 -2
- agentscope_runtime/engine/deployers/utils/service_utils/fastapi_factory.py +13 -0
- agentscope_runtime/engine/runner.py +31 -6
- agentscope_runtime/engine/schemas/agent_schemas.py +28 -0
- agentscope_runtime/engine/services/sandbox/sandbox_service.py +41 -9
- agentscope_runtime/sandbox/box/base/base_sandbox.py +4 -0
- agentscope_runtime/sandbox/box/browser/browser_sandbox.py +4 -0
- agentscope_runtime/sandbox/box/dummy/dummy_sandbox.py +9 -2
- agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +4 -0
- agentscope_runtime/sandbox/box/gui/gui_sandbox.py +5 -1
- agentscope_runtime/sandbox/box/mobile/mobile_sandbox.py +4 -0
- agentscope_runtime/sandbox/box/sandbox.py +122 -13
- agentscope_runtime/sandbox/client/async_http_client.py +1 -0
- agentscope_runtime/sandbox/client/base.py +0 -1
- agentscope_runtime/sandbox/client/http_client.py +0 -2
- agentscope_runtime/sandbox/manager/heartbeat_mixin.py +486 -0
- agentscope_runtime/sandbox/manager/sandbox_manager.py +740 -153
- agentscope_runtime/sandbox/manager/server/app.py +18 -11
- agentscope_runtime/sandbox/manager/server/config.py +10 -2
- agentscope_runtime/sandbox/mcp_server.py +0 -1
- agentscope_runtime/sandbox/model/__init__.py +2 -1
- agentscope_runtime/sandbox/model/container.py +90 -3
- agentscope_runtime/sandbox/model/manager_config.py +45 -1
- agentscope_runtime/version.py +1 -1
- {agentscope_runtime-1.0.5.post1.dist-info → agentscope_runtime-1.1.0b3.dist-info}/METADATA +37 -54
- {agentscope_runtime-1.0.5.post1.dist-info → agentscope_runtime-1.1.0b3.dist-info}/RECORD +50 -69
- agentscope_runtime/adapters/agentscope/long_term_memory/__init__.py +0 -6
- agentscope_runtime/adapters/agentscope/long_term_memory/_long_term_memory_adapter.py +0 -258
- agentscope_runtime/adapters/agentscope/memory/__init__.py +0 -6
- agentscope_runtime/adapters/agentscope/memory/_memory_adapter.py +0 -152
- agentscope_runtime/engine/services/agent_state/__init__.py +0 -25
- agentscope_runtime/engine/services/agent_state/redis_state_service.py +0 -166
- agentscope_runtime/engine/services/agent_state/state_service.py +0 -179
- agentscope_runtime/engine/services/agent_state/state_service_factory.py +0 -52
- agentscope_runtime/engine/services/memory/__init__.py +0 -33
- agentscope_runtime/engine/services/memory/mem0_memory_service.py +0 -128
- agentscope_runtime/engine/services/memory/memory_service.py +0 -292
- agentscope_runtime/engine/services/memory/memory_service_factory.py +0 -126
- agentscope_runtime/engine/services/memory/redis_memory_service.py +0 -290
- agentscope_runtime/engine/services/memory/reme_personal_memory_service.py +0 -109
- agentscope_runtime/engine/services/memory/reme_task_memory_service.py +0 -11
- agentscope_runtime/engine/services/memory/tablestore_memory_service.py +0 -301
- agentscope_runtime/engine/services/session_history/__init__.py +0 -32
- agentscope_runtime/engine/services/session_history/redis_session_history_service.py +0 -283
- agentscope_runtime/engine/services/session_history/session_history_service.py +0 -267
- agentscope_runtime/engine/services/session_history/session_history_service_factory.py +0 -73
- agentscope_runtime/engine/services/session_history/tablestore_session_history_service.py +0 -288
- {agentscope_runtime-1.0.5.post1.dist-info → agentscope_runtime-1.1.0b3.dist-info}/WHEEL +0 -0
- {agentscope_runtime-1.0.5.post1.dist-info → agentscope_runtime-1.1.0b3.dist-info}/entry_points.txt +0 -0
- {agentscope_runtime-1.0.5.post1.dist-info → agentscope_runtime-1.1.0b3.dist-info}/licenses/LICENSE +0 -0
- {agentscope_runtime-1.0.5.post1.dist-info → agentscope_runtime-1.1.0b3.dist-info}/top_level.txt +0 -0
agentscope_runtime/__init__.py
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
import json
|
|
5
5
|
|
|
6
6
|
from collections import OrderedDict
|
|
7
|
-
from typing import Union, List
|
|
7
|
+
from typing import Union, List, Callable, Optional, Dict, Literal
|
|
8
8
|
from urllib.parse import urlparse
|
|
9
|
+
from typing_extensions import TypedDict, Required
|
|
9
10
|
|
|
10
11
|
from mcp.types import CallToolResult
|
|
11
12
|
from agentscope.message import (
|
|
@@ -24,317 +25,45 @@ from agentscope.mcp._client_base import MCPClientBase
|
|
|
24
25
|
|
|
25
26
|
from ...engine.schemas.agent_schemas import (
|
|
26
27
|
Message,
|
|
27
|
-
FunctionCall,
|
|
28
|
-
FunctionCallOutput,
|
|
29
28
|
MessageType,
|
|
30
29
|
)
|
|
31
|
-
from ...engine.helpers.agent_api_builder import ResponseBuilder
|
|
32
30
|
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
expected_keys = set(typed_dict_cls.__annotations__.keys())
|
|
38
|
-
return expected_keys == set(obj.keys())
|
|
32
|
+
# TODO: support in core framework
|
|
33
|
+
class FileBlock(TypedDict, total=False):
|
|
34
|
+
"""The file block"""
|
|
39
35
|
|
|
36
|
+
type: Required[Literal["file"]]
|
|
37
|
+
"""The type of the block"""
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
) -> List[Message]:
|
|
44
|
-
"""
|
|
45
|
-
Convert AgentScope Msg(s) into one or more runtime Message objects
|
|
39
|
+
source: Required[Base64Source | URLSource]
|
|
40
|
+
"""The src of the file"""
|
|
46
41
|
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
filename: Optional[str]
|
|
43
|
+
"""Optional filename hint (e.g. `report.pdf`)"""
|
|
49
44
|
|
|
50
|
-
Returns:
|
|
51
|
-
List[Message]: One or more constructed runtime Message objects.
|
|
52
|
-
"""
|
|
53
|
-
if isinstance(messages, Msg):
|
|
54
|
-
msgs = [messages]
|
|
55
|
-
elif isinstance(messages, list):
|
|
56
|
-
msgs = messages
|
|
57
|
-
else:
|
|
58
|
-
raise TypeError(f"Expected Msg or list[Msg], got {type(messages)}")
|
|
59
|
-
|
|
60
|
-
results: List[Message] = []
|
|
61
|
-
|
|
62
|
-
for msg in msgs:
|
|
63
|
-
role = msg.role or "assistant"
|
|
64
|
-
|
|
65
|
-
if isinstance(msg.content, str):
|
|
66
|
-
# Only text
|
|
67
|
-
rb = ResponseBuilder()
|
|
68
|
-
mb = rb.create_message_builder(
|
|
69
|
-
role=role,
|
|
70
|
-
message_type=MessageType.MESSAGE,
|
|
71
|
-
)
|
|
72
|
-
# add meta field to store old id and name
|
|
73
|
-
mb.message.metadata = {
|
|
74
|
-
"original_id": msg.id,
|
|
75
|
-
"original_name": msg.name,
|
|
76
|
-
"metadata": msg.metadata,
|
|
77
|
-
}
|
|
78
|
-
cb = mb.create_content_builder(content_type="text")
|
|
79
|
-
cb.set_text(msg.content)
|
|
80
|
-
cb.complete()
|
|
81
|
-
mb.complete()
|
|
82
|
-
results.append(mb.get_message_data())
|
|
83
|
-
continue
|
|
84
|
-
|
|
85
|
-
# msg.content is a list of blocks
|
|
86
|
-
# We group blocks by high-level message type
|
|
87
|
-
current_mb = None
|
|
88
|
-
current_type = None
|
|
89
|
-
|
|
90
|
-
for block in msg.content:
|
|
91
|
-
if isinstance(block, dict):
|
|
92
|
-
btype = block.get("type", "text")
|
|
93
|
-
else:
|
|
94
|
-
continue
|
|
95
|
-
|
|
96
|
-
if btype == "text":
|
|
97
|
-
# Create/continue MESSAGE type
|
|
98
|
-
if current_type != MessageType.MESSAGE:
|
|
99
|
-
if current_mb:
|
|
100
|
-
current_mb.complete()
|
|
101
|
-
results.append(current_mb.get_message_data())
|
|
102
|
-
rb = ResponseBuilder()
|
|
103
|
-
current_mb = rb.create_message_builder(
|
|
104
|
-
role=role,
|
|
105
|
-
message_type=MessageType.MESSAGE,
|
|
106
|
-
)
|
|
107
|
-
# add meta field to store old id and name
|
|
108
|
-
current_mb.message.metadata = {
|
|
109
|
-
"original_id": msg.id,
|
|
110
|
-
"original_name": msg.name,
|
|
111
|
-
"metadata": msg.metadata,
|
|
112
|
-
}
|
|
113
|
-
current_type = MessageType.MESSAGE
|
|
114
|
-
cb = current_mb.create_content_builder(content_type="text")
|
|
115
|
-
cb.set_text(block.get("text", ""))
|
|
116
|
-
cb.complete()
|
|
117
|
-
|
|
118
|
-
elif btype == "thinking":
|
|
119
|
-
# Create/continue REASONING type
|
|
120
|
-
if current_type != MessageType.REASONING:
|
|
121
|
-
if current_mb:
|
|
122
|
-
current_mb.complete()
|
|
123
|
-
results.append(current_mb.get_message_data())
|
|
124
|
-
rb = ResponseBuilder()
|
|
125
|
-
current_mb = rb.create_message_builder(
|
|
126
|
-
role=role,
|
|
127
|
-
message_type=MessageType.REASONING,
|
|
128
|
-
)
|
|
129
|
-
# add meta field to store old id and name
|
|
130
|
-
current_mb.message.metadata = {
|
|
131
|
-
"original_id": msg.id,
|
|
132
|
-
"original_name": msg.name,
|
|
133
|
-
"metadata": msg.metadata,
|
|
134
|
-
}
|
|
135
|
-
current_type = MessageType.REASONING
|
|
136
|
-
cb = current_mb.create_content_builder(content_type="text")
|
|
137
|
-
cb.set_text(block.get("thinking", ""))
|
|
138
|
-
cb.complete()
|
|
139
|
-
|
|
140
|
-
elif btype == "tool_use":
|
|
141
|
-
# Always start a new PLUGIN_CALL message
|
|
142
|
-
if current_mb:
|
|
143
|
-
current_mb.complete()
|
|
144
|
-
results.append(current_mb.get_message_data())
|
|
145
|
-
rb = ResponseBuilder()
|
|
146
|
-
current_mb = rb.create_message_builder(
|
|
147
|
-
role=role,
|
|
148
|
-
message_type=MessageType.PLUGIN_CALL,
|
|
149
|
-
)
|
|
150
|
-
# add meta field to store old id and name
|
|
151
|
-
current_mb.message.metadata = {
|
|
152
|
-
"original_id": msg.id,
|
|
153
|
-
"original_name": msg.name,
|
|
154
|
-
"metadata": msg.metadata,
|
|
155
|
-
}
|
|
156
|
-
current_type = MessageType.PLUGIN_CALL
|
|
157
|
-
cb = current_mb.create_content_builder(content_type="data")
|
|
158
|
-
|
|
159
|
-
if isinstance(block.get("input"), (dict, list)):
|
|
160
|
-
arguments = json.dumps(block.get("input"))
|
|
161
|
-
else:
|
|
162
|
-
arguments = block.get("input")
|
|
163
|
-
|
|
164
|
-
call_data = FunctionCall(
|
|
165
|
-
call_id=block.get("id"),
|
|
166
|
-
name=block.get("name"),
|
|
167
|
-
arguments=arguments,
|
|
168
|
-
).model_dump()
|
|
169
|
-
cb.set_data(call_data)
|
|
170
|
-
cb.complete()
|
|
171
|
-
|
|
172
|
-
elif btype == "tool_result":
|
|
173
|
-
# Always start a new PLUGIN_CALL_OUTPUT message
|
|
174
|
-
if current_mb:
|
|
175
|
-
current_mb.complete()
|
|
176
|
-
results.append(current_mb.get_message_data())
|
|
177
|
-
rb = ResponseBuilder()
|
|
178
|
-
current_mb = rb.create_message_builder(
|
|
179
|
-
role=role,
|
|
180
|
-
message_type=MessageType.PLUGIN_CALL_OUTPUT,
|
|
181
|
-
)
|
|
182
|
-
# add meta field to store old id and name
|
|
183
|
-
current_mb.message.metadata = {
|
|
184
|
-
"original_id": msg.id,
|
|
185
|
-
"original_name": msg.name,
|
|
186
|
-
"metadata": msg.metadata,
|
|
187
|
-
}
|
|
188
|
-
current_type = MessageType.PLUGIN_CALL_OUTPUT
|
|
189
|
-
cb = current_mb.create_content_builder(content_type="data")
|
|
190
|
-
|
|
191
|
-
if isinstance(block.get("output"), (dict, list)):
|
|
192
|
-
output = json.dumps(block.get("output"))
|
|
193
|
-
else:
|
|
194
|
-
output = block.get("output")
|
|
195
|
-
|
|
196
|
-
output_data = FunctionCallOutput(
|
|
197
|
-
call_id=block.get("id"),
|
|
198
|
-
name=block.get("name"),
|
|
199
|
-
output=output,
|
|
200
|
-
).model_dump(exclude_none=True)
|
|
201
|
-
cb.set_data(output_data)
|
|
202
|
-
cb.complete()
|
|
203
|
-
|
|
204
|
-
elif btype == "image":
|
|
205
|
-
# Create/continue MESSAGE type with image
|
|
206
|
-
if current_type != MessageType.MESSAGE:
|
|
207
|
-
if current_mb:
|
|
208
|
-
current_mb.complete()
|
|
209
|
-
results.append(current_mb.get_message_data())
|
|
210
|
-
rb = ResponseBuilder()
|
|
211
|
-
current_mb = rb.create_message_builder(
|
|
212
|
-
role=role,
|
|
213
|
-
message_type=MessageType.MESSAGE,
|
|
214
|
-
)
|
|
215
|
-
# add meta field to store old id and name
|
|
216
|
-
current_mb.message.metadata = {
|
|
217
|
-
"original_id": msg.id,
|
|
218
|
-
"original_name": msg.name,
|
|
219
|
-
"metadata": msg.metadata,
|
|
220
|
-
}
|
|
221
|
-
current_type = MessageType.MESSAGE
|
|
222
|
-
cb = current_mb.create_content_builder(content_type="image")
|
|
223
|
-
|
|
224
|
-
if (
|
|
225
|
-
isinstance(block.get("source"), dict)
|
|
226
|
-
and block.get("source", {}).get("type") == "url"
|
|
227
|
-
):
|
|
228
|
-
cb.set_image_url(block.get("source", {}).get("url"))
|
|
229
|
-
|
|
230
|
-
elif (
|
|
231
|
-
isinstance(block.get("source"), dict)
|
|
232
|
-
and block.get("source").get(
|
|
233
|
-
"type",
|
|
234
|
-
)
|
|
235
|
-
== "base64"
|
|
236
|
-
):
|
|
237
|
-
media_type = block.get("source", {}).get(
|
|
238
|
-
"media_type",
|
|
239
|
-
"image/jpeg",
|
|
240
|
-
)
|
|
241
|
-
base64_data = block.get("source", {}).get("data", "")
|
|
242
|
-
url = f"data:{media_type};base64,{base64_data}"
|
|
243
|
-
cb.set_image_url(url)
|
|
244
|
-
|
|
245
|
-
cb.complete()
|
|
246
|
-
|
|
247
|
-
elif btype == "audio":
|
|
248
|
-
# Create/continue MESSAGE type with audio
|
|
249
|
-
if current_type != MessageType.MESSAGE:
|
|
250
|
-
if current_mb:
|
|
251
|
-
current_mb.complete()
|
|
252
|
-
results.append(current_mb.get_message_data())
|
|
253
|
-
rb = ResponseBuilder()
|
|
254
|
-
current_mb = rb.create_message_builder(
|
|
255
|
-
role=role,
|
|
256
|
-
message_type=MessageType.MESSAGE,
|
|
257
|
-
)
|
|
258
|
-
# add meta field to store old id and name
|
|
259
|
-
current_mb.message.metadata = {
|
|
260
|
-
"original_id": msg.id,
|
|
261
|
-
"original_name": msg.name,
|
|
262
|
-
"metadata": msg.metadata,
|
|
263
|
-
}
|
|
264
|
-
current_type = MessageType.MESSAGE
|
|
265
|
-
cb = current_mb.create_content_builder(content_type="audio")
|
|
266
|
-
# URLSource runtime check (dict with type == "url")
|
|
267
|
-
if (
|
|
268
|
-
isinstance(block.get("source"), dict)
|
|
269
|
-
and block.get("source", {}).get(
|
|
270
|
-
"type",
|
|
271
|
-
)
|
|
272
|
-
== "url"
|
|
273
|
-
):
|
|
274
|
-
url = block.get("source", {}).get("url")
|
|
275
|
-
cb.content.data = url
|
|
276
|
-
try:
|
|
277
|
-
cb.content.format = urlparse(url).path.split(".")[-1]
|
|
278
|
-
except (AttributeError, IndexError, ValueError):
|
|
279
|
-
cb.content.format = None
|
|
280
|
-
|
|
281
|
-
# Base64Source runtime check (dict with type == "base64")
|
|
282
|
-
elif (
|
|
283
|
-
isinstance(block.get("source"), dict)
|
|
284
|
-
and block.get("source").get(
|
|
285
|
-
"type",
|
|
286
|
-
)
|
|
287
|
-
== "base64"
|
|
288
|
-
):
|
|
289
|
-
media_type = block.get("source", {}).get(
|
|
290
|
-
"media_type",
|
|
291
|
-
)
|
|
292
|
-
base64_data = block.get("source", {}).get("data", "")
|
|
293
|
-
url = f"data:{media_type};base64,{base64_data}"
|
|
294
|
-
|
|
295
|
-
cb.content.data = url
|
|
296
|
-
cb.content.format = media_type
|
|
297
|
-
|
|
298
|
-
cb.complete()
|
|
299
45
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
results.append(current_mb.get_message_data())
|
|
306
|
-
rb = ResponseBuilder()
|
|
307
|
-
current_mb = rb.create_message_builder(
|
|
308
|
-
role=role,
|
|
309
|
-
message_type=MessageType.MESSAGE,
|
|
310
|
-
)
|
|
311
|
-
# add meta field to store old id and name
|
|
312
|
-
current_mb.message.metadata = {
|
|
313
|
-
"original_id": msg.id,
|
|
314
|
-
"original_name": msg.name,
|
|
315
|
-
"metadata": msg.metadata,
|
|
316
|
-
}
|
|
317
|
-
current_type = MessageType.MESSAGE
|
|
318
|
-
cb = current_mb.create_content_builder(content_type="text")
|
|
319
|
-
cb.set_text(str(block))
|
|
320
|
-
cb.complete()
|
|
321
|
-
|
|
322
|
-
# finalize last open message builder
|
|
323
|
-
if current_mb:
|
|
324
|
-
current_mb.complete()
|
|
325
|
-
results.append(current_mb.get_message_data())
|
|
326
|
-
|
|
327
|
-
return results
|
|
46
|
+
def matches_typed_dict_structure(obj, typed_dict_cls):
|
|
47
|
+
if not isinstance(obj, dict):
|
|
48
|
+
return False
|
|
49
|
+
expected_keys = set(typed_dict_cls.__annotations__.keys())
|
|
50
|
+
return expected_keys == set(obj.keys())
|
|
328
51
|
|
|
329
52
|
|
|
330
53
|
def message_to_agentscope_msg(
|
|
331
54
|
messages: Union[Message, List[Message]],
|
|
55
|
+
type_converters: Optional[Dict[str, Callable]] = None,
|
|
332
56
|
) -> Union[Msg, List[Msg]]:
|
|
333
57
|
"""
|
|
334
58
|
Convert AgentScope runtime Message(s) to AgentScope Msg(s).
|
|
335
59
|
|
|
336
60
|
Args:
|
|
337
61
|
messages: A single AgentScope runtime Message or list of Messages.
|
|
62
|
+
type_converters: Optional mapping from ``message.type`` to a callable
|
|
63
|
+
``converter(message)``. When provided and the current
|
|
64
|
+
``message.type`` exists in the mapping, the corresponding converter
|
|
65
|
+
will be used and the built-in conversion logic will be skipped for
|
|
66
|
+
that message.
|
|
338
67
|
|
|
339
68
|
Returns:
|
|
340
69
|
A single Msg object or a list of Msg objects.
|
|
@@ -351,6 +80,10 @@ def message_to_agentscope_msg(
|
|
|
351
80
|
return default
|
|
352
81
|
|
|
353
82
|
def _convert_one(message: Message) -> Msg:
|
|
83
|
+
# Used for custom conversion
|
|
84
|
+
if type_converters and message.type in type_converters:
|
|
85
|
+
return type_converters[message.type](message)
|
|
86
|
+
|
|
354
87
|
# Normalize role
|
|
355
88
|
if message.role == "tool":
|
|
356
89
|
role_label = "system" # AgentScope not support tool as role
|
|
@@ -474,8 +207,8 @@ def message_to_agentscope_msg(
|
|
|
474
207
|
"image": (ImageBlock, "image_url"),
|
|
475
208
|
"audio": (AudioBlock, "data"),
|
|
476
209
|
"data": (TextBlock, "data"),
|
|
477
|
-
|
|
478
|
-
|
|
210
|
+
"video": (VideoBlock, "video_url"),
|
|
211
|
+
"file": (FileBlock, "file_url"),
|
|
479
212
|
}
|
|
480
213
|
|
|
481
214
|
msg_content = []
|
|
@@ -547,6 +280,63 @@ def message_to_agentscope_msg(
|
|
|
547
280
|
msg_content.append(
|
|
548
281
|
block_cls(type=cnt_type, source=base64_source),
|
|
549
282
|
)
|
|
283
|
+
elif cnt_type == "video":
|
|
284
|
+
if (
|
|
285
|
+
value
|
|
286
|
+
and isinstance(value, str)
|
|
287
|
+
and value.startswith("data:")
|
|
288
|
+
):
|
|
289
|
+
mediatype_part = value.split(";")[0].replace(
|
|
290
|
+
"data:",
|
|
291
|
+
"",
|
|
292
|
+
)
|
|
293
|
+
base64_data = value.split(",")[1]
|
|
294
|
+
base64_source = Base64Source(
|
|
295
|
+
type="base64",
|
|
296
|
+
media_type=mediatype_part,
|
|
297
|
+
data=base64_data,
|
|
298
|
+
)
|
|
299
|
+
msg_content.append(
|
|
300
|
+
block_cls(type=cnt_type, source=base64_source),
|
|
301
|
+
)
|
|
302
|
+
else:
|
|
303
|
+
url_source = URLSource(type="url", url=value)
|
|
304
|
+
msg_content.append(
|
|
305
|
+
block_cls(type=cnt_type, source=url_source),
|
|
306
|
+
)
|
|
307
|
+
elif cnt_type == "file":
|
|
308
|
+
filename = cnt.filename
|
|
309
|
+
if (
|
|
310
|
+
value
|
|
311
|
+
and isinstance(value, str)
|
|
312
|
+
and value.startswith("data:")
|
|
313
|
+
):
|
|
314
|
+
mediatype_part = value.split(";")[0].replace(
|
|
315
|
+
"data:",
|
|
316
|
+
"",
|
|
317
|
+
)
|
|
318
|
+
base64_data = value.split(",")[1]
|
|
319
|
+
base64_source = Base64Source(
|
|
320
|
+
type="base64",
|
|
321
|
+
media_type=mediatype_part,
|
|
322
|
+
data=base64_data,
|
|
323
|
+
)
|
|
324
|
+
msg_content.append(
|
|
325
|
+
block_cls(
|
|
326
|
+
type=cnt_type,
|
|
327
|
+
source=base64_source,
|
|
328
|
+
filename=filename,
|
|
329
|
+
),
|
|
330
|
+
)
|
|
331
|
+
else:
|
|
332
|
+
url_source = URLSource(type="url", url=value)
|
|
333
|
+
msg_content.append(
|
|
334
|
+
block_cls(
|
|
335
|
+
type=cnt_type,
|
|
336
|
+
source=url_source,
|
|
337
|
+
filename=filename,
|
|
338
|
+
),
|
|
339
|
+
)
|
|
550
340
|
else:
|
|
551
341
|
# text & data
|
|
552
342
|
if isinstance(value, str):
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
# pylint: disable=too-many-nested-blocks,too-many-branches,too-many-statements
|
|
3
3
|
import copy
|
|
4
|
+
import inspect
|
|
4
5
|
import json
|
|
5
6
|
|
|
6
|
-
from typing import AsyncIterator, Tuple, List, Union
|
|
7
|
+
from typing import AsyncIterator, Tuple, List, Union, Optional, Callable, Dict
|
|
7
8
|
from urllib.parse import urlparse
|
|
8
9
|
|
|
9
10
|
from agentscope import setup_logger
|
|
@@ -16,7 +17,9 @@ from ...engine.schemas.agent_schemas import (
|
|
|
16
17
|
TextContent,
|
|
17
18
|
ImageContent,
|
|
18
19
|
AudioContent,
|
|
20
|
+
VideoContent,
|
|
19
21
|
DataContent,
|
|
22
|
+
FileContent,
|
|
20
23
|
McpCall,
|
|
21
24
|
McpCallOutput,
|
|
22
25
|
FunctionCall,
|
|
@@ -29,6 +32,8 @@ setup_logger("ERROR")
|
|
|
29
32
|
|
|
30
33
|
async def adapt_agentscope_message_stream(
|
|
31
34
|
source_stream: AsyncIterator[Tuple[Msg, bool]],
|
|
35
|
+
type_converters: Optional[Dict[str, Callable]] = None,
|
|
36
|
+
**kwargs, # pylint:disable=unused-argument
|
|
32
37
|
) -> AsyncIterator[Union[Message, Content]]:
|
|
33
38
|
# Initialize variables to avoid uncaught errors
|
|
34
39
|
msg_id = None
|
|
@@ -136,6 +141,44 @@ async def adapt_agentscope_message_stream(
|
|
|
136
141
|
index = text_delta_content.index
|
|
137
142
|
yield text_delta_content
|
|
138
143
|
elif isinstance(element, dict):
|
|
144
|
+
# Used for custom conversion
|
|
145
|
+
if (
|
|
146
|
+
type_converters
|
|
147
|
+
and element.get("type") in type_converters
|
|
148
|
+
):
|
|
149
|
+
blk_type = element.get("type")
|
|
150
|
+
if not isinstance(blk_type, str):
|
|
151
|
+
continue
|
|
152
|
+
fn = type_converters[blk_type]
|
|
153
|
+
# Send message, element, last, tool_start, metadata
|
|
154
|
+
# and usage
|
|
155
|
+
out = fn(
|
|
156
|
+
element,
|
|
157
|
+
message,
|
|
158
|
+
last,
|
|
159
|
+
tool_start,
|
|
160
|
+
metadata,
|
|
161
|
+
usage,
|
|
162
|
+
)
|
|
163
|
+
# Case 1: async generator / async iterator
|
|
164
|
+
if hasattr(out, "__aiter__"):
|
|
165
|
+
async for ev in out:
|
|
166
|
+
yield ev
|
|
167
|
+
continue
|
|
168
|
+
|
|
169
|
+
# Case 2: sync generator / iterator
|
|
170
|
+
if inspect.isgenerator(out):
|
|
171
|
+
for ev in out:
|
|
172
|
+
yield ev
|
|
173
|
+
continue
|
|
174
|
+
|
|
175
|
+
# Only generator styles are supported
|
|
176
|
+
raise TypeError(
|
|
177
|
+
f"type_converters['{blk_type}'] must return a "
|
|
178
|
+
f"generator/iterator or an async generator/async "
|
|
179
|
+
f"iterator, got: {type(out)}",
|
|
180
|
+
)
|
|
181
|
+
|
|
139
182
|
if element.get("type") == "text": # Text
|
|
140
183
|
text = element.get(
|
|
141
184
|
"text",
|
|
@@ -446,7 +489,12 @@ async def adapt_agentscope_message_stream(
|
|
|
446
489
|
== "url"
|
|
447
490
|
):
|
|
448
491
|
kwargs.update(
|
|
449
|
-
{
|
|
492
|
+
{
|
|
493
|
+
"image_url": element.get(
|
|
494
|
+
"source",
|
|
495
|
+
{},
|
|
496
|
+
).get("url"),
|
|
497
|
+
},
|
|
450
498
|
)
|
|
451
499
|
|
|
452
500
|
elif (
|
|
@@ -471,7 +519,7 @@ async def adapt_agentscope_message_stream(
|
|
|
471
519
|
index=index,
|
|
472
520
|
**kwargs,
|
|
473
521
|
)
|
|
474
|
-
elif element.get("
|
|
522
|
+
elif element.get("type") == "audio":
|
|
475
523
|
kwargs = {}
|
|
476
524
|
if (
|
|
477
525
|
isinstance(element.get("source"), dict)
|
|
@@ -515,6 +563,88 @@ async def adapt_agentscope_message_stream(
|
|
|
515
563
|
index=index,
|
|
516
564
|
**kwargs,
|
|
517
565
|
)
|
|
566
|
+
elif element.get("type") == "video":
|
|
567
|
+
kwargs = {}
|
|
568
|
+
if (
|
|
569
|
+
isinstance(element.get("source"), dict)
|
|
570
|
+
and element.get("source", {}).get(
|
|
571
|
+
"type",
|
|
572
|
+
)
|
|
573
|
+
== "url"
|
|
574
|
+
):
|
|
575
|
+
kwargs.update(
|
|
576
|
+
{
|
|
577
|
+
"video_url": element.get(
|
|
578
|
+
"source",
|
|
579
|
+
{},
|
|
580
|
+
).get("url"),
|
|
581
|
+
},
|
|
582
|
+
)
|
|
583
|
+
|
|
584
|
+
elif (
|
|
585
|
+
isinstance(element.get("source"), dict)
|
|
586
|
+
and element.get("source").get(
|
|
587
|
+
"type",
|
|
588
|
+
)
|
|
589
|
+
== "base64"
|
|
590
|
+
):
|
|
591
|
+
media_type = element.get("source", {}).get(
|
|
592
|
+
"media_type",
|
|
593
|
+
"video/mp4",
|
|
594
|
+
)
|
|
595
|
+
base64_data = element.get("source", {}).get(
|
|
596
|
+
"data",
|
|
597
|
+
"",
|
|
598
|
+
)
|
|
599
|
+
url = f"data:{media_type};base64,{base64_data}"
|
|
600
|
+
kwargs.update({"video_url": url})
|
|
601
|
+
delta_content = VideoContent(
|
|
602
|
+
delta=True,
|
|
603
|
+
index=index,
|
|
604
|
+
**kwargs,
|
|
605
|
+
)
|
|
606
|
+
elif element.get("type") == "file":
|
|
607
|
+
kwargs = {
|
|
608
|
+
"filename": element.get("filename"),
|
|
609
|
+
}
|
|
610
|
+
if (
|
|
611
|
+
isinstance(element.get("source"), dict)
|
|
612
|
+
and element.get("source", {}).get(
|
|
613
|
+
"type",
|
|
614
|
+
)
|
|
615
|
+
== "url"
|
|
616
|
+
):
|
|
617
|
+
kwargs.update(
|
|
618
|
+
{
|
|
619
|
+
"file_url": element.get(
|
|
620
|
+
"source",
|
|
621
|
+
{},
|
|
622
|
+
).get("url"),
|
|
623
|
+
},
|
|
624
|
+
)
|
|
625
|
+
|
|
626
|
+
elif (
|
|
627
|
+
isinstance(element.get("source"), dict)
|
|
628
|
+
and element.get("source").get(
|
|
629
|
+
"type",
|
|
630
|
+
)
|
|
631
|
+
== "base64"
|
|
632
|
+
):
|
|
633
|
+
media_type = element.get("source", {}).get(
|
|
634
|
+
"media_type",
|
|
635
|
+
"application/octet-stream",
|
|
636
|
+
)
|
|
637
|
+
base64_data = element.get("source", {}).get(
|
|
638
|
+
"data",
|
|
639
|
+
"",
|
|
640
|
+
)
|
|
641
|
+
url = f"data:{media_type};base64,{base64_data}"
|
|
642
|
+
kwargs.update({"file_url": url})
|
|
643
|
+
delta_content = FileContent(
|
|
644
|
+
delta=True,
|
|
645
|
+
index=index,
|
|
646
|
+
**kwargs,
|
|
647
|
+
)
|
|
518
648
|
else:
|
|
519
649
|
delta_content = TextContent(
|
|
520
650
|
delta=True,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
from typing import Union, List
|
|
2
|
+
from typing import Union, List, Callable, Optional, Dict
|
|
3
3
|
|
|
4
4
|
from agentscope.formatter import OpenAIChatFormatter
|
|
5
5
|
|
|
@@ -9,18 +9,27 @@ from ..agentscope.message import message_to_agentscope_msg
|
|
|
9
9
|
|
|
10
10
|
async def message_to_agno_message(
|
|
11
11
|
messages: Union[Message, List[Message]],
|
|
12
|
+
type_converters: Optional[Dict[str, Callable]] = None,
|
|
12
13
|
) -> Union[dict, List[dict]]:
|
|
13
14
|
"""
|
|
14
15
|
Convert AgentScope runtime Message(s) to Agno Message(s).
|
|
15
16
|
|
|
16
17
|
Args:
|
|
17
18
|
messages: A single AgentScope runtime Message or list of Messages.
|
|
19
|
+
type_converters: Optional mapping from ``message.type`` to a callable
|
|
20
|
+
``converter(message)``. When provided and the current
|
|
21
|
+
``message.type`` exists in the mapping, the corresponding converter
|
|
22
|
+
will be used and the built-in conversion logic will be skipped for
|
|
23
|
+
that message.
|
|
18
24
|
|
|
19
25
|
Returns:
|
|
20
26
|
A single AgnoMessage object or a list of AgnoMessage objects.
|
|
21
27
|
"""
|
|
22
28
|
|
|
23
|
-
as_msgs = message_to_agentscope_msg(
|
|
29
|
+
as_msgs = message_to_agentscope_msg(
|
|
30
|
+
messages,
|
|
31
|
+
type_converters=type_converters,
|
|
32
|
+
)
|
|
24
33
|
raw_list = isinstance(as_msgs, list)
|
|
25
34
|
as_msgs = as_msgs if raw_list else [as_msgs]
|
|
26
35
|
|
|
@@ -31,6 +31,7 @@ from ...engine.helpers.agent_api_builder import ResponseBuilder
|
|
|
31
31
|
|
|
32
32
|
async def adapt_agno_message_stream(
|
|
33
33
|
source_stream: AsyncIterator[BaseAgentRunEvent],
|
|
34
|
+
**kwargs, # pylint:disable=unused-argument
|
|
34
35
|
) -> AsyncIterator[Union[Message, Content]]:
|
|
35
36
|
rb = ResponseBuilder()
|
|
36
37
|
mb = None
|
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
"""LangGraph adapter for AgentScope runtime."""
|
|
3
3
|
|
|
4
4
|
# todo Message(reasoning) Adapter
|
|
5
|
-
# todo Memory Adapter
|
|
6
5
|
# todo Sandbox Tools Adapter
|
|
7
|
-
from .message import
|
|
6
|
+
from .message import message_to_langgraph_msg
|
|
8
7
|
|
|
9
8
|
__all__ = [
|
|
10
|
-
"langgraph_msg_to_message",
|
|
11
9
|
"message_to_langgraph_msg",
|
|
12
10
|
]
|