agentscope-runtime 1.0.4a1__py3-none-any.whl → 1.0.5__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 (79) hide show
  1. agentscope_runtime/adapters/agentscope/stream.py +2 -8
  2. agentscope_runtime/adapters/langgraph/stream.py +120 -70
  3. agentscope_runtime/adapters/ms_agent_framework/__init__.py +0 -0
  4. agentscope_runtime/adapters/ms_agent_framework/message.py +205 -0
  5. agentscope_runtime/adapters/ms_agent_framework/stream.py +418 -0
  6. agentscope_runtime/adapters/utils.py +6 -0
  7. agentscope_runtime/cli/commands/deploy.py +836 -1
  8. agentscope_runtime/cli/commands/stop.py +16 -0
  9. agentscope_runtime/common/container_clients/__init__.py +52 -0
  10. agentscope_runtime/common/container_clients/agentrun_client.py +6 -4
  11. agentscope_runtime/common/container_clients/boxlite_client.py +442 -0
  12. agentscope_runtime/common/container_clients/docker_client.py +0 -20
  13. agentscope_runtime/common/container_clients/fc_client.py +6 -4
  14. agentscope_runtime/common/container_clients/gvisor_client.py +38 -0
  15. agentscope_runtime/common/container_clients/knative_client.py +467 -0
  16. agentscope_runtime/common/utils/deprecation.py +164 -0
  17. agentscope_runtime/engine/__init__.py +4 -0
  18. agentscope_runtime/engine/app/agent_app.py +16 -4
  19. agentscope_runtime/engine/constant.py +1 -0
  20. agentscope_runtime/engine/deployers/__init__.py +34 -11
  21. agentscope_runtime/engine/deployers/adapter/__init__.py +8 -0
  22. agentscope_runtime/engine/deployers/adapter/a2a/__init__.py +26 -51
  23. agentscope_runtime/engine/deployers/adapter/a2a/a2a_protocol_adapter.py +23 -13
  24. agentscope_runtime/engine/deployers/adapter/a2a/a2a_registry.py +4 -201
  25. agentscope_runtime/engine/deployers/adapter/a2a/nacos_a2a_registry.py +152 -25
  26. agentscope_runtime/engine/deployers/adapter/agui/__init__.py +8 -0
  27. agentscope_runtime/engine/deployers/adapter/agui/agui_adapter_utils.py +652 -0
  28. agentscope_runtime/engine/deployers/adapter/agui/agui_protocol_adapter.py +225 -0
  29. agentscope_runtime/engine/deployers/agentrun_deployer.py +2 -2
  30. agentscope_runtime/engine/deployers/fc_deployer.py +1506 -0
  31. agentscope_runtime/engine/deployers/knative_deployer.py +290 -0
  32. agentscope_runtime/engine/deployers/pai_deployer.py +2335 -0
  33. agentscope_runtime/engine/deployers/utils/net_utils.py +37 -0
  34. agentscope_runtime/engine/deployers/utils/oss_utils.py +38 -0
  35. agentscope_runtime/engine/deployers/utils/package.py +46 -42
  36. agentscope_runtime/engine/helpers/agent_api_client.py +372 -0
  37. agentscope_runtime/engine/runner.py +13 -0
  38. agentscope_runtime/engine/schemas/agent_schemas.py +9 -3
  39. agentscope_runtime/engine/services/agent_state/__init__.py +7 -0
  40. agentscope_runtime/engine/services/memory/__init__.py +7 -0
  41. agentscope_runtime/engine/services/memory/redis_memory_service.py +15 -16
  42. agentscope_runtime/engine/services/session_history/__init__.py +7 -0
  43. agentscope_runtime/engine/tracing/local_logging_handler.py +2 -3
  44. agentscope_runtime/engine/tracing/wrapper.py +18 -4
  45. agentscope_runtime/sandbox/__init__.py +14 -6
  46. agentscope_runtime/sandbox/box/base/__init__.py +2 -2
  47. agentscope_runtime/sandbox/box/base/base_sandbox.py +51 -1
  48. agentscope_runtime/sandbox/box/browser/__init__.py +2 -2
  49. agentscope_runtime/sandbox/box/browser/browser_sandbox.py +198 -2
  50. agentscope_runtime/sandbox/box/filesystem/__init__.py +2 -2
  51. agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +99 -2
  52. agentscope_runtime/sandbox/box/gui/__init__.py +2 -2
  53. agentscope_runtime/sandbox/box/gui/gui_sandbox.py +117 -1
  54. agentscope_runtime/sandbox/box/mobile/__init__.py +2 -2
  55. agentscope_runtime/sandbox/box/mobile/mobile_sandbox.py +247 -100
  56. agentscope_runtime/sandbox/box/sandbox.py +102 -65
  57. agentscope_runtime/sandbox/box/shared/routers/generic.py +36 -29
  58. agentscope_runtime/sandbox/client/__init__.py +6 -1
  59. agentscope_runtime/sandbox/client/async_http_client.py +339 -0
  60. agentscope_runtime/sandbox/client/base.py +74 -0
  61. agentscope_runtime/sandbox/client/http_client.py +108 -329
  62. agentscope_runtime/sandbox/enums.py +7 -0
  63. agentscope_runtime/sandbox/manager/sandbox_manager.py +275 -29
  64. agentscope_runtime/sandbox/manager/server/app.py +7 -1
  65. agentscope_runtime/sandbox/manager/server/config.py +3 -1
  66. agentscope_runtime/sandbox/model/manager_config.py +11 -9
  67. agentscope_runtime/tools/modelstudio_memory/__init__.py +106 -0
  68. agentscope_runtime/tools/modelstudio_memory/base.py +220 -0
  69. agentscope_runtime/tools/modelstudio_memory/config.py +86 -0
  70. agentscope_runtime/tools/modelstudio_memory/core.py +594 -0
  71. agentscope_runtime/tools/modelstudio_memory/exceptions.py +60 -0
  72. agentscope_runtime/tools/modelstudio_memory/schemas.py +253 -0
  73. agentscope_runtime/version.py +1 -1
  74. {agentscope_runtime-1.0.4a1.dist-info → agentscope_runtime-1.0.5.dist-info}/METADATA +186 -73
  75. {agentscope_runtime-1.0.4a1.dist-info → agentscope_runtime-1.0.5.dist-info}/RECORD +79 -55
  76. {agentscope_runtime-1.0.4a1.dist-info → agentscope_runtime-1.0.5.dist-info}/WHEEL +0 -0
  77. {agentscope_runtime-1.0.4a1.dist-info → agentscope_runtime-1.0.5.dist-info}/entry_points.txt +0 -0
  78. {agentscope_runtime-1.0.4a1.dist-info → agentscope_runtime-1.0.5.dist-info}/licenses/LICENSE +0 -0
  79. {agentscope_runtime-1.0.4a1.dist-info → agentscope_runtime-1.0.5.dist-info}/top_level.txt +0 -0
