agentscope-runtime 1.0.4a1__py3-none-any.whl → 1.0.5.post1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agentscope_runtime/adapters/agentscope/stream.py +2 -8
- agentscope_runtime/adapters/langgraph/stream.py +120 -70
- agentscope_runtime/adapters/ms_agent_framework/__init__.py +0 -0
- agentscope_runtime/adapters/ms_agent_framework/message.py +205 -0
- agentscope_runtime/adapters/ms_agent_framework/stream.py +418 -0
- agentscope_runtime/adapters/utils.py +6 -0
- agentscope_runtime/cli/commands/deploy.py +836 -1
- agentscope_runtime/cli/commands/stop.py +16 -0
- agentscope_runtime/common/container_clients/__init__.py +52 -0
- agentscope_runtime/common/container_clients/agentrun_client.py +6 -4
- agentscope_runtime/common/container_clients/boxlite_client.py +442 -0
- agentscope_runtime/common/container_clients/docker_client.py +0 -20
- agentscope_runtime/common/container_clients/fc_client.py +6 -4
- agentscope_runtime/common/container_clients/gvisor_client.py +38 -0
- agentscope_runtime/common/container_clients/knative_client.py +467 -0
- agentscope_runtime/common/utils/deprecation.py +164 -0
- agentscope_runtime/engine/__init__.py +4 -0
- agentscope_runtime/engine/app/agent_app.py +16 -4
- agentscope_runtime/engine/constant.py +1 -0
- agentscope_runtime/engine/deployers/__init__.py +34 -11
- agentscope_runtime/engine/deployers/adapter/__init__.py +8 -0
- agentscope_runtime/engine/deployers/adapter/a2a/__init__.py +26 -51
- agentscope_runtime/engine/deployers/adapter/a2a/a2a_protocol_adapter.py +23 -13
- agentscope_runtime/engine/deployers/adapter/a2a/a2a_registry.py +4 -201
- agentscope_runtime/engine/deployers/adapter/a2a/nacos_a2a_registry.py +152 -25
- agentscope_runtime/engine/deployers/adapter/agui/__init__.py +8 -0
- agentscope_runtime/engine/deployers/adapter/agui/agui_adapter_utils.py +652 -0
- agentscope_runtime/engine/deployers/adapter/agui/agui_protocol_adapter.py +225 -0
- agentscope_runtime/engine/deployers/agentrun_deployer.py +2 -2
- agentscope_runtime/engine/deployers/fc_deployer.py +1506 -0
- agentscope_runtime/engine/deployers/knative_deployer.py +290 -0
- agentscope_runtime/engine/deployers/pai_deployer.py +2335 -0
- agentscope_runtime/engine/deployers/utils/net_utils.py +37 -0
- agentscope_runtime/engine/deployers/utils/oss_utils.py +38 -0
- agentscope_runtime/engine/deployers/utils/package.py +46 -42
- agentscope_runtime/engine/helpers/agent_api_client.py +372 -0
- agentscope_runtime/engine/runner.py +13 -0
- agentscope_runtime/engine/schemas/agent_schemas.py +9 -3
- agentscope_runtime/engine/services/agent_state/__init__.py +7 -0
- agentscope_runtime/engine/services/memory/__init__.py +7 -0
- agentscope_runtime/engine/services/memory/redis_memory_service.py +15 -16
- agentscope_runtime/engine/services/session_history/__init__.py +7 -0
- agentscope_runtime/engine/tracing/local_logging_handler.py +2 -3
- agentscope_runtime/engine/tracing/wrapper.py +18 -4
- agentscope_runtime/sandbox/__init__.py +14 -6
- agentscope_runtime/sandbox/box/base/__init__.py +2 -2
- agentscope_runtime/sandbox/box/base/base_sandbox.py +51 -1
- agentscope_runtime/sandbox/box/browser/__init__.py +2 -2
- agentscope_runtime/sandbox/box/browser/browser_sandbox.py +198 -2
- agentscope_runtime/sandbox/box/filesystem/__init__.py +2 -2
- agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +99 -2
- agentscope_runtime/sandbox/box/gui/__init__.py +2 -2
- agentscope_runtime/sandbox/box/gui/gui_sandbox.py +117 -1
- agentscope_runtime/sandbox/box/mobile/__init__.py +2 -2
- agentscope_runtime/sandbox/box/mobile/mobile_sandbox.py +247 -100
- agentscope_runtime/sandbox/box/sandbox.py +102 -65
- agentscope_runtime/sandbox/box/shared/routers/generic.py +36 -29
- agentscope_runtime/sandbox/client/__init__.py +6 -1
- agentscope_runtime/sandbox/client/async_http_client.py +339 -0
- agentscope_runtime/sandbox/client/base.py +74 -0
- agentscope_runtime/sandbox/client/http_client.py +108 -329
- agentscope_runtime/sandbox/enums.py +7 -0
- agentscope_runtime/sandbox/manager/sandbox_manager.py +275 -29
- agentscope_runtime/sandbox/manager/server/app.py +7 -1
- agentscope_runtime/sandbox/manager/server/config.py +3 -1
- agentscope_runtime/sandbox/model/manager_config.py +11 -9
- agentscope_runtime/tools/modelstudio_memory/__init__.py +106 -0
- agentscope_runtime/tools/modelstudio_memory/base.py +220 -0
- agentscope_runtime/tools/modelstudio_memory/config.py +86 -0
- agentscope_runtime/tools/modelstudio_memory/core.py +594 -0
- agentscope_runtime/tools/modelstudio_memory/exceptions.py +60 -0
- agentscope_runtime/tools/modelstudio_memory/schemas.py +253 -0
- agentscope_runtime/version.py +1 -1
- {agentscope_runtime-1.0.4a1.dist-info → agentscope_runtime-1.0.5.post1.dist-info}/METADATA +187 -74
- {agentscope_runtime-1.0.4a1.dist-info → agentscope_runtime-1.0.5.post1.dist-info}/RECORD +79 -55
- {agentscope_runtime-1.0.4a1.dist-info → agentscope_runtime-1.0.5.post1.dist-info}/WHEEL +1 -1
- {agentscope_runtime-1.0.4a1.dist-info → agentscope_runtime-1.0.5.post1.dist-info}/entry_points.txt +0 -0
- {agentscope_runtime-1.0.4a1.dist-info → agentscope_runtime-1.0.5.post1.dist-info}/licenses/LICENSE +0 -0
- {agentscope_runtime-1.0.4a1.dist-info → agentscope_runtime-1.0.5.post1.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
|
-
|
|
37
|
+
(default: 5.0).
|
|
38
38
|
max_connections: Maximum number of connections in the pool
|
|
39
|
-
|
|
40
|
-
retry_on_timeout: Whether to retry on timeout (default: True)
|
|
41
|
-
ttl_seconds: Time-to-live in seconds for memory data.
|
|
42
|
-
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
health_check_interval: Interval in seconds for health checks
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
9
|
-
|
|
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
|
]
|
|
@@ -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
|
+
)
|
|
@@ -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
|
+
)
|
|
@@ -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", {})
|