agentscope-runtime 0.1.5b2__py3-none-any.whl → 0.2.0b2__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/common/__init__.py +0 -0
- agentscope_runtime/common/collections/in_memory_mapping.py +27 -0
- agentscope_runtime/common/collections/redis_mapping.py +42 -0
- agentscope_runtime/common/container_clients/__init__.py +0 -0
- agentscope_runtime/common/container_clients/agentrun_client.py +1098 -0
- agentscope_runtime/common/container_clients/docker_client.py +250 -0
- agentscope_runtime/{sandbox/manager → common}/container_clients/kubernetes_client.py +6 -13
- agentscope_runtime/engine/__init__.py +12 -0
- agentscope_runtime/engine/agents/agentscope_agent.py +488 -0
- agentscope_runtime/engine/agents/agno_agent.py +26 -27
- agentscope_runtime/engine/agents/autogen_agent.py +13 -8
- agentscope_runtime/engine/agents/utils.py +53 -0
- agentscope_runtime/engine/app/__init__.py +6 -0
- agentscope_runtime/engine/app/agent_app.py +239 -0
- agentscope_runtime/engine/app/base_app.py +181 -0
- agentscope_runtime/engine/app/celery_mixin.py +92 -0
- agentscope_runtime/engine/deployers/base.py +1 -0
- agentscope_runtime/engine/deployers/cli_fc_deploy.py +39 -20
- agentscope_runtime/engine/deployers/kubernetes_deployer.py +12 -5
- agentscope_runtime/engine/deployers/local_deployer.py +61 -3
- agentscope_runtime/engine/deployers/modelstudio_deployer.py +10 -11
- agentscope_runtime/engine/deployers/utils/docker_image_utils/runner_image_factory.py +9 -0
- agentscope_runtime/engine/deployers/utils/package_project_utils.py +234 -3
- agentscope_runtime/engine/deployers/utils/service_utils/fastapi_factory.py +567 -7
- agentscope_runtime/engine/deployers/utils/service_utils/standalone_main.py.j2 +211 -0
- agentscope_runtime/engine/deployers/utils/wheel_packager.py +1 -1
- agentscope_runtime/engine/helpers/helper.py +60 -41
- agentscope_runtime/engine/runner.py +35 -24
- agentscope_runtime/engine/schemas/agent_schemas.py +42 -0
- agentscope_runtime/engine/schemas/modelstudio_llm.py +14 -14
- agentscope_runtime/engine/services/sandbox_service.py +62 -70
- agentscope_runtime/engine/services/tablestore_memory_service.py +307 -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/engine/tracing/__init__.py +9 -3
- agentscope_runtime/engine/tracing/asyncio_util.py +24 -0
- agentscope_runtime/engine/tracing/base.py +66 -34
- agentscope_runtime/engine/tracing/local_logging_handler.py +45 -31
- agentscope_runtime/engine/tracing/message_util.py +528 -0
- agentscope_runtime/engine/tracing/tracing_metric.py +20 -8
- agentscope_runtime/engine/tracing/tracing_util.py +130 -0
- agentscope_runtime/engine/tracing/wrapper.py +794 -169
- agentscope_runtime/sandbox/__init__.py +2 -0
- agentscope_runtime/sandbox/box/base/__init__.py +4 -0
- agentscope_runtime/sandbox/box/base/base_sandbox.py +6 -4
- agentscope_runtime/sandbox/box/browser/__init__.py +4 -0
- agentscope_runtime/sandbox/box/browser/browser_sandbox.py +10 -14
- agentscope_runtime/sandbox/box/dummy/__init__.py +4 -0
- agentscope_runtime/sandbox/box/dummy/dummy_sandbox.py +2 -1
- agentscope_runtime/sandbox/box/filesystem/__init__.py +4 -0
- agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +10 -7
- agentscope_runtime/sandbox/box/gui/__init__.py +4 -0
- agentscope_runtime/sandbox/box/gui/box/__init__.py +0 -0
- agentscope_runtime/sandbox/box/gui/gui_sandbox.py +81 -0
- agentscope_runtime/sandbox/box/sandbox.py +5 -2
- agentscope_runtime/sandbox/box/shared/routers/generic.py +20 -1
- agentscope_runtime/sandbox/box/training_box/__init__.py +4 -0
- agentscope_runtime/sandbox/box/training_box/training_box.py +7 -54
- agentscope_runtime/sandbox/build.py +143 -58
- agentscope_runtime/sandbox/client/http_client.py +87 -59
- agentscope_runtime/sandbox/client/training_client.py +0 -1
- agentscope_runtime/sandbox/constant.py +27 -1
- agentscope_runtime/sandbox/custom/custom_sandbox.py +7 -6
- agentscope_runtime/sandbox/custom/example.py +4 -3
- agentscope_runtime/sandbox/enums.py +1 -1
- agentscope_runtime/sandbox/manager/sandbox_manager.py +212 -106
- agentscope_runtime/sandbox/manager/server/app.py +82 -14
- agentscope_runtime/sandbox/manager/server/config.py +50 -3
- agentscope_runtime/sandbox/model/container.py +12 -23
- agentscope_runtime/sandbox/model/manager_config.py +93 -5
- agentscope_runtime/sandbox/registry.py +1 -1
- agentscope_runtime/sandbox/tools/gui/__init__.py +7 -0
- agentscope_runtime/sandbox/tools/gui/tool.py +77 -0
- agentscope_runtime/sandbox/tools/mcp_tool.py +6 -2
- agentscope_runtime/sandbox/tools/tool.py +4 -0
- agentscope_runtime/sandbox/utils.py +124 -0
- agentscope_runtime/version.py +1 -1
- {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.2.0b2.dist-info}/METADATA +214 -102
- {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.2.0b2.dist-info}/RECORD +94 -78
- agentscope_runtime/engine/agents/agentscope_agent/__init__.py +0 -6
- agentscope_runtime/engine/agents/agentscope_agent/agent.py +0 -401
- agentscope_runtime/engine/agents/agentscope_agent/hooks.py +0 -169
- 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/sandbox/manager/collections/in_memory_mapping.py +0 -22
- agentscope_runtime/sandbox/manager/collections/redis_mapping.py +0 -26
- agentscope_runtime/sandbox/manager/container_clients/__init__.py +0 -10
- agentscope_runtime/sandbox/manager/container_clients/docker_client.py +0 -422
- /agentscope_runtime/{sandbox/manager → common}/collections/__init__.py +0 -0
- /agentscope_runtime/{sandbox/manager → common}/collections/base_mapping.py +0 -0
- /agentscope_runtime/{sandbox/manager → common}/collections/base_queue.py +0 -0
- /agentscope_runtime/{sandbox/manager → common}/collections/base_set.py +0 -0
- /agentscope_runtime/{sandbox/manager → common}/collections/in_memory_queue.py +0 -0
- /agentscope_runtime/{sandbox/manager → common}/collections/in_memory_set.py +0 -0
- /agentscope_runtime/{sandbox/manager → common}/collections/redis_queue.py +0 -0
- /agentscope_runtime/{sandbox/manager → common}/collections/redis_set.py +0 -0
- /agentscope_runtime/{sandbox/manager → common}/container_clients/base_client.py +0 -0
- {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.2.0b2.dist-info}/WHEEL +0 -0
- {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.2.0b2.dist-info}/entry_points.txt +0 -0
- {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.2.0b2.dist-info}/licenses/LICENSE +0 -0
- {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.2.0b2.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
# pylint: disable=too-many-statements
|
|
2
|
+
# pylint: disable=too-many-statements,too-many-branches
|
|
3
3
|
import argparse
|
|
4
4
|
import logging
|
|
5
5
|
import os
|
|
@@ -11,6 +11,15 @@ import requests
|
|
|
11
11
|
|
|
12
12
|
from .enums import SandboxType
|
|
13
13
|
from .registry import SandboxRegistry
|
|
14
|
+
from .utils import dynamic_import, get_platform
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
DOCKER_PLATFORMS = [
|
|
20
|
+
"linux/amd64",
|
|
21
|
+
"linux/arm64",
|
|
22
|
+
]
|
|
14
23
|
|
|
15
24
|
|
|
16
25
|
def find_free_port(start_port, end_port):
|
|
@@ -18,7 +27,7 @@ def find_free_port(start_port, end_port):
|
|
|
18
27
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
|
19
28
|
if sock.connect_ex(("localhost", port)) != 0:
|
|
20
29
|
return port
|
|
21
|
-
|
|
30
|
+
logger.error(
|
|
22
31
|
f"No free ports available in the range {start_port}-{end_port}",
|
|
23
32
|
)
|
|
24
33
|
raise RuntimeError(
|
|
@@ -30,7 +39,7 @@ def check_health(url, secret_token, timeout=120, interval=5):
|
|
|
30
39
|
headers = {"Authorization": f"Bearer {secret_token}"}
|
|
31
40
|
spent_time = 0
|
|
32
41
|
while spent_time < timeout:
|
|
33
|
-
|
|
42
|
+
logger.info(
|
|
34
43
|
f"Attempting to connect to {url} (Elapsed time: {spent_time} "
|
|
35
44
|
f"seconds)...",
|
|
36
45
|
)
|
|
@@ -41,35 +50,52 @@ def check_health(url, secret_token, timeout=120, interval=5):
|
|
|
41
50
|
return True
|
|
42
51
|
except requests.exceptions.RequestException:
|
|
43
52
|
pass
|
|
44
|
-
|
|
53
|
+
logger.info(
|
|
45
54
|
f"Health check failed for {url}. Retrying in {interval} "
|
|
46
55
|
f"seconds...",
|
|
47
56
|
)
|
|
48
57
|
time.sleep(interval)
|
|
49
58
|
spent_time += interval
|
|
50
|
-
|
|
59
|
+
logger.error(f"Health check failed for {url} after {timeout} seconds.")
|
|
51
60
|
return False
|
|
52
61
|
|
|
53
62
|
|
|
54
|
-
def build_image(
|
|
63
|
+
def build_image(
|
|
64
|
+
build_type,
|
|
65
|
+
dockerfile_path=None,
|
|
66
|
+
platform_choice="linux/amd64",
|
|
67
|
+
):
|
|
68
|
+
assert platform_choice in DOCKER_PLATFORMS, (
|
|
69
|
+
f"Invalid platform: {platform_choice}. Valid options:"
|
|
70
|
+
f" {DOCKER_PLATFORMS}"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
platform_tag = ""
|
|
74
|
+
if platform_choice == "linux/arm64":
|
|
75
|
+
platform_tag = "-arm64"
|
|
76
|
+
|
|
77
|
+
buildx_enable = platform_choice != get_platform()
|
|
78
|
+
|
|
55
79
|
if dockerfile_path is None:
|
|
56
80
|
dockerfile_path = (
|
|
57
81
|
f"src/agentscope_runtime/sandbox/box/{build_type}/Dockerfile"
|
|
58
82
|
)
|
|
59
83
|
|
|
60
|
-
|
|
84
|
+
logger.info(f"Building {build_type} with `{dockerfile_path}`...")
|
|
61
85
|
|
|
62
86
|
# Initialize and update Git submodule
|
|
63
|
-
|
|
87
|
+
logger.info("Initializing and updating Git submodule...")
|
|
64
88
|
subprocess.run(
|
|
65
89
|
["git", "submodule", "update", "--init", "--recursive"],
|
|
66
90
|
check=True,
|
|
67
91
|
)
|
|
68
92
|
|
|
69
93
|
secret_token = "secret_token123"
|
|
70
|
-
image_name = SandboxRegistry.get_image_by_type(build_type)
|
|
71
94
|
|
|
72
|
-
|
|
95
|
+
# Add platform tag
|
|
96
|
+
image_name = SandboxRegistry.get_image_by_type(build_type) + platform_tag
|
|
97
|
+
|
|
98
|
+
logger.info(f"Building Docker image {image_name}...")
|
|
73
99
|
|
|
74
100
|
# Check if image exists
|
|
75
101
|
result = subprocess.run(
|
|
@@ -87,7 +113,7 @@ def build_image(build_type, dockerfile_path=None):
|
|
|
87
113
|
f"you want to overwrite it? (y/N): ",
|
|
88
114
|
)
|
|
89
115
|
if choice.lower() != "y":
|
|
90
|
-
|
|
116
|
+
logger.info("Exiting without overwriting the existing image.")
|
|
91
117
|
return
|
|
92
118
|
|
|
93
119
|
if not os.path.exists(dockerfile_path):
|
|
@@ -97,70 +123,101 @@ def build_image(build_type, dockerfile_path=None):
|
|
|
97
123
|
)
|
|
98
124
|
|
|
99
125
|
# Build Docker image
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
126
|
+
if not buildx_enable:
|
|
127
|
+
subprocess.run(
|
|
128
|
+
[
|
|
129
|
+
"docker",
|
|
130
|
+
"build",
|
|
131
|
+
"-f",
|
|
132
|
+
dockerfile_path,
|
|
133
|
+
"-t",
|
|
134
|
+
f"{image_name}dev",
|
|
135
|
+
".",
|
|
136
|
+
],
|
|
137
|
+
check=False,
|
|
138
|
+
)
|
|
139
|
+
else:
|
|
140
|
+
subprocess.run(
|
|
141
|
+
[
|
|
142
|
+
"docker",
|
|
143
|
+
"buildx",
|
|
144
|
+
"build",
|
|
145
|
+
"--platform",
|
|
146
|
+
platform_choice,
|
|
147
|
+
"-f",
|
|
148
|
+
dockerfile_path,
|
|
149
|
+
"-t",
|
|
150
|
+
f"{image_name}dev",
|
|
151
|
+
"--load",
|
|
152
|
+
".",
|
|
153
|
+
],
|
|
154
|
+
check=False,
|
|
155
|
+
)
|
|
113
156
|
|
|
114
|
-
|
|
157
|
+
logger.info(f"Docker image {image_name}dev built successfully.")
|
|
158
|
+
|
|
159
|
+
logger.info(f"Start to build image {image_name}.")
|
|
115
160
|
|
|
116
161
|
# Run the container with port mapping and environment variable
|
|
117
162
|
free_port = find_free_port(8080, 8090)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
163
|
+
|
|
164
|
+
if not buildx_enable:
|
|
165
|
+
result = subprocess.run(
|
|
166
|
+
[
|
|
167
|
+
"docker",
|
|
168
|
+
"run",
|
|
169
|
+
"-d",
|
|
170
|
+
"-p",
|
|
171
|
+
f"{free_port}:80",
|
|
172
|
+
"-e",
|
|
173
|
+
f"SECRET_TOKEN={secret_token}",
|
|
174
|
+
f"{image_name}dev",
|
|
175
|
+
],
|
|
176
|
+
capture_output=True,
|
|
177
|
+
text=True,
|
|
178
|
+
check=False,
|
|
179
|
+
)
|
|
180
|
+
else:
|
|
181
|
+
result = subprocess.run(
|
|
182
|
+
[
|
|
183
|
+
"docker",
|
|
184
|
+
"run",
|
|
185
|
+
"--platform",
|
|
186
|
+
platform_choice,
|
|
187
|
+
"-d",
|
|
188
|
+
"-p",
|
|
189
|
+
f"{free_port}:80",
|
|
190
|
+
"-e",
|
|
191
|
+
f"SECRET_TOKEN={secret_token}",
|
|
192
|
+
f"{image_name}dev",
|
|
193
|
+
],
|
|
194
|
+
capture_output=True,
|
|
195
|
+
text=True,
|
|
196
|
+
check=False,
|
|
197
|
+
)
|
|
198
|
+
|
|
133
199
|
container_id = result.stdout.strip()
|
|
134
|
-
|
|
200
|
+
logger.info(f"Running container {container_id} on port {free_port}")
|
|
135
201
|
|
|
136
202
|
# Check health endpoints
|
|
137
203
|
fastapi_health_url = f"http://localhost:{free_port}/fastapi/healthz"
|
|
138
|
-
steelapi_health_url = (
|
|
139
|
-
f"http://localhost:{free_port}/steel-api/{secret_token}/v1/health"
|
|
140
|
-
)
|
|
141
204
|
|
|
142
205
|
# Check health for FASTAPI
|
|
143
206
|
fastapi_healthy = check_health(fastapi_health_url, secret_token)
|
|
144
207
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
browser_healthy = check_health(steelapi_health_url, secret_token)
|
|
148
|
-
else:
|
|
149
|
-
browser_healthy = True
|
|
150
|
-
|
|
151
|
-
if browser_healthy and fastapi_healthy:
|
|
152
|
-
logging.info("Health checks passed.")
|
|
208
|
+
if fastapi_healthy:
|
|
209
|
+
logger.info("Health checks passed.")
|
|
153
210
|
subprocess.run(
|
|
154
211
|
["docker", "commit", container_id, f"{image_name}"],
|
|
155
212
|
check=True,
|
|
156
213
|
)
|
|
157
|
-
|
|
214
|
+
logger.info(
|
|
158
215
|
f"Docker image {image_name} committed successfully.",
|
|
159
216
|
)
|
|
160
217
|
subprocess.run(["docker", "stop", container_id], check=True)
|
|
161
218
|
subprocess.run(["docker", "rm", container_id], check=True)
|
|
162
219
|
else:
|
|
163
|
-
|
|
220
|
+
logger.error("Health checks failed.")
|
|
164
221
|
subprocess.run(["docker", "stop", container_id], check=True)
|
|
165
222
|
|
|
166
223
|
choice = input(
|
|
@@ -171,9 +228,9 @@ def build_image(build_type, dockerfile_path=None):
|
|
|
171
228
|
["docker", "rmi", "-f", f"{image_name}dev"],
|
|
172
229
|
check=True,
|
|
173
230
|
)
|
|
174
|
-
|
|
231
|
+
logger.info(f"Dev image {image_name}dev deleted.")
|
|
175
232
|
else:
|
|
176
|
-
|
|
233
|
+
logger.info(f"Dev image {image_name}dev retained.")
|
|
177
234
|
|
|
178
235
|
|
|
179
236
|
def main():
|
|
@@ -182,8 +239,8 @@ def main():
|
|
|
182
239
|
)
|
|
183
240
|
parser.add_argument(
|
|
184
241
|
"build_type",
|
|
242
|
+
nargs="?",
|
|
185
243
|
default="base",
|
|
186
|
-
choices=[x.value for x in SandboxType] + ["all"],
|
|
187
244
|
help="Specify the build type to execute.",
|
|
188
245
|
)
|
|
189
246
|
|
|
@@ -193,20 +250,48 @@ def main():
|
|
|
193
250
|
help="Specify the path for the Dockerfile.",
|
|
194
251
|
)
|
|
195
252
|
|
|
253
|
+
parser.add_argument(
|
|
254
|
+
"--extension",
|
|
255
|
+
action="append",
|
|
256
|
+
help="Path to a Python file or module name to load as an extension",
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
parser.add_argument(
|
|
260
|
+
"--platform",
|
|
261
|
+
default=get_platform(),
|
|
262
|
+
choices=DOCKER_PLATFORMS,
|
|
263
|
+
help="Specify target platform for Docker image (default: current "
|
|
264
|
+
f"system platform: {get_platform()})",
|
|
265
|
+
)
|
|
266
|
+
|
|
196
267
|
args = parser.parse_args()
|
|
197
268
|
|
|
269
|
+
if args.extension:
|
|
270
|
+
for ext in args.extension:
|
|
271
|
+
logger.info(f"Loading extension: {ext}")
|
|
272
|
+
mod = dynamic_import(ext)
|
|
273
|
+
logger.info(f"Extension loaded: {mod.__name__}")
|
|
274
|
+
|
|
198
275
|
if args.build_type == "all":
|
|
199
276
|
# Only build the built-in images
|
|
200
277
|
for build_type in [x.value for x in SandboxType.get_builtin_members()]:
|
|
201
278
|
build_image(build_type)
|
|
202
279
|
else:
|
|
280
|
+
assert args.build_type in [
|
|
281
|
+
x.value for x in SandboxType
|
|
282
|
+
], f"Invalid build type: {args.build_type}"
|
|
283
|
+
|
|
203
284
|
if args.build_type not in [
|
|
204
285
|
x.value for x in SandboxType.get_builtin_members()
|
|
205
286
|
]:
|
|
206
287
|
assert (
|
|
207
288
|
args.dockerfile_path is not None
|
|
208
289
|
), "Dockerfile path is required for custom images"
|
|
209
|
-
build_image(
|
|
290
|
+
build_image(
|
|
291
|
+
args.build_type,
|
|
292
|
+
args.dockerfile_path,
|
|
293
|
+
platform_choice=args.platform,
|
|
294
|
+
)
|
|
210
295
|
|
|
211
296
|
|
|
212
297
|
if __name__ == "__main__":
|
|
@@ -3,15 +3,16 @@
|
|
|
3
3
|
import logging
|
|
4
4
|
import time
|
|
5
5
|
from typing import Any, Optional
|
|
6
|
+
from urllib.parse import urljoin
|
|
6
7
|
|
|
7
8
|
import requests
|
|
8
9
|
from pydantic import Field
|
|
9
|
-
from steel import Steel
|
|
10
10
|
|
|
11
11
|
from ..model import ContainerModel
|
|
12
|
-
from ..constant import BROWSER_SESSION_ID
|
|
13
12
|
|
|
14
13
|
|
|
14
|
+
DEFAULT_TIMEOUT = 60
|
|
15
|
+
|
|
15
16
|
logging.getLogger("httpx").setLevel(logging.CRITICAL)
|
|
16
17
|
logging.basicConfig(level=logging.INFO)
|
|
17
18
|
logger = logging.getLogger(__name__)
|
|
@@ -69,8 +70,7 @@ class SandboxHttpClient:
|
|
|
69
70
|
def __init__(
|
|
70
71
|
self,
|
|
71
72
|
model: Optional[ContainerModel] = None,
|
|
72
|
-
timeout: int =
|
|
73
|
-
enable_browser: bool = True,
|
|
73
|
+
timeout: int = 60,
|
|
74
74
|
domain: str = "localhost",
|
|
75
75
|
) -> None:
|
|
76
76
|
"""
|
|
@@ -81,54 +81,39 @@ class SandboxHttpClient:
|
|
|
81
81
|
runtime sandbox.
|
|
82
82
|
"""
|
|
83
83
|
self.session_id = model.session_id
|
|
84
|
-
self.base_url =
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
"localhost",
|
|
88
|
-
domain,
|
|
84
|
+
self.base_url = urljoin(
|
|
85
|
+
model.url.replace("localhost", domain),
|
|
86
|
+
"fastapi",
|
|
89
87
|
)
|
|
90
88
|
|
|
91
|
-
self.
|
|
92
|
-
self.timeout = timeout
|
|
89
|
+
self.start_timeout = timeout
|
|
90
|
+
self.timeout = model.timeout or DEFAULT_TIMEOUT
|
|
93
91
|
self.session = requests.Session()
|
|
94
92
|
self.built_in_tools = []
|
|
95
93
|
self.secret = model.runtime_token
|
|
96
94
|
|
|
97
95
|
# Update headers with secret if provided
|
|
98
|
-
headers = {
|
|
96
|
+
headers = {
|
|
97
|
+
"Content-Type": "application/json",
|
|
98
|
+
"x-agentrun-session-id": "s" + self.session_id,
|
|
99
|
+
}
|
|
99
100
|
if self.secret:
|
|
100
101
|
headers["Authorization"] = f"Bearer {self.secret}"
|
|
101
102
|
self.session.headers.update(headers)
|
|
102
103
|
|
|
103
|
-
self.steel_client = None
|
|
104
|
-
|
|
105
104
|
def __enter__(self):
|
|
106
105
|
# Wait for the runtime api server to be healthy
|
|
107
106
|
self.wait_until_healthy()
|
|
108
|
-
|
|
109
|
-
if self.enable_browser:
|
|
110
|
-
self.steel_client = Steel(
|
|
111
|
-
steel_api_key="dummy",
|
|
112
|
-
base_url=self.browser_url,
|
|
113
|
-
)
|
|
114
|
-
|
|
115
|
-
# Create a new browser session if it doesn't exist
|
|
116
|
-
try:
|
|
117
|
-
# Try to connet to existing session
|
|
118
|
-
self.steel_client.sessions.retrieve(
|
|
119
|
-
BROWSER_SESSION_ID,
|
|
120
|
-
)
|
|
121
|
-
except Exception:
|
|
122
|
-
# Session not found, create a new one
|
|
123
|
-
self.steel_client.sessions.create(
|
|
124
|
-
session_id=BROWSER_SESSION_ID,
|
|
125
|
-
)
|
|
126
|
-
|
|
127
107
|
return self
|
|
128
108
|
|
|
129
109
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
130
110
|
pass
|
|
131
111
|
|
|
112
|
+
def _request(self, method: str, url: str, **kwargs):
|
|
113
|
+
if "timeout" not in kwargs:
|
|
114
|
+
kwargs["timeout"] = self.timeout
|
|
115
|
+
return self.session.request(method, url, **kwargs)
|
|
116
|
+
|
|
132
117
|
def check_health(self) -> bool:
|
|
133
118
|
"""
|
|
134
119
|
Checks if the runtime service is running by verifying the health
|
|
@@ -138,17 +123,9 @@ class SandboxHttpClient:
|
|
|
138
123
|
bool: True if the service is reachable, False otherwise
|
|
139
124
|
"""
|
|
140
125
|
endpoint = f"{self.base_url}/healthz"
|
|
141
|
-
browser_endpoint = f"{self.browser_url}/v1/health"
|
|
142
126
|
try:
|
|
143
127
|
response_api = self.session.get(endpoint)
|
|
144
|
-
|
|
145
|
-
response_browser = self.session.get(browser_endpoint)
|
|
146
|
-
return (
|
|
147
|
-
response_api.status_code == 200
|
|
148
|
-
and response_browser.status_code == 200
|
|
149
|
-
)
|
|
150
|
-
else:
|
|
151
|
-
return response_api.status_code == 200
|
|
128
|
+
return response_api.status_code == 200
|
|
152
129
|
except requests.RequestException:
|
|
153
130
|
return False
|
|
154
131
|
|
|
@@ -157,7 +134,7 @@ class SandboxHttpClient:
|
|
|
157
134
|
Waits until the runtime service is running for a specified timeout.
|
|
158
135
|
"""
|
|
159
136
|
start_time = time.time()
|
|
160
|
-
while time.time() - start_time < self.
|
|
137
|
+
while time.time() - start_time < self.start_timeout:
|
|
161
138
|
if self.check_health():
|
|
162
139
|
return
|
|
163
140
|
time.sleep(1)
|
|
@@ -171,7 +148,8 @@ class SandboxHttpClient:
|
|
|
171
148
|
"""
|
|
172
149
|
try:
|
|
173
150
|
endpoint = f"{self.base_url}/mcp/add_servers"
|
|
174
|
-
response = self.
|
|
151
|
+
response = self._request(
|
|
152
|
+
"post",
|
|
175
153
|
endpoint,
|
|
176
154
|
json={
|
|
177
155
|
"server_configs": server_configs,
|
|
@@ -190,7 +168,10 @@ class SandboxHttpClient:
|
|
|
190
168
|
def list_tools(self, tool_type=None, **kwargs) -> dict:
|
|
191
169
|
try:
|
|
192
170
|
endpoint = f"{self.base_url}/mcp/list_tools"
|
|
193
|
-
response = self.
|
|
171
|
+
response = self._request(
|
|
172
|
+
"get",
|
|
173
|
+
endpoint,
|
|
174
|
+
)
|
|
194
175
|
response.raise_for_status()
|
|
195
176
|
mcp_tools = response.json()
|
|
196
177
|
mcp_tools["generic"] = self.generic_tools
|
|
@@ -220,7 +201,8 @@ class SandboxHttpClient:
|
|
|
220
201
|
|
|
221
202
|
try:
|
|
222
203
|
endpoint = f"{self.base_url}/mcp/call_tool"
|
|
223
|
-
response = self.
|
|
204
|
+
response = self._request(
|
|
205
|
+
"post",
|
|
224
206
|
endpoint,
|
|
225
207
|
json={
|
|
226
208
|
"tool_name": name,
|
|
@@ -246,7 +228,11 @@ class SandboxHttpClient:
|
|
|
246
228
|
"""Run an IPython cell."""
|
|
247
229
|
try:
|
|
248
230
|
endpoint = f"{self.base_url}/tools/run_ipython_cell"
|
|
249
|
-
response = self.
|
|
231
|
+
response = self._request(
|
|
232
|
+
"post",
|
|
233
|
+
endpoint,
|
|
234
|
+
json={"code": code},
|
|
235
|
+
)
|
|
250
236
|
response.raise_for_status()
|
|
251
237
|
return response.json()
|
|
252
238
|
except requests.exceptions.RequestException as e:
|
|
@@ -265,7 +251,11 @@ class SandboxHttpClient:
|
|
|
265
251
|
"""Run a shell command."""
|
|
266
252
|
try:
|
|
267
253
|
endpoint = f"{self.base_url}/tools/run_shell_command"
|
|
268
|
-
response = self.
|
|
254
|
+
response = self._request(
|
|
255
|
+
"post",
|
|
256
|
+
endpoint,
|
|
257
|
+
json={"command": command},
|
|
258
|
+
)
|
|
269
259
|
response.raise_for_status()
|
|
270
260
|
return response.json()
|
|
271
261
|
except requests.exceptions.RequestException as e:
|
|
@@ -286,7 +276,8 @@ class SandboxHttpClient:
|
|
|
286
276
|
"""
|
|
287
277
|
try:
|
|
288
278
|
endpoint = f"{self.base_url}/watcher/commit_changes"
|
|
289
|
-
response = self.
|
|
279
|
+
response = self._request(
|
|
280
|
+
"post",
|
|
290
281
|
endpoint,
|
|
291
282
|
json={"commit_message": commit_message},
|
|
292
283
|
)
|
|
@@ -310,7 +301,8 @@ class SandboxHttpClient:
|
|
|
310
301
|
"""
|
|
311
302
|
try:
|
|
312
303
|
endpoint = f"{self.base_url}/watcher/generate_diff"
|
|
313
|
-
response = self.
|
|
304
|
+
response = self._request(
|
|
305
|
+
"post",
|
|
314
306
|
endpoint,
|
|
315
307
|
json={"commit_a": commit_a, "commit_b": commit_b},
|
|
316
308
|
)
|
|
@@ -329,7 +321,10 @@ class SandboxHttpClient:
|
|
|
329
321
|
"""
|
|
330
322
|
try:
|
|
331
323
|
endpoint = f"{self.base_url}/watcher/git_logs"
|
|
332
|
-
response = self.
|
|
324
|
+
response = self._request(
|
|
325
|
+
"get",
|
|
326
|
+
endpoint,
|
|
327
|
+
)
|
|
333
328
|
response.raise_for_status()
|
|
334
329
|
return response.json()
|
|
335
330
|
except requests.exceptions.RequestException as e:
|
|
@@ -346,7 +341,11 @@ class SandboxHttpClient:
|
|
|
346
341
|
try:
|
|
347
342
|
endpoint = f"{self.base_url}/workspace/files"
|
|
348
343
|
params = {"file_path": file_path}
|
|
349
|
-
response = self.
|
|
344
|
+
response = self._request(
|
|
345
|
+
"get",
|
|
346
|
+
endpoint,
|
|
347
|
+
params=params,
|
|
348
|
+
)
|
|
350
349
|
response.raise_for_status()
|
|
351
350
|
# Return the binary content of the file
|
|
352
351
|
# Check for empty content
|
|
@@ -379,7 +378,12 @@ class SandboxHttpClient:
|
|
|
379
378
|
endpoint = f"{self.base_url}/workspace/files"
|
|
380
379
|
params = {"file_path": file_path}
|
|
381
380
|
data = {"content": content}
|
|
382
|
-
response = self.
|
|
381
|
+
response = self._request(
|
|
382
|
+
"post",
|
|
383
|
+
endpoint,
|
|
384
|
+
params=params,
|
|
385
|
+
json=data,
|
|
386
|
+
)
|
|
383
387
|
response.raise_for_status()
|
|
384
388
|
return response.json()
|
|
385
389
|
except requests.exceptions.RequestException as e:
|
|
@@ -402,7 +406,11 @@ class SandboxHttpClient:
|
|
|
402
406
|
try:
|
|
403
407
|
endpoint = f"{self.base_url}/workspace/list-directories"
|
|
404
408
|
params = {"directory": directory}
|
|
405
|
-
response = self.
|
|
409
|
+
response = self._request(
|
|
410
|
+
"get",
|
|
411
|
+
endpoint,
|
|
412
|
+
params=params,
|
|
413
|
+
)
|
|
406
414
|
response.raise_for_status()
|
|
407
415
|
return response.json()
|
|
408
416
|
except requests.exceptions.RequestException as e:
|
|
@@ -419,7 +427,11 @@ class SandboxHttpClient:
|
|
|
419
427
|
try:
|
|
420
428
|
endpoint = f"{self.base_url}/workspace/directories"
|
|
421
429
|
params = {"directory_path": directory_path}
|
|
422
|
-
response = self.
|
|
430
|
+
response = self._request(
|
|
431
|
+
"post",
|
|
432
|
+
endpoint,
|
|
433
|
+
params=params,
|
|
434
|
+
)
|
|
423
435
|
response.raise_for_status()
|
|
424
436
|
return response.json()
|
|
425
437
|
except requests.exceptions.RequestException as e:
|
|
@@ -438,7 +450,11 @@ class SandboxHttpClient:
|
|
|
438
450
|
try:
|
|
439
451
|
endpoint = f"{self.base_url}/workspace/files"
|
|
440
452
|
params = {"file_path": file_path}
|
|
441
|
-
response = self.
|
|
453
|
+
response = self._request(
|
|
454
|
+
"delete",
|
|
455
|
+
endpoint,
|
|
456
|
+
params=params,
|
|
457
|
+
)
|
|
442
458
|
response.raise_for_status()
|
|
443
459
|
return response.json()
|
|
444
460
|
except requests.exceptions.RequestException as e:
|
|
@@ -461,7 +477,11 @@ class SandboxHttpClient:
|
|
|
461
477
|
try:
|
|
462
478
|
endpoint = f"{self.base_url}/workspace/directories"
|
|
463
479
|
params = {"directory_path": directory_path, "recursive": recursive}
|
|
464
|
-
response = self.
|
|
480
|
+
response = self._request(
|
|
481
|
+
"delete",
|
|
482
|
+
endpoint,
|
|
483
|
+
params=params,
|
|
484
|
+
)
|
|
465
485
|
response.raise_for_status()
|
|
466
486
|
return response.json()
|
|
467
487
|
except requests.exceptions.RequestException as e:
|
|
@@ -487,7 +507,11 @@ class SandboxHttpClient:
|
|
|
487
507
|
"source_path": source_path,
|
|
488
508
|
"destination_path": destination_path,
|
|
489
509
|
}
|
|
490
|
-
response = self.
|
|
510
|
+
response = self._request(
|
|
511
|
+
"put",
|
|
512
|
+
endpoint,
|
|
513
|
+
params=params,
|
|
514
|
+
)
|
|
491
515
|
response.raise_for_status()
|
|
492
516
|
return response.json()
|
|
493
517
|
except requests.exceptions.RequestException as e:
|
|
@@ -514,7 +538,11 @@ class SandboxHttpClient:
|
|
|
514
538
|
"source_path": source_path,
|
|
515
539
|
"destination_path": destination_path,
|
|
516
540
|
}
|
|
517
|
-
response = self.
|
|
541
|
+
response = self._request(
|
|
542
|
+
"post",
|
|
543
|
+
endpoint,
|
|
544
|
+
params=params,
|
|
545
|
+
)
|
|
518
546
|
response.raise_for_status()
|
|
519
547
|
return response.json()
|
|
520
548
|
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")
|
|
5
|
-
|
|
29
|
+
|
|
30
|
+
# Timeout
|
|
31
|
+
TIMEOUT = int(os.getenv("RUNTIME_SANDBOX_TIMEOUT", "60"))
|