agentscope-runtime 1.0.4__py3-none-any.whl → 1.0.4a1__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 (46) hide show
  1. agentscope_runtime/adapters/agentscope/stream.py +7 -1
  2. agentscope_runtime/cli/commands/deploy.py +0 -371
  3. agentscope_runtime/engine/__init__.py +0 -4
  4. agentscope_runtime/engine/constant.py +0 -1
  5. agentscope_runtime/engine/deployers/__init__.py +0 -12
  6. agentscope_runtime/engine/deployers/adapter/a2a/__init__.py +51 -26
  7. agentscope_runtime/engine/deployers/adapter/a2a/a2a_protocol_adapter.py +10 -19
  8. agentscope_runtime/engine/deployers/adapter/a2a/a2a_registry.py +201 -4
  9. agentscope_runtime/engine/deployers/adapter/a2a/nacos_a2a_registry.py +25 -134
  10. agentscope_runtime/engine/deployers/agentrun_deployer.py +2 -2
  11. agentscope_runtime/engine/runner.py +0 -12
  12. agentscope_runtime/engine/tracing/wrapper.py +4 -18
  13. agentscope_runtime/sandbox/__init__.py +6 -14
  14. agentscope_runtime/sandbox/box/base/__init__.py +2 -2
  15. agentscope_runtime/sandbox/box/base/base_sandbox.py +1 -51
  16. agentscope_runtime/sandbox/box/browser/__init__.py +2 -2
  17. agentscope_runtime/sandbox/box/browser/browser_sandbox.py +2 -198
  18. agentscope_runtime/sandbox/box/filesystem/__init__.py +2 -2
  19. agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +2 -99
  20. agentscope_runtime/sandbox/box/gui/__init__.py +2 -2
  21. agentscope_runtime/sandbox/box/gui/gui_sandbox.py +1 -117
  22. agentscope_runtime/sandbox/box/mobile/__init__.py +2 -2
  23. agentscope_runtime/sandbox/box/mobile/mobile_sandbox.py +100 -247
  24. agentscope_runtime/sandbox/box/sandbox.py +65 -98
  25. agentscope_runtime/sandbox/box/shared/routers/generic.py +29 -36
  26. agentscope_runtime/sandbox/client/__init__.py +1 -6
  27. agentscope_runtime/sandbox/client/http_client.py +329 -108
  28. agentscope_runtime/sandbox/enums.py +0 -7
  29. agentscope_runtime/sandbox/manager/sandbox_manager.py +4 -264
  30. agentscope_runtime/sandbox/manager/server/app.py +1 -7
  31. agentscope_runtime/version.py +1 -1
  32. {agentscope_runtime-1.0.4.dist-info → agentscope_runtime-1.0.4a1.dist-info}/METADATA +28 -102
  33. {agentscope_runtime-1.0.4.dist-info → agentscope_runtime-1.0.4a1.dist-info}/RECORD +37 -46
  34. agentscope_runtime/adapters/ms_agent_framework/__init__.py +0 -0
  35. agentscope_runtime/adapters/ms_agent_framework/message.py +0 -205
  36. agentscope_runtime/adapters/ms_agent_framework/stream.py +0 -418
  37. agentscope_runtime/adapters/utils.py +0 -6
  38. agentscope_runtime/common/container_clients/knative_client.py +0 -466
  39. agentscope_runtime/engine/deployers/fc_deployer.py +0 -1506
  40. agentscope_runtime/engine/deployers/knative_deployer.py +0 -290
  41. agentscope_runtime/sandbox/client/async_http_client.py +0 -339
  42. agentscope_runtime/sandbox/client/base.py +0 -74
  43. {agentscope_runtime-1.0.4.dist-info → agentscope_runtime-1.0.4a1.dist-info}/WHEEL +0 -0
  44. {agentscope_runtime-1.0.4.dist-info → agentscope_runtime-1.0.4a1.dist-info}/entry_points.txt +0 -0
  45. {agentscope_runtime-1.0.4.dist-info → agentscope_runtime-1.0.4a1.dist-info}/licenses/LICENSE +0 -0
  46. {agentscope_runtime-1.0.4.dist-info → agentscope_runtime-1.0.4a1.dist-info}/top_level.txt +0 -0
