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
@@ -5,7 +5,7 @@ import platform
5
5
  from typing import Optional, List, Union
6
6
  from urllib.parse import urlencode, urljoin
7
7
 
8
- from ..sandbox import Sandbox, SandboxAsync
8
+ from agentscope_runtime.sandbox.box.sandbox import Sandbox
9
9
 
10
10
  from ...utils import build_image_uri
11
11
  from ...registry import SandboxRegistry
@@ -15,107 +15,6 @@ from ...constant import TIMEOUT
15
15
  logger = logging.getLogger(__name__)
16
16
 
17
17
 
18
- class HostPrerequisiteError(Exception):
19
- """Exception raised when host prerequisites
20
- for MobileSandbox are not met."""
21
-
22
-
23
- def _check_host_readiness() -> None:
24
- logger.info(
25
- "Performing one-time host environment check for MobileSandbox...",
26
- )
27
-
28
- architecture = platform.machine().lower()
29
- if architecture in ("aarch64", "arm64"):
30
- logger.warning(
31
- "\n======================== WARNING ========================\n"
32
- "ARM64/aarch64 architecture detected (e.g., Apple M-series).\n"
33
- "Running this mobile sandbox on a non-x86_64 host may lead \n"
34
- " to unexpected compatibility or performance issues.\n"
35
- "=========================================================",
36
- )
37
-
38
- os_type = platform.system()
39
- if os_type == "Linux":
40
- try:
41
- result = subprocess.run(
42
- ["lsmod"],
43
- capture_output=True,
44
- text=True,
45
- check=True,
46
- )
47
- loaded_modules = result.stdout
48
- except (FileNotFoundError, subprocess.CalledProcessError):
49
- loaded_modules = ""
50
- logger.warning(
51
- "Could not execute 'lsmod' to verify kernel modules.",
52
- )
53
-
54
- if "binder_linux" not in loaded_modules:
55
- error_message = (
56
- "\n========== HOST PREREQUISITE FAILED ==========\n"
57
- "MobileSandbox requires specific kernel modules"
58
- " that appear to be missing or not loaded.\n\n"
59
- "To fix this, please run the following commands"
60
- " on your Linux host:\n\n"
61
- "## Install required kernel modules\n"
62
- "sudo apt update"
63
- " && sudo apt install -y linux-modules-extra-`uname -r`\n"
64
- "sudo modprobe binder_linux"
65
- ' devices="binder,hwbinder,vndbinder"\n'
66
- "## (Optional) Load the ashmem driver for older kernels\n"
67
- "sudo modprobe ashmem_linux\n"
68
- "=================================================="
69
- )
70
- raise HostPrerequisiteError(error_message)
71
-
72
- if os_type == "Windows":
73
- try:
74
- result = subprocess.run(
75
- ["wsl", "lsmod"],
76
- capture_output=True,
77
- text=True,
78
- check=True,
79
- encoding="utf-8",
80
- )
81
- loaded_modules = result.stdout
82
- except (FileNotFoundError, subprocess.CalledProcessError):
83
- loaded_modules = ""
84
- logger.warning(
85
- "Could not execute 'wsl lsmod' to verify kernel modules.",
86
- )
87
-
88
- if "binder_linux" not in loaded_modules:
89
- error_message = (
90
- "\n========== HOST PREREQUISITE FAILED ==========\n"
91
- "MobileSandbox on Windows requires Docker Desktop "
92
- "with the WSL 2 backend.\n"
93
- "The required kernel modules seem to be missing "
94
- "in your WSL 2 environment.\n\n"
95
- "To fix this, please follow these steps:\n\n"
96
- "1. **Ensure Docker Desktop is using WSL 2**:\n"
97
- " - Open Docker Desktop -> Settings -> General.\n"
98
- " - Make sure 'Use the WSL 2 based engine' "
99
- "is checked.\n\n"
100
- "2. **Ensure WSL is installed and updated**:\n"
101
- " - Open PowerShell or Command Prompt "
102
- "as Administrator.\n"
103
- " - Run: wsl --install\n"
104
- " - Run: wsl --update\n"
105
- " (An update usually installs a recent Linux kernel "
106
- "with the required modules.)\n\n"
107
- "3. **Verify manually (Optional)**:\n"
108
- " - After updating, run 'wsl lsmod | findstr binder' "
109
- "in your terminal.\n"
110
- " - If it shows 'binder_linux', "
111
- "the issue should be resolved.\n"
112
- "=================================================="
113
- )
114
- raise HostPrerequisiteError(error_message)
115
-
116
- logger.info("Host environment check passed.")
117
-
118
-
119
18
  class MobileMixin:
120
19
  @property
121
20
  def mobile_url(self):
@@ -142,41 +41,9 @@ class MobileMixin:
142
41
  )
143
42
 
144
43
 
145
- class AsyncMobileMixin:
146
- async def get_mobile_url_async(self):
147
- """
148
- Asynchronously retrieve the mobile VNC/websockify connection URL.
149
-
150
- Returns:
151
- str: Fully qualified URL to access the mobile sandbox UI remotely.
152
-
153
- Raises:
154
- RuntimeError: If the sandbox is not healthy.
155
- """
156
- # Check health asynchronously
157
- is_healthy = await self.manager_api.check_health_async(
158
- identity=self.sandbox_id,
159
- )
160
- if not is_healthy:
161
- raise RuntimeError(f"Sandbox {self.sandbox_id} is not healthy")
162
-
163
- # Get container info asynchronously
164
- info = await self.get_info_async()
165
-
166
- # Local path and remote path (currently the same)
167
- path = "/websockify/"
168
- remote_path = "/websockify/"
169
- params = {"password": info["runtime_token"]}
170
-
171
- # Local URL if base_url is not set
172
- if self.base_url is None:
173
- return urljoin(info["url"], path) + "?" + urlencode(params)
174
-
175
- # Remote URL
176
- return (
177
- f"{self.base_url}/desktop/{self.sandbox_id}{remote_path}"
178
- f"?{urlencode(params)}"
179
- )
44
+ class HostPrerequisiteError(Exception):
45
+ """Exception raised when host prerequisites
46
+ for MobileSandbox are not met."""
180
47
 
181
48
 
182
49
  @SandboxRegistry.register(
@@ -199,7 +66,7 @@ class MobileSandbox(MobileMixin, Sandbox):
199
66
  sandbox_type: SandboxType = SandboxType.MOBILE,
200
67
  ):
201
68
  if base_url is None and not self.__class__._host_check_done:
202
- _check_host_readiness()
69
+ self._check_host_readiness()
203
70
  self.__class__._host_check_done = True
204
71
 
205
72
  super().__init__(
@@ -210,6 +77,101 @@ class MobileSandbox(MobileMixin, Sandbox):
210
77
  sandbox_type,
211
78
  )
212
79
 
