agentscope-runtime 0.1.0__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/__init__.py +4 -0
- agentscope_runtime/engine/__init__.py +9 -0
- agentscope_runtime/engine/agents/__init__.py +2 -0
- agentscope_runtime/engine/agents/agentscope_agent/__init__.py +6 -0
- agentscope_runtime/engine/agents/agentscope_agent/agent.py +342 -0
- agentscope_runtime/engine/agents/agentscope_agent/hooks.py +156 -0
- agentscope_runtime/engine/agents/agno_agent.py +220 -0
- agentscope_runtime/engine/agents/base_agent.py +29 -0
- agentscope_runtime/engine/agents/langgraph_agent.py +59 -0
- agentscope_runtime/engine/agents/llm_agent.py +51 -0
- agentscope_runtime/engine/deployers/__init__.py +3 -0
- agentscope_runtime/engine/deployers/adapter/__init__.py +0 -0
- agentscope_runtime/engine/deployers/adapter/a2a/__init__.py +2 -0
- agentscope_runtime/engine/deployers/adapter/a2a/a2a_adapter_utils.py +425 -0
- agentscope_runtime/engine/deployers/adapter/a2a/a2a_agent_adapter.py +69 -0
- agentscope_runtime/engine/deployers/adapter/a2a/a2a_protocol_adapter.py +60 -0
- agentscope_runtime/engine/deployers/adapter/protocol_adapter.py +24 -0
- agentscope_runtime/engine/deployers/base.py +17 -0
- agentscope_runtime/engine/deployers/local_deployer.py +586 -0
- agentscope_runtime/engine/helpers/helper.py +127 -0
- agentscope_runtime/engine/llms/__init__.py +3 -0
- agentscope_runtime/engine/llms/base_llm.py +60 -0
- agentscope_runtime/engine/llms/qwen_llm.py +47 -0
- agentscope_runtime/engine/misc/__init__.py +0 -0
- agentscope_runtime/engine/runner.py +186 -0
- agentscope_runtime/engine/schemas/__init__.py +0 -0
- agentscope_runtime/engine/schemas/agent_schemas.py +551 -0
- agentscope_runtime/engine/schemas/context.py +54 -0
- agentscope_runtime/engine/services/__init__.py +9 -0
- agentscope_runtime/engine/services/base.py +77 -0
- agentscope_runtime/engine/services/context_manager.py +129 -0
- agentscope_runtime/engine/services/environment_manager.py +50 -0
- agentscope_runtime/engine/services/manager.py +174 -0
- agentscope_runtime/engine/services/memory_service.py +270 -0
- agentscope_runtime/engine/services/sandbox_service.py +198 -0
- agentscope_runtime/engine/services/session_history_service.py +256 -0
- agentscope_runtime/engine/tracing/__init__.py +40 -0
- agentscope_runtime/engine/tracing/base.py +309 -0
- agentscope_runtime/engine/tracing/local_logging_handler.py +356 -0
- agentscope_runtime/engine/tracing/tracing_metric.py +69 -0
- agentscope_runtime/engine/tracing/wrapper.py +321 -0
- agentscope_runtime/sandbox/__init__.py +14 -0
- agentscope_runtime/sandbox/box/__init__.py +0 -0
- agentscope_runtime/sandbox/box/base/__init__.py +0 -0
- agentscope_runtime/sandbox/box/base/base_sandbox.py +37 -0
- agentscope_runtime/sandbox/box/base/box/__init__.py +0 -0
- agentscope_runtime/sandbox/box/browser/__init__.py +0 -0
- agentscope_runtime/sandbox/box/browser/box/__init__.py +0 -0
- agentscope_runtime/sandbox/box/browser/browser_sandbox.py +176 -0
- agentscope_runtime/sandbox/box/dummy/__init__.py +0 -0
- agentscope_runtime/sandbox/box/dummy/dummy_sandbox.py +26 -0
- agentscope_runtime/sandbox/box/filesystem/__init__.py +0 -0
- agentscope_runtime/sandbox/box/filesystem/box/__init__.py +0 -0
- agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +87 -0
- agentscope_runtime/sandbox/box/sandbox.py +115 -0
- agentscope_runtime/sandbox/box/shared/__init__.py +0 -0
- agentscope_runtime/sandbox/box/shared/app.py +44 -0
- agentscope_runtime/sandbox/box/shared/dependencies/__init__.py +5 -0
- agentscope_runtime/sandbox/box/shared/dependencies/deps.py +22 -0
- agentscope_runtime/sandbox/box/shared/routers/__init__.py +12 -0
- agentscope_runtime/sandbox/box/shared/routers/generic.py +173 -0
- agentscope_runtime/sandbox/box/shared/routers/mcp.py +207 -0
- agentscope_runtime/sandbox/box/shared/routers/mcp_utils.py +153 -0
- agentscope_runtime/sandbox/box/shared/routers/runtime_watcher.py +187 -0
- agentscope_runtime/sandbox/box/shared/routers/workspace.py +325 -0
- agentscope_runtime/sandbox/box/training_box/__init__.py +0 -0
- agentscope_runtime/sandbox/box/training_box/base.py +120 -0
- agentscope_runtime/sandbox/box/training_box/env_service.py +752 -0
- agentscope_runtime/sandbox/box/training_box/environments/__init__.py +0 -0
- agentscope_runtime/sandbox/box/training_box/environments/appworld/appworld_env.py +987 -0
- agentscope_runtime/sandbox/box/training_box/registry.py +54 -0
- agentscope_runtime/sandbox/box/training_box/src/trajectory.py +278 -0
- agentscope_runtime/sandbox/box/training_box/training_box.py +219 -0
- agentscope_runtime/sandbox/build.py +213 -0
- agentscope_runtime/sandbox/client/__init__.py +5 -0
- agentscope_runtime/sandbox/client/http_client.py +527 -0
- agentscope_runtime/sandbox/client/training_client.py +265 -0
- agentscope_runtime/sandbox/constant.py +5 -0
- agentscope_runtime/sandbox/custom/__init__.py +16 -0
- agentscope_runtime/sandbox/custom/custom_sandbox.py +40 -0
- agentscope_runtime/sandbox/custom/example.py +37 -0
- agentscope_runtime/sandbox/enums.py +68 -0
- agentscope_runtime/sandbox/manager/__init__.py +4 -0
- agentscope_runtime/sandbox/manager/collections/__init__.py +22 -0
- agentscope_runtime/sandbox/manager/collections/base_mapping.py +20 -0
- agentscope_runtime/sandbox/manager/collections/base_queue.py +25 -0
- agentscope_runtime/sandbox/manager/collections/base_set.py +25 -0
- agentscope_runtime/sandbox/manager/collections/in_memory_mapping.py +22 -0
- agentscope_runtime/sandbox/manager/collections/in_memory_queue.py +28 -0
- agentscope_runtime/sandbox/manager/collections/in_memory_set.py +27 -0
- agentscope_runtime/sandbox/manager/collections/redis_mapping.py +26 -0
- agentscope_runtime/sandbox/manager/collections/redis_queue.py +27 -0
- agentscope_runtime/sandbox/manager/collections/redis_set.py +23 -0
- agentscope_runtime/sandbox/manager/container_clients/__init__.py +8 -0
- agentscope_runtime/sandbox/manager/container_clients/base_client.py +39 -0
- agentscope_runtime/sandbox/manager/container_clients/docker_client.py +170 -0
- agentscope_runtime/sandbox/manager/sandbox_manager.py +694 -0
- agentscope_runtime/sandbox/manager/server/__init__.py +0 -0
- agentscope_runtime/sandbox/manager/server/app.py +194 -0
- agentscope_runtime/sandbox/manager/server/config.py +68 -0
- agentscope_runtime/sandbox/manager/server/models.py +17 -0
- agentscope_runtime/sandbox/manager/storage/__init__.py +10 -0
- agentscope_runtime/sandbox/manager/storage/data_storage.py +16 -0
- agentscope_runtime/sandbox/manager/storage/local_storage.py +44 -0
- agentscope_runtime/sandbox/manager/storage/oss_storage.py +89 -0
- agentscope_runtime/sandbox/manager/utils.py +78 -0
- agentscope_runtime/sandbox/mcp_server.py +192 -0
- agentscope_runtime/sandbox/model/__init__.py +12 -0
- agentscope_runtime/sandbox/model/api.py +16 -0
- agentscope_runtime/sandbox/model/container.py +72 -0
- agentscope_runtime/sandbox/model/manager_config.py +158 -0
- agentscope_runtime/sandbox/registry.py +129 -0
- agentscope_runtime/sandbox/tools/__init__.py +12 -0
- agentscope_runtime/sandbox/tools/base/__init__.py +8 -0
- agentscope_runtime/sandbox/tools/base/tool.py +52 -0
- agentscope_runtime/sandbox/tools/browser/__init__.py +57 -0
- agentscope_runtime/sandbox/tools/browser/tool.py +597 -0
- agentscope_runtime/sandbox/tools/filesystem/__init__.py +32 -0
- agentscope_runtime/sandbox/tools/filesystem/tool.py +319 -0
- agentscope_runtime/sandbox/tools/function_tool.py +321 -0
- agentscope_runtime/sandbox/tools/mcp_tool.py +191 -0
- agentscope_runtime/sandbox/tools/sandbox_tool.py +104 -0
- agentscope_runtime/sandbox/tools/tool.py +123 -0
- agentscope_runtime/sandbox/tools/utils.py +68 -0
- agentscope_runtime/version.py +2 -0
- agentscope_runtime-0.1.0.dist-info/METADATA +327 -0
- agentscope_runtime-0.1.0.dist-info/RECORD +131 -0
- agentscope_runtime-0.1.0.dist-info/WHEEL +5 -0
- agentscope_runtime-0.1.0.dist-info/entry_points.txt +4 -0
- agentscope_runtime-0.1.0.dist-info/licenses/LICENSE +202 -0
- agentscope_runtime-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""Module for the training sandbox client."""
|
|
3
|
+
# -*- coding: utf-8 -*-
|
|
4
|
+
# pylint: disable=unused-argument,too-many-return-statements
|
|
5
|
+
import time
|
|
6
|
+
import logging
|
|
7
|
+
from typing import Dict, List, Optional, Any
|
|
8
|
+
|
|
9
|
+
import requests
|
|
10
|
+
from requests.exceptions import HTTPError, JSONDecodeError
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TrainingSandboxClient:
|
|
16
|
+
"""Client for interacting with the training sandbox."""
|
|
17
|
+
|
|
18
|
+
def __init__(self, base_url: str = "http://localhost:8000"):
|
|
19
|
+
self.base_url = base_url.rstrip("/")
|
|
20
|
+
self.timeout = 100
|
|
21
|
+
self.session = requests.Session()
|
|
22
|
+
|
|
23
|
+
def __enter__(self):
|
|
24
|
+
# Wait for the runtime api server to be healthy
|
|
25
|
+
self.wait_until_healthy()
|
|
26
|
+
return self
|
|
27
|
+
|
|
28
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
def wait_until_healthy(self) -> None:
|
|
32
|
+
"""
|
|
33
|
+
Waits until the runtime service is running for a specified timeout.
|
|
34
|
+
"""
|
|
35
|
+
start_time = time.time()
|
|
36
|
+
while time.time() - start_time < self.timeout:
|
|
37
|
+
if self.check_health():
|
|
38
|
+
return
|
|
39
|
+
time.sleep(1)
|
|
40
|
+
raise TimeoutError(
|
|
41
|
+
"Runtime service did not start within the specified timeout.",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
def check_health(self) -> bool:
|
|
45
|
+
"""
|
|
46
|
+
Checks if the runtime service is running by verifying the health
|
|
47
|
+
endpoint.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
bool: True if the service is reachable, False otherwise
|
|
51
|
+
"""
|
|
52
|
+
endpoint = f"{self.base_url}/healthz"
|
|
53
|
+
|
|
54
|
+
try:
|
|
55
|
+
response_api = self.session.get(endpoint)
|
|
56
|
+
|
|
57
|
+
return response_api.status_code == 200
|
|
58
|
+
except requests.RequestException:
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
def _make_request(
|
|
62
|
+
self,
|
|
63
|
+
endpoint: str,
|
|
64
|
+
env_type: str = "default",
|
|
65
|
+
task_id: str = None,
|
|
66
|
+
instance_id: str = None,
|
|
67
|
+
messages: Dict[str, Any] = None,
|
|
68
|
+
params: Dict[str, Any] = None,
|
|
69
|
+
) -> Dict:
|
|
70
|
+
"""Request from fastapi"""
|
|
71
|
+
url = f"{self.base_url}/{endpoint}"
|
|
72
|
+
data = {
|
|
73
|
+
"env_type": env_type,
|
|
74
|
+
"task_id": task_id,
|
|
75
|
+
"instance_id": instance_id,
|
|
76
|
+
"messages": messages or {},
|
|
77
|
+
"params": params or {},
|
|
78
|
+
}
|
|
79
|
+
response = self.session.post(url, json=data)
|
|
80
|
+
try:
|
|
81
|
+
response.raise_for_status()
|
|
82
|
+
except HTTPError as e:
|
|
83
|
+
try:
|
|
84
|
+
detail = response.json().get("detail", "")
|
|
85
|
+
except JSONDecodeError:
|
|
86
|
+
detail = response.text
|
|
87
|
+
|
|
88
|
+
raise ValueError(
|
|
89
|
+
f"HTTP Error {e.response.status_code}: {detail}",
|
|
90
|
+
) from e
|
|
91
|
+
|
|
92
|
+
return response.json()
|
|
93
|
+
|
|
94
|
+
def get_task_ids(
|
|
95
|
+
self,
|
|
96
|
+
env_type: str,
|
|
97
|
+
split: str = "train",
|
|
98
|
+
params: dict | None = None,
|
|
99
|
+
) -> List[str]:
|
|
100
|
+
"""Get task id list"""
|
|
101
|
+
payload = {"env_type": env_type}
|
|
102
|
+
if params:
|
|
103
|
+
payload["params"] = params
|
|
104
|
+
response = self._make_request(
|
|
105
|
+
endpoint="get_env_profile",
|
|
106
|
+
env_type=env_type,
|
|
107
|
+
params={"split": split},
|
|
108
|
+
)
|
|
109
|
+
return response["data"]
|
|
110
|
+
|
|
111
|
+
def get_env_profile(
|
|
112
|
+
self,
|
|
113
|
+
env_type: str,
|
|
114
|
+
split: str = "train",
|
|
115
|
+
params: dict | None = None,
|
|
116
|
+
) -> List[str]:
|
|
117
|
+
"""get environment profile"""
|
|
118
|
+
payload = {"env_type": env_type}
|
|
119
|
+
if params:
|
|
120
|
+
payload["params"] = params
|
|
121
|
+
response = self._make_request(
|
|
122
|
+
endpoint="get_env_profile",
|
|
123
|
+
env_type=env_type,
|
|
124
|
+
params={"split": split},
|
|
125
|
+
)
|
|
126
|
+
return response["data"]
|
|
127
|
+
|
|
128
|
+
def get_tools_info(
|
|
129
|
+
self,
|
|
130
|
+
instance_id: str,
|
|
131
|
+
messages: Dict = None,
|
|
132
|
+
params: Dict = None,
|
|
133
|
+
) -> float:
|
|
134
|
+
"""get tools information"""
|
|
135
|
+
messages = messages or {}
|
|
136
|
+
params = params or {}
|
|
137
|
+
|
|
138
|
+
response = self._make_request(
|
|
139
|
+
endpoint="get_info",
|
|
140
|
+
instance_id=instance_id,
|
|
141
|
+
messages=messages,
|
|
142
|
+
params=params,
|
|
143
|
+
)
|
|
144
|
+
return response["data"]
|
|
145
|
+
|
|
146
|
+
def create_instance(
|
|
147
|
+
self,
|
|
148
|
+
env_type: str,
|
|
149
|
+
task_id: str,
|
|
150
|
+
instance_id: str = None,
|
|
151
|
+
params: Dict = None,
|
|
152
|
+
) -> Dict[str, str]:
|
|
153
|
+
"""create instance of a task"""
|
|
154
|
+
response = self._make_request(
|
|
155
|
+
endpoint="create",
|
|
156
|
+
env_type=env_type,
|
|
157
|
+
task_id=task_id,
|
|
158
|
+
instance_id=instance_id,
|
|
159
|
+
params=params,
|
|
160
|
+
)
|
|
161
|
+
return response["data"]
|
|
162
|
+
|
|
163
|
+
def step(
|
|
164
|
+
self,
|
|
165
|
+
instance_id: str,
|
|
166
|
+
action: Dict = None,
|
|
167
|
+
params: Dict = None,
|
|
168
|
+
) -> str:
|
|
169
|
+
"""execute step transmission"""
|
|
170
|
+
action = action or {}
|
|
171
|
+
params = params or {}
|
|
172
|
+
|
|
173
|
+
response = self._make_request(
|
|
174
|
+
endpoint="step",
|
|
175
|
+
instance_id=instance_id,
|
|
176
|
+
messages=action,
|
|
177
|
+
params=params,
|
|
178
|
+
)
|
|
179
|
+
return response["data"]
|
|
180
|
+
|
|
181
|
+
def evaluate(
|
|
182
|
+
self,
|
|
183
|
+
instance_id: str,
|
|
184
|
+
messages: Dict = None,
|
|
185
|
+
params: Dict = None,
|
|
186
|
+
) -> float:
|
|
187
|
+
"""evaluate instance execution"""
|
|
188
|
+
messages = messages or {}
|
|
189
|
+
params = params or {}
|
|
190
|
+
|
|
191
|
+
response = self._make_request(
|
|
192
|
+
endpoint="evaluate",
|
|
193
|
+
instance_id=instance_id,
|
|
194
|
+
messages=messages,
|
|
195
|
+
params=params,
|
|
196
|
+
)
|
|
197
|
+
return response["data"]
|
|
198
|
+
|
|
199
|
+
def release_instance(self, instance_id: str) -> bool:
|
|
200
|
+
"""release instance from memory"""
|
|
201
|
+
response = self._make_request(
|
|
202
|
+
endpoint="release",
|
|
203
|
+
instance_id=instance_id,
|
|
204
|
+
)
|
|
205
|
+
return response["success"]
|
|
206
|
+
|
|
207
|
+
# remined for future
|
|
208
|
+
def add_mcp_servers(self, server_configs, overwrite=False):
|
|
209
|
+
"""add mcp for future"""
|
|
210
|
+
return None
|
|
211
|
+
|
|
212
|
+
def list_tools(self, **kwargs):
|
|
213
|
+
"""list tools"""
|
|
214
|
+
if "instance_id" in kwargs:
|
|
215
|
+
# 只传get_tools_info的方法参数
|
|
216
|
+
return self.get_tools_info(
|
|
217
|
+
instance_id=kwargs.get("instance_id"),
|
|
218
|
+
messages=kwargs.get("messages", {}),
|
|
219
|
+
params=kwargs.get("params", {}),
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
return None
|
|
223
|
+
|
|
224
|
+
def call_tool(
|
|
225
|
+
self,
|
|
226
|
+
name: str,
|
|
227
|
+
arguments: Optional[dict[str, Any]] = None,
|
|
228
|
+
) -> Any:
|
|
229
|
+
"""release call tools"""
|
|
230
|
+
if arguments is None:
|
|
231
|
+
return None
|
|
232
|
+
if name == "create_instance":
|
|
233
|
+
return self.create_instance(
|
|
234
|
+
env_type=arguments.get("env_type", ""),
|
|
235
|
+
task_id=arguments.get("task_id", ""),
|
|
236
|
+
instance_id=arguments.get("instance_id", None),
|
|
237
|
+
params=arguments.get("params", {}),
|
|
238
|
+
)
|
|
239
|
+
if name == "release_instance":
|
|
240
|
+
return self.release_instance(instance_id=arguments["instance_id"])
|
|
241
|
+
if name == "evaluate":
|
|
242
|
+
return self.evaluate(
|
|
243
|
+
instance_id=arguments["instance_id"],
|
|
244
|
+
messages=arguments["messages"],
|
|
245
|
+
params=arguments["params"],
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
if name == "step":
|
|
249
|
+
return self.step(
|
|
250
|
+
instance_id=arguments["instance_id"],
|
|
251
|
+
action=arguments["action"],
|
|
252
|
+
params=arguments["params"],
|
|
253
|
+
)
|
|
254
|
+
if name in ["get_task_ids", "get_env_profile"]:
|
|
255
|
+
return self.get_env_profile(
|
|
256
|
+
env_type=arguments["env_type"],
|
|
257
|
+
split=arguments["split"],
|
|
258
|
+
params=arguments["params"],
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
logger.warning(
|
|
262
|
+
"missing function type of %s, please check the sandbox_client.py",
|
|
263
|
+
name,
|
|
264
|
+
)
|
|
265
|
+
return None
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import copy
|
|
3
|
+
from os.path import dirname, basename, isfile, join
|
|
4
|
+
import glob
|
|
5
|
+
|
|
6
|
+
modules = glob.glob(join(dirname(__file__), "*.py"))
|
|
7
|
+
__all__ = [
|
|
8
|
+
basename(f)[:-3]
|
|
9
|
+
for f in modules
|
|
10
|
+
if isfile(f) and not f.endswith("__init__.py")
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
# to ensure the sub-configs registered before set up the global config
|
|
14
|
+
all_sub_configs_contrib = copy.copy(__all__)
|
|
15
|
+
if "config" in all_sub_configs_contrib:
|
|
16
|
+
all_sub_configs_contrib.remove("config")
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from ..constant import IMAGE_TAG
|
|
7
|
+
from ..registry import SandboxRegistry
|
|
8
|
+
from ..enums import SandboxType
|
|
9
|
+
from ..box.sandbox import Sandbox
|
|
10
|
+
|
|
11
|
+
SANDBOXTYPE = "custom_sandbox"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@SandboxRegistry.register(
|
|
15
|
+
f"agentscope/runtime-sandbox-{SANDBOXTYPE}:{IMAGE_TAG}",
|
|
16
|
+
sandbox_type=SANDBOXTYPE,
|
|
17
|
+
resource_limits={"memory": "16Gi", "cpu": "4"},
|
|
18
|
+
security_level="medium",
|
|
19
|
+
timeout=60,
|
|
20
|
+
description="my sandbox",
|
|
21
|
+
environment={
|
|
22
|
+
"TAVILY_API_KEY": os.getenv("TAVILY_API_KEY", ""),
|
|
23
|
+
"AMAP_MAPS_API_KEY": os.getenv("AMAP_MAPS_API_KEY", ""),
|
|
24
|
+
},
|
|
25
|
+
)
|
|
26
|
+
class CustomSandbox(Sandbox):
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
sandbox_id: Optional[str] = None,
|
|
30
|
+
timeout: int = 3000,
|
|
31
|
+
base_url: Optional[str] = None,
|
|
32
|
+
bearer_token: Optional[str] = None,
|
|
33
|
+
):
|
|
34
|
+
super().__init__(
|
|
35
|
+
sandbox_id,
|
|
36
|
+
timeout,
|
|
37
|
+
base_url,
|
|
38
|
+
bearer_token,
|
|
39
|
+
SandboxType(SANDBOXTYPE),
|
|
40
|
+
)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from ..constant import IMAGE_TAG
|
|
5
|
+
from ..registry import SandboxRegistry
|
|
6
|
+
from ..enums import SandboxType
|
|
7
|
+
from ..box.sandbox import Sandbox
|
|
8
|
+
|
|
9
|
+
SANDBOX_TYPE = "example"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@SandboxRegistry.register(
|
|
13
|
+
f"agentscope/runtime-sandbox-{SANDBOX_TYPE}:{IMAGE_TAG}",
|
|
14
|
+
sandbox_type=SANDBOX_TYPE,
|
|
15
|
+
resource_limits={"memory": "16Gi", "cpu": "4"},
|
|
16
|
+
security_level="medium",
|
|
17
|
+
timeout=60,
|
|
18
|
+
description="Example sandbox",
|
|
19
|
+
)
|
|
20
|
+
class ExampleSandbox(Sandbox):
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
sandbox_id: Optional[str] = None,
|
|
24
|
+
timeout: int = 3000,
|
|
25
|
+
base_url: Optional[str] = None,
|
|
26
|
+
bearer_token: Optional[str] = None,
|
|
27
|
+
):
|
|
28
|
+
super().__init__(
|
|
29
|
+
sandbox_id,
|
|
30
|
+
timeout,
|
|
31
|
+
base_url,
|
|
32
|
+
bearer_token,
|
|
33
|
+
SandboxType(SANDBOX_TYPE),
|
|
34
|
+
)
|
|
35
|
+
raise NotImplementedError(
|
|
36
|
+
"This sandbox is just a template and not implemented yet.",
|
|
37
|
+
)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from enum import Enum, EnumMeta
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class DynamicEnumMeta(EnumMeta):
|
|
6
|
+
def __new__(
|
|
7
|
+
metacls,
|
|
8
|
+
cls,
|
|
9
|
+
bases,
|
|
10
|
+
classdict,
|
|
11
|
+
**kwds,
|
|
12
|
+
): # pylint: disable=bad-mcs-classmethod-argument
|
|
13
|
+
enum_class = super().__new__(metacls, cls, bases, classdict, **kwds)
|
|
14
|
+
for member in enum_class:
|
|
15
|
+
member.builtin = True
|
|
16
|
+
return enum_class
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class DynamicEnum(Enum, metaclass=DynamicEnumMeta):
|
|
20
|
+
def __init__(self, value): # pylint: disable=unused-argument
|
|
21
|
+
self.builtin = True
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def add_member(cls, name: str, value=None):
|
|
25
|
+
if name in cls.__members__:
|
|
26
|
+
raise ValueError(f"Member '{name}' already exists.")
|
|
27
|
+
|
|
28
|
+
if value is None:
|
|
29
|
+
value = name.lower()
|
|
30
|
+
|
|
31
|
+
# Add new member
|
|
32
|
+
new_member = cls._create_pseudo_member(name, value)
|
|
33
|
+
new_member.builtin = False
|
|
34
|
+
cls._member_map_[name] = new_member
|
|
35
|
+
cls._value2member_map_[value] = new_member
|
|
36
|
+
# Update ordered members
|
|
37
|
+
cls._member_names_.append(name)
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def _create_pseudo_member(cls, name, value):
|
|
41
|
+
temp = object.__new__(cls)
|
|
42
|
+
temp._value_ = value
|
|
43
|
+
temp._name_ = name
|
|
44
|
+
temp.__objclass__ = cls
|
|
45
|
+
return temp
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def get_builtin_members(cls):
|
|
49
|
+
return [member for member in cls if getattr(member, "builtin", False)]
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def get_dynamic_members(cls):
|
|
53
|
+
return [
|
|
54
|
+
member for member in cls if not getattr(member, "builtin", False)
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
def is_builtin(self):
|
|
58
|
+
return getattr(self, "builtin", False)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class SandboxType(DynamicEnum):
|
|
62
|
+
"""Sandbox type enumeration"""
|
|
63
|
+
|
|
64
|
+
DUMMY = "dummy"
|
|
65
|
+
BASE = "base"
|
|
66
|
+
BROWSER = "browser"
|
|
67
|
+
FILESYSTEM = "filesystem"
|
|
68
|
+
APPWORLD = "appworld"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from .base_mapping import Mapping
|
|
3
|
+
from .base_set import SetCollection
|
|
4
|
+
from .base_queue import Queue
|
|
5
|
+
from .redis_set import RedisSetCollection
|
|
6
|
+
from .redis_queue import RedisQueue
|
|
7
|
+
from .redis_mapping import RedisMapping
|
|
8
|
+
from .in_memory_queue import InMemoryQueue
|
|
9
|
+
from .in_memory_set import InMemorySetCollection
|
|
10
|
+
from .in_memory_mapping import InMemoryMapping
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"Mapping",
|
|
14
|
+
"SetCollection",
|
|
15
|
+
"Queue",
|
|
16
|
+
"RedisSetCollection",
|
|
17
|
+
"RedisQueue",
|
|
18
|
+
"RedisMapping",
|
|
19
|
+
"InMemoryQueue",
|
|
20
|
+
"InMemorySetCollection",
|
|
21
|
+
"InMemoryMapping",
|
|
22
|
+
]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Mapping(ABC):
|
|
6
|
+
@abstractmethod
|
|
7
|
+
def set(self, key: str, value: dict):
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
@abstractmethod
|
|
11
|
+
def get(self, key: str) -> dict:
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
@abstractmethod
|
|
15
|
+
def delete(self, key: str):
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def scan(self, prefix: str):
|
|
20
|
+
pass
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# file: base_queue.py
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Queue(ABC):
|
|
7
|
+
@abstractmethod
|
|
8
|
+
def enqueue(self, item: dict):
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
@abstractmethod
|
|
12
|
+
def dequeue(self) -> dict:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
@abstractmethod
|
|
16
|
+
def peek(self) -> dict:
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def is_empty(self) -> bool:
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def size(self) -> int:
|
|
25
|
+
pass
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# file: base_set_collection.py
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class SetCollection(ABC):
|
|
7
|
+
@abstractmethod
|
|
8
|
+
def add(self, value: str):
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
@abstractmethod
|
|
12
|
+
def remove(self, value: str):
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
@abstractmethod
|
|
16
|
+
def contains(self, value: str) -> bool:
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def clear(self):
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def to_list(self) -> list:
|
|
25
|
+
pass
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from .base_mapping import Mapping
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class InMemoryMapping(Mapping):
|
|
6
|
+
def __init__(self):
|
|
7
|
+
self.store = {}
|
|
8
|
+
|
|
9
|
+
def set(self, key: str, value: dict):
|
|
10
|
+
self.store[key] = value
|
|
11
|
+
|
|
12
|
+
def get(self, key: str) -> dict:
|
|
13
|
+
return self.store.get(key)
|
|
14
|
+
|
|
15
|
+
def delete(self, key: str):
|
|
16
|
+
if key in self.store:
|
|
17
|
+
del self.store[key]
|
|
18
|
+
|
|
19
|
+
def scan(self, prefix: str):
|
|
20
|
+
for key in list(self.store.keys()):
|
|
21
|
+
if key.startswith(prefix):
|
|
22
|
+
yield key
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# file: in_memory_queue.py
|
|
3
|
+
from .base_queue import Queue
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class InMemoryQueue(Queue):
|
|
7
|
+
def __init__(self):
|
|
8
|
+
self.queue = []
|
|
9
|
+
|
|
10
|
+
def enqueue(self, item: dict):
|
|
11
|
+
self.queue.append(item)
|
|
12
|
+
|
|
13
|
+
def dequeue(self):
|
|
14
|
+
if self.queue:
|
|
15
|
+
return self.queue.pop(0)
|
|
16
|
+
return None
|
|
17
|
+
|
|
18
|
+
def peek(self):
|
|
19
|
+
if self.queue:
|
|
20
|
+
return self.queue[0]
|
|
21
|
+
return None
|
|
22
|
+
|
|
23
|
+
def is_empty(self) -> bool:
|
|
24
|
+
return len(self.queue) == 0
|
|
25
|
+
|
|
26
|
+
def size(self) -> int:
|
|
27
|
+
"""Returns the number of items in the queue."""
|
|
28
|
+
return len(self.queue)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# file: in_memory_set_collection.py
|
|
3
|
+
from .base_set import SetCollection
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class InMemorySetCollection(SetCollection):
|
|
7
|
+
def __init__(self):
|
|
8
|
+
self.set = set()
|
|
9
|
+
|
|
10
|
+
def add(self, value: str):
|
|
11
|
+
if value in self.set:
|
|
12
|
+
return False
|
|
13
|
+
else:
|
|
14
|
+
self.set.add(value)
|
|
15
|
+
return True
|
|
16
|
+
|
|
17
|
+
def remove(self, value: str):
|
|
18
|
+
self.set.discard(value)
|
|
19
|
+
|
|
20
|
+
def contains(self, value: str) -> bool:
|
|
21
|
+
return value in self.set
|
|
22
|
+
|
|
23
|
+
def clear(self):
|
|
24
|
+
self.set.clear()
|
|
25
|
+
|
|
26
|
+
def to_list(self) -> list:
|
|
27
|
+
return list(self.set)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
from .base_mapping import Mapping
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class RedisMapping(Mapping):
|
|
8
|
+
def __init__(self, redis_client):
|
|
9
|
+
self.client = redis_client
|
|
10
|
+
|
|
11
|
+
def set(self, key: str, value: dict):
|
|
12
|
+
self.client.set(key, json.dumps(value))
|
|
13
|
+
|
|
14
|
+
def get(self, key: str) -> dict:
|
|
15
|
+
value = self.client.get(key)
|
|
16
|
+
return json.loads(value) if value else None
|
|
17
|
+
|
|
18
|
+
def delete(self, key: str):
|
|
19
|
+
self.client.delete(key)
|
|
20
|
+
|
|
21
|
+
def scan(self, prefix: str):
|
|
22
|
+
cursor = 0
|
|
23
|
+
while cursor != 0:
|
|
24
|
+
cursor, keys = self.client.scan(cursor=cursor, match=f"{prefix}*")
|
|
25
|
+
for key in keys:
|
|
26
|
+
yield key.decode("utf-8")
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# file: redis_queue.py
|
|
3
|
+
import json
|
|
4
|
+
from .base_queue import Queue
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class RedisQueue(Queue):
|
|
8
|
+
def __init__(self, redis_client, queue_name: str):
|
|
9
|
+
self.client = redis_client
|
|
10
|
+
self.queue_name = queue_name
|
|
11
|
+
|
|
12
|
+
def enqueue(self, item: dict):
|
|
13
|
+
self.client.rpush(self.queue_name, json.dumps(item))
|
|
14
|
+
|
|
15
|
+
def dequeue(self) -> dict:
|
|
16
|
+
item = self.client.lpop(self.queue_name)
|
|
17
|
+
return json.loads(item) if item is not None else None
|
|
18
|
+
|
|
19
|
+
def peek(self) -> dict:
|
|
20
|
+
item = self.client.lindex(self.queue_name, 0)
|
|
21
|
+
return json.loads(item) if item is not None else None
|
|
22
|
+
|
|
23
|
+
def is_empty(self) -> bool:
|
|
24
|
+
return self.client.llen(self.queue_name) == 0
|
|
25
|
+
|
|
26
|
+
def size(self) -> int:
|
|
27
|
+
return self.client.llen(self.queue_name)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from .base_set import SetCollection
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class RedisSetCollection(SetCollection):
|
|
6
|
+
def __init__(self, redis_client, set_name: str):
|
|
7
|
+
self.client = redis_client
|
|
8
|
+
self.set_name = set_name
|
|
9
|
+
|
|
10
|
+
def add(self, value: str):
|
|
11
|
+
return self.client.sadd(self.set_name, value) == 1
|
|
12
|
+
|
|
13
|
+
def remove(self, value: str):
|
|
14
|
+
self.client.srem(self.set_name, value)
|
|
15
|
+
|
|
16
|
+
def contains(self, value: str) -> bool:
|
|
17
|
+
return self.client.sismember(self.set_name, value)
|
|
18
|
+
|
|
19
|
+
def clear(self):
|
|
20
|
+
self.client.delete(self.set_name)
|
|
21
|
+
|
|
22
|
+
def to_list(self) -> list:
|
|
23
|
+
return list(self.client.smembers(self.set_name))
|