agentscope-runtime 1.0.4a1__py3-none-any.whl → 1.0.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/adapters/agentscope/stream.py +2 -8
- agentscope_runtime/adapters/langgraph/stream.py +120 -70
- agentscope_runtime/adapters/ms_agent_framework/__init__.py +0 -0
- agentscope_runtime/adapters/ms_agent_framework/message.py +205 -0
- agentscope_runtime/adapters/ms_agent_framework/stream.py +418 -0
- agentscope_runtime/adapters/utils.py +6 -0
- agentscope_runtime/cli/commands/deploy.py +836 -1
- agentscope_runtime/cli/commands/stop.py +16 -0
- agentscope_runtime/common/container_clients/__init__.py +52 -0
- agentscope_runtime/common/container_clients/agentrun_client.py +6 -4
- agentscope_runtime/common/container_clients/boxlite_client.py +442 -0
- agentscope_runtime/common/container_clients/docker_client.py +0 -20
- agentscope_runtime/common/container_clients/fc_client.py +6 -4
- agentscope_runtime/common/container_clients/gvisor_client.py +38 -0
- agentscope_runtime/common/container_clients/knative_client.py +467 -0
- agentscope_runtime/common/utils/deprecation.py +164 -0
- agentscope_runtime/engine/__init__.py +4 -0
- agentscope_runtime/engine/app/agent_app.py +16 -4
- agentscope_runtime/engine/constant.py +1 -0
- agentscope_runtime/engine/deployers/__init__.py +34 -11
- agentscope_runtime/engine/deployers/adapter/__init__.py +8 -0
- agentscope_runtime/engine/deployers/adapter/a2a/__init__.py +26 -51
- agentscope_runtime/engine/deployers/adapter/a2a/a2a_protocol_adapter.py +23 -13
- agentscope_runtime/engine/deployers/adapter/a2a/a2a_registry.py +4 -201
- agentscope_runtime/engine/deployers/adapter/a2a/nacos_a2a_registry.py +152 -25
- agentscope_runtime/engine/deployers/adapter/agui/__init__.py +8 -0
- agentscope_runtime/engine/deployers/adapter/agui/agui_adapter_utils.py +652 -0
- agentscope_runtime/engine/deployers/adapter/agui/agui_protocol_adapter.py +225 -0
- agentscope_runtime/engine/deployers/agentrun_deployer.py +2 -2
- agentscope_runtime/engine/deployers/fc_deployer.py +1506 -0
- agentscope_runtime/engine/deployers/knative_deployer.py +290 -0
- agentscope_runtime/engine/deployers/pai_deployer.py +2335 -0
- agentscope_runtime/engine/deployers/utils/net_utils.py +37 -0
- agentscope_runtime/engine/deployers/utils/oss_utils.py +38 -0
- agentscope_runtime/engine/deployers/utils/package.py +46 -42
- agentscope_runtime/engine/helpers/agent_api_client.py +372 -0
- agentscope_runtime/engine/runner.py +13 -0
- agentscope_runtime/engine/schemas/agent_schemas.py +9 -3
- agentscope_runtime/engine/services/agent_state/__init__.py +7 -0
- agentscope_runtime/engine/services/memory/__init__.py +7 -0
- agentscope_runtime/engine/services/memory/redis_memory_service.py +15 -16
- agentscope_runtime/engine/services/session_history/__init__.py +7 -0
- agentscope_runtime/engine/tracing/local_logging_handler.py +2 -3
- agentscope_runtime/engine/tracing/wrapper.py +18 -4
- agentscope_runtime/sandbox/__init__.py +14 -6
- agentscope_runtime/sandbox/box/base/__init__.py +2 -2
- agentscope_runtime/sandbox/box/base/base_sandbox.py +51 -1
- agentscope_runtime/sandbox/box/browser/__init__.py +2 -2
- agentscope_runtime/sandbox/box/browser/browser_sandbox.py +198 -2
- agentscope_runtime/sandbox/box/filesystem/__init__.py +2 -2
- agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +99 -2
- agentscope_runtime/sandbox/box/gui/__init__.py +2 -2
- agentscope_runtime/sandbox/box/gui/gui_sandbox.py +117 -1
- agentscope_runtime/sandbox/box/mobile/__init__.py +2 -2
- agentscope_runtime/sandbox/box/mobile/mobile_sandbox.py +247 -100
- agentscope_runtime/sandbox/box/sandbox.py +102 -65
- agentscope_runtime/sandbox/box/shared/routers/generic.py +36 -29
- agentscope_runtime/sandbox/client/__init__.py +6 -1
- agentscope_runtime/sandbox/client/async_http_client.py +339 -0
- agentscope_runtime/sandbox/client/base.py +74 -0
- agentscope_runtime/sandbox/client/http_client.py +108 -329
- agentscope_runtime/sandbox/enums.py +7 -0
- agentscope_runtime/sandbox/manager/sandbox_manager.py +275 -29
- agentscope_runtime/sandbox/manager/server/app.py +7 -1
- agentscope_runtime/sandbox/manager/server/config.py +3 -1
- agentscope_runtime/sandbox/model/manager_config.py +11 -9
- agentscope_runtime/tools/modelstudio_memory/__init__.py +106 -0
- agentscope_runtime/tools/modelstudio_memory/base.py +220 -0
- agentscope_runtime/tools/modelstudio_memory/config.py +86 -0
- agentscope_runtime/tools/modelstudio_memory/core.py +594 -0
- agentscope_runtime/tools/modelstudio_memory/exceptions.py +60 -0
- agentscope_runtime/tools/modelstudio_memory/schemas.py +253 -0
- agentscope_runtime/version.py +1 -1
- {agentscope_runtime-1.0.4a1.dist-info → agentscope_runtime-1.0.5.dist-info}/METADATA +186 -73
- {agentscope_runtime-1.0.4a1.dist-info → agentscope_runtime-1.0.5.dist-info}/RECORD +79 -55
- {agentscope_runtime-1.0.4a1.dist-info → agentscope_runtime-1.0.5.dist-info}/WHEEL +0 -0
- {agentscope_runtime-1.0.4a1.dist-info → agentscope_runtime-1.0.5.dist-info}/entry_points.txt +0 -0
- {agentscope_runtime-1.0.4a1.dist-info → agentscope_runtime-1.0.5.dist-info}/licenses/LICENSE +0 -0
- {agentscope_runtime-1.0.4a1.dist-info → agentscope_runtime-1.0.5.dist-info}/top_level.txt +0 -0
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
# pylint: disable=redefined-outer-name, protected-access
|
|
3
3
|
# pylint: disable=too-many-branches, too-many-statements
|
|
4
4
|
# pylint: disable=redefined-outer-name, protected-access, too-many-branches
|
|
5
|
+
# pylint: disable=too-many-public-methods
|
|
6
|
+
import asyncio
|
|
5
7
|
import inspect
|
|
6
8
|
import json
|
|
7
9
|
import logging
|
|
@@ -13,8 +15,13 @@ from typing import Optional, Dict, Union, List
|
|
|
13
15
|
|
|
14
16
|
import requests
|
|
15
17
|
import shortuuid
|
|
18
|
+
import httpx
|
|
16
19
|
|
|
17
|
-
from ..client import
|
|
20
|
+
from ..client import (
|
|
21
|
+
SandboxHttpClient,
|
|
22
|
+
TrainingSandboxClient,
|
|
23
|
+
SandboxHttpAsyncClient,
|
|
24
|
+
)
|
|
18
25
|
from ..enums import SandboxType
|
|
19
26
|
from ..manager.storage import (
|
|
20
27
|
LocalStorage,
|
|
@@ -31,6 +38,8 @@ from ...common.collections import (
|
|
|
31
38
|
InMemoryMapping,
|
|
32
39
|
InMemoryQueue,
|
|
33
40
|
)
|
|
41
|
+
from ...common.container_clients import ContainerClientFactory
|
|
42
|
+
from ..constant import TIMEOUT
|
|
34
43
|
|
|
35
44
|
logging.basicConfig(level=logging.INFO)
|
|
36
45
|
logger = logging.getLogger(__name__)
|
|
@@ -76,6 +85,51 @@ def remote_wrapper(
|
|
|
76
85
|
return decorator
|
|
77
86
|
|
|
78
87
|
|
|
88
|
+
def remote_wrapper_async(
|
|
89
|
+
method: str = "POST",
|
|
90
|
+
success_key: str = "data",
|
|
91
|
+
):
|
|
92
|
+
"""
|
|
93
|
+
Async decorator to handle both remote and local method execution.
|
|
94
|
+
Supports awaitable functions.
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
def decorator(func):
|
|
98
|
+
@wraps(func)
|
|
99
|
+
async def wrapper(self, *args, **kwargs):
|
|
100
|
+
# Remote mode
|
|
101
|
+
if hasattr(self, "httpx_client") and self.httpx_client is not None:
|
|
102
|
+
endpoint = "/" + func.__name__
|
|
103
|
+
|
|
104
|
+
# Build JSON data from args/kwargs
|
|
105
|
+
sig = inspect.signature(func)
|
|
106
|
+
param_names = list(sig.parameters.keys())[1:] # Skip 'self'
|
|
107
|
+
data = dict(zip(param_names, args))
|
|
108
|
+
data.update(kwargs)
|
|
109
|
+
|
|
110
|
+
# Make async HTTP request
|
|
111
|
+
response = await self._make_request_async(
|
|
112
|
+
method,
|
|
113
|
+
endpoint,
|
|
114
|
+
data,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
if success_key:
|
|
118
|
+
return response.get(success_key)
|
|
119
|
+
return response
|
|
120
|
+
|
|
121
|
+
# Local mode
|
|
122
|
+
return await func(self, *args, **kwargs)
|
|
123
|
+
|
|
124
|
+
wrapper._is_remote_wrapper = True
|
|
125
|
+
wrapper._http_method = method
|
|
126
|
+
wrapper._path = "/" + func.__name__
|
|
127
|
+
|
|
128
|
+
return wrapper
|
|
129
|
+
|
|
130
|
+
return decorator
|
|
131
|
+
|
|
132
|
+
|
|
79
133
|
class SandboxManager:
|
|
80
134
|
def __init__(
|
|
81
135
|
self,
|
|
@@ -92,19 +146,31 @@ class SandboxManager:
|
|
|
92
146
|
# Initialize HTTP session for remote mode with bearer token
|
|
93
147
|
# authentication
|
|
94
148
|
self.http_session = requests.Session()
|
|
95
|
-
|
|
149
|
+
|
|
150
|
+
# For async HTTP
|
|
151
|
+
self.httpx_client = httpx.AsyncClient(timeout=TIMEOUT)
|
|
152
|
+
|
|
96
153
|
self.base_url = base_url.rstrip("/")
|
|
97
154
|
if bearer_token:
|
|
98
155
|
self.http_session.headers.update(
|
|
99
156
|
{"Authorization": f"Bearer {bearer_token}"},
|
|
100
157
|
)
|
|
158
|
+
self.httpx_client.headers.update(
|
|
159
|
+
{"Authorization": f"Bearer {bearer_token}"},
|
|
160
|
+
)
|
|
101
161
|
# Remote mode, return directly
|
|
102
162
|
return
|
|
103
163
|
else:
|
|
104
164
|
self.http_session = None
|
|
165
|
+
self.httpx_client = None
|
|
105
166
|
self.base_url = None
|
|
106
167
|
|
|
107
|
-
if
|
|
168
|
+
if config:
|
|
169
|
+
logger.debug(
|
|
170
|
+
f"Launching sandbox manager with config:"
|
|
171
|
+
f"\n{config.model_dump()}",
|
|
172
|
+
)
|
|
173
|
+
else:
|
|
108
174
|
config = SandboxManagerEnvConfig(
|
|
109
175
|
file_system="local",
|
|
110
176
|
redis_enabled=False,
|
|
@@ -170,30 +236,10 @@ class SandboxManager:
|
|
|
170
236
|
self.container_deployment = self.config.container_deployment
|
|
171
237
|
|
|
172
238
|
if base_url is None:
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
self.client = DockerClient(config=self.config)
|
|
179
|
-
elif self.container_deployment == "k8s":
|
|
180
|
-
from ...common.container_clients.kubernetes_client import (
|
|
181
|
-
KubernetesClient,
|
|
182
|
-
)
|
|
183
|
-
|
|
184
|
-
self.client = KubernetesClient(config=self.config)
|
|
185
|
-
elif self.container_deployment == "agentrun":
|
|
186
|
-
from ...common.container_clients.agentrun_client import (
|
|
187
|
-
AgentRunClient,
|
|
188
|
-
)
|
|
189
|
-
|
|
190
|
-
self.client = AgentRunClient(config=self.config)
|
|
191
|
-
elif self.container_deployment == "fc":
|
|
192
|
-
from ...common.container_clients.fc_client import FCClient
|
|
193
|
-
|
|
194
|
-
self.client = FCClient(config=self.config)
|
|
195
|
-
else:
|
|
196
|
-
raise NotImplementedError("Not implemented")
|
|
239
|
+
self.client = ContainerClientFactory.create_client(
|
|
240
|
+
deployment_type=self.container_deployment,
|
|
241
|
+
config=self.config,
|
|
242
|
+
)
|
|
197
243
|
else:
|
|
198
244
|
self.client = None
|
|
199
245
|
|
|
@@ -226,6 +272,51 @@ class SandboxManager:
|
|
|
226
272
|
)
|
|
227
273
|
self.cleanup()
|
|
228
274
|
|
|
275
|
+
if self.http_session:
|
|
276
|
+
try:
|
|
277
|
+
self.http_session.close()
|
|
278
|
+
logger.debug("HTTP session closed.")
|
|
279
|
+
except Exception as e:
|
|
280
|
+
logger.warning(f"Error closing http_session: {e}")
|
|
281
|
+
|
|
282
|
+
if self.httpx_client:
|
|
283
|
+
try:
|
|
284
|
+
loop = asyncio.get_event_loop()
|
|
285
|
+
if loop.is_running():
|
|
286
|
+
asyncio.ensure_future(self.httpx_client.aclose())
|
|
287
|
+
else:
|
|
288
|
+
loop.run_until_complete(self.httpx_client.aclose())
|
|
289
|
+
logger.debug("HTTPX async client closed.")
|
|
290
|
+
except Exception as e:
|
|
291
|
+
logger.warning(f"Error closing httpx_client: {e}")
|
|
292
|
+
|
|
293
|
+
async def __aenter__(self):
|
|
294
|
+
logger.debug(
|
|
295
|
+
"Entering SandboxManager context (async). "
|
|
296
|
+
"Cleanup will be performed automatically on async exit.",
|
|
297
|
+
)
|
|
298
|
+
return self
|
|
299
|
+
|
|
300
|
+
async def __aexit__(self, exc_type, exc_value, tb):
|
|
301
|
+
logger.debug(
|
|
302
|
+
"Exiting SandboxManager context (async). Cleaning up resources.",
|
|
303
|
+
)
|
|
304
|
+
await self.cleanup_async()
|
|
305
|
+
|
|
306
|
+
if self.http_session:
|
|
307
|
+
try:
|
|
308
|
+
self.http_session.close()
|
|
309
|
+
logger.debug("HTTP session closed.")
|
|
310
|
+
except Exception as e:
|
|
311
|
+
logger.warning(f"Error closing http_session: {e}")
|
|
312
|
+
|
|
313
|
+
if self.httpx_client:
|
|
314
|
+
try:
|
|
315
|
+
await self.httpx_client.aclose()
|
|
316
|
+
logger.debug("HTTPX async client closed.")
|
|
317
|
+
except Exception as e:
|
|
318
|
+
logger.warning(f"Error closing httpx_client: {e}")
|
|
319
|
+
|
|
229
320
|
def _generate_container_key(self, session_id):
|
|
230
321
|
return f"{self.prefix}{session_id}"
|
|
231
322
|
|
|
@@ -235,9 +326,14 @@ class SandboxManager:
|
|
|
235
326
|
"""
|
|
236
327
|
url = f"{self.base_url}/{endpoint.lstrip('/')}"
|
|
237
328
|
if method.upper() == "GET":
|
|
238
|
-
response = self.http_session.get(url, params=data)
|
|
329
|
+
response = self.http_session.get(url, params=data, timeout=TIMEOUT)
|
|
239
330
|
else:
|
|
240
|
-
response = self.http_session.request(
|
|
331
|
+
response = self.http_session.request(
|
|
332
|
+
method,
|
|
333
|
+
url,
|
|
334
|
+
json=data,
|
|
335
|
+
timeout=TIMEOUT,
|
|
336
|
+
)
|
|
241
337
|
|
|
242
338
|
try:
|
|
243
339
|
response.raise_for_status()
|
|
@@ -274,6 +370,56 @@ class SandboxManager:
|
|
|
274
370
|
|
|
275
371
|
return response.json()
|
|
276
372
|
|
|
373
|
+
async def _make_request_async(
|
|
374
|
+
self,
|
|
375
|
+
method: str,
|
|
376
|
+
endpoint: str,
|
|
377
|
+
data: dict,
|
|
378
|
+
):
|
|
379
|
+
"""
|
|
380
|
+
Make an asynchronous HTTP request to the specified endpoint.
|
|
381
|
+
"""
|
|
382
|
+
url = f"{self.base_url}/{endpoint.lstrip('/')}"
|
|
383
|
+
if method.upper() == "GET":
|
|
384
|
+
response = await self.httpx_client.get(url, params=data)
|
|
385
|
+
else:
|
|
386
|
+
response = await self.httpx_client.request(method, url, json=data)
|
|
387
|
+
|
|
388
|
+
try:
|
|
389
|
+
response.raise_for_status()
|
|
390
|
+
except httpx.HTTPStatusError as e:
|
|
391
|
+
error_components = [
|
|
392
|
+
f"HTTP {response.status_code} Error: {str(e)}",
|
|
393
|
+
]
|
|
394
|
+
|
|
395
|
+
try:
|
|
396
|
+
server_response = response.json()
|
|
397
|
+
if "detail" in server_response:
|
|
398
|
+
error_components.append(
|
|
399
|
+
f"Server Detail: {server_response['detail']}",
|
|
400
|
+
)
|
|
401
|
+
elif "error" in server_response:
|
|
402
|
+
error_components.append(
|
|
403
|
+
f"Server Error: {server_response['error']}",
|
|
404
|
+
)
|
|
405
|
+
else:
|
|
406
|
+
error_components.append(
|
|
407
|
+
f"Server Response: {server_response}",
|
|
408
|
+
)
|
|
409
|
+
except (ValueError, json.JSONDecodeError):
|
|
410
|
+
if response.text:
|
|
411
|
+
error_components.append(
|
|
412
|
+
f"Server Response: {response.text}",
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
error = " | ".join(error_components)
|
|
416
|
+
|
|
417
|
+
logger.error(f"Error making request: {error}")
|
|
418
|
+
|
|
419
|
+
return {"data": f"Error: {error}"}
|
|
420
|
+
|
|
421
|
+
return response.json()
|
|
422
|
+
|
|
277
423
|
def _init_container_pool(self):
|
|
278
424
|
"""
|
|
279
425
|
Init runtime pool
|
|
@@ -337,6 +483,11 @@ class SandboxManager:
|
|
|
337
483
|
f"Error cleaning up container {key}: {e}",
|
|
338
484
|
)
|
|
339
485
|
|
|
486
|
+
@remote_wrapper_async()
|
|
487
|
+
async def cleanup_async(self, *args, **kwargs):
|
|
488
|
+
"""Async wrapper for cleanup()."""
|
|
489
|
+
return await asyncio.to_thread(self.cleanup, *args, **kwargs)
|
|
490
|
+
|
|
340
491
|
@remote_wrapper()
|
|
341
492
|
def create_from_pool(self, sandbox_type=None, meta: Optional[Dict] = None):
|
|
342
493
|
"""Try to get a container from runtime pool"""
|
|
@@ -444,6 +595,11 @@ class SandboxManager:
|
|
|
444
595
|
logger.debug(f"{e}: {traceback.format_exc()}")
|
|
445
596
|
return self.create()
|
|
446
597
|
|
|
598
|
+
@remote_wrapper_async()
|
|
599
|
+
async def create_from_pool_async(self, *args, **kwargs):
|
|
600
|
+
"""Async wrapper for create_from_pool()."""
|
|
601
|
+
return await asyncio.to_thread(self.create_from_pool, *args, **kwargs)
|
|
602
|
+
|
|
447
603
|
@remote_wrapper()
|
|
448
604
|
def create(
|
|
449
605
|
self,
|
|
@@ -621,6 +777,11 @@ class SandboxManager:
|
|
|
621
777
|
self.release(identity=container_name)
|
|
622
778
|
return None
|
|
623
779
|
|
|
780
|
+
@remote_wrapper_async()
|
|
781
|
+
async def create_async(self, *args, **kwargs):
|
|
782
|
+
"""Async wrapper for create()."""
|
|
783
|
+
return await asyncio.to_thread(self.create, *args, **kwargs)
|
|
784
|
+
|
|
624
785
|
@remote_wrapper()
|
|
625
786
|
def release(self, identity):
|
|
626
787
|
try:
|
|
@@ -671,6 +832,11 @@ class SandboxManager:
|
|
|
671
832
|
logger.debug(f"{traceback.format_exc()}")
|
|
672
833
|
return False
|
|
673
834
|
|
|
835
|
+
@remote_wrapper_async()
|
|
836
|
+
async def release_async(self, *args, **kwargs):
|
|
837
|
+
"""Async wrapper for release()."""
|
|
838
|
+
return await asyncio.to_thread(self.release, *args, **kwargs)
|
|
839
|
+
|
|
674
840
|
@remote_wrapper()
|
|
675
841
|
def start(self, identity):
|
|
676
842
|
try:
|
|
@@ -703,6 +869,11 @@ class SandboxManager:
|
|
|
703
869
|
)
|
|
704
870
|
return False
|
|
705
871
|
|
|
872
|
+
@remote_wrapper_async()
|
|
873
|
+
async def start_async(self, *args, **kwargs):
|
|
874
|
+
"""Async wrapper for start()."""
|
|
875
|
+
return await asyncio.to_thread(self.start, *args, **kwargs)
|
|
876
|
+
|
|
706
877
|
@remote_wrapper()
|
|
707
878
|
def stop(self, identity):
|
|
708
879
|
try:
|
|
@@ -733,11 +904,21 @@ class SandboxManager:
|
|
|
733
904
|
)
|
|
734
905
|
return False
|
|
735
906
|
|
|
907
|
+
@remote_wrapper_async()
|
|
908
|
+
async def stop_async(self, *args, **kwargs):
|
|
909
|
+
"""Async wrapper for stop()."""
|
|
910
|
+
return await asyncio.to_thread(self.stop, *args, **kwargs)
|
|
911
|
+
|
|
736
912
|
@remote_wrapper()
|
|
737
913
|
def get_status(self, identity):
|
|
738
914
|
"""Get container status by container_name or container_id."""
|
|
739
915
|
return self.client.get_status(identity)
|
|
740
916
|
|
|
917
|
+
@remote_wrapper_async()
|
|
918
|
+
async def get_status_async(self, *args, **kwargs):
|
|
919
|
+
"""Async wrapper for get_status()."""
|
|
920
|
+
return await asyncio.to_thread(self.get_status, *args, **kwargs)
|
|
921
|
+
|
|
741
922
|
@remote_wrapper()
|
|
742
923
|
def get_info(self, identity):
|
|
743
924
|
"""Get container information by container_name or container_id."""
|
|
@@ -753,6 +934,11 @@ class SandboxManager:
|
|
|
753
934
|
|
|
754
935
|
return container_model
|
|
755
936
|
|
|
937
|
+
@remote_wrapper_async()
|
|
938
|
+
async def get_info_async(self, *args, **kwargs):
|
|
939
|
+
"""Async wrapper for get_info()."""
|
|
940
|
+
return await asyncio.to_thread(self.get_info, *args, **kwargs)
|
|
941
|
+
|
|
756
942
|
def _establish_connection(self, identity):
|
|
757
943
|
container_model = ContainerModel(**self.get_info(identity))
|
|
758
944
|
|
|
@@ -769,24 +955,54 @@ class SandboxManager:
|
|
|
769
955
|
container_model,
|
|
770
956
|
).__enter__()
|
|
771
957
|
|
|
958
|
+
async def _establish_connection_async(self, identity):
|
|
959
|
+
container_model = ContainerModel(**self.get_info(identity))
|
|
960
|
+
|
|
961
|
+
# TODO: TrainingSandboxClient lacks async, can use asyncio.to_thread()
|
|
962
|
+
if (
|
|
963
|
+
"sandbox-appworld" in container_model.version
|
|
964
|
+
or "sandbox-bfcl" in container_model.version
|
|
965
|
+
):
|
|
966
|
+
client = TrainingSandboxClient(base_url=container_model.url)
|
|
967
|
+
return client.__enter__()
|
|
968
|
+
async_client = SandboxHttpAsyncClient(container_model)
|
|
969
|
+
await async_client.__aenter__()
|
|
970
|
+
return async_client
|
|
971
|
+
|
|
772
972
|
@remote_wrapper()
|
|
773
973
|
def check_health(self, identity):
|
|
774
974
|
"""List tool"""
|
|
775
975
|
client = self._establish_connection(identity)
|
|
776
976
|
return client.check_health()
|
|
777
977
|
|
|
978
|
+
@remote_wrapper_async()
|
|
979
|
+
async def check_health_async(self, identity):
|
|
980
|
+
client = await self._establish_connection_async(identity)
|
|
981
|
+
return await client.check_health()
|
|
982
|
+
|
|
778
983
|
@remote_wrapper()
|
|
779
984
|
def list_tools(self, identity, tool_type=None, **kwargs):
|
|
780
985
|
"""List tool"""
|
|
781
986
|
client = self._establish_connection(identity)
|
|
782
987
|
return client.list_tools(tool_type=tool_type, **kwargs)
|
|
783
988
|
|
|
989
|
+
@remote_wrapper_async()
|
|
990
|
+
async def list_tools_async(self, identity, tool_type=None, **kwargs):
|
|
991
|
+
client = await self._establish_connection_async(identity)
|
|
992
|
+
return await client.list_tools(tool_type=tool_type, **kwargs)
|
|
993
|
+
|
|
784
994
|
@remote_wrapper()
|
|
785
995
|
def call_tool(self, identity, tool_name=None, arguments=None):
|
|
786
996
|
"""Call tool"""
|
|
787
997
|
client = self._establish_connection(identity)
|
|
788
998
|
return client.call_tool(tool_name, arguments)
|
|
789
999
|
|
|
1000
|
+
@remote_wrapper_async()
|
|
1001
|
+
async def call_tool_async(self, identity, tool_name=None, arguments=None):
|
|
1002
|
+
"""Call tool (async)"""
|
|
1003
|
+
client = await self._establish_connection_async(identity)
|
|
1004
|
+
return await client.call_tool(tool_name, arguments)
|
|
1005
|
+
|
|
790
1006
|
@remote_wrapper()
|
|
791
1007
|
def add_mcp_servers(self, identity, server_configs, overwrite=False):
|
|
792
1008
|
"""
|
|
@@ -798,11 +1014,36 @@ class SandboxManager:
|
|
|
798
1014
|
overwrite=overwrite,
|
|
799
1015
|
)
|
|
800
1016
|
|
|
1017
|
+
@remote_wrapper_async()
|
|
1018
|
+
async def add_mcp_servers_async(
|
|
1019
|
+
self,
|
|
1020
|
+
identity,
|
|
1021
|
+
server_configs,
|
|
1022
|
+
overwrite=False,
|
|
1023
|
+
):
|
|
1024
|
+
"""
|
|
1025
|
+
Add MCP servers to runtime (async).
|
|
1026
|
+
"""
|
|
1027
|
+
client = await self._establish_connection_async(identity)
|
|
1028
|
+
return await client.add_mcp_servers(
|
|
1029
|
+
server_configs=server_configs,
|
|
1030
|
+
overwrite=overwrite,
|
|
1031
|
+
)
|
|
1032
|
+
|
|
801
1033
|
@remote_wrapper()
|
|
802
1034
|
def get_session_mapping(self, session_ctx_id: str) -> list:
|
|
803
1035
|
"""Get all container names bound to a session context"""
|
|
804
1036
|
return self.session_mapping.get(session_ctx_id) or []
|
|
805
1037
|
|
|
1038
|
+
@remote_wrapper_async()
|
|
1039
|
+
async def get_session_mapping_async(self, *args, **kwargs):
|
|
1040
|
+
"""Async wrapper for get_session_mapping()."""
|
|
1041
|
+
return await asyncio.to_thread(
|
|
1042
|
+
self.get_session_mapping,
|
|
1043
|
+
*args,
|
|
1044
|
+
**kwargs,
|
|
1045
|
+
)
|
|
1046
|
+
|
|
806
1047
|
@remote_wrapper()
|
|
807
1048
|
def list_session_keys(self) -> list:
|
|
808
1049
|
"""Return all session_ctx_id keys currently in mapping"""
|
|
@@ -810,3 +1051,8 @@ class SandboxManager:
|
|
|
810
1051
|
for key in self.session_mapping.scan():
|
|
811
1052
|
session_keys.append(key)
|
|
812
1053
|
return session_keys
|
|
1054
|
+
|
|
1055
|
+
@remote_wrapper_async()
|
|
1056
|
+
async def list_session_keys_async(self, *args, **kwargs):
|
|
1057
|
+
"""Async wrapper for list_session_keys()."""
|
|
1058
|
+
return await asyncio.to_thread(self.list_session_keys, *args, **kwargs)
|
|
@@ -245,7 +245,13 @@ async def proxy_vnc_static(sandbox_id: str, path: str):
|
|
|
245
245
|
target_url = f"{base_url}/{path}"
|
|
246
246
|
|
|
247
247
|
try:
|
|
248
|
-
async with httpx.AsyncClient(
|
|
248
|
+
async with httpx.AsyncClient(
|
|
249
|
+
headers={ # For FC
|
|
250
|
+
"Content-Type": "application/json",
|
|
251
|
+
"x-agentrun-session-id": "s" + sandbox_id,
|
|
252
|
+
"x-agentscope-runtime-session-id": "s" + sandbox_id,
|
|
253
|
+
},
|
|
254
|
+
) as client:
|
|
249
255
|
upstream = await client.get(target_url)
|
|
250
256
|
return Response(
|
|
251
257
|
content=upstream.content,
|
|
@@ -20,7 +20,7 @@ class Settings(BaseSettings):
|
|
|
20
20
|
|
|
21
21
|
# Runtime Manager settings
|
|
22
22
|
DEFAULT_SANDBOX_TYPE: Union[str, List[str]] = "base"
|
|
23
|
-
POOL_SIZE: int =
|
|
23
|
+
POOL_SIZE: int = 0
|
|
24
24
|
AUTO_CLEANUP: bool = True
|
|
25
25
|
CONTAINER_PREFIX_KEY: str = "runtime_sandbox_container_"
|
|
26
26
|
CONTAINER_DEPLOYMENT: Literal[
|
|
@@ -29,6 +29,8 @@ class Settings(BaseSettings):
|
|
|
29
29
|
"k8s",
|
|
30
30
|
"agentrun",
|
|
31
31
|
"fc",
|
|
32
|
+
"gvisor",
|
|
33
|
+
"boxlite",
|
|
32
34
|
] = "docker"
|
|
33
35
|
DEFAULT_MOUNT_DIR: str = "sessions_mount_dir"
|
|
34
36
|
# Read-only mounts (host_path -> container_path)
|
|
@@ -16,15 +16,15 @@ class SandboxManagerEnvConfig(BaseModel):
|
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
file_system: Literal["local", "oss"] = Field(
|
|
19
|
-
|
|
19
|
+
"local",
|
|
20
20
|
description="Type of file system to use: 'local' or 'oss'.",
|
|
21
21
|
)
|
|
22
22
|
storage_folder: Optional[str] = Field(
|
|
23
|
-
"",
|
|
23
|
+
"runtime_sandbox_storage",
|
|
24
24
|
description="Folder path in storage.",
|
|
25
25
|
)
|
|
26
26
|
redis_enabled: bool = Field(
|
|
27
|
-
|
|
27
|
+
False,
|
|
28
28
|
description="Indicates if Redis is enabled.",
|
|
29
29
|
)
|
|
30
30
|
container_deployment: Literal[
|
|
@@ -33,14 +33,16 @@ class SandboxManagerEnvConfig(BaseModel):
|
|
|
33
33
|
"k8s",
|
|
34
34
|
"agentrun",
|
|
35
35
|
"fc",
|
|
36
|
+
"gvisor",
|
|
37
|
+
"boxlite",
|
|
36
38
|
] = Field(
|
|
37
|
-
|
|
39
|
+
"docker",
|
|
38
40
|
description="Container deployment backend: 'docker', 'cloud', 'k8s'"
|
|
39
|
-
" 'agentrun' or '
|
|
41
|
+
" 'agentrun', 'fc', 'knative', or 'gvisor'.",
|
|
40
42
|
)
|
|
41
43
|
|
|
42
44
|
default_mount_dir: Optional[str] = Field(
|
|
43
|
-
|
|
45
|
+
"sessions_mount_dir",
|
|
44
46
|
description="Path for local file system storage.",
|
|
45
47
|
)
|
|
46
48
|
|
|
@@ -67,16 +69,16 @@ class SandboxManagerEnvConfig(BaseModel):
|
|
|
67
69
|
description="OSS endpoint URL. Required if file_system is 'oss'.",
|
|
68
70
|
)
|
|
69
71
|
oss_access_key_id: Optional[str] = Field(
|
|
70
|
-
|
|
72
|
+
"your-access-key-id",
|
|
71
73
|
description="Access key ID for OSS. Required if file_system is 'oss'.",
|
|
72
74
|
)
|
|
73
75
|
oss_access_key_secret: Optional[str] = Field(
|
|
74
|
-
|
|
76
|
+
"your-access-key-secret",
|
|
75
77
|
description="Access key secret for OSS. Required if file_system is "
|
|
76
78
|
"'oss'.",
|
|
77
79
|
)
|
|
78
80
|
oss_bucket_name: Optional[str] = Field(
|
|
79
|
-
|
|
81
|
+
"your-bucket-name",
|
|
80
82
|
description="Bucket name in OSS. Required if file_system is 'oss'.",
|
|
81
83
|
)
|
|
82
84
|
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
ModelStudio Memory Components.
|
|
4
|
+
|
|
5
|
+
This package provides components for interacting with the ModelStudio Memory
|
|
6
|
+
service.
|
|
7
|
+
|
|
8
|
+
Components:
|
|
9
|
+
- AddMemory: Store conversation messages as memory nodes
|
|
10
|
+
- SearchMemory: Search for relevant memories
|
|
11
|
+
- ListMemory: List memory nodes with pagination
|
|
12
|
+
- DeleteMemory: Delete a specific memory node
|
|
13
|
+
- CreateProfileSchema: Create a user profile schema
|
|
14
|
+
- GetUserProfile: Retrieve a user profile
|
|
15
|
+
|
|
16
|
+
Schemas:
|
|
17
|
+
All Pydantic schemas for input/output are available in the schemas
|
|
18
|
+
submodule.
|
|
19
|
+
|
|
20
|
+
Exceptions:
|
|
21
|
+
Custom exceptions for better error handling are available in the
|
|
22
|
+
exceptions submodule.
|
|
23
|
+
|
|
24
|
+
Configuration:
|
|
25
|
+
Configuration can be managed through environment variables or by
|
|
26
|
+
providing a MemoryServiceConfig instance.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
# Configuration
|
|
30
|
+
from .config import MemoryServiceConfig
|
|
31
|
+
|
|
32
|
+
# Exceptions
|
|
33
|
+
from .exceptions import (
|
|
34
|
+
MemoryAPIError,
|
|
35
|
+
MemoryAuthenticationError,
|
|
36
|
+
MemoryNetworkError,
|
|
37
|
+
MemoryNotFoundError,
|
|
38
|
+
MemoryValidationError,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Components
|
|
42
|
+
from .core import (
|
|
43
|
+
AddMemory,
|
|
44
|
+
SearchMemory,
|
|
45
|
+
ListMemory,
|
|
46
|
+
DeleteMemory,
|
|
47
|
+
CreateProfileSchema,
|
|
48
|
+
GetUserProfile,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# Schemas - Import commonly used schemas for convenience
|
|
52
|
+
from .schemas import (
|
|
53
|
+
AddMemoryInput,
|
|
54
|
+
AddMemoryOutput,
|
|
55
|
+
CreateProfileSchemaInput,
|
|
56
|
+
CreateProfileSchemaOutput,
|
|
57
|
+
DeleteMemoryInput,
|
|
58
|
+
DeleteMemoryOutput,
|
|
59
|
+
GetUserProfileInput,
|
|
60
|
+
GetUserProfileOutput,
|
|
61
|
+
ListMemoryInput,
|
|
62
|
+
ListMemoryOutput,
|
|
63
|
+
MemoryNode,
|
|
64
|
+
Message,
|
|
65
|
+
ProfileAttribute,
|
|
66
|
+
SearchMemoryInput,
|
|
67
|
+
SearchMemoryOutput,
|
|
68
|
+
UserProfile,
|
|
69
|
+
UserProfileAttribute,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
__all__ = [
|
|
73
|
+
# Core Components
|
|
74
|
+
"AddMemory",
|
|
75
|
+
"SearchMemory",
|
|
76
|
+
"ListMemory",
|
|
77
|
+
"DeleteMemory",
|
|
78
|
+
"CreateProfileSchema",
|
|
79
|
+
"GetUserProfile",
|
|
80
|
+
# Configuration
|
|
81
|
+
"MemoryServiceConfig",
|
|
82
|
+
# Exceptions
|
|
83
|
+
"MemoryAPIError",
|
|
84
|
+
"MemoryAuthenticationError",
|
|
85
|
+
"MemoryNetworkError",
|
|
86
|
+
"MemoryNotFoundError",
|
|
87
|
+
"MemoryValidationError",
|
|
88
|
+
# Schemas
|
|
89
|
+
"Message",
|
|
90
|
+
"MemoryNode",
|
|
91
|
+
"AddMemoryInput",
|
|
92
|
+
"AddMemoryOutput",
|
|
93
|
+
"SearchMemoryInput",
|
|
94
|
+
"SearchMemoryOutput",
|
|
95
|
+
"ListMemoryInput",
|
|
96
|
+
"ListMemoryOutput",
|
|
97
|
+
"DeleteMemoryInput",
|
|
98
|
+
"DeleteMemoryOutput",
|
|
99
|
+
"ProfileAttribute",
|
|
100
|
+
"CreateProfileSchemaInput",
|
|
101
|
+
"CreateProfileSchemaOutput",
|
|
102
|
+
"UserProfileAttribute",
|
|
103
|
+
"UserProfile",
|
|
104
|
+
"GetUserProfileInput",
|
|
105
|
+
"GetUserProfileOutput",
|
|
106
|
+
]
|