@@ -30,25 +30,24 @@ class RedisMemoryService(MemoryService):
30
30
  Initialize RedisMemoryService.
31
31
 
32
32
  Args:
33
- redis_url: Redis connection URL
34
- redis_client: Optional pre-configured Redis client
35
- socket_timeout: Socket timeout in seconds (default: 5.0)
33
+ redis_url: Redis connection URL.
34
+ redis_client: Optional pre-configured Redis client.
35
+ socket_timeout: Socket timeout in seconds (default: 5.0).
36
36
  socket_connect_timeout: Socket connect timeout in seconds
37
- (default: 5.0)
37
+ (default: 5.0).
38
38
  max_connections: Maximum number of connections in the pool
39
- (default: None)
40
- retry_on_timeout: Whether to retry on timeout (default: True)
41
- ttl_seconds: Time-to-live in seconds for memory data.
42
- If None, data never expires (default: 3600, i.e., 1 hour)
39
+ (default: None).
40
+ retry_on_timeout: Whether to retry on timeout (default: True).
41
+ ttl_seconds: Time-to-live in seconds for memory data. If None,
42
+ data never expires (default: 3600, i.e., 1 hour).
43
43
  max_messages_per_session: Maximum number of messages stored per
44
- session_id field within a user's Redis memory hash.
45
- If None, no limit (default: None)
46
- health_check_interval: Interval in seconds for health checks
47
- on idle connections (default: 30.0).
48
- Connections idle longer than this will be checked before reuse.
49
- Set to 0 to disable.
50
- socket_keepalive: Enable TCP keepalive to prevent
51
- silent disconnections (default: True)
44
+ session_id field within a user's Redis memory hash. If None,
45
+ no limit (default: None).
46
+ health_check_interval: Interval in seconds for health checks on
47
+ idle connections (default: 30.0). Connections idle longer
48
+ than this will be checked before reuse. Set to 0 to disable.
49
+ socket_keepalive: Enable TCP keepalive to prevent silent
50
+ disconnections (default: True).
52
51
  """
53
52
  self._redis_url = redis_url
54
53
  self._redis = redis_client
@@ -1,6 +1,13 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  from typing import TYPE_CHECKING
3
3
  from ....common.utils.lazy_loader import install_lazy_loader
4
+ from ....common.utils.deprecation import deprecated_module
5
+
6
+ deprecated_module(
7
+ module_name=__name__,
8
+ removed_in="v1.1",
9
+ alternative="agentscope.memory",
10
+ )
4
11
 
5
12
  if TYPE_CHECKING:
6
13
  from .session_history_service import (
@@ -7,7 +7,7 @@ from datetime import datetime
7
7
  from logging.handlers import RotatingFileHandler
8
8
  from typing import Any, Dict, Optional
9
9
 
10
- from pydantic import BaseModel
10
+ from pydantic import BaseModel, ConfigDict
11
11
 
12
12
  from . import TracingUtil
13
13
  from .base import TracerHandler
@@ -39,8 +39,7 @@ class LogContext(BaseModel):
39
39
  ds_service_id: str = ""
40
40
  ds_service_name: str = ""
41
41
 
42
- class Config:
43
- extra = "ignore" # ignore additional key
42
+ model_config = ConfigDict(extra="allow")
44
43
 
45
44
 
46
45
  class JsonFormatter(logging.Formatter):
@@ -26,7 +26,11 @@ from typing import (
26
26
  from pydantic import BaseModel
27
27
  from opentelemetry.propagate import extract
28
28
  from opentelemetry.context import attach
29
- from opentelemetry.trace import StatusCode, NoOpTracerProvider
29
+ from opentelemetry.trace import (
30
+ ProxyTracerProvider,
31
+ StatusCode,
32
+ NoOpTracerProvider,
33
+ )
30
34
  from opentelemetry import trace as ot_trace
31
35
  from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
32
36
  OTLPSpanExporter as OTLPSpanGrpcExporter,
@@ -917,12 +921,22 @@ def _get_ot_tracer() -> ot_trace.Tracer:
917
921
  ot_trace.Tracer: The OpenTelemetry tracer instance.
918
922
  """
