agentscope-runtime 1.0.4__py3-none-any.whl → 1.0.4a1__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 +7 -1
- agentscope_runtime/cli/commands/deploy.py +0 -371
- agentscope_runtime/engine/__init__.py +0 -4
- agentscope_runtime/engine/constant.py +0 -1
- agentscope_runtime/engine/deployers/__init__.py +0 -12
- agentscope_runtime/engine/deployers/adapter/a2a/__init__.py +51 -26
- agentscope_runtime/engine/deployers/adapter/a2a/a2a_protocol_adapter.py +10 -19
- agentscope_runtime/engine/deployers/adapter/a2a/a2a_registry.py +201 -4
- agentscope_runtime/engine/deployers/adapter/a2a/nacos_a2a_registry.py +25 -134
- agentscope_runtime/engine/deployers/agentrun_deployer.py +2 -2
- agentscope_runtime/engine/runner.py +0 -12
- agentscope_runtime/engine/tracing/wrapper.py +4 -18
- agentscope_runtime/sandbox/__init__.py +6 -14
- agentscope_runtime/sandbox/box/base/__init__.py +2 -2
- agentscope_runtime/sandbox/box/base/base_sandbox.py +1 -51
- agentscope_runtime/sandbox/box/browser/__init__.py +2 -2
- agentscope_runtime/sandbox/box/browser/browser_sandbox.py +2 -198
- agentscope_runtime/sandbox/box/filesystem/__init__.py +2 -2
- agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +2 -99
- agentscope_runtime/sandbox/box/gui/__init__.py +2 -2
- agentscope_runtime/sandbox/box/gui/gui_sandbox.py +1 -117
- agentscope_runtime/sandbox/box/mobile/__init__.py +2 -2
- agentscope_runtime/sandbox/box/mobile/mobile_sandbox.py +100 -247
- agentscope_runtime/sandbox/box/sandbox.py +65 -98
- agentscope_runtime/sandbox/box/shared/routers/generic.py +29 -36
- agentscope_runtime/sandbox/client/__init__.py +1 -6
- agentscope_runtime/sandbox/client/http_client.py +329 -108
- agentscope_runtime/sandbox/enums.py +0 -7
- agentscope_runtime/sandbox/manager/sandbox_manager.py +4 -264
- agentscope_runtime/sandbox/manager/server/app.py +1 -7
- agentscope_runtime/version.py +1 -1
- {agentscope_runtime-1.0.4.dist-info → agentscope_runtime-1.0.4a1.dist-info}/METADATA +28 -102
- {agentscope_runtime-1.0.4.dist-info → agentscope_runtime-1.0.4a1.dist-info}/RECORD +37 -46
- agentscope_runtime/adapters/ms_agent_framework/__init__.py +0 -0
- agentscope_runtime/adapters/ms_agent_framework/message.py +0 -205
- agentscope_runtime/adapters/ms_agent_framework/stream.py +0 -418
- agentscope_runtime/adapters/utils.py +0 -6
- agentscope_runtime/common/container_clients/knative_client.py +0 -466
- agentscope_runtime/engine/deployers/fc_deployer.py +0 -1506
- agentscope_runtime/engine/deployers/knative_deployer.py +0 -290
- agentscope_runtime/sandbox/client/async_http_client.py +0 -339
- agentscope_runtime/sandbox/client/base.py +0 -74
- {agentscope_runtime-1.0.4.dist-info → agentscope_runtime-1.0.4a1.dist-info}/WHEEL +0 -0
- {agentscope_runtime-1.0.4.dist-info → agentscope_runtime-1.0.4a1.dist-info}/entry_points.txt +0 -0
- {agentscope_runtime-1.0.4.dist-info → agentscope_runtime-1.0.4a1.dist-info}/licenses/LICENSE +0 -0
- {agentscope_runtime-1.0.4.dist-info → agentscope_runtime-1.0.4a1.dist-info}/top_level.txt +0 -0
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
import logging
|
|
3
|
-
import os
|
|
4
|
-
from typing import Optional, Dict, List, Union, Any
|
|
5
|
-
|
|
6
|
-
from pydantic import BaseModel, Field
|
|
7
|
-
from .utils.docker_image_utils import (
|
|
8
|
-
ImageFactory,
|
|
9
|
-
RegistryConfig,
|
|
10
|
-
)
|
|
11
|
-
from .adapter.protocol_adapter import ProtocolAdapter
|
|
12
|
-
from .base import DeployManager
|
|
13
|
-
from ...common.container_clients.knative_client import (
|
|
14
|
-
KnativeClient,
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
logger = logging.getLogger(__name__)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class K8sConfig(BaseModel):
|
|
21
|
-
# Kubernetes settings
|
|
22
|
-
k8s_namespace: Optional[str] = Field(
|
|
23
|
-
"agentscope-runtime",
|
|
24
|
-
description="Kubernetes namespace to deploy KService. ",
|
|
25
|
-
)
|
|
26
|
-
kubeconfig_path: Optional[str] = Field(
|
|
27
|
-
None,
|
|
28
|
-
description="Path to kubeconfig file. If not set, will try "
|
|
29
|
-
"in-cluster config or default kubeconfig.",
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class BuildConfig(BaseModel):
|
|
34
|
-
"""Build configuration"""
|
|
35
|
-
|
|
36
|
-
build_context_dir: str = "/tmp/k8s_build"
|
|
37
|
-
dockerfile_template: str = None
|
|
38
|
-
build_timeout: int = 600 # 10 minutes
|
|
39
|
-
push_timeout: int = 300 # 5 minutes
|
|
40
|
-
cleanup_after_build: bool = True
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class KnativeDeployManager(DeployManager):
|
|
44
|
-
"""
|
|
45
|
-
Deploy an AgentScope runner as a Knative Service.
|
|
46
|
-
Requires a Kubernetes cluster with Knative Serving installed.
|
|
47
|
-
"""
|
|
48
|
-
|
|
49
|
-
def __init__(
|
|
50
|
-
self,
|
|
51
|
-
kube_config: K8sConfig = None,
|
|
52
|
-
registry_config: RegistryConfig = RegistryConfig(),
|
|
53
|
-
build_context_dir: str = "/tmp/k8s_build",
|
|
54
|
-
):
|
|
55
|
-
"""
|
|
56
|
-
Initialize the Knative deployer.
|
|
57
|
-
"""
|
|
58
|
-
super().__init__()
|
|
59
|
-
self.kubeconfig = kube_config
|
|
60
|
-
self.registry_config = registry_config
|
|
61
|
-
self.image_factory = ImageFactory()
|
|
62
|
-
self.build_context_dir = build_context_dir
|
|
63
|
-
self._deployed_resources = {}
|
|
64
|
-
self._built_images = {}
|
|
65
|
-
|
|
66
|
-
self.knative_client = KnativeClient(
|
|
67
|
-
config=self.kubeconfig,
|
|
68
|
-
image_registry=self.registry_config.get_full_url(),
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
async def deploy(
|
|
72
|
-
self,
|
|
73
|
-
app=None,
|
|
74
|
-
runner=None,
|
|
75
|
-
stream: bool = True,
|
|
76
|
-
protocol_adapters: Optional[list[ProtocolAdapter]] = None,
|
|
77
|
-
requirements: Optional[Union[str, List[str]]] = None,
|
|
78
|
-
extra_packages: Optional[List[str]] = None,
|
|
79
|
-
base_image: str = "python:3.9-slim",
|
|
80
|
-
environment: Dict = None,
|
|
81
|
-
runtime_config: Dict = None,
|
|
82
|
-
annotations: Dict = None,
|
|
83
|
-
labels: Dict = None,
|
|
84
|
-
port: int = 8080,
|
|
85
|
-
mount_dir: str = None,
|
|
86
|
-
image_name: str = "agent_llm",
|
|
87
|
-
image_tag: str = "latest",
|
|
88
|
-
push_to_registry: bool = False,
|
|
89
|
-
**kwargs,
|
|
90
|
-
) -> Dict[str, Any]:
|
|
91
|
-
"""
|
|
92
|
-
Deploy the runner as a Knative Service.
|
|
93
|
-
|
|
94
|
-
Args:
|
|
95
|
-
app: Agent app to be deployed
|
|
96
|
-
runner: Complete Runner object with agent, environment_manager,
|
|
97
|
-
context_manager
|
|
98
|
-
stream: Enable streaming responses
|
|
99
|
-
protocol_adapters: protocol adapters
|
|
100
|
-
requirements: PyPI dependencies (following _agent_engines.py
|
|
101
|
-
pattern)
|
|
102
|
-
extra_packages: User code directory/file path
|
|
103
|
-
base_image: Docker base image
|
|
104
|
-
port: Container port
|
|
105
|
-
environment: Environment variables dict
|
|
106
|
-
mount_dir: Mount directory
|
|
107
|
-
runtime_config: K8s runtime configuration
|
|
108
|
-
annotations: knative service annotations
|
|
109
|
-
labels: knative service labels
|
|
110
|
-
# Backward compatibility
|
|
111
|
-
image_name: Image name
|
|
112
|
-
image_tag: Image tag
|
|
113
|
-
push_to_registry: Push to registry
|
|
114
|
-
**kwargs: Additional arguments
|
|
115
|
-
|
|
116
|
-
Returns:
|
|
117
|
-
Dict containing deploy_id, url, resource_name
|
|
118
|
-
|
|
119
|
-
Raises:
|
|
120
|
-
RuntimeError: If kservice fails
|
|
121
|
-
|
|
122
|
-
"""
|
|
123
|
-
created_resources = []
|
|
124
|
-
deploy_id = self.deploy_id
|
|
125
|
-
try:
|
|
126
|
-
logger.info(f"Starting Knative Service {deploy_id}")
|
|
127
|
-
|
|
128
|
-
# Step 1: Build image with proper error handling
|
|
129
|
-
logger.info("Building runner image...")
|
|
130
|
-
try:
|
|
131
|
-
built_image_name = self.image_factory.build_image(
|
|
132
|
-
app=app,
|
|
133
|
-
runner=runner,
|
|
134
|
-
base_image=base_image,
|
|
135
|
-
build_context_dir=self.build_context_dir,
|
|
136
|
-
registry_config=self.registry_config,
|
|
137
|
-
image_name=image_name,
|
|
138
|
-
image_tag=image_tag,
|
|
139
|
-
push_to_registry=push_to_registry,
|
|
140
|
-
port=port,
|
|
141
|
-
protocol_adapters=protocol_adapters,
|
|
142
|
-
**kwargs,
|
|
143
|
-
)
|
|
144
|
-
if not built_image_name:
|
|
145
|
-
raise RuntimeError(
|
|
146
|
-
"Image build failed - no image name returned",
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
created_resources.append(f"image:{built_image_name}")
|
|
150
|
-
self._built_images[deploy_id] = built_image_name
|
|
151
|
-
logger.info(f"Image built successfully: {built_image_name}")
|
|
152
|
-
except Exception as e:
|
|
153
|
-
logger.error(f"Image build failed: {e}")
|
|
154
|
-
raise RuntimeError(f"Failed to build image: {e}") from e
|
|
155
|
-
|
|
156
|
-
if mount_dir:
|
|
157
|
-
if not os.path.isabs(mount_dir):
|
|
158
|
-
mount_dir = os.path.abspath(mount_dir)
|
|
159
|
-
|
|
160
|
-
volume_bindings = {
|
|
161
|
-
mount_dir: {
|
|
162
|
-
"bind": mount_dir,
|
|
163
|
-
"mode": "rw",
|
|
164
|
-
},
|
|
165
|
-
}
|
|
166
|
-
else:
|
|
167
|
-
volume_bindings = {}
|
|
168
|
-
|
|
169
|
-
resource_name = self.get_resource_name(deploy_id)
|
|
170
|
-
|
|
171
|
-
logger.info(f"Building Knative Service for {deploy_id}")
|
|
172
|
-
|
|
173
|
-
# Create Knative Service
|
|
174
|
-
name, url = self.knative_client.create_kservice(
|
|
175
|
-
name=resource_name,
|
|
176
|
-
image=built_image_name,
|
|
177
|
-
ports=[port],
|
|
178
|
-
volumes=volume_bindings,
|
|
179
|
-
environment=environment,
|
|
180
|
-
runtime_config=runtime_config or {},
|
|
181
|
-
annotations=annotations or {},
|
|
182
|
-
labels=labels or {},
|
|
183
|
-
)
|
|
184
|
-
if not url:
|
|
185
|
-
import traceback
|
|
186
|
-
|
|
187
|
-
raise RuntimeError(
|
|
188
|
-
f"Failed to create resource: "
|
|
189
|
-
f"{resource_name}, {traceback.format_exc()}",
|
|
190
|
-
)
|
|
191
|
-
|
|
192
|
-
logger.info(f"Knative Service url {url} successful")
|
|
193
|
-
self._deployed_resources[deploy_id] = {
|
|
194
|
-
"resource_name": name,
|
|
195
|
-
"config": {
|
|
196
|
-
"runner": runner.__class__.__name__,
|
|
197
|
-
"extra_packages": extra_packages,
|
|
198
|
-
"requirements": requirements, # New format
|
|
199
|
-
"base_image": base_image,
|
|
200
|
-
"port": port,
|
|
201
|
-
"environment": environment,
|
|
202
|
-
"runtime_config": runtime_config,
|
|
203
|
-
"stream": stream,
|
|
204
|
-
"protocol_adapters": protocol_adapters,
|
|
205
|
-
**kwargs,
|
|
206
|
-
},
|
|
207
|
-
}
|
|
208
|
-
return {
|
|
209
|
-
"deploy_id": deploy_id,
|
|
210
|
-
"resource_name": resource_name,
|
|
211
|
-
"url": url,
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
except Exception as e:
|
|
215
|
-
import traceback
|
|
216
|
-
|
|
217
|
-
logger.error(f"Knative Service {deploy_id} failed: {e}")
|
|
218
|
-
# Enhanced rollback with better error handling
|
|
219
|
-
raise RuntimeError(
|
|
220
|
-
f"Knative Service failed: {e}, {traceback.format_exc()}",
|
|
221
|
-
) from e
|
|
222
|
-
|
|
223
|
-
@staticmethod
|
|
224
|
-
def get_resource_name(deploy_id: str) -> str:
|
|
225
|
-
return f"agent-{deploy_id[:8]}"
|
|
226
|
-
|
|
227
|
-
async def stop(
|
|
228
|
-
self,
|
|
229
|
-
deploy_id: str,
|
|
230
|
-
**kwargs,
|
|
231
|
-
) -> Dict[str, Any]:
|
|
232
|
-
"""Stop Knative Service.
|
|
233
|
-
|
|
234
|
-
Args:
|
|
235
|
-
deploy_id: Deployment identifier
|
|
236
|
-
**kwargs: Additional parameters
|
|
237
|
-
|
|
238
|
-
Returns:
|
|
239
|
-
Dict with success status, message, and details
|
|
240
|
-
"""
|
|
241
|
-
|
|
242
|
-
resource_name = self.get_resource_name(deploy_id)
|
|
243
|
-
try:
|
|
244
|
-
# Try to remove the KService
|
|
245
|
-
success = self.knative_client.delete_kservice(resource_name)
|
|
246
|
-
|
|
247
|
-
if success:
|
|
248
|
-
return {
|
|
249
|
-
"success": True,
|
|
250
|
-
"message": f"Knative deployment {resource_name} "
|
|
251
|
-
f"removed",
|
|
252
|
-
"details": {
|
|
253
|
-
"deploy_id": deploy_id,
|
|
254
|
-
"resource_name": resource_name,
|
|
255
|
-
},
|
|
256
|
-
}
|
|
257
|
-
else:
|
|
258
|
-
return {
|
|
259
|
-
"success": False,
|
|
260
|
-
"message": f"Knative deployment {resource_name} not "
|
|
261
|
-
f"found (may already be deleted), Please check the "
|
|
262
|
-
f"detail in cluster",
|
|
263
|
-
"details": {
|
|
264
|
-
"deploy_id": deploy_id,
|
|
265
|
-
"resource_name": resource_name,
|
|
266
|
-
},
|
|
267
|
-
}
|
|
268
|
-
except Exception as e:
|
|
269
|
-
logger.error(
|
|
270
|
-
f"Failed to remove Knative service {resource_name}: {e}",
|
|
271
|
-
)
|
|
272
|
-
return {
|
|
273
|
-
"success": False,
|
|
274
|
-
"message": f"Failed to remove Knative service: {e}",
|
|
275
|
-
"details": {
|
|
276
|
-
"deploy_id": deploy_id,
|
|
277
|
-
"resource_name": resource_name,
|
|
278
|
-
"error": str(e),
|
|
279
|
-
},
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
def get_status(self) -> str:
|
|
283
|
-
"""Get KService status"""
|
|
284
|
-
if self.deploy_id not in self._deployed_resources:
|
|
285
|
-
return "not_found"
|
|
286
|
-
|
|
287
|
-
resources = self._deployed_resources[self.deploy_id]
|
|
288
|
-
kservice_name = resources["resource_name"]
|
|
289
|
-
|
|
290
|
-
return self.knative_client.get_kservice_status(kservice_name)
|
|
@@ -1,339 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
# pylint: disable=unused-argument
|
|
3
|
-
import logging
|
|
4
|
-
import asyncio
|
|
5
|
-
from typing import Any, Optional
|
|
6
|
-
|
|
7
|
-
import httpx
|
|
8
|
-
from pydantic import Field
|
|
9
|
-
|
|
10
|
-
from .base import SandboxHttpBase
|
|
11
|
-
from ..model import ContainerModel
|
|
12
|
-
|
|
13
|
-
logger = logging.getLogger(__name__)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class SandboxHttpAsyncClient(SandboxHttpBase):
|
|
17
|
-
"""
|
|
18
|
-
A Python async client for interacting with the runtime API.
|
|
19
|
-
Connect directly to the container.
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
def __init__(
|
|
23
|
-
self,
|
|
24
|
-
model: Optional[ContainerModel] = None,
|
|
25
|
-
timeout: int = 60,
|
|
26
|
-
domain: str = "localhost",
|
|
27
|
-
) -> None:
|
|
28
|
-
"""
|
|
29
|
-
Initialize the Python async client.
|
|
30
|
-
|
|
31
|
-
Args:
|
|
32
|
-
model (ContainerModel): The pydantic model representing the
|
|
33
|
-
runtime sandbox.
|
|
34
|
-
"""
|
|
35
|
-
super().__init__(model, timeout, domain)
|
|
36
|
-
self.client = httpx.AsyncClient(
|
|
37
|
-
timeout=self.timeout,
|
|
38
|
-
headers=self.headers,
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
async def __aenter__(self):
|
|
42
|
-
# Wait for the runtime api server to be healthy
|
|
43
|
-
await self.wait_until_healthy()
|
|
44
|
-
return self
|
|
45
|
-
|
|
46
|
-
async def __aexit__(self, exc_type, exc_value, traceback):
|
|
47
|
-
await self.client.aclose()
|
|
48
|
-
|
|
49
|
-
async def _request(self, method: str, url: str, **kwargs):
|
|
50
|
-
return await self.client.request(method, url, **kwargs)
|
|
51
|
-
|
|
52
|
-
async def safe_request(self, method: str, url: str, **kwargs):
|
|
53
|
-
"""
|
|
54
|
-
Unified HTTP request method with async exception handling.
|
|
55
|
-
Returns JSON if possible, otherwise plain text.
|
|
56
|
-
"""
|
|
57
|
-
try:
|
|
58
|
-
r = await self._request(method, url, **kwargs)
|
|
59
|
-
r.raise_for_status()
|
|
60
|
-
try:
|
|
61
|
-
return r.json()
|
|
62
|
-
except ValueError:
|
|
63
|
-
return r.text
|
|
64
|
-
except httpx.RequestError as e:
|
|
65
|
-
logger.error(f"HTTP error: {e}")
|
|
66
|
-
return {
|
|
67
|
-
"isError": True,
|
|
68
|
-
"content": [{"type": "text", "text": str(e)}],
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async def check_health(self) -> bool:
|
|
72
|
-
"""
|
|
73
|
-
Check if the runtime service is running by verifying the health
|
|
74
|
-
endpoint.
|
|
75
|
-
|
|
76
|
-
Returns:
|
|
77
|
-
bool: True if the service is reachable, False otherwise.
|
|
78
|
-
"""
|
|
79
|
-
try:
|
|
80
|
-
r = await self._request(
|
|
81
|
-
"get",
|
|
82
|
-
f"{self.base_url}/healthz",
|
|
83
|
-
)
|
|
84
|
-
return r.status_code == 200
|
|
85
|
-
except httpx.RequestError:
|
|
86
|
-
return False
|
|
87
|
-
|
|
88
|
-
async def wait_until_healthy(self) -> None:
|
|
89
|
-
"""
|
|
90
|
-
Wait until the runtime service is running for a specified timeout.
|
|
91
|
-
"""
|
|
92
|
-
start_time = asyncio.get_event_loop().time()
|
|
93
|
-
while (
|
|
94
|
-
asyncio.get_event_loop().time() - start_time < self.start_timeout
|
|
95
|
-
):
|
|
96
|
-
if await self.check_health():
|
|
97
|
-
return
|
|
98
|
-
await asyncio.sleep(1)
|
|
99
|
-
raise TimeoutError(
|
|
100
|
-
"Runtime service did not start within the specified timeout.",
|
|
101
|
-
)
|
|
102
|
-
|
|
103
|
-
async def add_mcp_servers(self, server_configs, overwrite=False):
|
|
104
|
-
"""
|
|
105
|
-
Add MCP servers to runtime.
|
|
106
|
-
"""
|
|
107
|
-
endpoint = f"{self.base_url}/mcp/add_servers"
|
|
108
|
-
return await self.safe_request(
|
|
109
|
-
"post",
|
|
110
|
-
endpoint,
|
|
111
|
-
json={"server_configs": server_configs, "overwrite": overwrite},
|
|
112
|
-
)
|
|
113
|
-
|
|
114
|
-
async def list_tools(self, tool_type=None, **kwargs) -> dict:
|
|
115
|
-
"""
|
|
116
|
-
List available MCP tools plus generic built-in tools.
|
|
117
|
-
"""
|
|
118
|
-
data = await self.safe_request(
|
|
119
|
-
"get",
|
|
120
|
-
f"{self.base_url}/mcp/list_tools",
|
|
121
|
-
)
|
|
122
|
-
if isinstance(data, dict) and "isError" not in data:
|
|
123
|
-
data["generic"] = self.generic_tools
|
|
124
|
-
if tool_type:
|
|
125
|
-
return {tool_type: data.get(tool_type, {})}
|
|
126
|
-
return data
|
|
127
|
-
|
|
128
|
-
async def call_tool(
|
|
129
|
-
self,
|
|
130
|
-
name: str,
|
|
131
|
-
arguments: Optional[dict[str, Any]] = None,
|
|
132
|
-
) -> dict:
|
|
133
|
-
"""
|
|
134
|
-
Call a specific MCP tool.
|
|
135
|
-
|
|
136
|
-
If it's a generic tool, call the corresponding local method.
|
|
137
|
-
"""
|
|
138
|
-
if arguments is None:
|
|
139
|
-
arguments = {}
|
|
140
|
-
if name in self.generic_tools:
|
|
141
|
-
if name == "run_ipython_cell":
|
|
142
|
-
return await self.run_ipython_cell(**arguments)
|
|
143
|
-
elif name == "run_shell_command":
|
|
144
|
-
return await self.run_shell_command(**arguments)
|
|
145
|
-
|
|
146
|
-
return await self.safe_request(
|
|
147
|
-
"post",
|
|
148
|
-
f"{self.base_url}/mcp/call_tool",
|
|
149
|
-
json={"tool_name": name, "arguments": arguments},
|
|
150
|
-
)
|
|
151
|
-
|
|
152
|
-
async def run_ipython_cell(
|
|
153
|
-
self,
|
|
154
|
-
code: str = Field(description="IPython code to execute"),
|
|
155
|
-
) -> dict:
|
|
156
|
-
"""
|
|
157
|
-
Run an IPython cell.
|
|
158
|
-
"""
|
|
159
|
-
return await self.safe_request(
|
|
160
|
-
"post",
|
|
161
|
-
f"{self.base_url}/tools/run_ipython_cell",
|
|
162
|
-
json={"code": code},
|
|
163
|
-
)
|
|
164
|
-
|
|
165
|
-
async def run_shell_command(
|
|
166
|
-
self,
|
|
167
|
-
command: str = Field(description="Shell command to execute"),
|
|
168
|
-
) -> dict:
|
|
169
|
-
"""
|
|
170
|
-
Run a shell command.
|
|
171
|
-
"""
|
|
172
|
-
return await self.safe_request(
|
|
173
|
-
"post",
|
|
174
|
-
f"{self.base_url}/tools/run_shell_command",
|
|
175
|
-
json={"command": command},
|
|
176
|
-
)
|
|
177
|
-
|
|
178
|
-
async def commit_changes(
|
|
179
|
-
self,
|
|
180
|
-
commit_message: str = "Automated commit",
|
|
181
|
-
) -> dict:
|
|
182
|
-
"""
|
|
183
|
-
Commit the uncommitted changes with a given commit message.
|
|
184
|
-
"""
|
|
185
|
-
return await self.safe_request(
|
|
186
|
-
"post",
|
|
187
|
-
f"{self.base_url}/watcher/commit_changes",
|
|
188
|
-
json={"commit_message": commit_message},
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
async def generate_diff(
|
|
192
|
-
self,
|
|
193
|
-
commit_a: Optional[str] = None,
|
|
194
|
-
commit_b: Optional[str] = None,
|
|
195
|
-
) -> dict:
|
|
196
|
-
"""
|
|
197
|
-
Generate the diff between two commits or between uncommitted changes
|
|
198
|
-
and the latest commit.
|
|
199
|
-
"""
|
|
200
|
-
return await self.safe_request(
|
|
201
|
-
"post",
|
|
202
|
-
f"{self.base_url}/watcher/generate_diff",
|
|
203
|
-
json={"commit_a": commit_a, "commit_b": commit_b},
|
|
204
|
-
)
|
|
205
|
-
|
|
206
|
-
async def git_logs(self) -> dict:
|
|
207
|
-
"""
|
|
208
|
-
Retrieve the git logs.
|
|
209
|
-
"""
|
|
210
|
-
return await self.safe_request(
|
|
211
|
-
"get",
|
|
212
|
-
f"{self.base_url}/watcher/git_logs",
|
|
213
|
-
)
|
|
214
|
-
|
|
215
|
-
# -------- Workspace File APIs --------
|
|
216
|
-
|
|
217
|
-
async def get_workspace_file(self, file_path: str) -> dict:
|
|
218
|
-
"""
|
|
219
|
-
Retrieve a file from the /workspace directory.
|
|
220
|
-
"""
|
|
221
|
-
try:
|
|
222
|
-
endpoint = f"{self.base_url}/workspace/files"
|
|
223
|
-
params = {"file_path": file_path}
|
|
224
|
-
r = await self._request("get", endpoint, params=params)
|
|
225
|
-
r.raise_for_status()
|
|
226
|
-
|
|
227
|
-
# Check for empty content
|
|
228
|
-
if r.headers.get("Content-Length") == "0":
|
|
229
|
-
logger.warning(f"The file {file_path} is empty.")
|
|
230
|
-
return {"data": b""}
|
|
231
|
-
|
|
232
|
-
# Accumulate the content in chunks
|
|
233
|
-
file_content = bytearray()
|
|
234
|
-
async for chunk in r.aiter_bytes():
|
|
235
|
-
file_content.extend(chunk)
|
|
236
|
-
|
|
237
|
-
return {"data": bytes(file_content)}
|
|
238
|
-
except httpx.RequestError as e:
|
|
239
|
-
logger.error(f"An error occurred while retrieving the file: {e}")
|
|
240
|
-
return {
|
|
241
|
-
"isError": True,
|
|
242
|
-
"content": [{"type": "text", "text": str(e)}],
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
async def create_or_edit_workspace_file(
|
|
246
|
-
self,
|
|
247
|
-
file_path: str,
|
|
248
|
-
content: str,
|
|
249
|
-
) -> dict:
|
|
250
|
-
"""
|
|
251
|
-
Create or edit a file within the /workspace directory.
|
|
252
|
-
"""
|
|
253
|
-
return await self.safe_request(
|
|
254
|
-
"post",
|
|
255
|
-
f"{self.base_url}/workspace/files",
|
|
256
|
-
params={"file_path": file_path},
|
|
257
|
-
json={"content": content},
|
|
258
|
-
)
|
|
259
|
-
|
|
260
|
-
async def list_workspace_directories(
|
|
261
|
-
self,
|
|
262
|
-
directory: str = "/workspace",
|
|
263
|
-
) -> dict:
|
|
264
|
-
"""
|
|
265
|
-
List files in the specified directory within the /workspace.
|
|
266
|
-
"""
|
|
267
|
-
return await self.safe_request(
|
|
268
|
-
"get",
|
|
269
|
-
f"{self.base_url}/workspace/list-directories",
|
|
270
|
-
params={"directory": directory},
|
|
271
|
-
)
|
|
272
|
-
|
|
273
|
-
async def create_workspace_directory(self, directory_path: str) -> dict:
|
|
274
|
-
"""
|
|
275
|
-
Create a directory within the /workspace directory.
|
|
276
|
-
"""
|
|
277
|
-
return await self.safe_request(
|
|
278
|
-
"post",
|
|
279
|
-
f"{self.base_url}/workspace/directories",
|
|
280
|
-
params={"directory_path": directory_path},
|
|
281
|
-
)
|
|
282
|
-
|
|
283
|
-
async def delete_workspace_file(self, file_path: str) -> dict:
|
|
284
|
-
"""
|
|
285
|
-
Delete a file within the /workspace directory.
|
|
286
|
-
"""
|
|
287
|
-
return await self.safe_request(
|
|
288
|
-
"delete",
|
|
289
|
-
f"{self.base_url}/workspace/files",
|
|
290
|
-
params={"file_path": file_path},
|
|
291
|
-
)
|
|
292
|
-
|
|
293
|
-
async def delete_workspace_directory(
|
|
294
|
-
self,
|
|
295
|
-
directory_path: str,
|
|
296
|
-
recursive: bool = False,
|
|
297
|
-
) -> dict:
|
|
298
|
-
"""
|
|
299
|
-
Delete a directory within the /workspace directory.
|
|
300
|
-
"""
|
|
301
|
-
return await self.safe_request(
|
|
302
|
-
"delete",
|
|
303
|
-
f"{self.base_url}/workspace/directories",
|
|
304
|
-
params={"directory_path": directory_path, "recursive": recursive},
|
|
305
|
-
)
|
|
306
|
-
|
|
307
|
-
async def move_or_rename_workspace_item(
|
|
308
|
-
self,
|
|
309
|
-
source_path: str,
|
|
310
|
-
destination_path: str,
|
|
311
|
-
) -> dict:
|
|
312
|
-
"""
|
|
313
|
-
Move or rename a file or directory within the /workspace directory.
|
|
314
|
-
"""
|
|
315
|
-
return await self.safe_request(
|
|
316
|
-
"put",
|
|
317
|
-
f"{self.base_url}/workspace/move",
|
|
318
|
-
params={
|
|
319
|
-
"source_path": source_path,
|
|
320
|
-
"destination_path": destination_path,
|
|
321
|
-
},
|
|
322
|
-
)
|
|
323
|
-
|
|
324
|
-
async def copy_workspace_item(
|
|
325
|
-
self,
|
|
326
|
-
source_path: str,
|
|
327
|
-
destination_path: str,
|
|
328
|
-
) -> dict:
|
|
329
|
-
"""
|
|
330
|
-
Copy a file or directory within the /workspace directory.
|
|
331
|
-
"""
|
|
332
|
-
return await self.safe_request(
|
|
333
|
-
"post",
|
|
334
|
-
f"{self.base_url}/workspace/copy",
|
|
335
|
-
params={
|
|
336
|
-
"source_path": source_path,
|
|
337
|
-
"destination_path": destination_path,
|
|
338
|
-
},
|
|
339
|
-
)
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
import logging
|
|
3
|
-
from urllib.parse import urljoin
|
|
4
|
-
|
|
5
|
-
DEFAULT_TIMEOUT = 60
|
|
6
|
-
|
|
7
|
-
logging.basicConfig(level=logging.INFO)
|
|
8
|
-
logger = logging.getLogger(__name__)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class SandboxHttpBase:
|
|
12
|
-
_generic_tools = {
|
|
13
|
-
"run_ipython_cell": {
|
|
14
|
-
"name": "run_ipython_cell",
|
|
15
|
-
"json_schema": {
|
|
16
|
-
"type": "function",
|
|
17
|
-
"function": {
|
|
18
|
-
"name": "run_ipython_cell",
|
|
19
|
-
"description": "Run an IPython cell.",
|
|
20
|
-
"parameters": {
|
|
21
|
-
"type": "object",
|
|
22
|
-
"properties": {
|
|
23
|
-
"code": {
|
|
24
|
-
"type": "string",
|
|
25
|
-
"description": "IPython code to execute",
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
"required": ["code"],
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
"run_shell_command": {
|
|
34
|
-
"name": "run_shell_command",
|
|
35
|
-
"json_schema": {
|
|
36
|
-
"type": "function",
|
|
37
|
-
"function": {
|
|
38
|
-
"name": "run_shell_command",
|
|
39
|
-
"description": "Run a shell command.",
|
|
40
|
-
"parameters": {
|
|
41
|
-
"type": "object",
|
|
42
|
-
"properties": {
|
|
43
|
-
"command": {
|
|
44
|
-
"type": "string",
|
|
45
|
-
"description": "Shell command to execute",
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
"required": ["command"],
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
def __init__(self, model, timeout: int = 60, domain: str = "localhost"):
|
|
56
|
-
self.base_url = urljoin(
|
|
57
|
-
model.url.replace("localhost", domain),
|
|
58
|
-
"fastapi",
|
|
59
|
-
)
|
|
60
|
-
self.start_timeout = timeout
|
|
61
|
-
self.timeout = model.timeout or DEFAULT_TIMEOUT
|
|
62
|
-
self.secret = model.runtime_token
|
|
63
|
-
|
|
64
|
-
self.headers = {
|
|
65
|
-
"Content-Type": "application/json",
|
|
66
|
-
"x-agentrun-session-id": "s" + model.container_id,
|
|
67
|
-
"x-agentscope-runtime-session-id": "s" + model.container_id,
|
|
68
|
-
}
|
|
69
|
-
if self.secret:
|
|
70
|
-
self.headers["Authorization"] = f"Bearer {self.secret}"
|
|
71
|
-
|
|
72
|
-
@property
|
|
73
|
-
def generic_tools(self) -> dict:
|
|
74
|
-
return self._generic_tools
|
|
File without changes
|
{agentscope_runtime-1.0.4.dist-info → agentscope_runtime-1.0.4a1.dist-info}/entry_points.txt
RENAMED
|
File without changes
|