80
+ def _check_host_readiness(self) -> None:
81
+ logger.info(
82
+ "Performing one-time host environment check for MobileSandbox...",
83
+ )
84
+
85
+ architecture = platform.machine().lower()
86
+ if architecture in ("aarch64", "arm64"):
87
+ logger.warning(
88
+ "\n======================== WARNING ========================\n"
89
+ "ARM64/aarch64 architecture detected (e.g., Apple M-series).\n"
90
+ "Running this mobile sandbox on a non-x86_64 host may lead \n"
91
+ " to unexpected compatibility or performance issues.\n"
92
+ "=========================================================",
93
+ )
94
+
95
+ os_type = platform.system()
96
+ if os_type == "Linux":
97
+ try:
98
+ result = subprocess.run(
99
+ ["lsmod"],
100
+ capture_output=True,
101
+ text=True,
102
+ check=True,
103
+ )
104
+ loaded_modules = result.stdout
105
+ except (FileNotFoundError, subprocess.CalledProcessError):
106
+ loaded_modules = ""
107
+ logger.warning(
108
+ "Could not execute 'lsmod' to verify kernel modules.",
109
+ )
110
+
111
+ if "binder_linux" not in loaded_modules:
112
+ error_message = (
113
+ "\n========== HOST PREREQUISITE FAILED ==========\n"
114
+ "MobileSandbox requires specific kernel modules"
115
+ " that appear to be missing or not loaded.\n\n"
116
+ "To fix this, please run the following commands"
117
+ " on your Linux host:\n\n"
118
+ "## Install required kernel modules\n"
119
+ "sudo apt update"
120
+ " && sudo apt install -y linux-modules-extra-`uname -r`\n"
121
+ "sudo modprobe binder_linux"
122
+ ' devices="binder,hwbinder,vndbinder"\n'
123
+ "## (Optional) Load the ashmem driver for older kernels\n"
124
+ "sudo modprobe ashmem_linux\n"
125
+ "=================================================="
126
+ )
127
+ raise HostPrerequisiteError(error_message)
128
+
129
+ if os_type == "Windows":
130
+ try:
131
+ result = subprocess.run(
132
+ ["wsl", "lsmod"],
133
+ capture_output=True,
134
+ text=True,
135
+ check=True,
136
+ encoding="utf-8",
137
+ )
138
+ loaded_modules = result.stdout
139
+ except (FileNotFoundError, subprocess.CalledProcessError):
140
+ loaded_modules = ""
141
+ logger.warning(
142
+ "Could not execute 'wsl lsmod' to verify kernel modules.",
143
+ )
144
+
145
+ if "binder_linux" not in loaded_modules:
146
+ error_message = (
147
+ "\n========== HOST PREREQUISITE FAILED ==========\n"
148
+ "MobileSandbox on Windows requires Docker Desktop "
149
+ "with the WSL 2 backend.\n"
150
+ "The required kernel modules seem to be missing "
151
+ "in your WSL 2 environment.\n\n"
152
+ "To fix this, please follow these steps:\n\n"
153
+ "1. **Ensure Docker Desktop is using WSL 2**:\n"
154
+ " - Open Docker Desktop -> Settings -> General.\n"
155
+ " - Make sure 'Use the WSL 2 based engine' "
156
+ "is checked.\n\n"
157
+ "2. **Ensure WSL is installed and updated**:\n"
158
+ " - Open PowerShell or Command Prompt "
159
+ "as Administrator.\n"
160
+ " - Run: wsl --install\n"
161
+ " - Run: wsl --update\n"
162
+ " (An update usually installs a recent Linux kernel "
163
+ "with the required modules.)\n\n"
164
+ "3. **Verify manually (Optional)**:\n"
165
+ " - After updating, run 'wsl lsmod | findstr binder' "
166
+ "in your terminal.\n"
167
+ " - If it shows 'binder_linux', "
168
+ "the issue should be resolved.\n"
169
+ "=================================================="
170
+ )
171
+ raise HostPrerequisiteError(error_message)
172
+
173
+ logger.info("Host environment check passed.")
174
+
213
175
  def adb_use(
214
176
  self,
215
177
  action: str,
@@ -326,112 +288,3 @@ class MobileSandbox(MobileMixin, Sandbox):
326
288
  def mobile_get_screenshot(self):
327
289
  """Take a screenshot of the current device screen."""
328
290
  return self.call_tool("adb", {"action": "get_screenshot"})
329
-
330
-
331
- @SandboxRegistry.register(
332
- build_image_uri("runtime-sandbox-mobile"),
333
- sandbox_type=SandboxType.MOBILE_ASYNC,
334
- security_level="high",
335
- timeout=TIMEOUT,
336
- description="Mobile Sandbox (Async)",
337
- runtime_config={"privileged": True},
338
- )
339
- class MobileSandboxAsync(MobileMixin, AsyncMobileMixin, SandboxAsync):
340
- _host_check_done = False
341
-
342
- def __init__(
343
- self,
344
- sandbox_id: Optional[str] = None,
345
- timeout: int = 3000,
346
- base_url: Optional[str] = None,
347
- bearer_token: Optional[str] = None,
348
- sandbox_type: SandboxType = SandboxType.MOBILE_ASYNC,
349
- ):
350
- if base_url is None and not self.__class__._host_check_done:
351
- _check_host_readiness()
352
- self.__class__._host_check_done = True
353
-
354
- super().__init__(
355
- sandbox_id,
356
- timeout,
357
- base_url,
358
- bearer_token,
359
- sandbox_type,
360
- )
361
-
362
- async def adb_use(
363
- self,
364
- action: str,
365
- coordinate: Optional[List[int]] = None,
366
- start: Optional[List[int]] = None,
367
- end: Optional[List[int]] = None,
368
- duration: Optional[int] = None,
369
- code: Optional[Union[int, str]] = None,
370
- text: Optional[str] = None,
371
- ):
372
- """
373
- Asynchronously execute a general-purpose ADB action.
374
- """
375
- payload = {"action": action}
376
- if coordinate is not None:
377
- payload["coordinate"] = coordinate
378
- if start is not None:
379
- payload["start"] = start
380
- if end is not None:
381
- payload["end"] = end
382
- if duration is not None:
383
- payload["duration"] = duration
384
- if code is not None:
385
- payload["code"] = code
386
- if text is not None:
387
- payload["text"] = text
388
-
389
- return await self.call_tool_async("adb", payload)
390
-
391
- async def mobile_get_screen_resolution(self):
392
- """Asynchronously get the screen resolution."""
393
- return await self.call_tool_async(
394
- "adb",
395
- {"action": "get_screen_resolution"},
396
- )
397
-
398
- async def mobile_tap(self, coordinate: List[int]):
399
- """Asynchronously tap specific screen coordinates."""
400
- return await self.call_tool_async(
401
- "adb",
402
- {"action": "tap", "coordinate": coordinate},
403
- )
404
-
405
- async def mobile_swipe(
406
- self,
407
- start: List[int],
408
- end: List[int],
409
- duration: Optional[int] = None,
410
- ):
411
- """Asynchronously perform a swipe gesture."""
412
- payload = {
413
- "action": "swipe",
414
- "start": start,
415
- "end": end,
416
- }
417
- if duration is not None:
418
- payload["duration"] = duration
419
- return await self.call_tool_async("adb", payload)
420
-
421
- async def mobile_input_text(self, text: str):
422
- """Asynchronously input text into the focused UI element."""
423
- return await self.call_tool_async(
424
- "adb",
425
- {"action": "input_text", "text": text},
426
- )
427
-
428
- async def mobile_key_event(self, code: Union[int, str]):
429
- """Asynchronously send a key event to the device."""
430
- return await self.call_tool_async(
431
- "adb",
432
- {"action": "key_event", "code": code},
433
- )
434
-
435
- async def mobile_get_screenshot(self):
436
- """Asynchronously take a screenshot."""
437
- return await self.call_tool_async("adb", {"action": "get_screenshot"})
@@ -12,46 +12,71 @@ logging.basicConfig(level=logging.INFO)
12
12
  logger = logging.getLogger(__name__)
13
13
 
14
14
 
15
- class SandboxBase:
15
+ class Sandbox:
16
16
  """
17
- Common base class for both sync and async Sandbox interfaces.
17
+ Sandbox Interface.
18
18
  """
19
19
 
20
20
  def __init__(
21
21
  self,
22
22
  sandbox_id: Optional[str] = None,
23
- timeout: int = 3000,
23
+ timeout: int = 3000, # TODO: enable life circle management
24
24
  base_url: Optional[str] = None,
25
- bearer_token: Optional[str] = None,
25
+ bearer_token: Optional[str] = None, # TODO: support api_key
26
26
  sandbox_type: SandboxType = SandboxType.BASE,
27
27
  ) -> None:
28
+ """
29
+ Initialize the sandbox interface.
30
+ """
28
31
  self.base_url = base_url
29
- self.embed_mode = not bool(base_url)
30
- self.sandbox_type = sandbox_type
31
- self.timeout = timeout
32
- self._sandbox_id = sandbox_id
33
-
34
32
  if base_url:
33
+ self.embed_mode = False
35
34
  self.manager_api = SandboxManager(
36
35
  base_url=base_url,
37
36
  bearer_token=bearer_token,
38
- )
37
+ ).__enter__()
39
38
  else:
39
+ # Launch a local manager
40
+ self.embed_mode = True
40
41
  self.manager_api = SandboxManager(
41
42
  default_type=sandbox_type,
42
43
  )
43
44
 
44
- @property
45
- def sandbox_id(self) -> Optional[str]:
46
- return self._sandbox_id
45
+ if sandbox_id is None:
46
+ logger.debug(
47
+ "You are using embed mode, it might take several seconds to "
48
+ "init the runtime, please wait.",
49
+ )
47
50
 
48
- @sandbox_id.setter
49
- def sandbox_id(self, value: str) -> None:
50
- if not value:
51
- raise ValueError("Sandbox ID cannot be empty.")
52
- self._sandbox_id = value
51
+ sandbox_id = self.manager_api.create_from_pool(
52
+ sandbox_type=SandboxType(sandbox_type).value,
53
+ )
54
+ if sandbox_id is None:
55
+ raise RuntimeError(
56
+ "No sandbox available. "
57
+ "Please check if sandbox images exist, build or pull "
58
+ "missing images in sandbox server.",
59
+ )
60
+ self._sandbox_id = sandbox_id
61
+
62
+ self._sandbox_id = sandbox_id
63
+ self.sandbox_type = sandbox_type
64
+ self.timeout = timeout
65
+
66
+ # Clean up function enabled in embed mode
67
+ if self.embed_mode:
68
+ atexit.register(self._cleanup)
69
+ self._register_signal_handlers()
70
+
71
+ def _register_signal_handlers(self) -> None:
72
+ """
73
+ Register signal handlers for graceful shutdown and cleanup.
74
+ Handles SIGINT (Ctrl+C) and, if available, SIGTERM to ensure that
75
+ the sandbox is properly cleaned up when the process receives these
76
+ signals. On platforms where SIGTERM is not available (e.g.,
77
+ Windows), only SIGINT is handled.
78
+ """
53
79
 