@@ -1,205 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- # pylint: disable=too-many-branches,too-many-statements
3
- import json
4
- from typing import Union, List
5
- from collections import OrderedDict
6
-
7
- from agent_framework import (
8
- ChatMessage,
9
- TextContent as MSTextContent,
10
- DataContent as MSDataContent,
11
- TextReasoningContent,
12
- UriContent,
13
- FunctionCallContent,
14
- FunctionResultContent,
15
- )
16
-
17
- from ...engine.schemas.agent_schemas import (
18
- Message,
19
- MessageType,
20
- )
21
-
22
-
23
- def message_to_ms_agent_framework_message(
24
- messages: Union[Message, List[Message]],
25
- ) -> Union[ChatMessage, List[ChatMessage]]:
26
- """
27
- Convert AgentScope runtime Message(s) to Microsoft agent framework
28
- Message(s).
29
-
30
- Reference:
31
- https://learn.microsoft.com/en-us/agent-framework/user-guide/agents
32
- /running-agents?pivots=programming-language-python
33
-
34
- Args:
35
- messages: A single AgentScope runtime Message or list of Messages.
36
-
37
- Returns:
38
- A single Microsoft agent framework Message object or a list of
39
- Microsoft agent framework Message objects.
40
- """
41
-
42
- def _try_loads(v, default, keep_original=False):
43
- if isinstance(v, (dict, list)):
44
- return v
45
- if isinstance(v, str) and v.strip():
46
- try:
47
- return json.loads(v)
48
- except Exception:
49
- return v if keep_original else default
50
- return default
51
-
52
- def _convert_one(message: Message) -> ChatMessage:
53
- result = {
54
- "author_name": getattr(message, "name", message.role),
55
- "role": message.role or "assistant",
56
- }
57
- _id = getattr(message, "id")
58
-
59
- # if meta exists, prefer original id/name from meta
60
- if hasattr(message, "metadata") and isinstance(message.metadata, dict):
61
- if "original_id" in message.metadata:
62
- _id = message.metadata["original_id"]
63
- if "original_name" in message.metadata:
64
- result["author_name"] = message.metadata["original_name"]
65
- if "metadata" in message.metadata:
66
- result["additional_properties"] = message.metadata["metadata"]
67
- result["message_id"] = _id
68
-
69
- if message.type in (
70
- MessageType.PLUGIN_CALL,
71
- MessageType.MCP_TOOL_CALL,
72
- MessageType.FUNCTION_CALL,
73
- ):
74
- # convert CALL to ToolUseBlock
75
- tool_args = None
76
- for cnt in reversed(message.content):
77
- if hasattr(cnt, "data"):
78
- v = cnt.data.get("arguments")
79
- if isinstance(v, (dict, list)) or (
80
- isinstance(v, str) and v.strip()
81
- ):
82
- tool_args = _try_loads(v, {}, keep_original=False)
83
- break
84
- if tool_args is None:
85
- tool_args = {}
86
- result["contents"] = [
87
- FunctionCallContent(
88
- call_id=message.content[0].data["call_id"],
89
- name=message.content[0].data.get("name"),
90
- arguments=tool_args,
91
- ),
92
- ]
93
- elif message.type in (
94
- MessageType.PLUGIN_CALL_OUTPUT,
95
- MessageType.MCP_TOOL_CALL_OUTPUT,
96
- MessageType.FUNCTION_CALL_OUTPUT,
97
- ):
98
- result["role"] = "tool"
99
- out = None
100
- for cnt in reversed(message.content):
101
- if hasattr(cnt, "data"):
102
- v = cnt.data.get("output")
103
- if isinstance(v, (dict, list)) or (
104
- isinstance(v, str) and v.strip()
105
- ):
106
- out = _try_loads(v, "", keep_original=True)
107
- break
108
- if out is None:
109
- out = ""
110
- blk = out
111
-
112
- result["contents"] = [
113
- FunctionResultContent(
114
- call_id=message.content[0].data["call_id"],
115
- result=blk,
116
- ),
117
- ]
118
- elif message.type in (MessageType.REASONING,):
119
- result["contents"] = [
120
- TextReasoningContent(
121
- text=message.content[0].text,
122
- ),
123
- ]
124
- else:
125
- type_mapping = {
126
- "text": (MSTextContent, "text"),
127
- "image": (UriContent, "image_url"),
128
- "audio": (UriContent, "data"),
129
- "data": (MSDataContent, "data"),
130
- "file": (MSDataContent, "file_url"), # Support file_url
131
- # "video": (VideoBlock, "video_url", True),
132
- # TODO: support video
133
- }
134
-
135
- msg_content = []
136
- for cnt in message.content:
137
- cnt_type = cnt.type or "text"
138
-
139
- if cnt_type not in type_mapping:
140
- raise ValueError(f"Unsupported message type: {cnt_type}")
141
-
142
- block_cls, attr_name = type_mapping[cnt_type]
143
- value = getattr(cnt, attr_name)
144
-
145
- if cnt_type in ("image", "audio", "file", "data"):
146
- msg_content.append(
147
- block_cls(
148
- data=value,
149
- type=cnt.type,
150
- ),
151
- )
152
-
153
- else:
154
- # text
155
- if isinstance(value, str):
156
- msg_content.append(
157
- MSTextContent(text=value),
158
- )
159
- else:
160
- try:
161
- json_str = json.dumps(value, ensure_ascii=False)
162
- except Exception:
163
- json_str = str(value)
164
- msg_content.append(MSTextContent(text=json_str))
165
-
166
- result["contents"] = msg_content
167
- _msg = ChatMessage(**result)
168
- return _msg
169
-
170
- # Handle single or list input
171
- if isinstance(messages, Message):
172
- return _convert_one(messages)
173
- elif isinstance(messages, list):
174
- converted_list = [_convert_one(m) for m in messages]
175
-
176
- # Group by original_id
177
- grouped = OrderedDict()
178
- for msg, orig_msg in zip(messages, converted_list):
179
- metadata = getattr(msg, "metadata")
180
- if metadata:
181
- orig_id = metadata.get(
182
- "original_id",
183
- orig_msg.message_id,
184
- )
185
- else:
186
- # In case metadata is not provided, use the original id
187
- orig_id = msg.id
188
-
189
- if orig_id not in grouped:
190
- ms_msg = ChatMessage(
191
- author_name=orig_msg.author_name,
192
- role=orig_msg.role,
193
- additional_properties=orig_msg.additional_properties,
194
- contents=list(orig_msg.contents),
195
- )
196
- ms_msg.message_id = orig_id
197
- grouped[orig_id] = ms_msg
198
- else:
199
- grouped[orig_id].contents.extend(orig_msg.contents)
200
-
201
- return list(grouped.values())
202
- else:
203
- raise TypeError(
204
- f"Expected Message or list[Message], got {type(messages)}",
205
- )
@@ -1,418 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- # pylint: disable=too-many-branches,too-many-statements
3
- import copy
4
- import json
5
-
6
- from typing import AsyncIterator, Union, List
7
-
8
- from agent_framework import (
9
- AgentRunResponseUpdate,
10
- TextContent as MSTextContent,
11
- DataContent as MSDataContent,
12
- TextReasoningContent,
13
- UriContent,
14
- FunctionCallContent,
15
- FunctionResultContent,
16
- ErrorContent,
17
- UsageContent,
18
- )
19
-
20
- from ..utils import _update_obj_attrs
21
- from ...engine.schemas.exception import AgentRuntimeErrorException
22
- from ...engine.schemas.agent_schemas import (
23
- Message,
24
- TextContent,
25
- Content,
26
- DataContent,
27
- FunctionCall,
28
- FunctionCallOutput,
29
- MessageType,
30
- ImageContent,
31
- AudioContent,
32
- FileContent,
33
- )
34
-
35
-
36
- async def adapt_ms_agent_framework_message_stream(
37
- source_stream: AsyncIterator[AgentRunResponseUpdate],
38
- ) -> AsyncIterator[Union[Message, Content]]:
39
- # Initialize variables to avoid uncaught errors
40
- msg_id = None
41
- usage = None
42
- tool_start = False
43
- message = None
44
- reasoning_message = None
45
- plugin_call_message = None
46
- call_id = None
47
- text_delta_content = None
48
- data_delta_content = None
49
- index = None
50
-
51
- # Run agent
52
- async for msg in source_stream:
53
- # deepcopy required to avoid modifying the original message object
54
- # which may be used elsewhere in the streaming pipeline
55
- msg = copy.deepcopy(msg)
56
-
57
- assert isinstance(
58
- msg,
59
- AgentRunResponseUpdate,
60
- ), f"Expected AgentRunResponseUpdate, got {type(msg)}"
61
-
62
- # If a new message, create new Message
63
- if msg.message_id != msg_id:
64
- # If a new message, yield previous content
65
- if text_delta_content is not None:
66
- yield text_delta_content.completed()
67
- text_delta_content = None
68
-
69
- if data_delta_content is not None:
70
- yield data_delta_content.completed()
71
- data_delta_content = None
72
-
73
- if message is not None:
74
- message = _update_obj_attrs(
75
- message,
76
- usage=usage,
77
- )
78
-
79
- yield message.completed()
80
- message = None
81
-
82
- if reasoning_message is not None:
83
- reasoning_message = _update_obj_attrs(
84
- reasoning_message,
85
- usage=usage,
86
- )
87
-
88
- yield reasoning_message.completed()
89
- reasoning_message = None
90
-
91
- if plugin_call_message is not None:
92
- plugin_call_message = _update_obj_attrs(
93
- plugin_call_message,
94
- usage=usage,
95
- )
96
-
97
- yield plugin_call_message.completed()
98
- plugin_call_message = None
99
-
100
- index = None
101
-
102
- # Note: Tool use content only happens in the last of messages
103
- tool_start = False
104
-
105
- # Cache msg id
106
- msg_id = msg.message_id
107
-
108
- new_blocks = []
109
- new_tool_blocks = []
110
- if isinstance(msg.contents, List):
111
- for block in msg.contents:
112
- if block.type != "function_call":
113
- new_blocks.append(block)
114
- else:
115
- new_tool_blocks.append(block)
116
- if new_tool_blocks:
117
- if tool_start:
118
- msg.contents = new_tool_blocks
119
- else:
120
- msg.contents = new_blocks
121
- tool_start = True
122
-
123
- else:
124
- msg.contents = new_blocks
125
-
126
- if not msg.contents:
127
- continue
128
-
129
- # msg content
130
- content = msg.contents
131
-
132
- for element in content:
133
- if isinstance(element, UsageContent):
134
- # TODO: consider keeping the same format with as
135
- usage = element.details.to_dict()
136
-
137
- elif isinstance(element, MSTextContent): # Text
138
- text = element.text
139
- if text:
140
- if message is None:
141
- message = Message(
142
- role="assistant",
143
- type=MessageType.MESSAGE,
144
- )
145
-
146
- index = None
147
- message = _update_obj_attrs(
148
- message,
149
- usage=usage,
150
- )
151
- yield message.in_progress()
152
-
153
- text_delta_content = TextContent(
154
- delta=True,
155
- index=index,
156
- text=text,
157
- )
158
- text_delta_content = message.add_delta_content(
159
- new_content=text_delta_content,
160
- )
161
- index = text_delta_content.index
162
-
163
- # Only yield valid text
164
- if text_delta_content.text:
165
- yield text_delta_content
166
-
167
- if tool_start:
168
- text_delta_content = message.content[index]
169
- if text_delta_content.text:
170
- yield text_delta_content.completed()
171
- text_delta_content = None
172
-
173
- message = _update_obj_attrs(
174
- message,
175
- usage=usage,
176
- )
177
- yield message.completed()
178
- message = None
179
- index = None
180
-
181
- elif isinstance(element, TextReasoningContent): # Thinking
182
- reasoning = element.text
183
- if reasoning:
184
- if reasoning_message is None:
185
- index = None
186
- reasoning_message = Message(
187
- role="assistant",
188
- type=MessageType.REASONING,
189
- )
190
-
191
- reasoning_message = _update_obj_attrs(
192
- reasoning_message,
193
- usage=usage,
194
- )
195
- yield reasoning_message.in_progress()
196
-
197
- text_delta_content = TextContent(
198
- delta=True,
199
- index=index,
200
- text=reasoning,
201
- )
202
- text_delta_content = reasoning_message.add_delta_content(
203
- new_content=text_delta_content,
204
- )
205
- index = text_delta_content.index
206
-
207
- # Only yield valid text
208
- if text_delta_content.text:
209
- yield text_delta_content
210
-
211
- if tool_start:
212
- text_delta_content = reasoning_message.content[index]
213
- if text_delta_content.text:
214
- yield text_delta_content.completed()
215
- text_delta_content = None
216
-
217
- reasoning_message = _update_obj_attrs(
218
- reasoning_message,
219
- usage=usage,
220
- )
221
- yield reasoning_message.completed()
222
- reasoning_message = None
223
- index = None
224
-
225
- elif isinstance(element, FunctionCallContent): # Tool use
226
- msg_type = MessageType.PLUGIN_CALL
227
- fc_cls = FunctionCall
228
- fc_kwargs = {}
229
-
230
- if element.call_id is not None: # New tool call
231
- index = None
232
- call_id = element.call_id
233
- plugin_call_message = Message(
234
- type=msg_type,
235
- role="assistant",
236
- )
237
- plugin_call_message = _update_obj_attrs(
238
- plugin_call_message,
239
- usage=usage,
240
- )
241
- yield plugin_call_message.in_progress()
242
- else:
243
- # The last plugin_call_message is completed
244
- if data_delta_content is not None:
245
- yield data_delta_content.completed()
246
- data_delta_content = None
247
- if plugin_call_message is not None:
248
- plugin_call_message = _update_obj_attrs(
249
- plugin_call_message,
250
- usage=usage,
251
- )
252
- yield plugin_call_message.completed()
253
- plugin_call_message = None
254
- index = None
255
-
256
- data_delta_content = DataContent(
257
- index=index,
258
- data=fc_cls(
259
- call_id=call_id,
260
- name=element.name,
261
- arguments=element.arguments,
262
- **fc_kwargs,
263
- ).model_dump(),
264
- delta=True,
265
- msg_id=plugin_call_message.id,
266
- )
267
- yield data_delta_content.in_progress()
268
-
269
- plugin_call_message = _update_obj_attrs(
270
- plugin_call_message,
271
- usage=usage,
272
- )
273
- yield plugin_call_message.in_progress()
274
-
275
- elif isinstance(element, FunctionResultContent): # Tool result
276
- try:
277
- json_str = json.dumps(
278
- element.result,
279
- ensure_ascii=False,
280
- )
281
- except Exception:
282
- json_str = str(element.result)
283
-
284
- data_delta_content = DataContent(
285
- index=None,
286
- data=FunctionCallOutput(
287
- call_id=element.call_id,
288
- output=json_str,
289
- ).model_dump(),
290
- )
291
- plugin_output_message = Message(
292
- type=MessageType.PLUGIN_CALL_OUTPUT,
293
- role="tool",
294
- content=[data_delta_content],
295
- )
296
- plugin_output_message = _update_obj_attrs(
297
- plugin_output_message,
298
- usage=usage,
299
- )
300
- yield plugin_output_message.completed()
301
- message = None
302
- reasoning_message = None
303
-
304
- index = None
305
-
306
- elif isinstance(element, MSDataContent):
307
- delta_content = DataContent(
308
- delta=True,
309
- index=index,
310
- data=element.uri,
311
- type=element.type,
312
- )
313
- delta_content = message.add_delta_content(
314
- new_content=delta_content,
315
- )
316
- index = delta_content.index
317
- yield delta_content
318
-
319
- elif isinstance(element, UriContent):
320
- kwargs = {}
321
-
322
- if "image" in element.type:
323
- cnt_cls = ImageContent
324
- kwargs.update(
325
- {
326
- "type": element.type,
327
- "image_url": element.uri,
328
- },
329
- )
330
- elif "audio" in element.type:
331
- cnt_cls = AudioContent
332
- kwargs.update(
333
- {
334
- "type": element.type,
335
- "data": element.uri,
336
- "format": element.media_type,
337
- },
338
- )
339
- elif "video" in element.type:
340
- # TODO: support video type
341
- cnt_cls = ImageContent
342
- kwargs.update(
343
- {
344
- "type": element.media_type,
345
- "image_url": element.uri,
346
- },
347
- )
348
- else:
349
- cnt_cls = FileContent
350
- kwargs.update(
351
- {
352
- "type": element.type,
353
- "file_url": element.uri,
354
- },
355
- )
356
-
357
- delta_content = cnt_cls(
358
- delta=False,
359
- index=index,
360
- **kwargs,
361
- )
362
- delta_content = message.add_delta_content(
363
- new_content=delta_content,
364
- )
365
- index = delta_content.index
366
- yield delta_content
367
-
368
- elif isinstance(element, ErrorContent):
369
- raise AgentRuntimeErrorException(
370
- code=element.error_code,
371
- message=element.message,
372
- details=element.details,
373
- )
374
-
375
- else:
376
- raise ValueError(f"Unknown element type: {type(element)}")
377
-
378
- if (
379
- text_delta_content is not None
380
- and text_delta_content.status == "in_progress"
381
- ):
382
- yield text_delta_content.completed()
383
-
384
- if (
385
- data_delta_content is not None
386
- and data_delta_content.status == "in_progress"
387
- ):
388
- yield data_delta_content.completed()
389
-
390
- if message is not None and message.status == "in_progress":
391
- message = _update_obj_attrs(
392
- message,
393
- usage=usage,
394
- )
395
-
396
- yield message.completed()
397
-
398
- if (
399
- reasoning_message is not None
400
- and reasoning_message.status == "in_progress"
401
- ):
402
- reasoning_message = _update_obj_attrs(
403
- reasoning_message,
404
- usage=usage,
405
- )
406
-
407
- yield reasoning_message.completed()
408
-
409
- if (
410
- plugin_call_message is not None
411
- and plugin_call_message.status == "in_progress"
412
- ):
413
- plugin_call_message = _update_obj_attrs(
414
- plugin_call_message,
415
- usage=usage,
416
- )
417
-
418
- yield plugin_call_message.completed()
@@ -1,6 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- def _update_obj_attrs(obj, **attrs):
3
- for key, value in attrs.items():
4
- if hasattr(obj, key):
5
- setattr(obj, key, value)
6
- return obj