919
923
 
920
- def _get_ot_tracer_inner() -> ot_trace.Tracer:
924
+ def _has_existing_trace_provider() -> bool:
925
+ from opentelemetry.trace import _TRACER_PROVIDER
926
+
921
927
  existing_provider = ot_trace.get_tracer_provider()
928
+ if isinstance(existing_provider, NoOpTracerProvider):
929
+ return False
930
+ elif isinstance(existing_provider, ProxyTracerProvider):
931
+ # ProxyTracerProvider will use the _TRACER_PROVIDER as real tracer
932
+ # provider to get the tracer
933
+ return bool(_TRACER_PROVIDER)
922
934
 
923
- if not isinstance(existing_provider, NoOpTracerProvider):
924
- return ot_trace.get_tracer("agentscope_runtime")
935
+ return True
925
936
 
937
+ def _get_ot_tracer_inner() -> ot_trace.Tracer:
938
+ if _has_existing_trace_provider():
939
+ return ot_trace.get_tracer("agentscope_runtime")
926
940
  resource = Resource(
927
941
  attributes={
928
942
  SERVICE_NAME: _get_service_name(),
@@ -3,22 +3,30 @@
3
3
  # This ensures SandboxRegistry.register() runs at import time.
4
4
  # Without this, lazy loading delays module import and types may not be
5
5
  # registered.
6
- from .box.base.base_sandbox import BaseSandbox
7
- from .box.browser.browser_sandbox import BrowserSandbox
8
- from .box.filesystem.filesystem_sandbox import FilesystemSandbox
9
- from .box.gui.gui_sandbox import GuiSandbox
6
+ from .box.base.base_sandbox import BaseSandbox, BaseSandboxAsync
7
+ from .box.browser.browser_sandbox import BrowserSandbox, BrowserSandboxAsync
8
+ from .box.filesystem.filesystem_sandbox import (
9
+ FilesystemSandbox,
10
+ FilesystemSandboxAsync,
11
+ )
12
+ from .box.gui.gui_sandbox import GuiSandbox, GuiSandboxAsync
13
+ from .box.mobile.mobile_sandbox import MobileSandbox, MobileSandboxAsync
10
14
  from .box.training_box.training_box import TrainingSandbox
11
15
  from .box.cloud.cloud_sandbox import CloudSandbox
12
- from .box.mobile.mobile_sandbox import MobileSandbox
13
16
  from .box.agentbay.agentbay_sandbox import AgentbaySandbox
14
17
 
15
18
  __all__ = [
16
19
  "BaseSandbox",
20
+ "BaseSandboxAsync",
17
21
  "BrowserSandbox",
22
+ "BrowserSandboxAsync",
18
23
  "FilesystemSandbox",
24
+ "FilesystemSandboxAsync",
19
25
  "GuiSandbox",
26
+ "GuiSandboxAsync",
27
+ "MobileSandbox",
28
+ "MobileSandboxAsync",
20
29
  "TrainingSandbox",
21
30
  "CloudSandbox",
22
- "MobileSandbox",
23
31
  "AgentbaySandbox",
24
32
  ]
@@ -1,4 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
- from .base_sandbox import BaseSandbox
2
+ from .base_sandbox import BaseSandbox, BaseSandboxAsync
3
3
 
4
- __all__ = ["BaseSandbox"]
4
+ __all__ = ["BaseSandbox", "BaseSandboxAsync"]
@@ -4,7 +4,7 @@ from typing import Optional
4
4
  from ...utils import build_image_uri
5
5
  from ...registry import SandboxRegistry
6
6
  from ...enums import SandboxType
7
- from ...box.sandbox import Sandbox
7
+ from ...box.sandbox import Sandbox, SandboxAsync
8
8
  from ...constant import TIMEOUT
9
9
 
10
10
 
@@ -49,3 +49,53 @@ class BaseSandbox(Sandbox):
49
49
  command (str): Shell command to execute.
50
50
  """
51
51
  return self.call_tool("run_shell_command", {"command": command})
52
+
53
+
54
+ @SandboxRegistry.register(
55
+ build_image_uri("runtime-sandbox-base"),
56
+ sandbox_type=SandboxType.BASE_ASYNC,
57
+ security_level="medium",
58
+ timeout=TIMEOUT,
59
+ description="Base Sandbox (Async)",
60
+ )
61
+ class BaseSandboxAsync(SandboxAsync):
62
+ def __init__(
63
+ self,
64
+ sandbox_id: Optional[str] = None,
65
+ timeout: int = 3000,
66
+ base_url: Optional[str] = None,
67
+ bearer_token: Optional[str] = None,
68
+ sandbox_type: SandboxType = SandboxType.BASE_ASYNC,
69
+ ):
70
+ super().__init__(
71
+ sandbox_id,
72
+ timeout,
73
+ base_url,
74
+ bearer_token,
75
+ sandbox_type,
76
+ )
77
+
78
+ async def run_ipython_cell(self, code: str):
79
+ """
80
+ Run an IPython cell asynchronously.
81
+
82
+ Args:
83
+ code (str): IPython code to execute.
84
+ Returns:
85
+ Any: Response from sandbox execution
86
+ """
87
+ return await self.call_tool_async("run_ipython_cell", {"code": code})
88
+
89
+ async def run_shell_command(self, command: str):
90
+ """
91
+ Run a shell command asynchronously.
92
+
93
+ Args:
94
+ command (str): Shell command to execute.
95
+ Returns:
96
+ Any: Response from sandbox execution
97
+ """
98
+ return await self.call_tool_async(
99
+ "run_shell_command",
100
+ {"command": command},
101
+ )
@@ -1,4 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
- from .browser_sandbox import BrowserSandbox
2
+ from .browser_sandbox import BrowserSandbox, BrowserSandboxAsync
3
3
 
4
- __all__ = ["BrowserSandbox"]
4
+ __all__ = ["BrowserSandbox", "BrowserSandboxAsync"]
@@ -6,8 +6,8 @@ from urllib.parse import urlparse, urlunparse
6
6
  from ...utils import build_image_uri
7
7
  from ...registry import SandboxRegistry
8
8
  from ...enums import SandboxType
9
- from ...box.base import BaseSandbox
10
- from ...box.gui import GUIMixin
9
+ from ...box.base import BaseSandbox, BaseSandboxAsync
10
+ from ...box.gui import GUIMixin, AsyncGUIMixin
11
11
  from ...constant import TIMEOUT
12
12
 
13
13
 
@@ -299,3 +299,199 @@ class BrowserSandbox(GUIMixin, BaseSandbox):
299
299
  "textGone": text_gone,
300
300
  },
301
301
  )
302
+
303
+
304
+ @SandboxRegistry.register(
305
+ build_image_uri("runtime-sandbox-browser"),
306
+ sandbox_type=SandboxType.BROWSER_ASYNC,
307
+ security_level="medium",
308
+ timeout=TIMEOUT,
309
+ description="Browser sandbox (Async)",
310
+ )
311
+ class BrowserSandboxAsync(GUIMixin, AsyncGUIMixin, BaseSandboxAsync):
312
+ def __init__( # pylint: disable=useless-parent-delegation
313
+ self,
314
+ sandbox_id: Optional[str] = None,
315
+ timeout: int = 3000,
316
+ base_url: Optional[str] = None,
317
+ bearer_token: Optional[str] = None,
318
+ sandbox_type: SandboxType = SandboxType.BROWSER_ASYNC,
319
+ ):
320
+ super().__init__(
321
+ sandbox_id,
322
+ timeout,
323
+ base_url,
324
+ bearer_token,
325
+ sandbox_type,
326
+ )
327
+
328
+ async def browser_close(self):
329
+ """Close the current browser page."""
330
+ return await self.call_tool_async("browser_close", {})
331
+
332
+ async def browser_resize(self, width: int, height: int):
333
+ """Resize the browser window."""
334
+ return await self.call_tool_async(
335
+ "browser_resize",
336
+ {"width": width, "height": height},
337
+ )
338
+
339
+ async def browser_console_messages(self):
340
+ """Return all console messages from the browser."""
341
+ return await self.call_tool_async("browser_console_messages", {})
342
+
343
+ async def browser_handle_dialog(self, accept: bool, prompt_text: str = ""):
344
+ """Handle a dialog popup."""
345
+ return await self.call_tool_async(
346
+ "browser_handle_dialog",
347
+ {"accept": accept, "promptText": prompt_text},
348
+ )
349
+
350
+ async def browser_file_upload(self, paths: list):
351
+ """Upload one or multiple files."""
352
+ return await self.call_tool_async(
353
+ "browser_file_upload",
354
+ {"paths": paths},
355
+ )
356
+
357
+ async def browser_press_key(self, key: str):
358
+ """Press a key in the browser."""
359
+ return await self.call_tool_async("browser_press_key", {"key": key})
360
+
361
+ async def browser_navigate(self, url: str):
362
+ """Navigate to a URL."""
363
+ return await self.call_tool_async("browser_navigate", {"url": url})
364
+
365
+ async def browser_navigate_back(self):
366
+ """Go back in browser history."""
367
+ return await self.call_tool_async("browser_navigate_back", {})
368
+
369
+ async def browser_navigate_forward(self):
370
+ """Go forward in browser history."""
371
+ return await self.call_tool_async("browser_navigate_forward", {})
372
+
373
+ async def browser_network_requests(self):
374
+ """Return network requests."""
375
+ return await self.call_tool_async("browser_network_requests", {})
376
+
377
+ async def browser_pdf_save(self, filename: str = ""):
378
+ """Save page as a PDF."""
379
+ return await self.call_tool_async(
380
+ "browser_pdf_save",
381
+ {"filename": filename},
382
+ )
383
+
384
+ async def browser_take_screenshot(
385
+ self,
386
+ raw=False,
387
+ filename="",
388
+ element="",
389
+ ref="",
390
+ ):
391
+ """Take a screenshot."""
392
+ return await self.call_tool_async(
393
+ "browser_take_screenshot",
394
+ {"raw": raw, "filename": filename, "element": element, "ref": ref},
395
+ )
396
+
397
+ async def browser_snapshot(self):
398
+ """Accessibility snapshot."""
399
+ return await self.call_tool_async("browser_snapshot", {})
400
+
401
+ async def browser_click(self, element: str, ref: str):
402
+ """Click an element."""
403
+ return await self.call_tool_async(
404
+ "browser_click",
405
+ {"element": element, "ref": ref},
406
+ )
407
+
408
+ async def browser_drag(
409
+ self,
410
+ start_element: str,
411
+ start_ref: str,
412
+ end_element: str,
413
+ end_ref: str,
414
+ ):
415
+ """Drag and drop."""
416
+ return await self.call_tool_async(
417
+ "browser_drag",
418
+ {
419
+ "startElement": start_element,
420
+ "startRef": start_ref,
421
+ "endElement": end_element,
422
+ "endRef": end_ref,
423
+ },
424
+ )
425
+
426
+ async def browser_hover(self, element: str, ref: str):
427
+ """Hover over an element."""
428
+ return await self.call_tool_async(
429
+ "browser_hover",
430
+ {"element": element, "ref": ref},
431
+ )
432
+
433
+ async def browser_type(
434
+ self,
435
+ element: str,
436
+ ref: str,
437
+ text: str,
438
+ submit=False,
439
+ slowly=False,
440
+ ):
441
+ """Type text into an element."""
442
+ return await self.call_tool_async(
443
+ "browser_type",
444
+ {
445
+ "element": element,
446
+ "ref": ref,
447
+ "text": text,
448
+ "submit": submit,
449
+ "slowly": slowly,
450
+ },
451
+ )
452
+
453
+ async def browser_select_option(
454
+ self,
455
+ element: str,
456
+ ref: str,
457
+ values: list,
458
+ ):
459
+ """Select options in a dropdown."""
460
+ return await self.call_tool_async(
461
+ "browser_select_option",
462
+ {"element": element, "ref": ref, "values": values},
463
+ )
464
+
465
+ async def browser_tab_list(self):
466
+ """List all tabs."""
467
+ return await self.call_tool_async("browser_tab_list", {})
468
+
469
+ async def browser_tab_new(self, url: str = ""):
470
+ """Open a new tab."""
471
+ return await self.call_tool_async("browser_tab_new", {"url": url})
472
+
473
+ async def browser_tab_select(self, index: int):
474
+ """Select tab by index."""
475
+ return await self.call_tool_async(
476
+ "browser_tab_select",
477
+ {"index": index},
478
+ )
479
+
480
+ async def browser_tab_close(self, index: int = None):
481
+ """Close a tab."""
482
+ return await self.call_tool_async(
483
+ "browser_tab_close",
484
+ {"index": index},
485
+ )
486
+
487
+ async def browser_wait_for(
488
+ self,
489
+ time: float = None,
490
+ text: str = None,
491
+ text_gone: str = None,
492
+ ):
493
+ """Wait for text or time."""
494
+ return await self.call_tool_async(
495
+ "browser_wait_for",
496
+ {"time": time, "text": text, "textGone": text_gone},
497
+ )
@@ -1,4 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
- from .filesystem_sandbox import FilesystemSandbox
2
+ from .filesystem_sandbox import FilesystemSandbox, FilesystemSandboxAsync
3
3
 
4
- __all__ = ["FilesystemSandbox"]
4
+ __all__ = ["FilesystemSandbox", "FilesystemSandboxAsync"]
@@ -5,8 +5,8 @@ from typing import Optional
5
5
  from ...utils import build_image_uri
6
6
  from ...registry import SandboxRegistry
7
7
  from ...enums import SandboxType
8
- from ...box.base import BaseSandbox
9
- from ...box.gui import GUIMixin
8
+ from ...box.base import BaseSandbox, BaseSandboxAsync
9
+ from ...box.gui import GUIMixin, AsyncGUIMixin
10
10
  from ...constant import TIMEOUT
11
11
 
12
12
 
@@ -154,3 +154,100 @@ class FilesystemSandbox(GUIMixin, BaseSandbox):
154
154
  Returns the list of directories that this serveris allowed to access.
155
155
  """
156
156
  return self.call_tool("list_allowed_directories", {})
157
+
158
+
159
+ @SandboxRegistry.register(
160
+ build_image_uri("runtime-sandbox-filesystem"),
161
+ sandbox_type=SandboxType.FILESYSTEM_ASYNC,
162
+ security_level="medium",
163
+ timeout=TIMEOUT,
164
+ description="Filesystem sandbox (Async)",
165
+ )
166
+ class FilesystemSandboxAsync(GUIMixin, AsyncGUIMixin, BaseSandboxAsync):
167
+ def __init__( # pylint: disable=useless-parent-delegation
168
+ self,
169
+ sandbox_id: Optional[str] = None,
170
+ timeout: int = 3000,
171
+ base_url: Optional[str] = None,
172
+ bearer_token: Optional[str] = None,
173
+ sandbox_type: SandboxType = SandboxType.FILESYSTEM_ASYNC,
174
+ ):
175
+ super().__init__(
176
+ sandbox_id,
177
+ timeout,
178
+ base_url,
179
+ bearer_token,
180
+ sandbox_type,
181
+ )
182
+
183
+ async def read_file(self, path: str):
184
+ """Read the complete contents of a file."""
185
+ return await self.call_tool_async("read_file", {"path": path})
186
+
187
+ async def read_multiple_files(self, paths: list):
188
+ """Read the contents of multiple files simultaneously."""
189
+ return await self.call_tool_async(
190
+ "read_multiple_files",
191
+ {"paths": paths},
192
+ )
193
+
194
+ async def write_file(self, path: str, content: str):
195
+ """Create or overwrite a file with new content."""
196
+ return await self.call_tool_async(
197
+ "write_file",
198
+ {"path": path, "content": content},
199
+ )
200
+
201
+ async def edit_file(self, path: str, edits: list, dry_run: bool = False):
202
+ """Make line-based edits to a text file."""
203
+ return await self.call_tool_async(
204
+ "edit_file",
205
+ {
206
+ "path": path,
207
+ "edits": edits,
208
+ "dryRun": dry_run,
209
+ },
210
+ )
211
+
212
+ async def create_directory(self, path: str):
213
+ """Create a new directory or ensure it exists."""
214
+ return await self.call_tool_async("create_directory", {"path": path})
215
+
216
+ async def list_directory(self, path: str):
217
+ """Get a detailed listing of all files and directories."""
218
+ return await self.call_tool_async("list_directory", {"path": path})
219
+
220
+ async def directory_tree(self, path: str):
221
+ """Get a recursive tree view of files and directories as JSON."""
222
+ return await self.call_tool_async("directory_tree", {"path": path})
223
+
224
+ async def move_file(self, source: str, destination: str):
225
+ """Move or rename files and directories."""
226
+ return await self.call_tool_async(
227
+ "move_file",
228
+ {"source": source, "destination": destination},
229
+ )
230
+
231
+ async def search_files(
232
+ self,
233
+ path: str,
234
+ pattern: str,
235
+ exclude_patterns: list = [],
236
+ ):
237
+ """Recursively search for files and directories matching a pattern."""
238
+ return await self.call_tool_async(
239
+ "search_files",
240
+ {
241
+ "path": path,
242
+ "pattern": pattern,
243
+ "excludePatterns": exclude_patterns,
244
+ },
245
+ )
246
+
247
+ async def get_file_info(self, path: str):
248
+ """Retrieve metadata about a file or directory."""
249
+ return await self.call_tool_async("get_file_info", {"path": path})
250
+
251
+ async def list_allowed_directories(self):
252
+ """Returns directories this server can access."""
253
+ return await self.call_tool_async("list_allowed_directories", {})
@@ -1,4 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
- from .gui_sandbox import GuiSandbox, GUIMixin
2
+ from .gui_sandbox import GuiSandbox, GuiSandboxAsync, GUIMixin, AsyncGUIMixin
3
3
 
4
- __all__ = ["GuiSandbox", "GUIMixin"]
4
+ __all__ = ["GuiSandbox", "GuiSandboxAsync", "GUIMixin", "AsyncGUIMixin"]