54
- def _register_signal_handlers(self):
55
80
  def _handler(signum, frame): # pylint: disable=unused-argument
56
81
  logger.debug(
57
82
  f"Received signal {signum}, stopping Sandbox"
@@ -60,6 +85,7 @@ class SandboxBase:
60
85
  self._cleanup()
61
86
  raise SystemExit(0)
62
87
 
88
+ # Windows does not support SIGTERM
63
89
  if hasattr(signal, "SIGTERM"):
64
90
  signals = [signal.SIGINT, signal.SIGTERM]
65
91
  else:
@@ -81,36 +107,39 @@ class SandboxBase:
81
107
  specific sandbox instance.
82
108
  """
83
109
  try:
110
+ # Remote not need to close the embed_manager
84
111
  if self.embed_mode:
112
+ # Clean all
85
113
  self.manager_api.__exit__(None, None, None)
86
114
  else:
115
+ # Clean the specific sandbox
87
116
  self.manager_api.release(self.sandbox_id)
88
117
  except Exception as e:
89
118
  import traceback
90
119
 
91
120
  logger.error(
92
- f"Cleanup {self.sandbox_id} error: {e}"
93
- f"\n{traceback.format_exc()}",
121
+ f"Cleanup {self.sandbox_id} error: {e}\n"
122
+ f"{traceback.format_exc()}",
94
123
  )
95
124
 
96
-
97
- class Sandbox(SandboxBase):
98
125
  def __enter__(self):
99
- # Create sandbox if sandbox_id not provided
100
- if self.sandbox_id is None:
101
- self.sandbox_id = self.manager_api.create_from_pool(
102
- sandbox_type=SandboxType(self.sandbox_type).value,
103
- )
104
- if self.sandbox_id is None:
105
- raise RuntimeError("No sandbox available.")
106
- if self.embed_mode:
107
- atexit.register(self._cleanup)
108
- self._register_signal_handlers()
109
126
  return self
110
127
 
111
128
  def __exit__(self, exc_type, exc_value, traceback):
112
129
  self._cleanup()
113
130
 
131
+ @property
132
+ def sandbox_id(self) -> str:
133
+ """Get the sandbox ID."""
134
+ return self._sandbox_id
135
+
136
+ @sandbox_id.setter
137
+ def sandbox_id(self, value: str) -> None:
138
+ """Set the sandbox ID."""
139
+ if not value:
140
+ raise ValueError("Sandbox ID cannot be empty.")
141
+ self._sandbox_id = value
142
+
114
143
  def get_info(self) -> dict:
115
144
  return self.manager_api.get_info(self.sandbox_id)
116
145
 
@@ -127,77 +156,15 @@ class Sandbox(SandboxBase):
127
156
  ) -> Any:
128
157
  if arguments is None:
129
158
  arguments = {}
130
- return self.manager_api.call_tool(self.sandbox_id, name, arguments)
131
159
 
132
- def add_mcp_servers(self, server_configs: dict, overwrite=False):
133
- return self.manager_api.add_mcp_servers(
134
- self.sandbox_id,
135
- server_configs,
136
- overwrite,
137
- )
138
-
139
-
140
- class SandboxAsync(SandboxBase):
141
- async def __aenter__(self):
142
- if self.sandbox_id is None:
143
- self.sandbox_id = await self.manager_api.create_from_pool_async(
144
- sandbox_type=SandboxType(self.sandbox_type).value,
145
- )
146
- if self.sandbox_id is None:
147
- raise RuntimeError("No sandbox available.")
148
- if self.embed_mode:
149
- atexit.register(self._cleanup)
150
- self._register_signal_handlers()
151
- return self
152
-
153
- async def __aexit__(self, exc_type, exc_value, traceback):
154
- await self._cleanup_async()
155
-
156
- async def _cleanup_async(self):
157
- try:
158
- if self.embed_mode:
159
- await self.manager_api.__aexit__(None, None, None)
160
- else:
161
- await self.manager_api.release_async(self.sandbox_id)
162
- except Exception as e:
163
- import traceback
164
-
165
- logger.error(
166
- f"Async Cleanup {self.sandbox_id} error: {e}"
167
- f"\n{traceback.format_exc()}",
168
- )
169
-
170
- async def get_info_async(self) -> dict:
171
- return await self.manager_api.get_info_async(self.sandbox_id)
172
-
173
- async def list_tools_async(
174
- self,
175
- tool_type: Optional[str] = None,
176
- ) -> dict:
177
- return await self.manager_api.list_tools_async(
178
- self.sandbox_id,
179
- tool_type=tool_type,
180
- )
181
-
182
- async def call_tool_async(
183
- self,
184
- name: str,
185
- arguments: Optional[dict[str, Any]] = None,
186
- ) -> Any:
187
- if arguments is None:
188
- arguments = {}
189
- return await self.manager_api.call_tool_async(
190
- self.sandbox_id,
191
- name,
192
- arguments,
193
- )
160
+ return self.manager_api.call_tool(self.sandbox_id, name, arguments)
194
161
 
195
- async def add_mcp_servers_async(
162
+ def add_mcp_servers(
196
163
  self,
197
164
  server_configs: dict,
198
165
  overwrite=False,
199
166
  ):
200
- return await self.manager_api.add_mcp_servers_async(
167
+ return self.manager_api.add_mcp_servers(
201
168
  self.sandbox_id,
202
169
  server_configs,
203
170
  overwrite,