agentscope-runtime 0.1.5b2__py3-none-any.whl → 0.1.6__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.py +447 -0
- agentscope_runtime/engine/agents/agno_agent.py +19 -18
- agentscope_runtime/engine/agents/autogen_agent.py +13 -8
- agentscope_runtime/engine/agents/utils.py +53 -0
- agentscope_runtime/engine/deployers/__init__.py +0 -13
- agentscope_runtime/engine/deployers/local_deployer.py +501 -356
- agentscope_runtime/engine/helpers/helper.py +60 -41
- agentscope_runtime/engine/runner.py +11 -36
- agentscope_runtime/engine/schemas/agent_schemas.py +2 -70
- agentscope_runtime/engine/services/sandbox_service.py +62 -70
- 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/tablestore_service_utils.py +352 -0
- agentscope_runtime/sandbox/__init__.py +2 -0
- agentscope_runtime/sandbox/box/base/__init__.py +4 -0
- agentscope_runtime/sandbox/box/base/base_sandbox.py +4 -3
- agentscope_runtime/sandbox/box/browser/__init__.py +4 -0
- agentscope_runtime/sandbox/box/browser/browser_sandbox.py +8 -13
- agentscope_runtime/sandbox/box/dummy/__init__.py +4 -0
- agentscope_runtime/sandbox/box/filesystem/__init__.py +4 -0
- agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +8 -6
- agentscope_runtime/sandbox/box/gui/__init__.py +4 -0
- agentscope_runtime/sandbox/box/gui/gui_sandbox.py +80 -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 +10 -15
- agentscope_runtime/sandbox/build.py +143 -58
- agentscope_runtime/sandbox/client/http_client.py +43 -49
- agentscope_runtime/sandbox/client/training_client.py +0 -1
- agentscope_runtime/sandbox/constant.py +24 -1
- agentscope_runtime/sandbox/custom/custom_sandbox.py +5 -5
- agentscope_runtime/sandbox/custom/example.py +2 -2
- agentscope_runtime/sandbox/enums.py +1 -0
- agentscope_runtime/sandbox/manager/collections/in_memory_mapping.py +11 -6
- 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 +1098 -0
- agentscope_runtime/sandbox/manager/container_clients/docker_client.py +33 -205
- agentscope_runtime/sandbox/manager/container_clients/kubernetes_client.py +8 -555
- agentscope_runtime/sandbox/manager/sandbox_manager.py +187 -88
- agentscope_runtime/sandbox/manager/server/app.py +82 -14
- agentscope_runtime/sandbox/manager/server/config.py +50 -3
- agentscope_runtime/sandbox/model/container.py +6 -23
- agentscope_runtime/sandbox/model/manager_config.py +93 -5
- 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/utils.py +124 -0
- agentscope_runtime/version.py +1 -1
- {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.1.6.dist-info}/METADATA +168 -77
- {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.1.6.dist-info}/RECORD +59 -78
- {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.1.6.dist-info}/entry_points.txt +0 -1
- 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/deployers/adapter/responses/response_api_adapter_utils.py +0 -2886
- agentscope_runtime/engine/deployers/adapter/responses/response_api_agent_adapter.py +0 -51
- agentscope_runtime/engine/deployers/adapter/responses/response_api_protocol_adapter.py +0 -314
- agentscope_runtime/engine/deployers/cli_fc_deploy.py +0 -184
- agentscope_runtime/engine/deployers/kubernetes_deployer.py +0 -265
- agentscope_runtime/engine/deployers/modelstudio_deployer.py +0 -677
- agentscope_runtime/engine/deployers/utils/deployment_modes.py +0 -14
- agentscope_runtime/engine/deployers/utils/docker_image_utils/__init__.py +0 -8
- agentscope_runtime/engine/deployers/utils/docker_image_utils/docker_image_builder.py +0 -429
- agentscope_runtime/engine/deployers/utils/docker_image_utils/dockerfile_generator.py +0 -240
- agentscope_runtime/engine/deployers/utils/docker_image_utils/runner_image_factory.py +0 -297
- agentscope_runtime/engine/deployers/utils/package_project_utils.py +0 -932
- agentscope_runtime/engine/deployers/utils/service_utils/__init__.py +0 -9
- agentscope_runtime/engine/deployers/utils/service_utils/fastapi_factory.py +0 -504
- agentscope_runtime/engine/deployers/utils/service_utils/fastapi_templates.py +0 -157
- agentscope_runtime/engine/deployers/utils/service_utils/process_manager.py +0 -268
- agentscope_runtime/engine/deployers/utils/service_utils/service_config.py +0 -75
- agentscope_runtime/engine/deployers/utils/service_utils/service_factory.py +0 -220
- agentscope_runtime/engine/deployers/utils/wheel_packager.py +0 -389
- agentscope_runtime/engine/helpers/agent_api_builder.py +0 -651
- 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/engine/schemas/embedding.py +0 -37
- agentscope_runtime/engine/schemas/modelstudio_llm.py +0 -310
- agentscope_runtime/engine/schemas/oai_llm.py +0 -538
- agentscope_runtime/engine/schemas/realtime.py +0 -254
- /agentscope_runtime/engine/{deployers/adapter/responses → services/utils}/__init__.py +0 -0
- /agentscope_runtime/{engine/deployers/utils → sandbox/box/gui/box}/__init__.py +0 -0
- {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.1.6.dist-info}/WHEEL +0 -0
- {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.1.6.dist-info}/licenses/LICENSE +0 -0
- {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.1.6.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
# pylint: disable=redefined-outer-name, protected-access
|
|
2
|
+
# pylint: disable=redefined-outer-name, protected-access
|
|
3
|
+
# pylint: disable=too-many-branches, too-many-statements
|
|
3
4
|
import logging
|
|
4
5
|
import os
|
|
5
6
|
import json
|
|
@@ -8,12 +9,13 @@ import inspect
|
|
|
8
9
|
import traceback
|
|
9
10
|
|
|
10
11
|
from functools import wraps
|
|
11
|
-
from typing import Optional, Dict
|
|
12
|
-
from urllib.parse import urlparse, urlunparse
|
|
12
|
+
from typing import Optional, Dict, Union, List
|
|
13
13
|
|
|
14
14
|
import shortuuid
|
|
15
15
|
import requests
|
|
16
16
|
|
|
17
|
+
from .container_clients.docker_client import DockerClient
|
|
18
|
+
from .container_clients.kubernetes_client import KubernetesClient
|
|
17
19
|
from ..model import (
|
|
18
20
|
ContainerModel,
|
|
19
21
|
SandboxManagerEnvConfig,
|
|
@@ -32,8 +34,6 @@ from ..manager.storage import (
|
|
|
32
34
|
LocalStorage,
|
|
33
35
|
OSSStorage,
|
|
34
36
|
)
|
|
35
|
-
from ..manager.container_clients import DockerClient, KubernetesClient
|
|
36
|
-
from ..constant import BROWSER_SESSION_ID
|
|
37
37
|
|
|
38
38
|
logging.basicConfig(level=logging.INFO)
|
|
39
39
|
logger = logging.getLogger(__name__)
|
|
@@ -85,7 +85,11 @@ class SandboxManager:
|
|
|
85
85
|
config: Optional[SandboxManagerEnvConfig] = None,
|
|
86
86
|
base_url=None,
|
|
87
87
|
bearer_token=None,
|
|
88
|
-
default_type:
|
|
88
|
+
default_type: Union[
|
|
89
|
+
SandboxType,
|
|
90
|
+
str,
|
|
91
|
+
List[Union[SandboxType, str]],
|
|
92
|
+
] = SandboxType.BASE,
|
|
89
93
|
):
|
|
90
94
|
if base_url:
|
|
91
95
|
# Initialize HTTP session for remote mode with bearer token
|
|
@@ -112,17 +116,24 @@ class SandboxManager:
|
|
|
112
116
|
default_mount_dir="sessions_mount_dir",
|
|
113
117
|
)
|
|
114
118
|
|
|
115
|
-
|
|
119
|
+
# Support multi sandbox pool
|
|
120
|
+
if isinstance(default_type, (SandboxType, str)):
|
|
121
|
+
self.default_type = [SandboxType(default_type)]
|
|
122
|
+
else:
|
|
123
|
+
self.default_type = [SandboxType(x) for x in list(default_type)]
|
|
124
|
+
|
|
116
125
|
self.workdir = "/workspace"
|
|
117
126
|
|
|
118
127
|
self.config = config
|
|
119
128
|
self.pool_size = self.config.pool_size
|
|
120
129
|
self.prefix = self.config.container_prefix_key
|
|
121
130
|
self.default_mount_dir = self.config.default_mount_dir
|
|
131
|
+
self.readonly_mounts = self.config.readonly_mounts
|
|
122
132
|
self.storage_folder = (
|
|
123
133
|
self.config.storage_folder or self.default_mount_dir
|
|
124
134
|
)
|
|
125
135
|
|
|
136
|
+
self.pool_queues = {}
|
|
126
137
|
if self.config.redis_enabled:
|
|
127
138
|
import redis
|
|
128
139
|
|
|
@@ -142,13 +153,22 @@ class SandboxManager:
|
|
|
142
153
|
) from e
|
|
143
154
|
|
|
144
155
|
self.container_mapping = RedisMapping(redis_client)
|
|
145
|
-
self.
|
|
156
|
+
self.session_mapping = RedisMapping(
|
|
146
157
|
redis_client,
|
|
147
|
-
|
|
158
|
+
prefix="session_mapping",
|
|
148
159
|
)
|
|
160
|
+
|
|
161
|
+
# Init multi sand box pool
|
|
162
|
+
for t in self.default_type:
|
|
163
|
+
queue_key = f"{self.config.redis_container_pool_key}:{t.value}"
|
|
164
|
+
self.pool_queues[t] = RedisQueue(redis_client, queue_key)
|
|
149
165
|
else:
|
|
150
166
|
self.container_mapping = InMemoryMapping()
|
|
151
|
-
self.
|
|
167
|
+
self.session_mapping = InMemoryMapping()
|
|
168
|
+
|
|
169
|
+
# Init multi sand box pool
|
|
170
|
+
for t in self.default_type:
|
|
171
|
+
self.pool_queues[t] = InMemoryQueue()
|
|
152
172
|
|
|
153
173
|
self.container_deployment = self.config.container_deployment
|
|
154
174
|
|
|
@@ -157,6 +177,10 @@ class SandboxManager:
|
|
|
157
177
|
self.client = DockerClient(config=self.config)
|
|
158
178
|
elif self.container_deployment == "k8s":
|
|
159
179
|
self.client = KubernetesClient(config=self.config)
|
|
180
|
+
elif self.container_deployment == "agentrun":
|
|
181
|
+
from .container_clients.agentrun_client import AgentRunClient
|
|
182
|
+
|
|
183
|
+
self.client = AgentRunClient(config=self.config)
|
|
160
184
|
else:
|
|
161
185
|
raise NotImplementedError("Not implemented")
|
|
162
186
|
else:
|
|
@@ -243,24 +267,28 @@ class SandboxManager:
|
|
|
243
267
|
"""
|
|
244
268
|
Init runtime pool
|
|
245
269
|
"""
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
270
|
+
for t in self.default_type:
|
|
271
|
+
queue = self.pool_queues[t]
|
|
272
|
+
while queue.size() < self.pool_size:
|
|
273
|
+
try:
|
|
274
|
+
container_name = self.create(sandbox_type=t.value)
|
|
275
|
+
container_model = self.container_mapping.get(
|
|
276
|
+
container_name,
|
|
277
|
+
)
|
|
278
|
+
if container_model:
|
|
279
|
+
# Check the pool size again to avoid race condition
|
|
280
|
+
if queue.size() < self.pool_size:
|
|
281
|
+
queue.enqueue(container_model)
|
|
282
|
+
else:
|
|
283
|
+
# The pool size has reached the limit
|
|
284
|
+
self.release(container_name)
|
|
285
|
+
break
|
|
254
286
|
else:
|
|
255
|
-
|
|
256
|
-
self.release(container_name)
|
|
287
|
+
logger.error("Failed to create container for pool")
|
|
257
288
|
break
|
|
258
|
-
|
|
259
|
-
logger.error("
|
|
289
|
+
except Exception as e:
|
|
290
|
+
logger.error(f"Error initializing runtime pool: {e}")
|
|
260
291
|
break
|
|
261
|
-
except Exception as e:
|
|
262
|
-
logger.error(f"Error initializing runtime pool: {e}")
|
|
263
|
-
break
|
|
264
292
|
|
|
265
293
|
@remote_wrapper()
|
|
266
294
|
def cleanup(self):
|
|
@@ -269,17 +297,19 @@ class SandboxManager:
|
|
|
269
297
|
)
|
|
270
298
|
|
|
271
299
|
# Clean up pool first
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
300
|
+
for queue in self.pool_queues.values():
|
|
301
|
+
try:
|
|
302
|
+
while queue.size() > 0:
|
|
303
|
+
container_json = queue.dequeue()
|
|
304
|
+
if container_json:
|
|
305
|
+
container_model = ContainerModel(**container_json)
|
|
306
|
+
logger.debug(
|
|
307
|
+
f"Destroy container"
|
|
308
|
+
f" {container_model.container_id}",
|
|
309
|
+
)
|
|
310
|
+
self.release(container_model.session_id)
|
|
311
|
+
except Exception as e:
|
|
312
|
+
logger.error(f"Error cleaning up runtime pool: {e}")
|
|
283
313
|
|
|
284
314
|
# Clean up rest container
|
|
285
315
|
for key in self.container_mapping.scan(self.prefix):
|
|
@@ -297,11 +327,15 @@ class SandboxManager:
|
|
|
297
327
|
)
|
|
298
328
|
|
|
299
329
|
@remote_wrapper()
|
|
300
|
-
def create_from_pool(self, sandbox_type=None):
|
|
330
|
+
def create_from_pool(self, sandbox_type=None, meta: Optional[Dict] = None):
|
|
301
331
|
"""Try to get a container from runtime pool"""
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
332
|
+
# If not specified, use the first one
|
|
333
|
+
sandbox_type = SandboxType(sandbox_type or self.default_type[0])
|
|
334
|
+
|
|
335
|
+
if sandbox_type not in self.pool_queues:
|
|
336
|
+
return self.create(sandbox_type=sandbox_type.value, meta=meta)
|
|
337
|
+
|
|
338
|
+
queue = self.pool_queues[sandbox_type]
|
|
305
339
|
|
|
306
340
|
cnt = 0
|
|
307
341
|
try:
|
|
@@ -313,17 +347,17 @@ class SandboxManager:
|
|
|
313
347
|
cnt += 1
|
|
314
348
|
|
|
315
349
|
# Add a new one to container
|
|
316
|
-
container_name = self.create()
|
|
350
|
+
container_name = self.create(sandbox_type=sandbox_type)
|
|
317
351
|
new_container_model = self.container_mapping.get(
|
|
318
352
|
container_name,
|
|
319
353
|
)
|
|
320
354
|
|
|
321
355
|
if new_container_model:
|
|
322
|
-
|
|
356
|
+
queue.enqueue(
|
|
323
357
|
new_container_model,
|
|
324
358
|
)
|
|
325
359
|
|
|
326
|
-
container_json =
|
|
360
|
+
container_json = queue.dequeue()
|
|
327
361
|
|
|
328
362
|
if not container_json:
|
|
329
363
|
raise RuntimeError(
|
|
@@ -331,6 +365,29 @@ class SandboxManager:
|
|
|
331
365
|
)
|
|
332
366
|
|
|
333
367
|
container_model = ContainerModel(**container_json)
|
|
368
|
+
|
|
369
|
+
# Add meta field to container
|
|
370
|
+
if meta and not container_model.meta:
|
|
371
|
+
container_model.meta = meta
|
|
372
|
+
self.container_mapping.set(
|
|
373
|
+
container_model.container_name,
|
|
374
|
+
container_model.model_dump(),
|
|
375
|
+
)
|
|
376
|
+
# Update session mapping
|
|
377
|
+
if "session_ctx_id" in meta:
|
|
378
|
+
env_ids = (
|
|
379
|
+
self.session_mapping.get(
|
|
380
|
+
meta["session_ctx_id"],
|
|
381
|
+
)
|
|
382
|
+
or []
|
|
383
|
+
)
|
|
384
|
+
if container_model.container_name not in env_ids:
|
|
385
|
+
env_ids.append(container_model.container_name)
|
|
386
|
+
self.session_mapping.set(
|
|
387
|
+
meta["session_ctx_id"],
|
|
388
|
+
env_ids,
|
|
389
|
+
)
|
|
390
|
+
|
|
334
391
|
logger.debug(
|
|
335
392
|
f"Retrieved container from pool:"
|
|
336
393
|
f" {container_model.session_id}",
|
|
@@ -339,7 +396,7 @@ class SandboxManager:
|
|
|
339
396
|
if (
|
|
340
397
|
container_model.version
|
|
341
398
|
!= SandboxRegistry.get_image_by_type(
|
|
342
|
-
|
|
399
|
+
sandbox_type,
|
|
343
400
|
)
|
|
344
401
|
):
|
|
345
402
|
logger.warning(
|
|
@@ -370,24 +427,25 @@ class SandboxManager:
|
|
|
370
427
|
self.release(container_model.session_id)
|
|
371
428
|
|
|
372
429
|
except Exception as e:
|
|
373
|
-
logger.
|
|
374
|
-
|
|
375
|
-
f"new one. {e}: {traceback.format_exc()}",
|
|
430
|
+
logger.warning(
|
|
431
|
+
"Error getting container from pool, create a new one.",
|
|
376
432
|
)
|
|
433
|
+
logger.debug(f"{e}: {traceback.format_exc()}")
|
|
377
434
|
return self.create()
|
|
378
435
|
|
|
379
436
|
@remote_wrapper()
|
|
380
437
|
def create(
|
|
381
438
|
self,
|
|
382
439
|
sandbox_type=None,
|
|
383
|
-
mount_dir=None,
|
|
440
|
+
mount_dir=None, # TODO: remove to avoid leaking
|
|
384
441
|
storage_path=None,
|
|
385
442
|
environment: Optional[Dict] = None,
|
|
443
|
+
meta: Optional[Dict] = None,
|
|
386
444
|
):
|
|
387
445
|
if sandbox_type is not None:
|
|
388
446
|
target_sandbox_type = SandboxType(sandbox_type)
|
|
389
447
|
else:
|
|
390
|
-
target_sandbox_type = self.default_type
|
|
448
|
+
target_sandbox_type = self.default_type[0]
|
|
391
449
|
|
|
392
450
|
image = SandboxRegistry.get_image_by_type(target_sandbox_type)
|
|
393
451
|
if not image:
|
|
@@ -396,7 +454,7 @@ class SandboxManager:
|
|
|
396
454
|
f"using default",
|
|
397
455
|
)
|
|
398
456
|
image = SandboxRegistry.get_image_by_type(
|
|
399
|
-
self.default_type,
|
|
457
|
+
self.default_type[0],
|
|
400
458
|
)
|
|
401
459
|
|
|
402
460
|
# TODO: enable for timeout for the sandbox (auto cleanup)
|
|
@@ -422,7 +480,7 @@ class SandboxManager:
|
|
|
422
480
|
mount_dir = os.path.join(self.default_mount_dir, session_id)
|
|
423
481
|
os.makedirs(mount_dir, exist_ok=True)
|
|
424
482
|
|
|
425
|
-
if mount_dir:
|
|
483
|
+
if mount_dir and self.container_deployment != "agentrun":
|
|
426
484
|
if not os.path.isabs(mount_dir):
|
|
427
485
|
mount_dir = os.path.abspath(mount_dir)
|
|
428
486
|
|
|
@@ -433,12 +491,16 @@ class SandboxManager:
|
|
|
433
491
|
session_id,
|
|
434
492
|
)
|
|
435
493
|
|
|
436
|
-
if
|
|
494
|
+
if (
|
|
495
|
+
mount_dir
|
|
496
|
+
and storage_path
|
|
497
|
+
and self.container_deployment != "agentrun"
|
|
498
|
+
):
|
|
437
499
|
self.storage.download_folder(storage_path, mount_dir)
|
|
438
500
|
|
|
501
|
+
# Check for an existing container with the same name
|
|
502
|
+
container_name = self._generate_container_key(session_id)
|
|
439
503
|
try:
|
|
440
|
-
# Check for an existing container with the same name
|
|
441
|
-
container_name = self._generate_container_key(session_id)
|
|
442
504
|
if self.client.inspect(container_name):
|
|
443
505
|
raise ValueError(
|
|
444
506
|
f"Container with name {container_name} already exists.",
|
|
@@ -448,7 +510,7 @@ class SandboxManager:
|
|
|
448
510
|
runtime_token = secrets.token_hex(16)
|
|
449
511
|
|
|
450
512
|
# Prepare volume bindings if a mount directory is provided
|
|
451
|
-
if mount_dir:
|
|
513
|
+
if mount_dir and self.container_deployment != "agentrun":
|
|
452
514
|
volume_bindings = {
|
|
453
515
|
mount_dir: {
|
|
454
516
|
"bind": self.workdir,
|
|
@@ -458,7 +520,16 @@ class SandboxManager:
|
|
|
458
520
|
else:
|
|
459
521
|
volume_bindings = {}
|
|
460
522
|
|
|
461
|
-
|
|
523
|
+
if self.readonly_mounts:
|
|
524
|
+
for host_path, container_path in self.readonly_mounts.items():
|
|
525
|
+
if not os.path.isabs(host_path):
|
|
526
|
+
host_path = os.path.abspath(host_path)
|
|
527
|
+
volume_bindings[host_path] = {
|
|
528
|
+
"bind": container_path,
|
|
529
|
+
"mode": "ro",
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
_id, ports, ip, *rest = self.client.create(
|
|
462
533
|
image,
|
|
463
534
|
name=container_name,
|
|
464
535
|
ports=["80/tcp"], # Nginx
|
|
@@ -470,6 +541,10 @@ class SandboxManager:
|
|
|
470
541
|
runtime_config=config.runtime_config,
|
|
471
542
|
)
|
|
472
543
|
|
|
544
|
+
http_protocol = "http"
|
|
545
|
+
if rest and rest[0] == "https":
|
|
546
|
+
http_protocol = "https"
|
|
547
|
+
|
|
473
548
|
if _id is None:
|
|
474
549
|
return None
|
|
475
550
|
|
|
@@ -487,37 +562,43 @@ class SandboxManager:
|
|
|
487
562
|
session_id=session_id,
|
|
488
563
|
container_id=_id,
|
|
489
564
|
container_name=container_name,
|
|
490
|
-
|
|
491
|
-
browser_url=f"http://{ip}:{ports[0]}/steel-api"
|
|
492
|
-
f"/{runtime_token}",
|
|
493
|
-
front_browser_ws=f"ws://{ip}:"
|
|
494
|
-
f"{ports[0]}/steel-api/"
|
|
495
|
-
f"{runtime_token}/v1/sessions/cast",
|
|
496
|
-
client_browser_ws=f"ws://{ip}:"
|
|
497
|
-
f"{ports[0]}/steel-api/{runtime_token}/&sessionId"
|
|
498
|
-
f"={BROWSER_SESSION_ID}",
|
|
499
|
-
artifacts_sio=f"http://{ip}:{ports[0]}/v1",
|
|
565
|
+
url=f"{http_protocol}://{ip}:{ports[0]}",
|
|
500
566
|
ports=[ports[0]],
|
|
501
567
|
mount_dir=str(mount_dir),
|
|
502
568
|
storage_path=storage_path,
|
|
503
569
|
runtime_token=runtime_token,
|
|
504
570
|
version=image,
|
|
571
|
+
meta=meta or {},
|
|
505
572
|
)
|
|
573
|
+
|
|
506
574
|
# Register in mapping
|
|
507
575
|
self.container_mapping.set(
|
|
508
576
|
container_model.container_name,
|
|
509
577
|
container_model.model_dump(),
|
|
510
578
|
)
|
|
511
579
|
|
|
580
|
+
# Build mapping session_ctx_id to container_name
|
|
581
|
+
if meta and "session_ctx_id" in meta:
|
|
582
|
+
env_ids = (
|
|
583
|
+
self.session_mapping.get(
|
|
584
|
+
meta["session_ctx_id"],
|
|
585
|
+
)
|
|
586
|
+
or []
|
|
587
|
+
)
|
|
588
|
+
env_ids.append(container_model.container_name)
|
|
589
|
+
self.session_mapping.set(meta["session_ctx_id"], env_ids)
|
|
590
|
+
|
|
512
591
|
logger.debug(
|
|
513
592
|
f"Created container {container_name}"
|
|
514
593
|
f":{container_model.model_dump()}",
|
|
515
594
|
)
|
|
516
595
|
return container_name
|
|
517
596
|
except Exception as e:
|
|
518
|
-
logger.
|
|
519
|
-
f"Failed to create container: {e}
|
|
597
|
+
logger.warning(
|
|
598
|
+
f"Failed to create container: {e}",
|
|
520
599
|
)
|
|
600
|
+
logger.debug(f"{traceback.format_exc()}")
|
|
601
|
+
self.release(identity=container_name)
|
|
521
602
|
return None
|
|
522
603
|
|
|
523
604
|
@remote_wrapper()
|
|
@@ -536,6 +617,20 @@ class SandboxManager:
|
|
|
536
617
|
# remove key in mapping before we remove container
|
|
537
618
|
self.container_mapping.delete(container_json.get("container_name"))
|
|
538
619
|
|
|
620
|
+
# remove key in mapping
|
|
621
|
+
session_ctx_id = container_info.meta.get("session_ctx_id")
|
|
622
|
+
if session_ctx_id:
|
|
623
|
+
env_ids = self.session_mapping.get(session_ctx_id) or []
|
|
624
|
+
env_ids = [
|
|
625
|
+
eid
|
|
626
|
+
for eid in env_ids
|
|
627
|
+
if eid != container_info.container_name
|
|
628
|
+
]
|
|
629
|
+
if env_ids:
|
|
630
|
+
self.session_mapping.set(session_ctx_id, env_ids)
|
|
631
|
+
else:
|
|
632
|
+
self.session_mapping.delete(session_ctx_id)
|
|
633
|
+
|
|
539
634
|
self.client.stop(container_info.container_id, timeout=1)
|
|
540
635
|
self.client.remove(container_info.container_id, force=True)
|
|
541
636
|
|
|
@@ -550,10 +645,10 @@ class SandboxManager:
|
|
|
550
645
|
|
|
551
646
|
return True
|
|
552
647
|
except Exception as e:
|
|
553
|
-
logger.
|
|
554
|
-
f"Failed to destroy container: {e}
|
|
555
|
-
f"{traceback.format_exc()}",
|
|
648
|
+
logger.warning(
|
|
649
|
+
f"Failed to destroy container: {e}",
|
|
556
650
|
)
|
|
651
|
+
logger.debug(f"{traceback.format_exc()}")
|
|
557
652
|
return False
|
|
558
653
|
|
|
559
654
|
@remote_wrapper()
|
|
@@ -632,7 +727,7 @@ class SandboxManager:
|
|
|
632
727
|
self._generate_container_key(identity),
|
|
633
728
|
)
|
|
634
729
|
if container_model is None:
|
|
635
|
-
|
|
730
|
+
raise RuntimeError(f"No container found with id: {identity}.")
|
|
636
731
|
if hasattr(container_model, "model_dump_json"):
|
|
637
732
|
container_model = container_model.model_dump_json()
|
|
638
733
|
|
|
@@ -640,35 +735,26 @@ class SandboxManager:
|
|
|
640
735
|
|
|
641
736
|
def _establish_connection(self, identity):
|
|
642
737
|
container_model = ContainerModel(**self.get_info(identity))
|
|
643
|
-
# TODO: make this more robust
|
|
644
|
-
enable_browser = "browser" in container_model.version
|
|
645
738
|
|
|
646
739
|
# TODO: remake docker name
|
|
647
740
|
if (
|
|
648
741
|
"sandbox-appworld" in container_model.version
|
|
649
742
|
or "sandbox-bfcl" in container_model.version
|
|
650
743
|
):
|
|
651
|
-
parsed = urlparse(container_model.base_url)
|
|
652
|
-
base_url = urlunparse(
|
|
653
|
-
(
|
|
654
|
-
parsed.scheme,
|
|
655
|
-
parsed.netloc,
|
|
656
|
-
"",
|
|
657
|
-
"",
|
|
658
|
-
"",
|
|
659
|
-
"",
|
|
660
|
-
),
|
|
661
|
-
)
|
|
662
|
-
|
|
663
744
|
return TrainingSandboxClient(
|
|
664
|
-
base_url=
|
|
745
|
+
base_url=container_model.url,
|
|
665
746
|
).__enter__()
|
|
666
747
|
|
|
667
748
|
return SandboxHttpClient(
|
|
668
749
|
container_model,
|
|
669
|
-
enable_browser=enable_browser,
|
|
670
750
|
).__enter__()
|
|
671
751
|
|
|
752
|
+
@remote_wrapper()
|
|
753
|
+
def check_health(self, identity):
|
|
754
|
+
"""List tool"""
|
|
755
|
+
client = self._establish_connection(identity)
|
|
756
|
+
return client.check_health()
|
|
757
|
+
|
|
672
758
|
@remote_wrapper()
|
|
673
759
|
def list_tools(self, identity, tool_type=None, **kwargs):
|
|
674
760
|
"""List tool"""
|
|
@@ -691,3 +777,16 @@ class SandboxManager:
|
|
|
691
777
|
server_configs=server_configs,
|
|
692
778
|
overwrite=overwrite,
|
|
693
779
|
)
|
|
780
|
+
|
|
781
|
+
@remote_wrapper()
|
|
782
|
+
def get_session_mapping(self, session_ctx_id: str) -> list:
|
|
783
|
+
"""Get all container names bound to a session context"""
|
|
784
|
+
return self.session_mapping.get(session_ctx_id) or []
|
|
785
|
+
|
|
786
|
+
@remote_wrapper()
|
|
787
|
+
def list_session_keys(self) -> list:
|
|
788
|
+
"""Return all session_ctx_id keys currently in mapping"""
|
|
789
|
+
session_keys = []
|
|
790
|
+
for key in self.session_mapping.scan():
|
|
791
|
+
session_keys.append(key)
|
|
792
|
+
return session_keys
|