agentscope-runtime 0.1.3__py3-none-any.whl → 0.1.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.
- agentscope_runtime/engine/agents/agentscope_agent/agent.py +56 -12
- agentscope_runtime/engine/agents/agentscope_agent/hooks.py +2 -1
- agentscope_runtime/engine/agents/agno_agent.py +11 -5
- agentscope_runtime/engine/agents/autogen_agent.py +10 -4
- agentscope_runtime/engine/agents/utils.py +53 -0
- agentscope_runtime/engine/services/context_manager.py +2 -0
- agentscope_runtime/engine/services/mem0_memory_service.py +124 -0
- agentscope_runtime/engine/services/memory_service.py +2 -1
- agentscope_runtime/engine/services/redis_session_history_service.py +4 -3
- agentscope_runtime/engine/services/sandbox_service.py +6 -16
- agentscope_runtime/engine/services/session_history_service.py +4 -3
- agentscope_runtime/engine/services/tablestore_memory_service.py +304 -0
- agentscope_runtime/engine/services/tablestore_rag_service.py +143 -0
- agentscope_runtime/engine/services/tablestore_session_history_service.py +293 -0
- agentscope_runtime/engine/services/utils/__init__.py +0 -0
- agentscope_runtime/engine/services/utils/tablestore_service_utils.py +352 -0
- agentscope_runtime/sandbox/box/base/base_sandbox.py +2 -2
- agentscope_runtime/sandbox/box/browser/browser_sandbox.py +2 -2
- agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +2 -2
- agentscope_runtime/sandbox/box/training_box/training_box.py +4 -12
- agentscope_runtime/sandbox/build.py +37 -17
- agentscope_runtime/sandbox/client/http_client.py +42 -10
- agentscope_runtime/sandbox/client/training_client.py +0 -1
- agentscope_runtime/sandbox/constant.py +26 -0
- agentscope_runtime/sandbox/custom/custom_sandbox.py +5 -5
- agentscope_runtime/sandbox/custom/example.py +2 -2
- agentscope_runtime/sandbox/manager/collections/in_memory_mapping.py +4 -2
- agentscope_runtime/sandbox/manager/collections/redis_mapping.py +25 -9
- agentscope_runtime/sandbox/manager/container_clients/__init__.py +0 -10
- agentscope_runtime/sandbox/manager/container_clients/agentrun_client.py +1096 -0
- agentscope_runtime/sandbox/manager/container_clients/docker_client.py +25 -201
- agentscope_runtime/sandbox/manager/container_clients/kubernetes_client.py +1 -3
- agentscope_runtime/sandbox/manager/sandbox_manager.py +40 -13
- agentscope_runtime/sandbox/manager/server/app.py +27 -0
- agentscope_runtime/sandbox/manager/server/config.py +30 -2
- agentscope_runtime/sandbox/model/container.py +1 -1
- agentscope_runtime/sandbox/model/manager_config.py +93 -5
- agentscope_runtime/sandbox/utils.py +97 -0
- agentscope_runtime/version.py +1 -1
- {agentscope_runtime-0.1.3.dist-info → agentscope_runtime-0.1.5.dist-info}/METADATA +56 -57
- {agentscope_runtime-0.1.3.dist-info → agentscope_runtime-0.1.5.dist-info}/RECORD +45 -40
- agentscope_runtime/engine/agents/llm_agent.py +0 -51
- agentscope_runtime/engine/llms/__init__.py +0 -3
- agentscope_runtime/engine/llms/base_llm.py +0 -60
- agentscope_runtime/engine/llms/qwen_llm.py +0 -47
- {agentscope_runtime-0.1.3.dist-info → agentscope_runtime-0.1.5.dist-info}/WHEEL +0 -0
- {agentscope_runtime-0.1.3.dist-info → agentscope_runtime-0.1.5.dist-info}/entry_points.txt +0 -0
- {agentscope_runtime-0.1.3.dist-info → agentscope_runtime-0.1.5.dist-info}/licenses/LICENSE +0 -0
- {agentscope_runtime-0.1.3.dist-info → agentscope_runtime-0.1.5.dist-info}/top_level.txt +0 -0
|
@@ -5,21 +5,13 @@ Module for the Training Sandbox implementation.
|
|
|
5
5
|
This module provides a sandbox environment for training tasks
|
|
6
6
|
with specific configuration and tool calling methods.
|
|
7
7
|
"""
|
|
8
|
-
import platform
|
|
9
8
|
from typing import Dict, Optional
|
|
10
9
|
import os
|
|
11
10
|
|
|
11
|
+
from ...utils import build_image_uri
|
|
12
12
|
from ...registry import SandboxRegistry
|
|
13
13
|
from ...enums import SandboxType
|
|
14
14
|
from ...box.sandbox import Sandbox
|
|
15
|
-
from ...constant import IMAGE_TAG
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def get_image_tag() -> str:
|
|
19
|
-
machine = platform.machine().lower()
|
|
20
|
-
if machine in ("arm64", "aarch64", "armv7l", "armv8"):
|
|
21
|
-
return f"{IMAGE_TAG}-arm64"
|
|
22
|
-
return IMAGE_TAG
|
|
23
15
|
|
|
24
16
|
|
|
25
17
|
class TrainingSandbox(Sandbox):
|
|
@@ -214,7 +206,7 @@ class TrainingSandbox(Sandbox):
|
|
|
214
206
|
|
|
215
207
|
|
|
216
208
|
@SandboxRegistry.register(
|
|
217
|
-
|
|
209
|
+
build_image_uri("runtime-sandbox-appworld", arm64_compatible=False),
|
|
218
210
|
sandbox_type=SandboxType.APPWORLD,
|
|
219
211
|
runtime_config={"shm_size": "5.06gb"},
|
|
220
212
|
security_level="medium",
|
|
@@ -258,7 +250,7 @@ DATASET_SUB_TYPE = os.environ.get("DATASET_SUB_TYPE", "multi_turn")
|
|
|
258
250
|
|
|
259
251
|
|
|
260
252
|
@SandboxRegistry.register(
|
|
261
|
-
|
|
253
|
+
build_image_uri("runtime-sandbox-bfcl", arm64_compatible=False),
|
|
262
254
|
sandbox_type=SandboxType.BFCL,
|
|
263
255
|
runtime_config={"shm_size": "8.06gb"},
|
|
264
256
|
security_level="medium",
|
|
@@ -309,7 +301,7 @@ class BFCLSandbox(TrainingSandbox):
|
|
|
309
301
|
|
|
310
302
|
|
|
311
303
|
@SandboxRegistry.register(
|
|
312
|
-
|
|
304
|
+
build_image_uri("runtime-sandbox-webshop", arm64_compatible=False),
|
|
313
305
|
sandbox_type=SandboxType.WEBSHOP,
|
|
314
306
|
runtime_config={"shm_size": "5.06gb"},
|
|
315
307
|
security_level="medium",
|
|
@@ -11,6 +11,10 @@ import requests
|
|
|
11
11
|
|
|
12
12
|
from .enums import SandboxType
|
|
13
13
|
from .registry import SandboxRegistry
|
|
14
|
+
from .utils import dynamic_import
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
14
18
|
|
|
15
19
|
|
|
16
20
|
def find_free_port(start_port, end_port):
|
|
@@ -18,7 +22,7 @@ def find_free_port(start_port, end_port):
|
|
|
18
22
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
|
19
23
|
if sock.connect_ex(("localhost", port)) != 0:
|
|
20
24
|
return port
|
|
21
|
-
|
|
25
|
+
logger.error(
|
|
22
26
|
f"No free ports available in the range {start_port}-{end_port}",
|
|
23
27
|
)
|
|
24
28
|
raise RuntimeError(
|
|
@@ -30,7 +34,7 @@ def check_health(url, secret_token, timeout=120, interval=5):
|
|
|
30
34
|
headers = {"Authorization": f"Bearer {secret_token}"}
|
|
31
35
|
spent_time = 0
|
|
32
36
|
while spent_time < timeout:
|
|
33
|
-
|
|
37
|
+
logger.info(
|
|
34
38
|
f"Attempting to connect to {url} (Elapsed time: {spent_time} "
|
|
35
39
|
f"seconds)...",
|
|
36
40
|
)
|
|
@@ -41,13 +45,13 @@ def check_health(url, secret_token, timeout=120, interval=5):
|
|
|
41
45
|
return True
|
|
42
46
|
except requests.exceptions.RequestException:
|
|
43
47
|
pass
|
|
44
|
-
|
|
48
|
+
logger.info(
|
|
45
49
|
f"Health check failed for {url}. Retrying in {interval} "
|
|
46
50
|
f"seconds...",
|
|
47
51
|
)
|
|
48
52
|
time.sleep(interval)
|
|
49
53
|
spent_time += interval
|
|
50
|
-
|
|
54
|
+
logger.error(f"Health check failed for {url} after {timeout} seconds.")
|
|
51
55
|
return False
|
|
52
56
|
|
|
53
57
|
|
|
@@ -57,10 +61,10 @@ def build_image(build_type, dockerfile_path=None):
|
|
|
57
61
|
f"src/agentscope_runtime/sandbox/box/{build_type}/Dockerfile"
|
|
58
62
|
)
|
|
59
63
|
|
|
60
|
-
|
|
64
|
+
logger.info(f"Building {build_type} with `{dockerfile_path}`...")
|
|
61
65
|
|
|
62
66
|
# Initialize and update Git submodule
|
|
63
|
-
|
|
67
|
+
logger.info("Initializing and updating Git submodule...")
|
|
64
68
|
subprocess.run(
|
|
65
69
|
["git", "submodule", "update", "--init", "--recursive"],
|
|
66
70
|
check=True,
|
|
@@ -69,7 +73,7 @@ def build_image(build_type, dockerfile_path=None):
|
|
|
69
73
|
secret_token = "secret_token123"
|
|
70
74
|
image_name = SandboxRegistry.get_image_by_type(build_type)
|
|
71
75
|
|
|
72
|
-
|
|
76
|
+
logger.info(f"Building Docker image {image_name}...")
|
|
73
77
|
|
|
74
78
|
# Check if image exists
|
|
75
79
|
result = subprocess.run(
|
|
@@ -87,7 +91,7 @@ def build_image(build_type, dockerfile_path=None):
|
|
|
87
91
|
f"you want to overwrite it? (y/N): ",
|
|
88
92
|
)
|
|
89
93
|
if choice.lower() != "y":
|
|
90
|
-
|
|
94
|
+
logger.info("Exiting without overwriting the existing image.")
|
|
91
95
|
return
|
|
92
96
|
|
|
93
97
|
if not os.path.exists(dockerfile_path):
|
|
@@ -109,9 +113,9 @@ def build_image(build_type, dockerfile_path=None):
|
|
|
109
113
|
],
|
|
110
114
|
check=False,
|
|
111
115
|
)
|
|
112
|
-
|
|
116
|
+
logger.info(f"Docker image {image_name}dev built successfully.")
|
|
113
117
|
|
|
114
|
-
|
|
118
|
+
logger.info(f"Start to build image {image_name}.")
|
|
115
119
|
|
|
116
120
|
# Run the container with port mapping and environment variable
|
|
117
121
|
free_port = find_free_port(8080, 8090)
|
|
@@ -131,7 +135,7 @@ def build_image(build_type, dockerfile_path=None):
|
|
|
131
135
|
check=False,
|
|
132
136
|
)
|
|
133
137
|
container_id = result.stdout.strip()
|
|
134
|
-
|
|
138
|
+
logger.info(f"Running container {container_id} on port {free_port}")
|
|
135
139
|
|
|
136
140
|
# Check health endpoints
|
|
137
141
|
fastapi_health_url = f"http://localhost:{free_port}/fastapi/healthz"
|
|
@@ -149,18 +153,18 @@ def build_image(build_type, dockerfile_path=None):
|
|
|
149
153
|
browser_healthy = True
|
|
150
154
|
|
|
151
155
|
if browser_healthy and fastapi_healthy:
|
|
152
|
-
|
|
156
|
+
logger.info("Health checks passed.")
|
|
153
157
|
subprocess.run(
|
|
154
158
|
["docker", "commit", container_id, f"{image_name}"],
|
|
155
159
|
check=True,
|
|
156
160
|
)
|
|
157
|
-
|
|
161
|
+
logger.info(
|
|
158
162
|
f"Docker image {image_name} committed successfully.",
|
|
159
163
|
)
|
|
160
164
|
subprocess.run(["docker", "stop", container_id], check=True)
|
|
161
165
|
subprocess.run(["docker", "rm", container_id], check=True)
|
|
162
166
|
else:
|
|
163
|
-
|
|
167
|
+
logger.error("Health checks failed.")
|
|
164
168
|
subprocess.run(["docker", "stop", container_id], check=True)
|
|
165
169
|
|
|
166
170
|
choice = input(
|
|
@@ -171,9 +175,9 @@ def build_image(build_type, dockerfile_path=None):
|
|
|
171
175
|
["docker", "rmi", "-f", f"{image_name}dev"],
|
|
172
176
|
check=True,
|
|
173
177
|
)
|
|
174
|
-
|
|
178
|
+
logger.info(f"Dev image {image_name}dev deleted.")
|
|
175
179
|
else:
|
|
176
|
-
|
|
180
|
+
logger.info(f"Dev image {image_name}dev retained.")
|
|
177
181
|
|
|
178
182
|
|
|
179
183
|
def main():
|
|
@@ -182,8 +186,8 @@ def main():
|
|
|
182
186
|
)
|
|
183
187
|
parser.add_argument(
|
|
184
188
|
"build_type",
|
|
189
|
+
nargs="?",
|
|
185
190
|
default="base",
|
|
186
|
-
choices=[x.value for x in SandboxType] + ["all"],
|
|
187
191
|
help="Specify the build type to execute.",
|
|
188
192
|
)
|
|
189
193
|
|
|
@@ -193,13 +197,29 @@ def main():
|
|
|
193
197
|
help="Specify the path for the Dockerfile.",
|
|
194
198
|
)
|
|
195
199
|
|
|
200
|
+
parser.add_argument(
|
|
201
|
+
"--extension",
|
|
202
|
+
action="append",
|
|
203
|
+
help="Path to a Python file or module name to load as an extension",
|
|
204
|
+
)
|
|
205
|
+
|
|
196
206
|
args = parser.parse_args()
|
|
197
207
|
|
|
208
|
+
if args.extension:
|
|
209
|
+
for ext in args.extension:
|
|
210
|
+
logger.info(f"Loading extension: {ext}")
|
|
211
|
+
mod = dynamic_import(ext)
|
|
212
|
+
logger.info(f"Extension loaded: {mod.__name__}")
|
|
213
|
+
|
|
198
214
|
if args.build_type == "all":
|
|
199
215
|
# Only build the built-in images
|
|
200
216
|
for build_type in [x.value for x in SandboxType.get_builtin_members()]:
|
|
201
217
|
build_image(build_type)
|
|
202
218
|
else:
|
|
219
|
+
assert args.build_type in [
|
|
220
|
+
x.value for x in SandboxType
|
|
221
|
+
], f"Invalid build type: {args.build_type}"
|
|
222
|
+
|
|
203
223
|
if args.build_type not in [
|
|
204
224
|
x.value for x in SandboxType.get_builtin_members()
|
|
205
225
|
]:
|
|
@@ -69,7 +69,7 @@ class SandboxHttpClient:
|
|
|
69
69
|
def __init__(
|
|
70
70
|
self,
|
|
71
71
|
model: Optional[ContainerModel] = None,
|
|
72
|
-
timeout: int =
|
|
72
|
+
timeout: int = 60,
|
|
73
73
|
enable_browser: bool = True,
|
|
74
74
|
domain: str = "localhost",
|
|
75
75
|
) -> None:
|
|
@@ -95,7 +95,10 @@ class SandboxHttpClient:
|
|
|
95
95
|
self.secret = model.runtime_token
|
|
96
96
|
|
|
97
97
|
# Update headers with secret if provided
|
|
98
|
-
headers = {
|
|
98
|
+
headers = {
|
|
99
|
+
"Content-Type": "application/json",
|
|
100
|
+
"x-agentrun-session-id": "s" + self.session_id,
|
|
101
|
+
}
|
|
99
102
|
if self.secret:
|
|
100
103
|
headers["Authorization"] = f"Bearer {self.secret}"
|
|
101
104
|
self.session.headers.update(headers)
|
|
@@ -112,16 +115,20 @@ class SandboxHttpClient:
|
|
|
112
115
|
base_url=self.browser_url,
|
|
113
116
|
)
|
|
114
117
|
|
|
118
|
+
headers = {"x-agentrun-session-id": "s" + self.session_id}
|
|
119
|
+
|
|
115
120
|
# Create a new browser session if it doesn't exist
|
|
116
121
|
try:
|
|
117
122
|
# Try to connet to existing session
|
|
118
123
|
self.steel_client.sessions.retrieve(
|
|
119
124
|
BROWSER_SESSION_ID,
|
|
125
|
+
extra_headers=headers,
|
|
120
126
|
)
|
|
121
127
|
except Exception:
|
|
122
128
|
# Session not found, create a new one
|
|
123
129
|
self.steel_client.sessions.create(
|
|
124
130
|
session_id=BROWSER_SESSION_ID,
|
|
131
|
+
extra_headers=headers,
|
|
125
132
|
)
|
|
126
133
|
|
|
127
134
|
return self
|
|
@@ -246,7 +253,10 @@ class SandboxHttpClient:
|
|
|
246
253
|
"""Run an IPython cell."""
|
|
247
254
|
try:
|
|
248
255
|
endpoint = f"{self.base_url}/tools/run_ipython_cell"
|
|
249
|
-
response = self.session.post(
|
|
256
|
+
response = self.session.post(
|
|
257
|
+
endpoint,
|
|
258
|
+
json={"code": code},
|
|
259
|
+
)
|
|
250
260
|
response.raise_for_status()
|
|
251
261
|
return response.json()
|
|
252
262
|
except requests.exceptions.RequestException as e:
|
|
@@ -379,7 +389,11 @@ class SandboxHttpClient:
|
|
|
379
389
|
endpoint = f"{self.base_url}/workspace/files"
|
|
380
390
|
params = {"file_path": file_path}
|
|
381
391
|
data = {"content": content}
|
|
382
|
-
response = self.session.post(
|
|
392
|
+
response = self.session.post(
|
|
393
|
+
endpoint,
|
|
394
|
+
params=params,
|
|
395
|
+
json=data,
|
|
396
|
+
)
|
|
383
397
|
response.raise_for_status()
|
|
384
398
|
return response.json()
|
|
385
399
|
except requests.exceptions.RequestException as e:
|
|
@@ -402,7 +416,10 @@ class SandboxHttpClient:
|
|
|
402
416
|
try:
|
|
403
417
|
endpoint = f"{self.base_url}/workspace/list-directories"
|
|
404
418
|
params = {"directory": directory}
|
|
405
|
-
response = self.session.get(
|
|
419
|
+
response = self.session.get(
|
|
420
|
+
endpoint,
|
|
421
|
+
params=params,
|
|
422
|
+
)
|
|
406
423
|
response.raise_for_status()
|
|
407
424
|
return response.json()
|
|
408
425
|
except requests.exceptions.RequestException as e:
|
|
@@ -419,7 +436,10 @@ class SandboxHttpClient:
|
|
|
419
436
|
try:
|
|
420
437
|
endpoint = f"{self.base_url}/workspace/directories"
|
|
421
438
|
params = {"directory_path": directory_path}
|
|
422
|
-
response = self.session.post(
|
|
439
|
+
response = self.session.post(
|
|
440
|
+
endpoint,
|
|
441
|
+
params=params,
|
|
442
|
+
)
|
|
423
443
|
response.raise_for_status()
|
|
424
444
|
return response.json()
|
|
425
445
|
except requests.exceptions.RequestException as e:
|
|
@@ -438,7 +458,10 @@ class SandboxHttpClient:
|
|
|
438
458
|
try:
|
|
439
459
|
endpoint = f"{self.base_url}/workspace/files"
|
|
440
460
|
params = {"file_path": file_path}
|
|
441
|
-
response = self.session.delete(
|
|
461
|
+
response = self.session.delete(
|
|
462
|
+
endpoint,
|
|
463
|
+
params=params,
|
|
464
|
+
)
|
|
442
465
|
response.raise_for_status()
|
|
443
466
|
return response.json()
|
|
444
467
|
except requests.exceptions.RequestException as e:
|
|
@@ -461,7 +484,10 @@ class SandboxHttpClient:
|
|
|
461
484
|
try:
|
|
462
485
|
endpoint = f"{self.base_url}/workspace/directories"
|
|
463
486
|
params = {"directory_path": directory_path, "recursive": recursive}
|
|
464
|
-
response = self.session.delete(
|
|
487
|
+
response = self.session.delete(
|
|
488
|
+
endpoint,
|
|
489
|
+
params=params,
|
|
490
|
+
)
|
|
465
491
|
response.raise_for_status()
|
|
466
492
|
return response.json()
|
|
467
493
|
except requests.exceptions.RequestException as e:
|
|
@@ -487,7 +513,10 @@ class SandboxHttpClient:
|
|
|
487
513
|
"source_path": source_path,
|
|
488
514
|
"destination_path": destination_path,
|
|
489
515
|
}
|
|
490
|
-
response = self.session.put(
|
|
516
|
+
response = self.session.put(
|
|
517
|
+
endpoint,
|
|
518
|
+
params=params,
|
|
519
|
+
)
|
|
491
520
|
response.raise_for_status()
|
|
492
521
|
return response.json()
|
|
493
522
|
except requests.exceptions.RequestException as e:
|
|
@@ -514,7 +543,10 @@ class SandboxHttpClient:
|
|
|
514
543
|
"source_path": source_path,
|
|
515
544
|
"destination_path": destination_path,
|
|
516
545
|
}
|
|
517
|
-
response = self.session.post(
|
|
546
|
+
response = self.session.post(
|
|
547
|
+
endpoint,
|
|
548
|
+
params=params,
|
|
549
|
+
)
|
|
518
550
|
response.raise_for_status()
|
|
519
551
|
return response.json()
|
|
520
552
|
except requests.exceptions.RequestException as e:
|
|
@@ -212,7 +212,6 @@ class TrainingSandboxClient:
|
|
|
212
212
|
def list_tools(self, **kwargs):
|
|
213
213
|
"""list tools"""
|
|
214
214
|
if "instance_id" in kwargs:
|
|
215
|
-
# 只传get_tools_info的方法参数
|
|
216
215
|
return self.get_tools_info(
|
|
217
216
|
instance_id=kwargs.get("instance_id"),
|
|
218
217
|
messages=kwargs.get("messages", {}),
|
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
import os
|
|
3
|
+
import sys
|
|
4
|
+
import logging
|
|
3
5
|
|
|
6
|
+
logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
# Image Registry: default "", means using Docker Hub.
|
|
9
|
+
# For AgentScope official registry, use
|
|
10
|
+
# "agentscope-registry.ap-southeast-1.cr.aliyuncs.com"
|
|
11
|
+
REGISTRY = os.getenv("RUNTIME_SANDBOX_REGISTRY", "")
|
|
12
|
+
if REGISTRY == "":
|
|
13
|
+
agentscope_acr = "agentscope-registry.ap-southeast-1.cr.aliyuncs.com"
|
|
14
|
+
if sys.platform.startswith("win"):
|
|
15
|
+
cmd = f"set RUNTIME_SANDBOX_REGISTRY={agentscope_acr}"
|
|
16
|
+
else:
|
|
17
|
+
cmd = f"export RUNTIME_SANDBOX_REGISTRY={agentscope_acr}"
|
|
18
|
+
logger.warning(
|
|
19
|
+
"Using Docker Hub as image registry. If pulling is slow or fails, "
|
|
20
|
+
f"you can switch to the AgentScope official registry by running:\n "
|
|
21
|
+
f"{cmd}\n",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
# Image Namespace
|
|
25
|
+
IMAGE_NAMESPACE = os.getenv("RUNTIME_SANDBOX_IMAGE_NAMESPACE", "agentscope")
|
|
26
|
+
|
|
27
|
+
# Image Tag
|
|
4
28
|
IMAGE_TAG = os.getenv("RUNTIME_SANDBOX_IMAGE_TAG", "latest")
|
|
29
|
+
|
|
30
|
+
# Browser Session ID
|
|
5
31
|
BROWSER_SESSION_ID = "123e4567-e89b-12d3-a456-426614174000"
|
|
@@ -3,17 +3,17 @@ import os
|
|
|
3
3
|
|
|
4
4
|
from typing import Optional
|
|
5
5
|
|
|
6
|
-
from ..
|
|
6
|
+
from ..utils import build_image_uri
|
|
7
7
|
from ..registry import SandboxRegistry
|
|
8
8
|
from ..enums import SandboxType
|
|
9
9
|
from ..box.sandbox import Sandbox
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
SANDBOX_TYPE = "custom_sandbox"
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
@SandboxRegistry.register(
|
|
15
|
-
f"
|
|
16
|
-
sandbox_type=
|
|
15
|
+
build_image_uri(f"runtime-sandbox-{SANDBOX_TYPE}"),
|
|
16
|
+
sandbox_type=SANDBOX_TYPE,
|
|
17
17
|
security_level="medium",
|
|
18
18
|
timeout=60,
|
|
19
19
|
description="my sandbox",
|
|
@@ -35,5 +35,5 @@ class CustomSandbox(Sandbox):
|
|
|
35
35
|
timeout,
|
|
36
36
|
base_url,
|
|
37
37
|
bearer_token,
|
|
38
|
-
SandboxType(
|
|
38
|
+
SandboxType(SANDBOX_TYPE),
|
|
39
39
|
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
from typing import Optional
|
|
3
3
|
|
|
4
|
-
from ..
|
|
4
|
+
from ..utils import build_image_uri
|
|
5
5
|
from ..registry import SandboxRegistry
|
|
6
6
|
from ..enums import SandboxType
|
|
7
7
|
from ..box.sandbox import Sandbox
|
|
@@ -10,7 +10,7 @@ SANDBOX_TYPE = "example"
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
@SandboxRegistry.register(
|
|
13
|
-
f"
|
|
13
|
+
build_image_uri(f"runtime-sandbox-{SANDBOX_TYPE}"),
|
|
14
14
|
sandbox_type=SANDBOX_TYPE,
|
|
15
15
|
security_level="medium",
|
|
16
16
|
timeout=60,
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
2
4
|
from .base_mapping import Mapping
|
|
3
5
|
|
|
4
6
|
|
|
@@ -6,10 +8,10 @@ class InMemoryMapping(Mapping):
|
|
|
6
8
|
def __init__(self):
|
|
7
9
|
self.store = {}
|
|
8
10
|
|
|
9
|
-
def set(self, key: str, value:
|
|
11
|
+
def set(self, key: str, value: Any):
|
|
10
12
|
self.store[key] = value
|
|
11
13
|
|
|
12
|
-
def get(self, key: str) ->
|
|
14
|
+
def get(self, key: str) -> Any:
|
|
13
15
|
return self.store.get(key)
|
|
14
16
|
|
|
15
17
|
def delete(self, key: str):
|
|
@@ -1,26 +1,42 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
import json
|
|
3
3
|
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
4
6
|
from .base_mapping import Mapping
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
class RedisMapping(Mapping):
|
|
8
|
-
def __init__(self, redis_client):
|
|
10
|
+
def __init__(self, redis_client, prefix: str = ""):
|
|
9
11
|
self.client = redis_client
|
|
12
|
+
self.prefix = prefix.rstrip(":") + ":" if prefix else ""
|
|
13
|
+
|
|
14
|
+
def _get_full_key(self, key: str) -> str:
|
|
15
|
+
return f"{self.prefix}{key}"
|
|
16
|
+
|
|
17
|
+
def _strip_prefix(self, full_key: str) -> str:
|
|
18
|
+
if self.prefix and full_key.startswith(self.prefix):
|
|
19
|
+
return full_key[len(self.prefix) :]
|
|
20
|
+
return full_key
|
|
10
21
|
|
|
11
|
-
def set(self, key: str, value:
|
|
12
|
-
self.client.set(key, json.dumps(value))
|
|
22
|
+
def set(self, key: str, value: Any):
|
|
23
|
+
self.client.set(self._get_full_key(key), json.dumps(value))
|
|
13
24
|
|
|
14
|
-
def get(self, key: str) ->
|
|
15
|
-
value = self.client.get(key)
|
|
25
|
+
def get(self, key: str) -> Any:
|
|
26
|
+
value = self.client.get(self._get_full_key(key))
|
|
16
27
|
return json.loads(value) if value else None
|
|
17
28
|
|
|
18
29
|
def delete(self, key: str):
|
|
19
|
-
self.client.delete(key)
|
|
30
|
+
self.client.delete(self._get_full_key(key))
|
|
20
31
|
|
|
21
|
-
def scan(self, prefix: str):
|
|
32
|
+
def scan(self, prefix: str = ""):
|
|
33
|
+
search_pattern = f"{self._get_full_key(prefix)}*"
|
|
22
34
|
cursor = 0
|
|
23
35
|
while cursor != 0:
|
|
24
|
-
cursor, keys = self.client.scan(
|
|
36
|
+
cursor, keys = self.client.scan(
|
|
37
|
+
cursor=cursor,
|
|
38
|
+
match=search_pattern,
|
|
39
|
+
)
|
|
25
40
|
for key in keys:
|
|
26
|
-
|
|
41
|
+
decoded_key = key.decode("utf-8")
|
|
42
|
+
yield self._strip_prefix(decoded_key)
|