agentscope-runtime 1.0.1__py3-none-any.whl → 1.0.3__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/message.py +32 -7
- agentscope_runtime/adapters/agentscope/stream.py +121 -91
- agentscope_runtime/adapters/agno/__init__.py +0 -0
- agentscope_runtime/adapters/agno/message.py +30 -0
- agentscope_runtime/adapters/agno/stream.py +122 -0
- agentscope_runtime/adapters/langgraph/__init__.py +12 -0
- agentscope_runtime/adapters/langgraph/message.py +257 -0
- agentscope_runtime/adapters/langgraph/stream.py +205 -0
- agentscope_runtime/cli/__init__.py +7 -0
- agentscope_runtime/cli/cli.py +63 -0
- agentscope_runtime/cli/commands/__init__.py +2 -0
- agentscope_runtime/cli/commands/chat.py +815 -0
- agentscope_runtime/cli/commands/deploy.py +1074 -0
- agentscope_runtime/cli/commands/invoke.py +58 -0
- agentscope_runtime/cli/commands/list_cmd.py +103 -0
- agentscope_runtime/cli/commands/run.py +176 -0
- agentscope_runtime/cli/commands/sandbox.py +128 -0
- agentscope_runtime/cli/commands/status.py +60 -0
- agentscope_runtime/cli/commands/stop.py +185 -0
- agentscope_runtime/cli/commands/web.py +166 -0
- agentscope_runtime/cli/loaders/__init__.py +6 -0
- agentscope_runtime/cli/loaders/agent_loader.py +295 -0
- agentscope_runtime/cli/state/__init__.py +10 -0
- agentscope_runtime/cli/utils/__init__.py +18 -0
- agentscope_runtime/cli/utils/console.py +378 -0
- agentscope_runtime/cli/utils/validators.py +118 -0
- agentscope_runtime/common/collections/redis_mapping.py +4 -1
- agentscope_runtime/engine/app/agent_app.py +55 -9
- agentscope_runtime/engine/deployers/__init__.py +1 -0
- agentscope_runtime/engine/deployers/adapter/a2a/__init__.py +56 -1
- agentscope_runtime/engine/deployers/adapter/a2a/a2a_protocol_adapter.py +449 -41
- agentscope_runtime/engine/deployers/adapter/a2a/a2a_registry.py +273 -0
- agentscope_runtime/engine/deployers/adapter/a2a/nacos_a2a_registry.py +640 -0
- agentscope_runtime/engine/deployers/agentrun_deployer.py +152 -22
- agentscope_runtime/engine/deployers/base.py +27 -2
- agentscope_runtime/engine/deployers/kubernetes_deployer.py +161 -31
- agentscope_runtime/engine/deployers/local_deployer.py +188 -25
- agentscope_runtime/engine/deployers/modelstudio_deployer.py +109 -18
- agentscope_runtime/engine/deployers/state/__init__.py +9 -0
- agentscope_runtime/engine/deployers/state/manager.py +388 -0
- agentscope_runtime/engine/deployers/state/schema.py +96 -0
- agentscope_runtime/engine/deployers/utils/build_cache.py +736 -0
- agentscope_runtime/engine/deployers/utils/detached_app.py +105 -30
- agentscope_runtime/engine/deployers/utils/docker_image_utils/docker_image_builder.py +31 -10
- agentscope_runtime/engine/deployers/utils/docker_image_utils/dockerfile_generator.py +23 -10
- agentscope_runtime/engine/deployers/utils/docker_image_utils/image_factory.py +35 -2
- agentscope_runtime/engine/deployers/utils/k8s_utils.py +241 -0
- agentscope_runtime/engine/deployers/utils/net_utils.py +65 -0
- agentscope_runtime/engine/deployers/utils/package.py +56 -6
- agentscope_runtime/engine/deployers/utils/service_utils/fastapi_factory.py +16 -2
- agentscope_runtime/engine/deployers/utils/service_utils/process_manager.py +155 -5
- agentscope_runtime/engine/deployers/utils/wheel_packager.py +107 -123
- agentscope_runtime/engine/runner.py +30 -9
- agentscope_runtime/engine/schemas/exception.py +604 -0
- agentscope_runtime/engine/services/agent_state/redis_state_service.py +61 -8
- agentscope_runtime/engine/services/agent_state/state_service_factory.py +2 -5
- agentscope_runtime/engine/services/memory/redis_memory_service.py +129 -25
- agentscope_runtime/engine/services/session_history/redis_session_history_service.py +160 -34
- agentscope_runtime/sandbox/box/mobile/mobile_sandbox.py +113 -39
- agentscope_runtime/sandbox/box/shared/routers/mcp_utils.py +20 -4
- agentscope_runtime/sandbox/build.py +50 -57
- agentscope_runtime/sandbox/utils.py +2 -0
- agentscope_runtime/version.py +1 -1
- {agentscope_runtime-1.0.1.dist-info → agentscope_runtime-1.0.3.dist-info}/METADATA +31 -8
- {agentscope_runtime-1.0.1.dist-info → agentscope_runtime-1.0.3.dist-info}/RECORD +69 -36
- {agentscope_runtime-1.0.1.dist-info → agentscope_runtime-1.0.3.dist-info}/entry_points.txt +1 -0
- {agentscope_runtime-1.0.1.dist-info → agentscope_runtime-1.0.3.dist-info}/WHEEL +0 -0
- {agentscope_runtime-1.0.1.dist-info → agentscope_runtime-1.0.3.dist-info}/licenses/LICENSE +0 -0
- {agentscope_runtime-1.0.1.dist-info → agentscope_runtime-1.0.3.dist-info}/top_level.txt +0 -0
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
# pylint:disable=too-many-return-statements
|
|
2
|
+
# pylint:disable=too-many-return-statements, too-many-branches
|
|
3
3
|
|
|
4
4
|
"""Shared helpers for building detached deployment bundles."""
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
7
|
-
import os
|
|
8
7
|
|
|
9
8
|
import json
|
|
9
|
+
import os
|
|
10
|
+
import re
|
|
10
11
|
import shutil
|
|
11
12
|
import tempfile
|
|
12
13
|
import zipfile
|
|
@@ -14,10 +15,14 @@ from pathlib import Path
|
|
|
14
15
|
from typing import Any, Dict, List, Optional, Tuple, Type, Union
|
|
15
16
|
|
|
16
17
|
from .app_runner_utils import ensure_runner_from_app
|
|
17
|
-
from .package import
|
|
18
|
+
from .package import (
|
|
19
|
+
package,
|
|
20
|
+
ProjectInfo,
|
|
21
|
+
DEFAULT_ENTRYPOINT_FILE,
|
|
22
|
+
DEPLOYMENT_ZIP,
|
|
23
|
+
generate_build_directory,
|
|
24
|
+
)
|
|
18
25
|
from ..adapter.protocol_adapter import ProtocolAdapter
|
|
19
|
-
from .package import DEPLOYMENT_ZIP
|
|
20
|
-
from .wheel_packager import _parse_pyproject_toml
|
|
21
26
|
|
|
22
27
|
try:
|
|
23
28
|
import tomllib # Python 3.11+
|
|
@@ -36,19 +41,25 @@ def build_detached_app(
|
|
|
36
41
|
*,
|
|
37
42
|
app=None,
|
|
38
43
|
runner=None,
|
|
44
|
+
entrypoint: Optional[str] = None,
|
|
39
45
|
requirements: Optional[Union[str, List[str]]] = None,
|
|
40
46
|
extra_packages: Optional[List[str]] = None,
|
|
41
47
|
output_dir: Optional[str] = None,
|
|
42
48
|
dockerfile_path: Optional[str] = None,
|
|
43
49
|
use_local_runtime: Optional[bool] = None,
|
|
50
|
+
platform: str = "unknown",
|
|
44
51
|
**kwargs,
|
|
45
52
|
) -> Tuple[str, ProjectInfo]:
|
|
46
53
|
"""
|
|
47
54
|
Create a detached bundle directory ready for execution.
|
|
48
55
|
|
|
56
|
+
All temporary files are created in cwd/.agentscope_runtime/ by default.
|
|
57
|
+
|
|
49
58
|
Args:
|
|
50
59
|
app: AgentApp instance to deploy
|
|
51
60
|
runner: Runner instance to deploy
|
|
61
|
+
entrypoint: Entrypoint specification (e.g., "app.py" or
|
|
62
|
+
"app.py:handler")
|
|
52
63
|
requirements: Additional pip requirements (string or list)
|
|
53
64
|
extra_packages: Additional Python packages to include
|
|
54
65
|
output_dir: Output directory (creates temp dir if None)
|
|
@@ -64,8 +75,8 @@ def build_detached_app(
|
|
|
64
75
|
if app is not None and runner is None:
|
|
65
76
|
runner = ensure_runner_from_app(app)
|
|
66
77
|
|
|
67
|
-
if runner is None and app is None:
|
|
68
|
-
raise ValueError("Either app or runner must be provided")
|
|
78
|
+
if runner is None and app is None and entrypoint is None:
|
|
79
|
+
raise ValueError("Either app or runner or entrypoint must be provided")
|
|
69
80
|
|
|
70
81
|
normalized_requirements = _normalize_requirements(requirements)
|
|
71
82
|
|
|
@@ -75,17 +86,18 @@ def build_detached_app(
|
|
|
75
86
|
shutil.rmtree(build_root)
|
|
76
87
|
build_root.mkdir(parents=True, exist_ok=True)
|
|
77
88
|
else:
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
),
|
|
82
|
-
)
|
|
89
|
+
# Use generate_build_directory for consistent naming
|
|
90
|
+
build_root = generate_build_directory(platform)
|
|
91
|
+
build_root.mkdir(parents=True, exist_ok=True)
|
|
83
92
|
|
|
84
93
|
package_path, project_info = package(
|
|
85
94
|
app=app,
|
|
86
95
|
runner=None if app is not None else runner,
|
|
96
|
+
entrypoint=entrypoint,
|
|
87
97
|
output_dir=str(build_root),
|
|
88
98
|
extra_packages=extra_packages,
|
|
99
|
+
requirements=normalized_requirements,
|
|
100
|
+
platform=platform,
|
|
89
101
|
**kwargs,
|
|
90
102
|
)
|
|
91
103
|
|
|
@@ -102,12 +114,7 @@ def build_detached_app(
|
|
|
102
114
|
with zipfile.ZipFile(deployment_zip, "r") as archive:
|
|
103
115
|
archive.extractall(project_root)
|
|
104
116
|
|
|
105
|
-
|
|
106
|
-
if use_local_runtime is None:
|
|
107
|
-
package_version = _get_package_version()
|
|
108
|
-
use_local_runtime = _is_dev_version(package_version)
|
|
109
|
-
|
|
110
|
-
_append_additional_requirements(
|
|
117
|
+
append_project_requirements(
|
|
111
118
|
project_root,
|
|
112
119
|
normalized_requirements,
|
|
113
120
|
use_local_runtime=use_local_runtime,
|
|
@@ -146,10 +153,10 @@ def _normalize_requirements(
|
|
|
146
153
|
return [str(item) for item in requirements]
|
|
147
154
|
|
|
148
155
|
|
|
149
|
-
def
|
|
156
|
+
def append_project_requirements(
|
|
150
157
|
extraction_dir: Path,
|
|
151
|
-
additional_requirements:
|
|
152
|
-
use_local_runtime: bool = False,
|
|
158
|
+
additional_requirements: Optional[Union[str, list]],
|
|
159
|
+
use_local_runtime: Optional[bool] = False,
|
|
153
160
|
) -> None:
|
|
154
161
|
"""
|
|
155
162
|
Append requirements to requirements.txt.
|
|
@@ -163,16 +170,15 @@ def _append_additional_requirements(
|
|
|
163
170
|
use_local_runtime: If True, build and use local runtime wheel.
|
|
164
171
|
Useful for development when runtime is not released.
|
|
165
172
|
"""
|
|
173
|
+
# Auto-detect if not specified
|
|
174
|
+
if use_local_runtime is None:
|
|
175
|
+
use_local_runtime = os.getenv("USE_LOCAL_RUNTIME", "False") == "True"
|
|
176
|
+
|
|
166
177
|
req_path = extraction_dir / "requirements.txt"
|
|
167
178
|
package_version = _get_package_version()
|
|
168
179
|
|
|
169
|
-
# Auto-detect if we should use local runtime
|
|
170
|
-
should_use_local = use_local_runtime or (
|
|
171
|
-
package_version and _is_dev_version(package_version)
|
|
172
|
-
)
|
|
173
|
-
|
|
174
180
|
with open(str(req_path), "w", encoding="utf-8") as f:
|
|
175
|
-
if
|
|
181
|
+
if use_local_runtime:
|
|
176
182
|
# Create wheels subdirectory
|
|
177
183
|
# Get base requirements from pyproject.toml
|
|
178
184
|
runtime_source = _get_runtime_source_path()
|
|
@@ -203,8 +209,6 @@ def _append_additional_requirements(
|
|
|
203
209
|
"fastapi",
|
|
204
210
|
"uvicorn",
|
|
205
211
|
f"agentscope-runtime=={package_version}",
|
|
206
|
-
f"agentscope-runtime[sandbox]=={package_version}",
|
|
207
|
-
f"agentscope-runtime[deployment]=={package_version}",
|
|
208
212
|
"pydantic",
|
|
209
213
|
"jinja2", # For template rendering
|
|
210
214
|
"psutil", # For process management
|
|
@@ -218,6 +222,9 @@ def _append_additional_requirements(
|
|
|
218
222
|
if not additional_requirements:
|
|
219
223
|
additional_requirements = []
|
|
220
224
|
|
|
225
|
+
if isinstance(additional_requirements, str):
|
|
226
|
+
additional_requirements = additional_requirements.split(",")
|
|
227
|
+
|
|
221
228
|
# Combine base requirements with user requirements
|
|
222
229
|
all_requirements = sorted(
|
|
223
230
|
list(
|
|
@@ -230,6 +237,72 @@ def _append_additional_requirements(
|
|
|
230
237
|
f.write(f"{req}\n")
|
|
231
238
|
|
|
232
239
|
|
|
240
|
+
def _parse_pyproject_toml(pyproject_path: Path) -> List[str]:
|
|
241
|
+
deps: List[str] = []
|
|
242
|
+
if not pyproject_path.is_file():
|
|
243
|
+
return deps
|
|
244
|
+
text = pyproject_path.read_text(encoding="utf-8")
|
|
245
|
+
|
|
246
|
+
try:
|
|
247
|
+
# Prefer stdlib tomllib (Python 3.11+)
|
|
248
|
+
if tomllib is None:
|
|
249
|
+
raise RuntimeError("tomllib not available")
|
|
250
|
+
data = tomllib.loads(text)
|
|
251
|
+
# PEP 621
|
|
252
|
+
proj = data.get("project") or {}
|
|
253
|
+
deps.extend(proj.get("dependencies") or [])
|
|
254
|
+
# Poetry fallback
|
|
255
|
+
poetry = (data.get("tool") or {}).get("poetry") or {}
|
|
256
|
+
poetry_deps = poetry.get("dependencies") or {}
|
|
257
|
+
for name, spec in poetry_deps.items():
|
|
258
|
+
if name.lower() == "python":
|
|
259
|
+
continue
|
|
260
|
+
if isinstance(spec, str):
|
|
261
|
+
deps.append(f"{name}{spec if spec.strip() else ''}")
|
|
262
|
+
elif isinstance(spec, dict):
|
|
263
|
+
version = spec.get("version")
|
|
264
|
+
if version:
|
|
265
|
+
deps.append(f"{name}{version}")
|
|
266
|
+
else:
|
|
267
|
+
deps.append(name)
|
|
268
|
+
except Exception:
|
|
269
|
+
# Minimal non-toml parser fallback
|
|
270
|
+
block_match = re.search(
|
|
271
|
+
r"dependencies\s*=\s*\[(.*?)\]",
|
|
272
|
+
text,
|
|
273
|
+
re.S | re.I,
|
|
274
|
+
)
|
|
275
|
+
if block_match:
|
|
276
|
+
block = block_match.group(1)
|
|
277
|
+
for m in re.finditer(r"['\"]([^'\"]+)['\"]", block):
|
|
278
|
+
deps.append(m.group(1))
|
|
279
|
+
# Poetry fallback: very limited, heuristic
|
|
280
|
+
poetry_block = re.search(
|
|
281
|
+
r"\[tool\.poetry\.dependencies\](.*?)\n\[",
|
|
282
|
+
text,
|
|
283
|
+
re.S,
|
|
284
|
+
)
|
|
285
|
+
if poetry_block:
|
|
286
|
+
for line in poetry_block.group(1).splitlines():
|
|
287
|
+
line = line.strip()
|
|
288
|
+
if not line or line.startswith("#"):
|
|
289
|
+
continue
|
|
290
|
+
if ":" in line:
|
|
291
|
+
# name = "^1.2.3"
|
|
292
|
+
m = re.match(
|
|
293
|
+
r"([A-Za-z0-9_.-]+)\s*=\s*['\"]([^'\"]+)['\"]",
|
|
294
|
+
line,
|
|
295
|
+
)
|
|
296
|
+
if m and m.group(1).lower() != "python":
|
|
297
|
+
deps.append(f"{m.group(1)}{m.group(2)}")
|
|
298
|
+
else:
|
|
299
|
+
# name without version
|
|
300
|
+
name = line.split("#")[0].strip()
|
|
301
|
+
if name and name.lower() != "python":
|
|
302
|
+
deps.append(name)
|
|
303
|
+
return deps
|
|
304
|
+
|
|
305
|
+
|
|
233
306
|
def _get_package_version() -> str:
|
|
234
307
|
"""
|
|
235
308
|
Get the package version from pyproject.toml file.
|
|
@@ -496,7 +569,9 @@ def _write_bundle_meta(bundle_dir: Path, entry_script: str) -> None:
|
|
|
496
569
|
meta_path.write_text(json.dumps(meta, indent=2), encoding="utf-8")
|
|
497
570
|
|
|
498
571
|
|
|
499
|
-
def get_bundle_entry_script(bundle_dir: Union[str, Path]) -> str:
|
|
572
|
+
def get_bundle_entry_script(bundle_dir: Optional[Union[str, Path]]) -> str:
|
|
573
|
+
if bundle_dir is None:
|
|
574
|
+
return DEFAULT_ENTRYPOINT_FILE
|
|
500
575
|
meta_path = Path(bundle_dir) / META_FILENAME
|
|
501
576
|
if meta_path.exists():
|
|
502
577
|
try:
|
|
@@ -17,11 +17,13 @@ class RegistryConfig(BaseModel):
|
|
|
17
17
|
registry_url: str = ""
|
|
18
18
|
username: str = None
|
|
19
19
|
password: str = None
|
|
20
|
-
namespace: str = "agentscope-runtime"
|
|
20
|
+
namespace: Optional[str] = "agentscope-runtime"
|
|
21
21
|
image_pull_secret: str = None
|
|
22
22
|
|
|
23
23
|
def get_full_url(self) -> str:
|
|
24
24
|
# Handle different registry URL formats
|
|
25
|
+
if self.registry_url == "localhost":
|
|
26
|
+
return self.registry_url
|
|
25
27
|
return f"{self.registry_url}/{self.namespace}"
|
|
26
28
|
|
|
27
29
|
|
|
@@ -201,27 +203,21 @@ class DockerImageBuilder:
|
|
|
201
203
|
error_msg,
|
|
202
204
|
) from e
|
|
203
205
|
|
|
204
|
-
def
|
|
206
|
+
def tag_image(
|
|
205
207
|
self,
|
|
206
208
|
image_name: str,
|
|
207
209
|
registry_config: Optional[RegistryConfig] = None,
|
|
208
|
-
quiet: bool = False,
|
|
209
210
|
) -> str:
|
|
210
211
|
"""
|
|
211
|
-
|
|
212
|
+
Tag image with registry info.
|
|
212
213
|
|
|
213
214
|
Args:
|
|
214
215
|
image_name: Full image name to push
|
|
215
216
|
registry_config: Optional registry config
|
|
216
217
|
(uses instance config if None)
|
|
217
|
-
quiet: Whether to suppress output
|
|
218
218
|
|
|
219
219
|
Returns:
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
Raises:
|
|
223
|
-
subprocess.CalledProcessError: If push fails
|
|
224
|
-
ValueError: If no registry configuration is available
|
|
220
|
+
registry_image_name: Full image name with url
|
|
225
221
|
"""
|
|
226
222
|
config = registry_config
|
|
227
223
|
if not config:
|
|
@@ -240,6 +236,31 @@ class DockerImageBuilder:
|
|
|
240
236
|
)
|
|
241
237
|
else:
|
|
242
238
|
registry_image_name = image_name
|
|
239
|
+
return registry_image_name
|
|
240
|
+
|
|
241
|
+
def push_image(
|
|
242
|
+
self,
|
|
243
|
+
image_name: str,
|
|
244
|
+
registry_config: Optional[RegistryConfig] = None,
|
|
245
|
+
quiet: bool = False,
|
|
246
|
+
) -> str:
|
|
247
|
+
"""
|
|
248
|
+
Push image to registry.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
image_name: Full image name to push
|
|
252
|
+
registry_config: Optional registry config
|
|
253
|
+
(uses instance config if None)
|
|
254
|
+
quiet: Whether to suppress output
|
|
255
|
+
|
|
256
|
+
Returns:
|
|
257
|
+
str: Full image name that was pushed
|
|
258
|
+
|
|
259
|
+
Raises:
|
|
260
|
+
subprocess.CalledProcessError: If push fails
|
|
261
|
+
ValueError: If no registry configuration is available
|
|
262
|
+
"""
|
|
263
|
+
registry_image_name = self.tag_image(image_name, registry_config)
|
|
243
264
|
|
|
244
265
|
try:
|
|
245
266
|
push_cmd = ["docker", "push", registry_image_name]
|
|
@@ -21,6 +21,8 @@ class DockerfileConfig(BaseModel):
|
|
|
21
21
|
startup_command: Optional[str] = None
|
|
22
22
|
health_check_endpoint: str = "/health"
|
|
23
23
|
custom_template: Optional[str] = None
|
|
24
|
+
platform: Optional[str] = None
|
|
25
|
+
pypi_mirror: Optional[str] = None
|
|
24
26
|
|
|
25
27
|
|
|
26
28
|
class DockerfileGenerator:
|
|
@@ -31,7 +33,7 @@ class DockerfileGenerator:
|
|
|
31
33
|
|
|
32
34
|
# Default Dockerfile template for Python applications
|
|
33
35
|
DEFAULT_TEMPLATE = """# Use official Python runtime as base image
|
|
34
|
-
FROM {base_image}
|
|
36
|
+
FROM --platform={platform} {base_image}
|
|
35
37
|
|
|
36
38
|
# Set working directory in container
|
|
37
39
|
WORKDIR /app
|
|
@@ -43,15 +45,20 @@ ENV PYTHONUNBUFFERED=1
|
|
|
43
45
|
# Configure package sources for better performance
|
|
44
46
|
RUN rm -f /etc/apt/sources.list.d/*.list
|
|
45
47
|
|
|
46
|
-
#
|
|
47
|
-
RUN echo "deb https://mirrors.aliyun.com/debian/ bookworm main contrib "
|
|
48
|
-
"non-free non-free-firmware" > /etc/apt/sources.list &&
|
|
49
|
-
echo "deb https://mirrors.aliyun.com/debian/ bookworm-updates main "
|
|
50
|
-
"contrib non-free non-free-firmware" >> /etc/apt/sources.list &&
|
|
51
|
-
echo "deb https://mirrors.aliyun.com/debian-security/ "
|
|
52
|
-
"bookworm-security main contrib non-free "
|
|
48
|
+
# add aliyun mirrors
|
|
49
|
+
RUN echo "deb https://mirrors.aliyun.com/debian/ bookworm main contrib " \
|
|
50
|
+
"non-free non-free-firmware" > /etc/apt/sources.list && \
|
|
51
|
+
echo "deb https://mirrors.aliyun.com/debian/ bookworm-updates main " \
|
|
52
|
+
"contrib non-free non-free-firmware" >> /etc/apt/sources.list && \
|
|
53
|
+
echo "deb https://mirrors.aliyun.com/debian-security/ " \
|
|
54
|
+
"bookworm-security main contrib non-free " \
|
|
53
55
|
"non-free-firmware" >> /etc/apt/sources.list
|
|
54
56
|
|
|
57
|
+
# replace debian to aliyun
|
|
58
|
+
RUN mkdir -p /etc/apt/sources.list.d && \
|
|
59
|
+
cat > /etc/apt/sources.list.d/debian.sources <<'EOF'
|
|
60
|
+
EOF
|
|
61
|
+
|
|
55
62
|
# Clean up package lists
|
|
56
63
|
RUN rm -rf /var/lib/apt/lists/*
|
|
57
64
|
|
|
@@ -67,8 +74,7 @@ COPY . {working_dir}/
|
|
|
67
74
|
# Install Python dependencies
|
|
68
75
|
RUN pip install --no-cache-dir --upgrade pip
|
|
69
76
|
RUN if [ -f requirements.txt ]; then \\
|
|
70
|
-
pip install --no-cache-dir -r requirements.txt
|
|
71
|
-
-i https://pypi.tuna.tsinghua.edu.cn/simple; fi
|
|
77
|
+
pip install --no-cache-dir -r requirements.txt{pypi_mirror_flag}; fi
|
|
72
78
|
|
|
73
79
|
# Create non-root user for security
|
|
74
80
|
RUN adduser --disabled-password --gecos '' {user} && \\
|
|
@@ -130,6 +136,11 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \\
|
|
|
130
136
|
f'"--port", "{config.port}"]'
|
|
131
137
|
)
|
|
132
138
|
|
|
139
|
+
# Prepare PyPI mirror flag
|
|
140
|
+
pypi_mirror_flag = ""
|
|
141
|
+
if config.pypi_mirror:
|
|
142
|
+
pypi_mirror_flag = f" -i {config.pypi_mirror}"
|
|
143
|
+
|
|
133
144
|
# Format template with configuration values
|
|
134
145
|
content = template.format(
|
|
135
146
|
base_image=config.base_image,
|
|
@@ -140,6 +151,8 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \\
|
|
|
140
151
|
additional_packages_section=additional_packages_section,
|
|
141
152
|
env_vars_section=env_vars_section,
|
|
142
153
|
startup_command_section=startup_command_section,
|
|
154
|
+
platform=config.platform,
|
|
155
|
+
pypi_mirror_flag=pypi_mirror_flag,
|
|
143
156
|
)
|
|
144
157
|
|
|
145
158
|
return content
|
|
@@ -28,7 +28,7 @@ class ImageConfig(BaseModel):
|
|
|
28
28
|
# Package configuration
|
|
29
29
|
requirements: Optional[List[str]] = None
|
|
30
30
|
extra_packages: Optional[List[str]] = None
|
|
31
|
-
build_context_dir: str =
|
|
31
|
+
build_context_dir: Optional[str] = None
|
|
32
32
|
endpoint_path: str = "/process"
|
|
33
33
|
protocol_adapters: Optional[List] = None # New: protocol adapters
|
|
34
34
|
custom_endpoints: Optional[
|
|
@@ -40,6 +40,7 @@ class ImageConfig(BaseModel):
|
|
|
40
40
|
port: int = 8000
|
|
41
41
|
env_vars: Dict[str, str] = Field(default_factory=lambda: {})
|
|
42
42
|
startup_command: Optional[str] = None
|
|
43
|
+
pypi_mirror: Optional[str] = None
|
|
43
44
|
|
|
44
45
|
# Runtime configuration
|
|
45
46
|
host: str = "0.0.0.0" # Container-friendly default
|
|
@@ -171,6 +172,8 @@ class ImageFactory:
|
|
|
171
172
|
app,
|
|
172
173
|
runner: Optional[Runner],
|
|
173
174
|
config: ImageConfig,
|
|
175
|
+
entrypoint: Optional[str] = None,
|
|
176
|
+
use_cache: bool = True,
|
|
174
177
|
) -> str:
|
|
175
178
|
"""
|
|
176
179
|
Build a complete Docker image for the Runner.
|
|
@@ -181,9 +184,15 @@ class ImageFactory:
|
|
|
181
184
|
3. Build Docker image
|
|
182
185
|
4. Optionally push to registry
|
|
183
186
|
|
|
187
|
+
All temporary files are created in cwd/.agentscope_runtime/ by default.
|
|
188
|
+
|
|
184
189
|
Args:
|
|
190
|
+
app: Agent app object
|
|
185
191
|
runner: Runner object containing agent and managers
|
|
186
192
|
config: Configuration for the image building process
|
|
193
|
+
entrypoint: Entrypoint specification (e.g., "app.py" or
|
|
194
|
+
"app.py:handler")
|
|
195
|
+
use_cache: Enable build cache (default: True)
|
|
187
196
|
|
|
188
197
|
Returns:
|
|
189
198
|
str: Full image name (with registry if pushed)
|
|
@@ -209,6 +218,8 @@ class ImageFactory:
|
|
|
209
218
|
port=config.port,
|
|
210
219
|
env_vars=config.env_vars,
|
|
211
220
|
startup_command=startup_command,
|
|
221
|
+
platform=config.platform,
|
|
222
|
+
pypi_mirror=config.pypi_mirror,
|
|
212
223
|
)
|
|
213
224
|
|
|
214
225
|
dockerfile_path = self.dockerfile_generator.create_dockerfile(
|
|
@@ -222,10 +233,13 @@ class ImageFactory:
|
|
|
222
233
|
project_dir, _ = build_detached_app(
|
|
223
234
|
app=app,
|
|
224
235
|
runner=runner,
|
|
236
|
+
entrypoint=entrypoint,
|
|
225
237
|
requirements=config.requirements,
|
|
226
238
|
extra_packages=config.extra_packages,
|
|
227
239
|
output_dir=config.build_context_dir,
|
|
228
240
|
dockerfile_path=dockerfile_path,
|
|
241
|
+
use_cache=use_cache,
|
|
242
|
+
platform="k8s",
|
|
229
243
|
)
|
|
230
244
|
is_updated = True
|
|
231
245
|
logger.info(f"Project packaged: {project_dir}")
|
|
@@ -260,6 +274,15 @@ class ImageFactory:
|
|
|
260
274
|
config=build_config,
|
|
261
275
|
source_updated=is_updated,
|
|
262
276
|
)
|
|
277
|
+
logger.info(f"Image built: {full_image_name}")
|
|
278
|
+
|
|
279
|
+
# make sure tag the image if not push
|
|
280
|
+
registry_full_name = self.image_builder.tag_image(
|
|
281
|
+
full_image_name,
|
|
282
|
+
config.registry_config,
|
|
283
|
+
)
|
|
284
|
+
logger.info(f"Image tag to: {registry_full_name}")
|
|
285
|
+
|
|
263
286
|
logger.info(f"Image built locally: {full_image_name}")
|
|
264
287
|
|
|
265
288
|
return full_image_name
|
|
@@ -276,6 +299,7 @@ class ImageFactory:
|
|
|
276
299
|
self,
|
|
277
300
|
app=None,
|
|
278
301
|
runner: Optional[Runner] = None,
|
|
302
|
+
entrypoint: Optional[str] = None,
|
|
279
303
|
requirements: Optional[Union[str, List[str]]] = None,
|
|
280
304
|
extra_packages: Optional[List[str]] = None,
|
|
281
305
|
base_image: str = "python:3.10-slim-bookworm",
|
|
@@ -291,14 +315,20 @@ class ImageFactory:
|
|
|
291
315
|
host: str = "0.0.0.0",
|
|
292
316
|
embed_task_processor: bool = True,
|
|
293
317
|
extra_startup_args: Optional[Dict[str, Union[str, int, bool]]] = None,
|
|
318
|
+
use_cache: bool = True,
|
|
319
|
+
pypi_mirror: Optional[str] = None,
|
|
294
320
|
**kwargs,
|
|
295
321
|
) -> str:
|
|
296
322
|
"""
|
|
297
323
|
Simplified interface for building Runner images.
|
|
298
324
|
|
|
325
|
+
All temporary files are created in cwd/.agentscope_runtime/ by default.
|
|
326
|
+
|
|
299
327
|
Args:
|
|
300
328
|
app: agent app object
|
|
301
329
|
runner: Runner object
|
|
330
|
+
entrypoint: Entrypoint specification (e.g., "app.py" or
|
|
331
|
+
"app.py:handler")
|
|
302
332
|
requirements: Python requirements
|
|
303
333
|
extra_packages: Additional files to include
|
|
304
334
|
base_image: Docker base image
|
|
@@ -311,6 +341,8 @@ class ImageFactory:
|
|
|
311
341
|
host: Host to bind to (default: 0.0.0.0 for containers)
|
|
312
342
|
embed_task_processor: Whether to embed task processor
|
|
313
343
|
extra_startup_args: Additional startup arguments
|
|
344
|
+
use_cache: Enable build cache (default: True)
|
|
345
|
+
pypi_mirror: PyPI mirror URL for pip package installation
|
|
314
346
|
**kwargs: Additional configuration options
|
|
315
347
|
|
|
316
348
|
Returns:
|
|
@@ -345,10 +377,11 @@ class ImageFactory:
|
|
|
345
377
|
host=host,
|
|
346
378
|
embed_task_processor=embed_task_processor,
|
|
347
379
|
extra_startup_args=extra_startup_args or {},
|
|
380
|
+
pypi_mirror=pypi_mirror,
|
|
348
381
|
**kwargs,
|
|
349
382
|
)
|
|
350
383
|
|
|
351
|
-
return self._build_image(app, runner, config)
|
|
384
|
+
return self._build_image(app, runner, config, entrypoint, use_cache)
|
|
352
385
|
|
|
353
386
|
def cleanup(self):
|
|
354
387
|
"""Clean up all temporary resources"""
|