agentscope-runtime 0.1.5b1__py3-none-any.whl → 0.2.0b1__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 (106) hide show
  1. agentscope_runtime/common/__init__.py +0 -0
  2. agentscope_runtime/common/collections/in_memory_mapping.py +27 -0
  3. agentscope_runtime/common/collections/redis_mapping.py +42 -0
  4. agentscope_runtime/common/container_clients/__init__.py +0 -0
  5. agentscope_runtime/common/container_clients/agentrun_client.py +1098 -0
  6. agentscope_runtime/common/container_clients/docker_client.py +250 -0
  7. agentscope_runtime/engine/__init__.py +12 -0
  8. agentscope_runtime/engine/agents/agentscope_agent.py +488 -0
  9. agentscope_runtime/engine/agents/agno_agent.py +19 -18
  10. agentscope_runtime/engine/agents/autogen_agent.py +13 -8
  11. agentscope_runtime/engine/agents/utils.py +53 -0
  12. agentscope_runtime/engine/app/__init__.py +6 -0
  13. agentscope_runtime/engine/app/agent_app.py +239 -0
  14. agentscope_runtime/engine/app/base_app.py +181 -0
  15. agentscope_runtime/engine/app/celery_mixin.py +92 -0
  16. agentscope_runtime/engine/deployers/base.py +1 -0
  17. agentscope_runtime/engine/deployers/cli_fc_deploy.py +72 -12
  18. agentscope_runtime/engine/deployers/kubernetes_deployer.py +12 -5
  19. agentscope_runtime/engine/deployers/local_deployer.py +61 -3
  20. agentscope_runtime/engine/deployers/modelstudio_deployer.py +77 -27
  21. agentscope_runtime/engine/deployers/utils/docker_image_utils/docker_image_builder.py +3 -3
  22. agentscope_runtime/engine/deployers/utils/docker_image_utils/runner_image_factory.py +9 -0
  23. agentscope_runtime/engine/deployers/utils/package_project_utils.py +234 -3
  24. agentscope_runtime/engine/deployers/utils/service_utils/fastapi_factory.py +567 -7
  25. agentscope_runtime/engine/deployers/utils/service_utils/standalone_main.py.j2 +211 -0
  26. agentscope_runtime/engine/deployers/utils/wheel_packager.py +1 -1
  27. agentscope_runtime/engine/helpers/helper.py +60 -41
  28. agentscope_runtime/engine/runner.py +35 -24
  29. agentscope_runtime/engine/schemas/agent_schemas.py +42 -0
  30. agentscope_runtime/engine/schemas/modelstudio_llm.py +14 -14
  31. agentscope_runtime/engine/services/sandbox_service.py +62 -70
  32. agentscope_runtime/engine/services/tablestore_memory_service.py +304 -0
  33. agentscope_runtime/engine/services/tablestore_rag_service.py +143 -0
  34. agentscope_runtime/engine/services/tablestore_session_history_service.py +293 -0
  35. agentscope_runtime/engine/services/utils/__init__.py +0 -0
  36. agentscope_runtime/engine/services/utils/tablestore_service_utils.py +352 -0
  37. agentscope_runtime/engine/tracing/__init__.py +9 -3
  38. agentscope_runtime/engine/tracing/asyncio_util.py +24 -0
  39. agentscope_runtime/engine/tracing/base.py +66 -34
  40. agentscope_runtime/engine/tracing/local_logging_handler.py +45 -31
  41. agentscope_runtime/engine/tracing/message_util.py +528 -0
  42. agentscope_runtime/engine/tracing/tracing_metric.py +20 -8
  43. agentscope_runtime/engine/tracing/tracing_util.py +130 -0
  44. agentscope_runtime/engine/tracing/wrapper.py +794 -169
  45. agentscope_runtime/sandbox/__init__.py +2 -0
  46. agentscope_runtime/sandbox/box/base/__init__.py +4 -0
  47. agentscope_runtime/sandbox/box/base/base_sandbox.py +6 -4
  48. agentscope_runtime/sandbox/box/browser/__init__.py +4 -0
  49. agentscope_runtime/sandbox/box/browser/browser_sandbox.py +10 -14
  50. agentscope_runtime/sandbox/box/dummy/__init__.py +4 -0
  51. agentscope_runtime/sandbox/box/dummy/dummy_sandbox.py +2 -1
  52. agentscope_runtime/sandbox/box/filesystem/__init__.py +4 -0
  53. agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +10 -7
  54. agentscope_runtime/sandbox/box/gui/__init__.py +4 -0
  55. agentscope_runtime/sandbox/box/gui/box/__init__.py +0 -0
  56. agentscope_runtime/sandbox/box/gui/gui_sandbox.py +81 -0
  57. agentscope_runtime/sandbox/box/sandbox.py +5 -2
  58. agentscope_runtime/sandbox/box/shared/routers/generic.py +20 -1
  59. agentscope_runtime/sandbox/box/training_box/__init__.py +4 -0
  60. agentscope_runtime/sandbox/box/training_box/training_box.py +10 -15
  61. agentscope_runtime/sandbox/build.py +143 -58
  62. agentscope_runtime/sandbox/client/http_client.py +87 -59
  63. agentscope_runtime/sandbox/client/training_client.py +0 -1
  64. agentscope_runtime/sandbox/constant.py +27 -1
  65. agentscope_runtime/sandbox/custom/custom_sandbox.py +7 -6
  66. agentscope_runtime/sandbox/custom/example.py +4 -3
  67. agentscope_runtime/sandbox/enums.py +1 -0
  68. agentscope_runtime/sandbox/manager/sandbox_manager.py +212 -106
  69. agentscope_runtime/sandbox/manager/server/app.py +82 -14
  70. agentscope_runtime/sandbox/manager/server/config.py +50 -3
  71. agentscope_runtime/sandbox/model/container.py +12 -23
  72. agentscope_runtime/sandbox/model/manager_config.py +93 -5
  73. agentscope_runtime/sandbox/registry.py +1 -1
  74. agentscope_runtime/sandbox/tools/gui/__init__.py +7 -0
  75. agentscope_runtime/sandbox/tools/gui/tool.py +77 -0
  76. agentscope_runtime/sandbox/tools/mcp_tool.py +6 -2
  77. agentscope_runtime/sandbox/tools/tool.py +4 -0
  78. agentscope_runtime/sandbox/utils.py +124 -0
  79. agentscope_runtime/version.py +1 -1
  80. {agentscope_runtime-0.1.5b1.dist-info → agentscope_runtime-0.2.0b1.dist-info}/METADATA +209 -101
  81. {agentscope_runtime-0.1.5b1.dist-info → agentscope_runtime-0.2.0b1.dist-info}/RECORD +95 -79
  82. agentscope_runtime/engine/agents/agentscope_agent/__init__.py +0 -6
  83. agentscope_runtime/engine/agents/agentscope_agent/agent.py +0 -401
  84. agentscope_runtime/engine/agents/agentscope_agent/hooks.py +0 -169
  85. agentscope_runtime/engine/agents/llm_agent.py +0 -51
  86. agentscope_runtime/engine/llms/__init__.py +0 -3
  87. agentscope_runtime/engine/llms/base_llm.py +0 -60
  88. agentscope_runtime/engine/llms/qwen_llm.py +0 -47
  89. agentscope_runtime/sandbox/manager/collections/in_memory_mapping.py +0 -22
  90. agentscope_runtime/sandbox/manager/collections/redis_mapping.py +0 -26
  91. agentscope_runtime/sandbox/manager/container_clients/__init__.py +0 -10
  92. agentscope_runtime/sandbox/manager/container_clients/docker_client.py +0 -422
  93. /agentscope_runtime/{sandbox/manager → common}/collections/__init__.py +0 -0
  94. /agentscope_runtime/{sandbox/manager → common}/collections/base_mapping.py +0 -0
  95. /agentscope_runtime/{sandbox/manager → common}/collections/base_queue.py +0 -0
  96. /agentscope_runtime/{sandbox/manager → common}/collections/base_set.py +0 -0
  97. /agentscope_runtime/{sandbox/manager → common}/collections/in_memory_queue.py +0 -0
  98. /agentscope_runtime/{sandbox/manager → common}/collections/in_memory_set.py +0 -0
  99. /agentscope_runtime/{sandbox/manager → common}/collections/redis_queue.py +0 -0
  100. /agentscope_runtime/{sandbox/manager → common}/collections/redis_set.py +0 -0
  101. /agentscope_runtime/{sandbox/manager → common}/container_clients/base_client.py +0 -0
  102. /agentscope_runtime/{sandbox/manager → common}/container_clients/kubernetes_client.py +0 -0
  103. {agentscope_runtime-0.1.5b1.dist-info → agentscope_runtime-0.2.0b1.dist-info}/WHEEL +0 -0
  104. {agentscope_runtime-0.1.5b1.dist-info → agentscope_runtime-0.2.0b1.dist-info}/entry_points.txt +0 -0
  105. {agentscope_runtime-0.1.5b1.dist-info → agentscope_runtime-0.2.0b1.dist-info}/licenses/LICENSE +0 -0
  106. {agentscope_runtime-0.1.5b1.dist-info → agentscope_runtime-0.2.0b1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1098 @@
1
+ # -*- coding: utf-8 -*-
2
+ # pylint: disable=line-too-long, arguments-renamed
3
+ import logging
4
+ import random
5
+ import string
6
+ import time
7
+ from http.client import HTTPS_PORT
8
+ from typing import List, Optional, Dict
9
+ from urllib.parse import urlparse
10
+
11
+ from alibabacloud_agentrun20250910.models import (
12
+ ContainerConfiguration,
13
+ CreateAgentRuntimeRequest,
14
+ CreateAgentRuntimeInput,
15
+ CreateAgentRuntimeEndpointRequest,
16
+ CreateAgentRuntimeEndpointInput,
17
+ NetworkConfiguration,
18
+ LogConfiguration,
19
+ GetAgentRuntimeRequest,
20
+ HealthCheckConfiguration,
21
+ )
22
+
23
+ from alibabacloud_agentrun20250910.client import Client
24
+ from alibabacloud_tea_openapi import models as open_api_models
25
+
26
+ from agentscope_runtime.sandbox.model import SandboxManagerEnvConfig
27
+ from .base_client import BaseClient
28
+
29
+ logger = logging.getLogger(__name__)
30
+
31
+
32
+ class AgentRunSessionManager:
33
+ """
34
+ Manager for AgentRun sessions that handles creation, retrieval,
35
+ updating, and deletion of sessions.
36
+ """
37
+
38
+ def __init__(self):
39
+ """Initialize the session manager with an empty session dictionary."""
40
+ self.sessions = {}
41
+ logger.debug("AgentRunSessionManager initialized")
42
+
43
+ def create_session(self, session_id: str, session_data: Dict):
44
+ """Create a new session with the given session_id and session_data.
45
+
46
+ Args:
47
+ session_id (str): Unique identifier for the session.
48
+ session_data (Dict): Data to store in the session.
49
+ """
50
+ self.sessions[session_id] = session_data
51
+ logger.info(f"Created AgentRun session: {session_id}")
52
+
53
+ def get_session(self, session_id: str) -> Optional[Dict]:
54
+ """Retrieve session data by session_id.
55
+
56
+ Args:
57
+ session_id (str): Unique identifier for the session.
58
+
59
+ Returns:
60
+ Optional[Dict]: Session data if found, None otherwise.
61
+ """
62
+ return self.sessions.get(session_id)
63
+
64
+ def update_session(self, session_id: str, updates: Dict):
65
+ """Update an existing session with new data.
66
+
67
+ Args:
68
+ session_id (str): Unique identifier for the session.
69
+ updates (Dict): Data to update in the session.
70
+ """
71
+ if session_id in self.sessions:
72
+ self.sessions[session_id].update(updates)
73
+ logger.debug(f"Updated AgentRun session: {session_id}")
74
+
75
+ def delete_session(self, session_id: str):
76
+ """Delete a session by session_id.
77
+
78
+ Args:
79
+ session_id (str): Unique identifier for the session.
80
+ """
81
+ if session_id in self.sessions:
82
+ del self.sessions[session_id]
83
+ logger.info(f"Deleted AgentRun session: {session_id}")
84
+
85
+ def list_sessions(self) -> List[str]:
86
+ """List all session IDs.
87
+
88
+ Returns:
89
+ List[str]: List of all session IDs.
90
+ """
91
+ return list(self.sessions.keys())
92
+
93
+
94
+ class AgentRunClient(BaseClient):
95
+ """
96
+ Client for managing AgentRun containers in the sandbox environment.
97
+
98
+ This client provides methods to create, start, stop, remove,
99
+ and inspect AgentRun sessions. It also handles the underlying AgentRun
100
+ API calls and status polling.
101
+ """
102
+
103
+ # Global attempts and interval for status polling
104
+ GET_AGENT_RUNTIME_STATUS_MAX_ATTEMPTS = 60
105
+ GET_AGENT_RUNTIME_STATUS_INTERVAL = 1
106
+
107
+ DEFAULT_ENDPOINT_NAME = "default-endpoint"
108
+
109
+ HTTPS_PROTOCOL = "https"
110
+
111
+ def __init__(self, config: SandboxManagerEnvConfig):
112
+ """Initialize the AgentRunClient with the provided configuration.
113
+
114
+ Args:
115
+ config (SandboxManagerEnvConfig): Configuration object
116
+ containing AgentRun settings.
117
+ """
118
+ self.config = config
119
+ self.client = self._create_agent_run_client()
120
+ self.session_manager = AgentRunSessionManager()
121
+ self.agent_run_prefix = config.agent_run_prefix or "agentscope-sandbox"
122
+ self._get_agent_runtime_status_max_attempts = (
123
+ self.GET_AGENT_RUNTIME_STATUS_MAX_ATTEMPTS
124
+ )
125
+ self._get_agent_runtime_status_interval = (
126
+ self.GET_AGENT_RUNTIME_STATUS_INTERVAL
127
+ )
128
+ logger.info(f"AgentRunClient initialized with config: {config}")
129
+
130
+ def create(
131
+ self,
132
+ image,
133
+ name=None,
134
+ ports=None,
135
+ volumes=None,
136
+ environment=None,
137
+ runtime_config=None,
138
+ ):
139
+ """Create a new AgentRun session with the specified parameters.
140
+
141
+ Args:
142
+ image (str): The container image to use for the AgentRun session.
143
+ name (str, optional): The name for the session. If not provided,
144
+ a random name will be generated.
145
+ ports (list, optional): List of ports to expose.
146
+ volumes (list, optional): List of volumes to mount.
147
+ environment (dict, optional): Environment variables to set in
148
+ the container.
149
+ runtime_config (dict, optional): Additional runtime configuration.
150
+
151
+ Returns:
152
+ tuple: A tuple containing (session_id, None, endpoint_public_url).
153
+
154
+ Raises:
155
+ Exception: If the AgentRun session creation fails.
156
+ """
157
+ logger.debug(f"Creating AgentRun session with image: {image}")
158
+ port = 80
159
+ if ports is not None and len(ports) > 0:
160
+ port = 80 if ports[0] == "80/tcp" else ports[0]
161
+
162
+ agent_run_image = self._replace_agent_runtime_images(image)
163
+
164
+ try:
165
+ session_id = name or self._generate_session_id()
166
+ logger.info(f"Created AgentRun session: {session_id}")
167
+ agent_runtime_name = f"{self.agent_run_prefix}-{session_id}"
168
+
169
+ # Prepare container configuration
170
+ container_config = ContainerConfiguration(
171
+ image=agent_run_image,
172
+ )
173
+
174
+ # Create agentRuntime
175
+
176
+ # Prepare network configuration if needed
177
+ if (
178
+ self.config.agent_run_vpc_id
179
+ and self.config.agent_run_security_group_id
180
+ and self.config.agent_run_vswitch_ids
181
+ ):
182
+ logger.info(
183
+ "Create agent runtime with PUBLIC_AND_PRIVATE network",
184
+ )
185
+ network_config = NetworkConfiguration(
186
+ network_mode="PUBLIC_AND_PRIVATE",
187
+ vpc_id=self.config.agent_run_vpc_id,
188
+ security_group_id=self.config.agent_run_security_group_id,
189
+ vswitch_ids=self.config.agent_run_vswitch_ids,
190
+ )
191
+ else:
192
+ logger.info("Create agent runtime with PUBLIC network")
193
+ network_config = NetworkConfiguration(
194
+ network_mode="PUBLIC",
195
+ )
196
+
197
+ # Prepare log configuration if needed
198
+ log_config = None
199
+ if (
200
+ self.config.agentrun_log_project
201
+ and self.config.agentrun_log_store
202
+ ):
203
+ log_config = LogConfiguration(
204
+ project=self.config.agentrun_log_project,
205
+ logstore=self.config.agentrun_log_store,
206
+ )
207
+
208
+ health_check_url = "/"
209
+ health_check_config = HealthCheckConfiguration(
210
+ http_get_url=health_check_url,
211
+ initial_delay_seconds=2,
212
+ period_seconds=1,
213
+ success_threshold=1,
214
+ failure_threshold=60,
215
+ timeout_seconds=1,
216
+ )
217
+
218
+ # Create the input object with all provided parameters
219
+ input_data = CreateAgentRuntimeInput(
220
+ agent_runtime_name=agent_runtime_name,
221
+ artifact_type="Container",
222
+ cpu=self.config.agent_run_cpu,
223
+ memory=self.config.agent_run_memory,
224
+ port=port,
225
+ container_configuration=container_config,
226
+ environment_variables=environment or {},
227
+ network_configuration=network_config,
228
+ log_configuration=log_config,
229
+ health_check_configuration=health_check_config,
230
+ description=f"agentScope sandbox deploy for"
231
+ f" {agent_runtime_name}",
232
+ )
233
+
234
+ # Create and check agent runtime
235
+ agent_runtime_id = self._create_and_check_agent_runtime(input_data)
236
+
237
+ # Create and check agent runtime endpoint
238
+ (
239
+ agent_runtime_endpoint_id,
240
+ endpoint_public_url,
241
+ ) = self._create_and_check_agent_runtime_endpoint(
242
+ agent_runtime_id,
243
+ agent_runtime_name,
244
+ )
245
+
246
+ # Store session information
247
+ session_data = {
248
+ "session_id": session_id,
249
+ "created_time": time.time(),
250
+ "agent_runtime_name": agent_runtime_name,
251
+ "agent_runtime_id": agent_runtime_id,
252
+ "agent_runtime_endpoint_id": agent_runtime_endpoint_id,
253
+ "endpoint_public_url": endpoint_public_url,
254
+ "status": "running",
255
+ "image": image,
256
+ "ports": ports,
257
+ "runtime_token": environment["SECRET_TOKEN"],
258
+ "environment": environment,
259
+ }
260
+
261
+ self.session_manager.create_session(session_id, session_data)
262
+ logger.info(
263
+ f"Success to create agent runtime with ID:"
264
+ f" {agent_runtime_id}, create session id: {session_id}",
265
+ )
266
+
267
+ logger.info(
268
+ f"endpoint_public_url: {endpoint_public_url}",
269
+ )
270
+
271
+ if not endpoint_public_url.endswith("/"):
272
+ endpoint_public_url = f"{endpoint_public_url}/"
273
+
274
+ parsed_url = urlparse(endpoint_public_url)
275
+
276
+ endpoint_public_url_domain = parsed_url.netloc
277
+ endpoint_public_url_path = parsed_url.path
278
+
279
+ # Agentrun should adapt for ip and port format
280
+ ports = [f"{HTTPS_PORT}{endpoint_public_url_path}"]
281
+
282
+ return (
283
+ session_id,
284
+ ports,
285
+ endpoint_public_url_domain,
286
+ self.HTTPS_PROTOCOL,
287
+ )
288
+
289
+ except Exception as e:
290
+ logger.error(f"Failed to create AgentRun session: {e}")
291
+ raise
292
+
293
+ def start(self, session_id):
294
+ """Start an AgentRun session by setting its status to running.
295
+
296
+ Args:
297
+ session_id (str): The ID of the session to start.
298
+
299
+ Returns:
300
+ bool: True if the session was successfully started,
301
+ False otherwise.
302
+ """
303
+ session = self.session_manager.get_session(session_id)
304
+ if not session:
305
+ logger.warning(f"AgentRun session id not found: {session_id}")
306
+ return False
307
+ agent_runtime_id = session["agent_runtime_id"]
308
+ try:
309
+ resp = self._get_agent_runtime_status(agent_runtime_id)
310
+ if resp.get("success"):
311
+ if resp.get("status") in ["READY"]:
312
+ self.session_manager.update_session(
313
+ session_id,
314
+ {"status": "running"},
315
+ )
316
+ logger.info(
317
+ f"set agentRun session status to running: {session_id}",
318
+ )
319
+ return True
320
+ except Exception as e:
321
+ logger.error(
322
+ f"failed to set agentRun session status to running:"
323
+ f" {session_id}: {e}",
324
+ )
325
+ return False
326
+
327
+ def stop(self, session_id, timeout=None):
328
+ """Stop an AgentRun session by setting its status to stopped.
329
+
330
+ Args:
331
+ session_id (str): The ID of the session to stop.
332
+ timeout (int, optional): Timeout for the stop operation (not
333
+ currently used).
334
+
335
+ Returns:
336
+ bool: True if the session was successfully stopped,
337
+ False otherwise.
338
+ """
339
+ session = self.session_manager.get_session(session_id)
340
+ if not session:
341
+ logger.warning(f"AgentRun session id not found: {session_id}")
342
+ return False
343
+
344
+ try:
345
+ self.session_manager.update_session(
346
+ session_id,
347
+ {"status": "stopped"},
348
+ )
349
+ logger.info(
350
+ f"set agentRun session status to stopped: {session_id}",
351
+ )
352
+ return True
353
+
354
+ except Exception as e:
355
+ logger.error(
356
+ f"failed to set agentRun session status to stopped:"
357
+ f" {session_id}: {e}",
358
+ )
359
+ return False
360
+
361
+ def remove(self, session_id, force=False):
362
+ """Remove an AgentRun session by deleting the underlying agent runtime.
363
+
364
+ Args:
365
+ session_id (str): The ID of the session to remove.
366
+ force (bool, optional): Whether to force removal (not currently
367
+ used).
368
+
369
+ Returns:
370
+ dict: A dictionary containing the result of the removal operation.
371
+ """
372
+ session = self.session_manager.get_session(session_id)
373
+ if not session:
374
+ logger.warning(f"AgentRun session id not found: {session_id}")
375
+ return False
376
+ agent_runtime_id = session["agent_runtime_id"]
377
+ try:
378
+ logger.info(f"Deleting agent runtime with ID: {agent_runtime_id}")
379
+
380
+ # Call the SDK method
381
+ response = self.client.delete_agent_runtime(agent_runtime_id)
382
+ # Check if the response is successful
383
+ if response.body and response.body.code == "SUCCESS":
384
+ logger.info(
385
+ f"Agent runtime deletion initiated successfully for ID:"
386
+ f" {agent_runtime_id}",
387
+ )
388
+
389
+ # Poll for status
390
+ status_result = None
391
+ status_reason = None
392
+ if agent_runtime_id:
393
+ logger.info(
394
+ f"Polling status for agent runtime deletion ID:"
395
+ f" {agent_runtime_id}",
396
+ )
397
+ poll_status = self._poll_agent_runtime_status(
398
+ agent_runtime_id,
399
+ )
400
+ if isinstance(poll_status, dict):
401
+ status_result = poll_status.get("status")
402
+ status_reason = poll_status.get("status_reason")
403
+ logger.info(
404
+ f"Agent runtime deletion status: {status_result}",
405
+ )
406
+
407
+ # Return a dictionary with relevant information from the
408
+ # response
409
+ return {
410
+ "success": True,
411
+ "message": "Agent runtime deletion initiated successfully",
412
+ "agent_runtime_id": agent_runtime_id,
413
+ "status": status_result,
414
+ "status_reason": status_reason,
415
+ "request_id": response.body.request_id,
416
+ }
417
+ else:
418
+ logger.error("Failed to delete agent runtime")
419
+ # Return error information if the request was not successful
420
+ return {
421
+ "success": False,
422
+ "code": response.body.code if response.body else None,
423
+ "message": "Failed to delete agent runtime",
424
+ "request_id": response.body.request_id
425
+ if response.body
426
+ else None,
427
+ }
428
+ except Exception as e:
429
+ logger.error(
430
+ f"Exception occurred while deleting agent runtime: {str(e)}",
431
+ )
432
+ # Return error information if an exception occurred
433
+ return {
434
+ "success": False,
435
+ "error": str(e),
436
+ "message": f"Exception occurred while deleting agent "
437
+ f"runtime: {str(e)}",
438
+ }
439
+
440
+ def inspect(self, session_id):
441
+ """Inspect an AgentRun session and return detailed information.
442
+
443
+ Args:
444
+ session_id (str): The ID of the session to inspect.
445
+
446
+ Returns:
447
+ dict: A dictionary containing session information,
448
+ agent runtime info, and status.
449
+ """
450
+ session = self.session_manager.get_session(session_id)
451
+ if not session:
452
+ logger.warning(f"AgentRun session id not found: {session_id}")
453
+ return False
454
+ agent_runtime_id = session["agent_runtime_id"]
455
+
456
+ # Get agent_runtime information
457
+ agent_runtime_info = {}
458
+ try:
459
+ if agent_runtime_id:
460
+ # Create the request object
461
+ request = GetAgentRuntimeRequest()
462
+
463
+ # Call the SDK method
464
+ response = self.client.get_agent_runtime(
465
+ agent_runtime_id,
466
+ request,
467
+ )
468
+
469
+ # Check if the response is successful
470
+ if (
471
+ response.body
472
+ and response.body.code == "SUCCESS"
473
+ and response.body.data
474
+ ):
475
+ # Extract relevant information from the agent runtime data
476
+ agent_runtime = response.body.data
477
+ agent_runtime_info = {
478
+ "agent_runtime_id": agent_runtime.agent_runtime_id,
479
+ "agent_runtime_name": agent_runtime.agent_runtime_name,
480
+ "agent_runtime_arn": agent_runtime.agent_runtime_arn,
481
+ "status": agent_runtime.status,
482
+ "status_reason": agent_runtime.status_reason,
483
+ "artifact_type": agent_runtime.artifact_type,
484
+ "cpu": agent_runtime.cpu,
485
+ "memory": agent_runtime.memory,
486
+ "port": agent_runtime.port,
487
+ "created_at": agent_runtime.created_at,
488
+ "last_updated_at": agent_runtime.last_updated_at,
489
+ "description": agent_runtime.description,
490
+ "agent_runtime_version": agent_runtime.agent_runtime_version, # noqa: E501
491
+ "environment_variables": agent_runtime.environment_variables, # noqa: E501
492
+ "request_id": response.body.request_id,
493
+ }
494
+ else:
495
+ logger.warning(
496
+ f"Failed to get agent runtime info for ID:"
497
+ f" {agent_runtime_id}",
498
+ )
499
+ agent_runtime_info = {
500
+ "error": "Failed to get agent runtime info",
501
+ "agent_runtime_id": agent_runtime_id,
502
+ "code": response.body.code if response.body else None,
503
+ "message": "Failed to get agent runtime info"
504
+ if response.body
505
+ else None,
506
+ }
507
+ except Exception as e:
508
+ logger.error(
509
+ f"Exception occurred while getting agent runtime info:"
510
+ f" {str(e)}",
511
+ )
512
+ agent_runtime_info = {
513
+ "error": str(e),
514
+ "message": f"Exception occurred while getting agent runtime "
515
+ f"info: {str(e)}",
516
+ "agent_runtime_id": agent_runtime_id,
517
+ }
518
+
519
+ return {
520
+ "session": session,
521
+ "agent_runtime_info": agent_runtime_info,
522
+ "runtime_token": session.get("runtime_token"),
523
+ "status": session.get("status", "unknown"),
524
+ "endpoint_url": session.get("endpoint_public_url"),
525
+ }
526
+
527
+ def get_status(self, session_id):
528
+ """Get the status of an AgentRun session.
529
+
530
+ Args:
531
+ session_id (str): The ID of the session to get status for.
532
+
533
+ Returns:
534
+ str: The status of the session (running, exited, starting,
535
+ or unknown).
536
+ """
537
+ session = self.session_manager.get_session(session_id)
538
+ if not session:
539
+ logger.warning(f"AgentRun session id not found: {session_id}")
540
+ return "unknown"
541
+ agent_runtime_id = session["agent_runtime_id"]
542
+ resp = self._get_agent_runtime_status(agent_runtime_id)
543
+ if resp.get("success"):
544
+ agent_run_status = resp.get("status")
545
+ if agent_run_status in ["READY", "ACTIVE"]:
546
+ return "running"
547
+ if agent_run_status in [
548
+ "CREATE_FAILED",
549
+ "UPDATE_FAILED",
550
+ "FAILED",
551
+ "DELETING",
552
+ ]:
553
+ return "exited"
554
+ if agent_run_status in ["CREATING", "UPDATING"]:
555
+ return "starting"
556
+ return session.get("status", "unknown")
557
+
558
+ def _create_agent_run_client(self) -> Client:
559
+ """Create and configure the AgentRun client.
560
+
561
+ Returns:
562
+ Client: Configured AgentRun client instance.
563
+ """
564
+ config = open_api_models.Config(
565
+ access_key_id=self.config.agent_run_access_key_id,
566
+ access_key_secret=self.config.agent_run_access_key_secret,
567
+ region_id=self.config.agent_run_region_id,
568
+ read_timeout=60 * 1000,
569
+ )
570
+ config.endpoint = (
571
+ f"agentrun.{self.config.agent_run_region_id}.aliyuncs.com"
572
+ )
573
+ return Client(config)
574
+
575
+ def _generate_session_id(self) -> str:
576
+ """Generate a random session ID.
577
+
578
+ Returns:
579
+ str: A random 6-character session ID.
580
+ """
581
+ return "".join(
582
+ random.choices(string.ascii_letters + string.digits, k=6),
583
+ )
584
+
585
+ def _create_and_check_agent_runtime(
586
+ self,
587
+ input_data: CreateAgentRuntimeInput,
588
+ ) -> str:
589
+ """Create an agent runtime and check its status until it's ready.
590
+
591
+ Args:
592
+ input_data (CreateAgentRuntimeInput): The input data for
593
+ creating the agent runtime.
594
+
595
+ Returns:
596
+ str: The agent runtime ID.
597
+
598
+ Raises:
599
+ Exception: If the agent runtime creation fails or the agent
600
+ runtime is not ready.
601
+ """
602
+ # Create the request object
603
+ agent_runtime_id = None
604
+ try:
605
+ create_agent_runtime_req = CreateAgentRuntimeRequest(
606
+ body=input_data,
607
+ )
608
+ create_agent_runtime_res = self.client.create_agent_runtime(
609
+ create_agent_runtime_req,
610
+ )
611
+
612
+ # Extract agent_runtime_id from response
613
+ if (
614
+ create_agent_runtime_res.body
615
+ and create_agent_runtime_res.body.data
616
+ ):
617
+ agent_runtime_id = (
618
+ create_agent_runtime_res.body.data.agent_runtime_id
619
+ )
620
+ except Exception as e:
621
+ logger.error(f"Failed to create agent runtime: {e}")
622
+ raise
623
+
624
+ # Poll and check agent runtime status
625
+ if agent_runtime_id:
626
+ status_response = self._poll_agent_runtime_status(agent_runtime_id)
627
+ if not status_response.get("success"):
628
+ logger.error(
629
+ f"Failed to get agent runtime status:"
630
+ f" {status_response.get('message')}",
631
+ )
632
+ raise RuntimeError(
633
+ f"Failed to get agent runtime status:"
634
+ f" {status_response.get('message')}",
635
+ )
636
+
637
+ if status_response.get("status") not in ["READY", "ACTIVE"]:
638
+ logger.error(
639
+ f"Agent runtime is not ready. Status:"
640
+ f" {status_response.get('status')}",
641
+ )
642
+ raise RuntimeError(
643
+ f"Agent runtime is not ready. Status:"
644
+ f" {status_response.get('status')}",
645
+ )
646
+
647
+ return agent_runtime_id
648
+
649
+ def _create_and_check_agent_runtime_endpoint(
650
+ self,
651
+ agent_runtime_id: str,
652
+ agent_runtime_name: str,
653
+ ) -> tuple:
654
+ """Create an agent runtime endpoint and check its status until it's
655
+ ready.
656
+
657
+ Args:
658
+ agent_runtime_id (str): The ID of the agent runtime.
659
+ agent_runtime_name (str): The name of the agent runtime.
660
+
661
+ Returns:
662
+ tuple: A tuple containing (agent_runtime_endpoint_id,
663
+ endpoint_public_url).
664
+
665
+ Raises:
666
+ Exception: If the agent runtime endpoint creation fails or the
667
+ endpoint is not ready.
668
+ """
669
+ # Create agent runtime endpoint
670
+ agent_runtime_endpoint_id = None
671
+ endpoint_public_url = None
672
+ if agent_runtime_id:
673
+ # Prepare endpoint configuration
674
+ endpoint_input = CreateAgentRuntimeEndpointInput(
675
+ agent_runtime_endpoint_name=self.DEFAULT_ENDPOINT_NAME,
676
+ target_version="LATEST",
677
+ description=f"agentScope deploy auto-generated endpoint for"
678
+ f" {agent_runtime_name}",
679
+ )
680
+
681
+ endpoint_request = CreateAgentRuntimeEndpointRequest(
682
+ body=endpoint_input,
683
+ )
684
+
685
+ try:
686
+ endpoint_response = self.client.create_agent_runtime_endpoint(
687
+ agent_runtime_id,
688
+ endpoint_request,
689
+ )
690
+ if endpoint_response.body and endpoint_response.body.data:
691
+ agent_runtime_endpoint_id = (
692
+ endpoint_response.body.data.agent_runtime_endpoint_id
693
+ )
694
+ endpoint_public_url = (
695
+ endpoint_response.body.data.endpoint_public_url
696
+ )
697
+ except Exception as e:
698
+ logger.error(f"Failed to create agent runtime endpoint: {e}")
699
+ raise
700
+
701
+ # Poll and check agent runtime endpoint status
702
+ if agent_runtime_id and agent_runtime_endpoint_id:
703
+ endpoint_status_response = (
704
+ self._poll_agent_runtime_endpoint_status(
705
+ agent_runtime_id,
706
+ agent_runtime_endpoint_id,
707
+ )
708
+ )
709
+ if not endpoint_status_response.get("success"):
710
+ logger.error(
711
+ f"Failed to get agent runtime endpoint status:"
712
+ f" {endpoint_status_response.get('message')}",
713
+ )
714
+ raise RuntimeError(
715
+ f"Failed to get agent runtime endpoint status:"
716
+ f" {endpoint_status_response.get('message')}",
717
+ )
718
+
719
+ if endpoint_status_response.get("status") not in [
720
+ "READY",
721
+ "ACTIVE",
722
+ ]:
723
+ logger.error(
724
+ f"Agent runtime endpoint is not ready. Status:"
725
+ f" {endpoint_status_response.get('status')}",
726
+ )
727
+ raise RuntimeError(
728
+ f"Agent runtime endpoint is not ready. Status:"
729
+ f" {endpoint_status_response.get('status')}",
730
+ )
731
+
732
+ return agent_runtime_endpoint_id, endpoint_public_url
733
+
734
+ def _poll_agent_runtime_endpoint_status(
735
+ self,
736
+ agent_runtime_id: str,
737
+ agent_runtime_endpoint_id: str,
738
+ ):
739
+ """
740
+ Poll agent runtime endpoint status until a terminal state is
741
+ reached or max attempts exceeded.
742
+
743
+ Args:
744
+ agent_runtime_id (str): The ID of the agent runtime.
745
+ agent_runtime_endpoint_id (str): The ID of the agent runtime
746
+ endpoint.
747
+
748
+ Returns:
749
+ Dict[str, Any]: A dictionary containing the final agent runtime
750
+ endpoint status or error information.
751
+ """
752
+ # Terminal states that indicate the end of polling for endpoints
753
+ terminal_states = {
754
+ "CREATE_FAILED",
755
+ "UPDATE_FAILED",
756
+ "READY",
757
+ "ACTIVE",
758
+ "FAILED",
759
+ "DELETING",
760
+ }
761
+
762
+ # Polling configuration
763
+ max_attempts = self._get_agent_runtime_status_max_attempts
764
+ interval_seconds = self._get_agent_runtime_status_interval
765
+
766
+ logger.info(
767
+ f"Starting to poll agent runtime endpoint status for ID:"
768
+ f" {agent_runtime_endpoint_id}",
769
+ )
770
+
771
+ for attempt in range(1, max_attempts + 1):
772
+ # Get current status
773
+ status_response = self._get_agent_runtime_endpoint_status(
774
+ agent_runtime_id,
775
+ agent_runtime_endpoint_id,
776
+ )
777
+
778
+ # Check if the request was successful
779
+ if not status_response.get("success"):
780
+ logger.warning(
781
+ f"Attempt {attempt}/{max_attempts}: Failed "
782
+ f"to get status - {status_response.get('message')}",
783
+ )
784
+ # Wait before next attempt unless this is the last attempt
785
+ if attempt < max_attempts:
786
+ time.sleep(interval_seconds)
787
+ continue
788
+
789
+ # Extract status information
790
+ current_status = status_response.get("status")
791
+ status_reason = status_response.get("status_reason")
792
+
793
+ # Log current status
794
+ logger.info(
795
+ f"Attempt {attempt}/{max_attempts}: Status = {current_status}",
796
+ )
797
+ if status_reason:
798
+ logger.info(f" Status reason: {status_reason}")
799
+
800
+ # Check if we've reached a terminal state
801
+ if current_status in terminal_states:
802
+ logger.info(
803
+ f"Reached terminal state '{current_status}' after"
804
+ f" {attempt} attempts",
805
+ )
806
+ return status_response
807
+
808
+ # Wait before next attempt unless this is the last attempt
809
+ if attempt < max_attempts:
810
+ time.sleep(interval_seconds)
811
+
812
+ # If we've exhausted all attempts without reaching a terminal state
813
+ logger.warning(
814
+ f"Exceeded maximum attempts ({max_attempts}) without reaching a "
815
+ f"terminal state",
816
+ )
817
+ return self._get_agent_runtime_endpoint_status(
818
+ agent_runtime_id,
819
+ agent_runtime_endpoint_id,
820
+ )
821
+
822
+ def _get_agent_runtime_status(
823
+ self,
824
+ agent_runtime_id: str,
825
+ agent_runtime_version: str = None,
826
+ ):
827
+ """Get agent runtime status.
828
+
829
+ Args:
830
+ agent_runtime_id (str): The ID of the agent runtime.
831
+ agent_runtime_version (str, optional): The version of the agent
832
+ runtime.
833
+
834
+ Returns:
835
+ Dict[str, Any]: A dictionary containing the agent runtime
836
+ status or error information.
837
+ """
838
+ try:
839
+ logger.debug(
840
+ f"Getting agent runtime status for ID: {agent_runtime_id}",
841
+ )
842
+
843
+ # Create the request object
844
+ request = GetAgentRuntimeRequest(
845
+ agent_runtime_version=agent_runtime_version,
846
+ )
847
+
848
+ # Call the SDK method
849
+ response = self.client.get_agent_runtime(agent_runtime_id, request)
850
+
851
+ # Check if the response is successful
852
+ if (
853
+ response.body
854
+ and response.body.code == "SUCCESS"
855
+ and response.body.data
856
+ ):
857
+ status = (
858
+ response.body.data.status
859
+ if hasattr(response.body.data, "status")
860
+ else None
861
+ )
862
+ logger.debug(
863
+ f"Agent runtime status for ID {agent_runtime_id}:"
864
+ f" {status}",
865
+ )
866
+ # Return the status from the agent runtime data
867
+ return {
868
+ "success": True,
869
+ "status": status,
870
+ "status_reason": response.body.data.status_reason
871
+ if hasattr(
872
+ response.body.data,
873
+ "status_reason",
874
+ )
875
+ else None,
876
+ "request_id": response.body.request_id,
877
+ }
878
+ else:
879
+ logger.error("Failed to get agent runtime status")
880
+ # Return error information if the request was not successful
881
+ return {
882
+ "success": False,
883
+ "code": response.body.code if response.body else None,
884
+ "message": "Failed to get agent runtime status",
885
+ "request_id": response.body.request_id
886
+ if response.body
887
+ else None,
888
+ }
889
+ except Exception as e:
890
+ logger.error(
891
+ f"Exception occurred while getting agent runtime status:"
892
+ f" {str(e)}",
893
+ )
894
+ # Return error information if an exception occurred
895
+ return {
896
+ "success": False,
897
+ "error": str(e),
898
+ "message": f"Exception occurred while getting agent runtime "
899
+ f"status: {str(e)}",
900
+ }
901
+
902
+ def _get_agent_runtime_endpoint_status(
903
+ self,
904
+ agent_runtime_id: str,
905
+ agent_runtime_endpoint_id: str,
906
+ ):
907
+ """Get agent runtime endpoint status.
908
+
909
+ Args:
910
+ agent_runtime_id (str): The ID of the agent runtime.
911
+ agent_runtime_endpoint_id (str): The ID of the agent runtime
912
+ endpoint.
913
+
914
+ Returns:
915
+ Dict[str, str]: A dictionary containing the agent runtime
916
+ endpoint status or error information.
917
+ """
918
+ try:
919
+ logger.debug(
920
+ f"Getting agent runtime endpoint status for ID:"
921
+ f" {agent_runtime_endpoint_id}",
922
+ )
923
+
924
+ # Call the SDK method
925
+ response = self.client.get_agent_runtime_endpoint(
926
+ agent_runtime_id,
927
+ agent_runtime_endpoint_id,
928
+ )
929
+
930
+ # Check if the response is successful
931
+ if (
932
+ response.body
933
+ and response.body.code == "SUCCESS"
934
+ and response.body.data
935
+ ):
936
+ status = (
937
+ response.body.data.status
938
+ if hasattr(response.body.data, "status")
939
+ else None
940
+ )
941
+ logger.debug(
942
+ f"Agent runtime endpoint status for ID"
943
+ f" {agent_runtime_endpoint_id}: {status}",
944
+ )
945
+ # Return the status from the agent runtime endpoint data
946
+ return {
947
+ "success": True,
948
+ "status": status,
949
+ "status_reason": response.body.data.status_reason
950
+ if hasattr(
951
+ response.body.data,
952
+ "status_reason",
953
+ )
954
+ else None,
955
+ "request_id": response.body.request_id,
956
+ }
957
+ else:
958
+ logger.debug("Failed to get agent runtime endpoint status")
959
+ # Return error information if the request was not successful
960
+ return {
961
+ "success": False,
962
+ "code": response.body.code if response.body else None,
963
+ "message": "Failed to get agent runtime endpoint status",
964
+ "request_id": response.body.request_id
965
+ if response.body
966
+ else None,
967
+ }
968
+ except Exception as e:
969
+ logger.debug(
970
+ f"Exception occurred while getting agent runtime endpoint "
971
+ f"status: {str(e)}",
972
+ )
973
+ # Return error information if an exception occurred
974
+ return {
975
+ "success": False,
976
+ "error": str(e),
977
+ "message": f"Exception occurred while getting agent runtime "
978
+ f"endpoint status: {str(e)}",
979
+ }
980
+
981
+ def _poll_agent_runtime_status(
982
+ self,
983
+ agent_runtime_id: str,
984
+ agent_runtime_version: str = None,
985
+ ):
986
+ """
987
+ Poll agent runtime status until a terminal state is reached or
988
+ max attempts exceeded.
989
+
990
+ Args:
991
+ agent_runtime_id (str): The ID of the agent runtime.
992
+ agent_runtime_version (str, optional): The version of the agent
993
+ runtime.
994
+
995
+ Returns:
996
+ Dict[str, Any]: A dictionary containing the final agent runtime
997
+ status or error information.
998
+ """
999
+ # Terminal states that indicate the end of polling for agent runtimes
1000
+ terminal_states = {
1001
+ "CREATE_FAILED",
1002
+ "UPDATE_FAILED",
1003
+ "READY",
1004
+ "ACTIVE",
1005
+ "FAILED",
1006
+ "DELETING",
1007
+ }
1008
+
1009
+ # Polling configuration
1010
+ max_attempts = self._get_agent_runtime_status_max_attempts
1011
+ interval_seconds = self._get_agent_runtime_status_interval
1012
+
1013
+ logger.info(
1014
+ f"Starting to poll agent runtime status for ID:"
1015
+ f" {agent_runtime_id}",
1016
+ )
1017
+
1018
+ for attempt in range(1, max_attempts + 1):
1019
+ # Get current status
1020
+ status_response = self._get_agent_runtime_status(
1021
+ agent_runtime_id,
1022
+ agent_runtime_version,
1023
+ )
1024
+
1025
+ # Check if the request was successful
1026
+ if not status_response.get("success"):
1027
+ logger.warning(
1028
+ f"Attempt {attempt}/{max_attempts}: Failed to "
1029
+ f"get status - {status_response.get('message')}",
1030
+ )
1031
+ # Wait before next attempt unless this is the last attempt
1032
+ if attempt < max_attempts:
1033
+ time.sleep(interval_seconds)
1034
+ continue
1035
+
1036
+ # Extract status information
1037
+ current_status = status_response.get("status")
1038
+ status_reason = status_response.get("status_reason")
1039
+
1040
+ # Log current status
1041
+ logger.info(
1042
+ f"Attempt {attempt}/{max_attempts}: Status = {current_status}",
1043
+ )
1044
+ if status_reason:
1045
+ logger.info(f" Status reason: {status_reason}")
1046
+
1047
+ # Check if we've reached a terminal state
1048
+ if current_status in terminal_states:
1049
+ logger.info(
1050
+ f"Reached terminal state '{current_status}' after"
1051
+ f" {attempt} attempts",
1052
+ )
1053
+ return status_response
1054
+
1055
+ # Wait before next attempt unless this is the last attempt
1056
+ if attempt < max_attempts:
1057
+ time.sleep(interval_seconds)
1058
+
1059
+ # If we've exhausted all attempts without reaching a terminal state
1060
+ logger.warning(
1061
+ f"Exceeded maximum attempts ({max_attempts}) without reaching a "
1062
+ f"terminal state",
1063
+ )
1064
+ return self._get_agent_runtime_status(
1065
+ agent_runtime_id,
1066
+ agent_runtime_version,
1067
+ )
1068
+
1069
+ def _replace_agent_runtime_images(self, image: str) -> str:
1070
+ """
1071
+ Replace agent runtime images with their corresponding remote images.
1072
+
1073
+ Args:
1074
+ image (str): The original image name.
1075
+
1076
+ Returns:
1077
+ str: The replaced image name with remote registry path.
1078
+ """
1079
+ replacement_map = {
1080
+ "agentscope/runtime-sandbox-base": "serverless-registry.cn-hangzhou.cr.aliyuncs.com/functionai" # noqa: E501
1081
+ "/agentscope_runtime-sandbox-base:20251027",
1082
+ "agentscope/runtime-sandbox-browser": "serverless-registry.cn-hangzhou.cr.aliyuncs.com/functionai" # noqa: E501
1083
+ "/agentscope_runtime-sandbox-browser:20251027",
1084
+ "agentscope/runtime-sandbox-filesystem": "serverless-registry.cn-hangzhou.cr.aliyuncs.com/functionai" # noqa: E501
1085
+ "/agentscope_runtime-sandbox-filesystem:20251027",
1086
+ "agentscope/runtime-sandbox-gui": "serverless-registry.cn-hangzhou.cr.aliyuncs.com/functionai" # noqa: E501
1087
+ "/agentscope_runtime-sandbox-gui:20251027",
1088
+ }
1089
+
1090
+ if ":" in image:
1091
+ image_name, _ = image.split(":", 1)
1092
+ else:
1093
+ image_name = image
1094
+
1095
+ return replacement_map.get(image_name.strip(), image)
1096
+
1097
+ def _is_browser_image(self, image: str):
1098
+ return image.startswith("agentscope/runtime-sandbox-browser")