agentscope-runtime 0.2.0b2__py3-none-any.whl → 1.0.0__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/__init__.py +0 -0
- agentscope_runtime/adapters/agentscope/__init__.py +0 -0
- agentscope_runtime/adapters/agentscope/long_term_memory/__init__.py +6 -0
- agentscope_runtime/adapters/agentscope/long_term_memory/_long_term_memory_adapter.py +258 -0
- agentscope_runtime/adapters/agentscope/memory/__init__.py +6 -0
- agentscope_runtime/adapters/agentscope/memory/_memory_adapter.py +152 -0
- agentscope_runtime/adapters/agentscope/message.py +535 -0
- agentscope_runtime/adapters/agentscope/stream.py +506 -0
- agentscope_runtime/adapters/agentscope/tool/__init__.py +9 -0
- agentscope_runtime/adapters/agentscope/tool/sandbox_tool.py +69 -0
- agentscope_runtime/adapters/agentscope/tool/tool.py +233 -0
- agentscope_runtime/adapters/autogen/__init__.py +0 -0
- agentscope_runtime/adapters/autogen/tool/__init__.py +7 -0
- agentscope_runtime/adapters/autogen/tool/tool.py +211 -0
- agentscope_runtime/adapters/text/__init__.py +0 -0
- agentscope_runtime/adapters/text/stream.py +29 -0
- agentscope_runtime/common/collections/redis_mapping.py +4 -1
- agentscope_runtime/common/container_clients/fc_client.py +855 -0
- agentscope_runtime/common/utils/__init__.py +0 -0
- agentscope_runtime/common/utils/lazy_loader.py +57 -0
- agentscope_runtime/engine/__init__.py +25 -18
- agentscope_runtime/engine/app/agent_app.py +161 -91
- agentscope_runtime/engine/app/base_app.py +4 -118
- agentscope_runtime/engine/constant.py +8 -0
- agentscope_runtime/engine/deployers/__init__.py +8 -0
- agentscope_runtime/engine/deployers/adapter/__init__.py +2 -0
- agentscope_runtime/engine/deployers/adapter/a2a/a2a_adapter_utils.py +0 -21
- agentscope_runtime/engine/deployers/adapter/a2a/a2a_protocol_adapter.py +28 -9
- agentscope_runtime/engine/deployers/adapter/responses/__init__.py +2 -0
- agentscope_runtime/engine/deployers/adapter/responses/response_api_adapter_utils.py +5 -2
- agentscope_runtime/engine/deployers/adapter/responses/response_api_protocol_adapter.py +1 -1
- agentscope_runtime/engine/deployers/agentrun_deployer.py +2541 -0
- agentscope_runtime/engine/deployers/cli_fc_deploy.py +1 -1
- agentscope_runtime/engine/deployers/kubernetes_deployer.py +9 -21
- agentscope_runtime/engine/deployers/local_deployer.py +47 -74
- agentscope_runtime/engine/deployers/modelstudio_deployer.py +216 -50
- agentscope_runtime/engine/deployers/utils/app_runner_utils.py +29 -0
- agentscope_runtime/engine/deployers/utils/detached_app.py +510 -0
- agentscope_runtime/engine/deployers/utils/docker_image_utils/__init__.py +1 -1
- agentscope_runtime/engine/deployers/utils/docker_image_utils/dockerfile_generator.py +1 -1
- agentscope_runtime/engine/deployers/utils/docker_image_utils/{runner_image_factory.py → image_factory.py} +121 -61
- agentscope_runtime/engine/deployers/utils/package.py +693 -0
- agentscope_runtime/engine/deployers/utils/service_utils/__init__.py +0 -5
- agentscope_runtime/engine/deployers/utils/service_utils/fastapi_factory.py +301 -282
- agentscope_runtime/engine/deployers/utils/service_utils/fastapi_templates.py +2 -4
- agentscope_runtime/engine/deployers/utils/service_utils/process_manager.py +23 -1
- agentscope_runtime/engine/deployers/utils/templates/app_main.py.j2 +84 -0
- agentscope_runtime/engine/deployers/utils/templates/runner_main.py.j2 +95 -0
- agentscope_runtime/engine/deployers/utils/{service_utils → templates}/standalone_main.py.j2 +0 -45
- agentscope_runtime/engine/deployers/utils/wheel_packager.py +119 -18
- agentscope_runtime/engine/helpers/runner.py +40 -0
- agentscope_runtime/engine/runner.py +171 -130
- agentscope_runtime/engine/schemas/agent_schemas.py +114 -3
- agentscope_runtime/engine/schemas/modelstudio_llm.py +4 -2
- agentscope_runtime/engine/schemas/oai_llm.py +23 -23
- agentscope_runtime/engine/schemas/response_api.py +65 -0
- agentscope_runtime/engine/schemas/session.py +24 -0
- agentscope_runtime/engine/services/__init__.py +0 -9
- agentscope_runtime/engine/services/agent_state/__init__.py +16 -0
- agentscope_runtime/engine/services/agent_state/redis_state_service.py +113 -0
- agentscope_runtime/engine/services/agent_state/state_service.py +179 -0
- agentscope_runtime/engine/services/memory/__init__.py +24 -0
- agentscope_runtime/engine/services/{mem0_memory_service.py → memory/mem0_memory_service.py} +17 -13
- agentscope_runtime/engine/services/{memory_service.py → memory/memory_service.py} +28 -7
- agentscope_runtime/engine/services/{redis_memory_service.py → memory/redis_memory_service.py} +1 -1
- agentscope_runtime/engine/services/{reme_personal_memory_service.py → memory/reme_personal_memory_service.py} +9 -6
- agentscope_runtime/engine/services/{reme_task_memory_service.py → memory/reme_task_memory_service.py} +2 -2
- agentscope_runtime/engine/services/{tablestore_memory_service.py → memory/tablestore_memory_service.py} +12 -18
- agentscope_runtime/engine/services/sandbox/__init__.py +13 -0
- agentscope_runtime/engine/services/{sandbox_service.py → sandbox/sandbox_service.py} +86 -71
- agentscope_runtime/engine/services/session_history/__init__.py +23 -0
- agentscope_runtime/engine/services/{redis_session_history_service.py → session_history/redis_session_history_service.py} +3 -2
- agentscope_runtime/engine/services/{session_history_service.py → session_history/session_history_service.py} +44 -34
- agentscope_runtime/engine/services/{tablestore_session_history_service.py → session_history/tablestore_session_history_service.py} +14 -19
- agentscope_runtime/engine/services/utils/tablestore_service_utils.py +2 -2
- agentscope_runtime/engine/tracing/base.py +10 -9
- agentscope_runtime/engine/tracing/message_util.py +1 -1
- agentscope_runtime/engine/tracing/tracing_util.py +7 -2
- agentscope_runtime/engine/tracing/wrapper.py +49 -31
- agentscope_runtime/sandbox/__init__.py +10 -2
- agentscope_runtime/sandbox/box/agentbay/__init__.py +4 -0
- agentscope_runtime/sandbox/box/agentbay/agentbay_sandbox.py +559 -0
- agentscope_runtime/sandbox/box/base/base_sandbox.py +12 -0
- agentscope_runtime/sandbox/box/browser/browser_sandbox.py +115 -11
- agentscope_runtime/sandbox/box/cloud/__init__.py +4 -0
- agentscope_runtime/sandbox/box/cloud/cloud_sandbox.py +254 -0
- agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +66 -0
- agentscope_runtime/sandbox/box/gui/gui_sandbox.py +42 -0
- agentscope_runtime/sandbox/box/mobile/__init__.py +4 -0
- agentscope_runtime/sandbox/box/mobile/box/__init__.py +0 -0
- agentscope_runtime/sandbox/box/mobile/mobile_sandbox.py +216 -0
- agentscope_runtime/sandbox/box/training_box/training_box.py +2 -2
- agentscope_runtime/sandbox/client/http_client.py +1 -0
- agentscope_runtime/sandbox/enums.py +2 -0
- agentscope_runtime/sandbox/manager/sandbox_manager.py +15 -2
- agentscope_runtime/sandbox/manager/server/app.py +12 -0
- agentscope_runtime/sandbox/manager/server/config.py +19 -0
- agentscope_runtime/sandbox/model/manager_config.py +79 -2
- agentscope_runtime/sandbox/utils.py +0 -18
- agentscope_runtime/tools/RAGs/__init__.py +0 -0
- agentscope_runtime/tools/RAGs/modelstudio_rag.py +377 -0
- agentscope_runtime/tools/RAGs/modelstudio_rag_lite.py +219 -0
- agentscope_runtime/tools/__init__.py +119 -0
- agentscope_runtime/tools/_constants.py +18 -0
- agentscope_runtime/tools/alipay/__init__.py +4 -0
- agentscope_runtime/tools/alipay/base.py +334 -0
- agentscope_runtime/tools/alipay/payment.py +835 -0
- agentscope_runtime/tools/alipay/subscribe.py +551 -0
- agentscope_runtime/tools/base.py +264 -0
- agentscope_runtime/tools/cli/__init__.py +0 -0
- agentscope_runtime/tools/cli/modelstudio_mcp_server.py +78 -0
- agentscope_runtime/tools/generations/__init__.py +75 -0
- agentscope_runtime/tools/generations/async_image_to_video.py +350 -0
- agentscope_runtime/tools/generations/async_image_to_video_wan25.py +366 -0
- agentscope_runtime/tools/generations/async_speech_to_video.py +422 -0
- agentscope_runtime/tools/generations/async_text_to_video.py +320 -0
- agentscope_runtime/tools/generations/async_text_to_video_wan25.py +334 -0
- agentscope_runtime/tools/generations/image_edit.py +208 -0
- agentscope_runtime/tools/generations/image_edit_wan25.py +193 -0
- agentscope_runtime/tools/generations/image_generation.py +202 -0
- agentscope_runtime/tools/generations/image_generation_wan25.py +201 -0
- agentscope_runtime/tools/generations/image_style_repaint.py +208 -0
- agentscope_runtime/tools/generations/image_to_video.py +233 -0
- agentscope_runtime/tools/generations/qwen_image_edit.py +205 -0
- agentscope_runtime/tools/generations/qwen_image_generation.py +214 -0
- agentscope_runtime/tools/generations/qwen_text_to_speech.py +154 -0
- agentscope_runtime/tools/generations/speech_to_text.py +260 -0
- agentscope_runtime/tools/generations/speech_to_video.py +314 -0
- agentscope_runtime/tools/generations/text_to_video.py +221 -0
- agentscope_runtime/tools/mcp_wrapper.py +215 -0
- agentscope_runtime/tools/realtime_clients/__init__.py +13 -0
- agentscope_runtime/tools/realtime_clients/asr_client.py +27 -0
- agentscope_runtime/tools/realtime_clients/azure_asr_client.py +195 -0
- agentscope_runtime/tools/realtime_clients/azure_tts_client.py +383 -0
- agentscope_runtime/tools/realtime_clients/modelstudio_asr_client.py +151 -0
- agentscope_runtime/tools/realtime_clients/modelstudio_tts_client.py +199 -0
- agentscope_runtime/tools/realtime_clients/realtime_tool.py +55 -0
- agentscope_runtime/tools/realtime_clients/tts_client.py +33 -0
- agentscope_runtime/tools/searches/__init__.py +3 -0
- agentscope_runtime/tools/searches/modelstudio_search.py +877 -0
- agentscope_runtime/tools/searches/modelstudio_search_lite.py +310 -0
- agentscope_runtime/tools/utils/__init__.py +0 -0
- agentscope_runtime/tools/utils/api_key_util.py +45 -0
- agentscope_runtime/tools/utils/crypto_utils.py +99 -0
- agentscope_runtime/tools/utils/mcp_util.py +35 -0
- agentscope_runtime/version.py +1 -1
- {agentscope_runtime-0.2.0b2.dist-info → agentscope_runtime-1.0.0.dist-info}/METADATA +240 -168
- agentscope_runtime-1.0.0.dist-info/RECORD +240 -0
- {agentscope_runtime-0.2.0b2.dist-info → agentscope_runtime-1.0.0.dist-info}/entry_points.txt +1 -0
- agentscope_runtime/engine/agents/__init__.py +0 -2
- agentscope_runtime/engine/agents/agentscope_agent.py +0 -488
- agentscope_runtime/engine/agents/agno_agent.py +0 -220
- agentscope_runtime/engine/agents/autogen_agent.py +0 -250
- agentscope_runtime/engine/agents/base_agent.py +0 -29
- agentscope_runtime/engine/agents/langgraph_agent.py +0 -59
- agentscope_runtime/engine/agents/utils.py +0 -53
- agentscope_runtime/engine/deployers/utils/package_project_utils.py +0 -1163
- 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/helpers/helper.py +0 -179
- agentscope_runtime/engine/schemas/context.py +0 -54
- agentscope_runtime/engine/services/context_manager.py +0 -164
- agentscope_runtime/engine/services/environment_manager.py +0 -50
- agentscope_runtime/engine/services/manager.py +0 -174
- agentscope_runtime/engine/services/rag_service.py +0 -195
- agentscope_runtime/engine/services/tablestore_rag_service.py +0 -143
- agentscope_runtime/sandbox/tools/__init__.py +0 -12
- agentscope_runtime/sandbox/tools/base/__init__.py +0 -8
- agentscope_runtime/sandbox/tools/base/tool.py +0 -52
- agentscope_runtime/sandbox/tools/browser/__init__.py +0 -57
- agentscope_runtime/sandbox/tools/browser/tool.py +0 -597
- agentscope_runtime/sandbox/tools/filesystem/__init__.py +0 -32
- agentscope_runtime/sandbox/tools/filesystem/tool.py +0 -319
- agentscope_runtime/sandbox/tools/function_tool.py +0 -321
- agentscope_runtime/sandbox/tools/gui/__init__.py +0 -7
- agentscope_runtime/sandbox/tools/gui/tool.py +0 -77
- agentscope_runtime/sandbox/tools/mcp_tool.py +0 -195
- agentscope_runtime/sandbox/tools/sandbox_tool.py +0 -104
- agentscope_runtime/sandbox/tools/tool.py +0 -238
- agentscope_runtime/sandbox/tools/utils.py +0 -68
- agentscope_runtime-0.2.0b2.dist-info/RECORD +0 -183
- {agentscope_runtime-0.2.0b2.dist-info → agentscope_runtime-1.0.0.dist-info}/WHEEL +0 -0
- {agentscope_runtime-0.2.0b2.dist-info → agentscope_runtime-1.0.0.dist-info}/licenses/LICENSE +0 -0
- {agentscope_runtime-0.2.0b2.dist-info → agentscope_runtime-1.0.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# pylint:disable=too-many-return-statements
|
|
3
|
+
|
|
4
|
+
"""Shared helpers for building detached deployment bundles."""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import shutil
|
|
11
|
+
import tempfile
|
|
12
|
+
import zipfile
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any, Dict, List, Optional, Tuple, Type, Union
|
|
15
|
+
|
|
16
|
+
from .app_runner_utils import ensure_runner_from_app
|
|
17
|
+
from .package import package, ProjectInfo, DEFAULT_ENTRYPOINT_FILE
|
|
18
|
+
from ..adapter.protocol_adapter import ProtocolAdapter
|
|
19
|
+
from .package import DEPLOYMENT_ZIP
|
|
20
|
+
from .wheel_packager import _parse_pyproject_toml
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
import tomllib # Python 3.11+
|
|
24
|
+
except ImportError:
|
|
25
|
+
try:
|
|
26
|
+
import tomli as tomllib # type: ignore[no-redef]
|
|
27
|
+
except ImportError:
|
|
28
|
+
tomllib = None
|
|
29
|
+
|
|
30
|
+
PROJECT_SUBDIR = ".agentscope_runtime"
|
|
31
|
+
CONFIG_FILENAME = "deploy_config.json"
|
|
32
|
+
META_FILENAME = "bundle_meta.json"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def build_detached_app(
|
|
36
|
+
*,
|
|
37
|
+
app=None,
|
|
38
|
+
runner=None,
|
|
39
|
+
requirements: Optional[Union[str, List[str]]] = None,
|
|
40
|
+
extra_packages: Optional[List[str]] = None,
|
|
41
|
+
output_dir: Optional[str] = None,
|
|
42
|
+
dockerfile_path: Optional[str] = None,
|
|
43
|
+
use_local_runtime: Optional[bool] = None,
|
|
44
|
+
**kwargs,
|
|
45
|
+
) -> Tuple[str, ProjectInfo]:
|
|
46
|
+
"""
|
|
47
|
+
Create a detached bundle directory ready for execution.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
app: AgentApp instance to deploy
|
|
51
|
+
runner: Runner instance to deploy
|
|
52
|
+
requirements: Additional pip requirements (string or list)
|
|
53
|
+
extra_packages: Additional Python packages to include
|
|
54
|
+
output_dir: Output directory (creates temp dir if None)
|
|
55
|
+
dockerfile_path: Optional custom Dockerfile path to include
|
|
56
|
+
use_local_runtime: If True, build and include local runtime wheel.
|
|
57
|
+
If None (default), auto-detect based on version.
|
|
58
|
+
Useful for development when runtime is not released.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Tuple of (project_root_path, project_info)
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
if app is not None and runner is None:
|
|
65
|
+
runner = ensure_runner_from_app(app)
|
|
66
|
+
|
|
67
|
+
if runner is None and app is None:
|
|
68
|
+
raise ValueError("Either app or runner must be provided")
|
|
69
|
+
|
|
70
|
+
normalized_requirements = _normalize_requirements(requirements)
|
|
71
|
+
|
|
72
|
+
if output_dir:
|
|
73
|
+
build_root = Path(output_dir)
|
|
74
|
+
if build_root.exists():
|
|
75
|
+
shutil.rmtree(build_root)
|
|
76
|
+
build_root.mkdir(parents=True, exist_ok=True)
|
|
77
|
+
else:
|
|
78
|
+
build_root = Path(
|
|
79
|
+
tempfile.mkdtemp(
|
|
80
|
+
prefix="agentscope_runtime_detached_",
|
|
81
|
+
),
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
package_path, project_info = package(
|
|
85
|
+
app=app,
|
|
86
|
+
runner=None if app is not None else runner,
|
|
87
|
+
output_dir=str(build_root),
|
|
88
|
+
extra_packages=extra_packages,
|
|
89
|
+
**kwargs,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
workspace_root = Path(package_path)
|
|
93
|
+
project_root = workspace_root / PROJECT_SUBDIR
|
|
94
|
+
project_root.mkdir(parents=True, exist_ok=True)
|
|
95
|
+
|
|
96
|
+
deployment_zip = workspace_root / DEPLOYMENT_ZIP
|
|
97
|
+
if not deployment_zip.exists():
|
|
98
|
+
raise RuntimeError(
|
|
99
|
+
f"deployment.zip not found in packaged output: {deployment_zip}",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
with zipfile.ZipFile(deployment_zip, "r") as archive:
|
|
103
|
+
archive.extractall(project_root)
|
|
104
|
+
|
|
105
|
+
# Auto-detect if not specified
|
|
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(
|
|
111
|
+
project_root,
|
|
112
|
+
normalized_requirements,
|
|
113
|
+
use_local_runtime=use_local_runtime,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
if not project_info.entrypoint_file:
|
|
117
|
+
raise RuntimeError("Unable to determine entrypoint file for project")
|
|
118
|
+
|
|
119
|
+
entry_script = project_info.entrypoint_file
|
|
120
|
+
|
|
121
|
+
if dockerfile_path:
|
|
122
|
+
dest = project_root / "Dockerfile"
|
|
123
|
+
with open(dockerfile_path, "r", encoding="utf-8") as f:
|
|
124
|
+
content = f.read()
|
|
125
|
+
|
|
126
|
+
new_content = content.replace(
|
|
127
|
+
DEFAULT_ENTRYPOINT_FILE,
|
|
128
|
+
project_info.entrypoint_file,
|
|
129
|
+
)
|
|
130
|
+
with open(dest, "w", encoding="utf-8") as f:
|
|
131
|
+
f.write(new_content)
|
|
132
|
+
os.remove(dockerfile_path)
|
|
133
|
+
|
|
134
|
+
_write_bundle_meta(project_root, entry_script)
|
|
135
|
+
|
|
136
|
+
return str(project_root), project_info
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _normalize_requirements(
|
|
140
|
+
requirements: Optional[Union[str, List[str]]],
|
|
141
|
+
) -> List[str]:
|
|
142
|
+
if requirements is None:
|
|
143
|
+
return []
|
|
144
|
+
if isinstance(requirements, str):
|
|
145
|
+
return [requirements]
|
|
146
|
+
return [str(item) for item in requirements]
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _append_additional_requirements(
|
|
150
|
+
extraction_dir: Path,
|
|
151
|
+
additional_requirements: List[str],
|
|
152
|
+
use_local_runtime: bool = False,
|
|
153
|
+
) -> None:
|
|
154
|
+
"""
|
|
155
|
+
Append requirements to requirements.txt.
|
|
156
|
+
|
|
157
|
+
For dev versions or when use_local_runtime=True, builds a wheel from
|
|
158
|
+
local source and places it in wheels/ subdirectory.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
extraction_dir: Directory where requirements.txt will be written
|
|
162
|
+
additional_requirements: Additional user requirements
|
|
163
|
+
use_local_runtime: If True, build and use local runtime wheel.
|
|
164
|
+
Useful for development when runtime is not released.
|
|
165
|
+
"""
|
|
166
|
+
req_path = extraction_dir / "requirements.txt"
|
|
167
|
+
package_version = _get_package_version()
|
|
168
|
+
|
|
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
|
+
with open(str(req_path), "w", encoding="utf-8") as f:
|
|
175
|
+
if should_use_local:
|
|
176
|
+
# Create wheels subdirectory
|
|
177
|
+
# Get base requirements from pyproject.toml
|
|
178
|
+
runtime_source = _get_runtime_source_path()
|
|
179
|
+
base_requirements = []
|
|
180
|
+
|
|
181
|
+
if runtime_source:
|
|
182
|
+
pyproject_path = runtime_source / "pyproject.toml"
|
|
183
|
+
try:
|
|
184
|
+
base_requirements = _parse_pyproject_toml(pyproject_path)
|
|
185
|
+
except Exception:
|
|
186
|
+
# Fallback to manual
|
|
187
|
+
base_requirements = _get_unversioned_requirements()
|
|
188
|
+
|
|
189
|
+
wheels_dir = extraction_dir / "wheels"
|
|
190
|
+
wheels_dir.mkdir(exist_ok=True)
|
|
191
|
+
|
|
192
|
+
# Build wheel and place it in wheels/
|
|
193
|
+
wheel_filename = _build_and_copy_wheel(wheels_dir)
|
|
194
|
+
if wheel_filename:
|
|
195
|
+
# Use path relative to extraction_dir
|
|
196
|
+
# In Docker: wheels/agentscope_runtime-0.2.0-py3-none-any.whl
|
|
197
|
+
base_requirements.append(
|
|
198
|
+
f"./wheels/{wheel_filename}",
|
|
199
|
+
)
|
|
200
|
+
elif package_version:
|
|
201
|
+
# Use versioned requirements for released versions
|
|
202
|
+
base_requirements = [
|
|
203
|
+
"fastapi",
|
|
204
|
+
"uvicorn",
|
|
205
|
+
f"agentscope-runtime=={package_version}",
|
|
206
|
+
f"agentscope-runtime[sandbox]=={package_version}",
|
|
207
|
+
f"agentscope-runtime[deployment]=={package_version}",
|
|
208
|
+
"pydantic",
|
|
209
|
+
"jinja2", # For template rendering
|
|
210
|
+
"psutil", # For process management
|
|
211
|
+
"redis", # For process management
|
|
212
|
+
"celery", # For task queue
|
|
213
|
+
]
|
|
214
|
+
else:
|
|
215
|
+
# Fallback to unversioned if version cannot be determined
|
|
216
|
+
base_requirements = _get_unversioned_requirements()
|
|
217
|
+
|
|
218
|
+
if not additional_requirements:
|
|
219
|
+
additional_requirements = []
|
|
220
|
+
|
|
221
|
+
# Combine base requirements with user requirements
|
|
222
|
+
all_requirements = sorted(
|
|
223
|
+
list(
|
|
224
|
+
set(
|
|
225
|
+
base_requirements + additional_requirements,
|
|
226
|
+
),
|
|
227
|
+
),
|
|
228
|
+
)
|
|
229
|
+
for req in all_requirements:
|
|
230
|
+
f.write(f"{req}\n")
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def _get_package_version() -> str:
|
|
234
|
+
"""
|
|
235
|
+
Get the package version from pyproject.toml file.
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
str: The version string, or empty string if not found
|
|
239
|
+
"""
|
|
240
|
+
# Try to find pyproject.toml in the current directory and parent
|
|
241
|
+
# directories
|
|
242
|
+
current_dir = Path(__file__).parent
|
|
243
|
+
for _ in range(6): # Look up to 6 levels up
|
|
244
|
+
pyproject_path = current_dir / "pyproject.toml"
|
|
245
|
+
if pyproject_path.exists():
|
|
246
|
+
break
|
|
247
|
+
current_dir = current_dir.parent
|
|
248
|
+
else:
|
|
249
|
+
# Also try the current working directory
|
|
250
|
+
pyproject_path = Path(os.getcwd()) / "pyproject.toml"
|
|
251
|
+
if not pyproject_path.exists():
|
|
252
|
+
return ""
|
|
253
|
+
|
|
254
|
+
try:
|
|
255
|
+
# Use tomllib to parse
|
|
256
|
+
with open(pyproject_path, "rb") as f:
|
|
257
|
+
data = tomllib.load(f)
|
|
258
|
+
project = data.get("project", {})
|
|
259
|
+
return project.get("version", "")
|
|
260
|
+
except Exception:
|
|
261
|
+
return ""
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def _is_dev_version(version: str) -> bool:
|
|
265
|
+
"""
|
|
266
|
+
Check if version is a development version.
|
|
267
|
+
|
|
268
|
+
Development versions include: 0.2.0.dev0, 0.2.0-dev, 0.2.0a1, etc.
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
version: Version string to check
|
|
272
|
+
|
|
273
|
+
Returns:
|
|
274
|
+
bool: True if this is a development version
|
|
275
|
+
"""
|
|
276
|
+
if not version:
|
|
277
|
+
return False
|
|
278
|
+
|
|
279
|
+
dev_indicators = [".dev", "-dev", "dev", "alpha", "beta", "rc", "a", "b"]
|
|
280
|
+
version_lower = version.lower()
|
|
281
|
+
|
|
282
|
+
return any(indicator in version_lower for indicator in dev_indicators)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def _get_runtime_source_path() -> Optional[Path]:
|
|
286
|
+
"""
|
|
287
|
+
Find the agentscope-runtime source code root directory.
|
|
288
|
+
|
|
289
|
+
Strategy:
|
|
290
|
+
1. Start from current file location (__file__)
|
|
291
|
+
2. Walk up directories to find pyproject.toml
|
|
292
|
+
3. Verify it's the agentscope-runtime project
|
|
293
|
+
|
|
294
|
+
Returns:
|
|
295
|
+
Path: Path to source root, or None if not found
|
|
296
|
+
"""
|
|
297
|
+
current_file = Path(__file__).resolve()
|
|
298
|
+
|
|
299
|
+
# Walk up the directory tree (up to 10 levels)
|
|
300
|
+
for parent in [current_file] + list(current_file.parents)[:10]:
|
|
301
|
+
pyproject_path = parent / "pyproject.toml"
|
|
302
|
+
|
|
303
|
+
if pyproject_path.exists():
|
|
304
|
+
try:
|
|
305
|
+
with open(pyproject_path, "rb") as f:
|
|
306
|
+
data = tomllib.load(f)
|
|
307
|
+
|
|
308
|
+
# Check if this is agentscope-runtime project
|
|
309
|
+
project_name = data.get("project", {}).get("name", "")
|
|
310
|
+
if project_name == "agentscope-runtime":
|
|
311
|
+
return parent
|
|
312
|
+
except Exception:
|
|
313
|
+
continue
|
|
314
|
+
|
|
315
|
+
return None
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def _build_and_copy_wheel(wheels_dir: Path) -> Optional[str]:
|
|
319
|
+
"""
|
|
320
|
+
Build a wheel from local agentscope-runtime source and copy to wheels_dir.
|
|
321
|
+
|
|
322
|
+
Args:
|
|
323
|
+
wheels_dir: Target directory where wheel will be placed
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
str: Wheel filename if successful, None otherwise
|
|
327
|
+
"""
|
|
328
|
+
import logging
|
|
329
|
+
import subprocess
|
|
330
|
+
|
|
331
|
+
logger = logging.getLogger(__name__)
|
|
332
|
+
|
|
333
|
+
runtime_source = _get_runtime_source_path()
|
|
334
|
+
|
|
335
|
+
if not runtime_source:
|
|
336
|
+
logger.warning(
|
|
337
|
+
"Could not locate agentscope-runtime source directory. "
|
|
338
|
+
"Falling back to unversioned requirements.",
|
|
339
|
+
)
|
|
340
|
+
return None
|
|
341
|
+
|
|
342
|
+
logger.info(f"Building wheel from source: {runtime_source}")
|
|
343
|
+
|
|
344
|
+
try:
|
|
345
|
+
# Create a temporary build directory
|
|
346
|
+
with tempfile.TemporaryDirectory() as temp_build_dir:
|
|
347
|
+
# Build wheel using python -m build or pip wheel
|
|
348
|
+
# Try using 'build' module first (recommended)
|
|
349
|
+
try:
|
|
350
|
+
result = subprocess.run(
|
|
351
|
+
[
|
|
352
|
+
"python",
|
|
353
|
+
"-m",
|
|
354
|
+
"build",
|
|
355
|
+
"--wheel",
|
|
356
|
+
"--outdir",
|
|
357
|
+
temp_build_dir,
|
|
358
|
+
],
|
|
359
|
+
cwd=str(runtime_source),
|
|
360
|
+
capture_output=True,
|
|
361
|
+
text=True,
|
|
362
|
+
timeout=120,
|
|
363
|
+
check=False,
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
if result.returncode != 0:
|
|
367
|
+
logger.error(f"Wheel build failed: {result.stderr}")
|
|
368
|
+
return None
|
|
369
|
+
|
|
370
|
+
except (ImportError, FileNotFoundError):
|
|
371
|
+
# Fallback to pip wheel
|
|
372
|
+
logger.info("'build' module not found, using pip wheel")
|
|
373
|
+
result = subprocess.run(
|
|
374
|
+
["pip", "wheel", "--no-deps", "-w", temp_build_dir, "."],
|
|
375
|
+
cwd=str(runtime_source),
|
|
376
|
+
capture_output=True,
|
|
377
|
+
text=True,
|
|
378
|
+
timeout=120,
|
|
379
|
+
check=False,
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
if result.returncode != 0:
|
|
383
|
+
logger.error(f"Wheel build failed: {result.stderr}")
|
|
384
|
+
return None
|
|
385
|
+
|
|
386
|
+
# Find the generated wheel file
|
|
387
|
+
wheel_files = list(
|
|
388
|
+
Path(temp_build_dir).glob("agentscope_runtime-*.whl"),
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
if not wheel_files:
|
|
392
|
+
logger.error("No wheel file generated")
|
|
393
|
+
return None
|
|
394
|
+
|
|
395
|
+
wheel_file = wheel_files[0]
|
|
396
|
+
wheel_filename = wheel_file.name
|
|
397
|
+
|
|
398
|
+
# Copy wheel to wheels_dir
|
|
399
|
+
dest_wheel = wheels_dir / wheel_filename
|
|
400
|
+
shutil.copy2(wheel_file, dest_wheel)
|
|
401
|
+
|
|
402
|
+
logger.info(f"Wheel built and copied to: {dest_wheel}")
|
|
403
|
+
return wheel_filename
|
|
404
|
+
|
|
405
|
+
except subprocess.TimeoutExpired:
|
|
406
|
+
logger.error("Wheel build timed out")
|
|
407
|
+
return None
|
|
408
|
+
except Exception as e:
|
|
409
|
+
logger.error(f"Failed to build wheel: {e}")
|
|
410
|
+
return None
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def _get_unversioned_requirements() -> List[str]:
|
|
414
|
+
"""
|
|
415
|
+
Get unversioned base requirements as fallback.
|
|
416
|
+
|
|
417
|
+
Returns:
|
|
418
|
+
List[str]: List of base requirements without version constraints
|
|
419
|
+
"""
|
|
420
|
+
return [
|
|
421
|
+
"fastapi",
|
|
422
|
+
"uvicorn",
|
|
423
|
+
"agentscope-runtime",
|
|
424
|
+
"agentscope-runtime[sandbox]",
|
|
425
|
+
"agentscope-runtime[deployment]",
|
|
426
|
+
"pydantic",
|
|
427
|
+
"jinja2", # For template rendering
|
|
428
|
+
"psutil", # For process management
|
|
429
|
+
"redis", # For process management
|
|
430
|
+
"celery", # For task queue
|
|
431
|
+
]
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def _serialize_protocol_adapters(
|
|
435
|
+
adapters: Optional[list[ProtocolAdapter]],
|
|
436
|
+
) -> List[Dict[str, str]]:
|
|
437
|
+
serialized: List[Dict[str, str]] = []
|
|
438
|
+
if not adapters:
|
|
439
|
+
return serialized
|
|
440
|
+
|
|
441
|
+
for adapter in adapters:
|
|
442
|
+
adapter_cls = adapter.__class__
|
|
443
|
+
serialized.append(
|
|
444
|
+
{
|
|
445
|
+
"module": adapter_cls.__module__,
|
|
446
|
+
"class": adapter_cls.__name__,
|
|
447
|
+
},
|
|
448
|
+
)
|
|
449
|
+
return serialized
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
def _serialize_request_model(
|
|
453
|
+
request_model: Optional[Type],
|
|
454
|
+
) -> Optional[Dict[str, str]]:
|
|
455
|
+
if request_model is None:
|
|
456
|
+
return None
|
|
457
|
+
|
|
458
|
+
return {
|
|
459
|
+
"module": request_model.__module__,
|
|
460
|
+
"class": request_model.__name__,
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def _serialize_custom_endpoints(
|
|
465
|
+
custom_endpoints: Optional[List[Dict]],
|
|
466
|
+
) -> List[Dict[str, Any]]:
|
|
467
|
+
serialized: List[Dict[str, Any]] = []
|
|
468
|
+
if not custom_endpoints:
|
|
469
|
+
return serialized
|
|
470
|
+
|
|
471
|
+
for endpoint in custom_endpoints:
|
|
472
|
+
handler = endpoint.get("handler")
|
|
473
|
+
serialized.append(
|
|
474
|
+
{
|
|
475
|
+
"path": endpoint.get("path"),
|
|
476
|
+
"methods": endpoint.get("methods"),
|
|
477
|
+
"module": getattr(
|
|
478
|
+
handler,
|
|
479
|
+
"__module__",
|
|
480
|
+
endpoint.get("module"),
|
|
481
|
+
),
|
|
482
|
+
"function_name": getattr(
|
|
483
|
+
handler,
|
|
484
|
+
"__name__",
|
|
485
|
+
endpoint.get("function_name"),
|
|
486
|
+
),
|
|
487
|
+
},
|
|
488
|
+
)
|
|
489
|
+
|
|
490
|
+
return serialized
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
def _write_bundle_meta(bundle_dir: Path, entry_script: str) -> None:
|
|
494
|
+
meta_path = bundle_dir / META_FILENAME
|
|
495
|
+
meta = {"entry_script": entry_script}
|
|
496
|
+
meta_path.write_text(json.dumps(meta, indent=2), encoding="utf-8")
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
def get_bundle_entry_script(bundle_dir: Union[str, Path]) -> str:
|
|
500
|
+
meta_path = Path(bundle_dir) / META_FILENAME
|
|
501
|
+
if meta_path.exists():
|
|
502
|
+
try:
|
|
503
|
+
meta = json.loads(meta_path.read_text(encoding="utf-8"))
|
|
504
|
+
script = meta.get("entry_script")
|
|
505
|
+
if script:
|
|
506
|
+
return script
|
|
507
|
+
except json.JSONDecodeError:
|
|
508
|
+
# Ignore invalid JSON and fall back to default entry script
|
|
509
|
+
pass
|
|
510
|
+
return DEFAULT_ENTRYPOINT_FILE
|
|
@@ -86,7 +86,7 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \\
|
|
|
86
86
|
# Command to run the application
|
|
87
87
|
{startup_command_section}"""
|
|
88
88
|
|
|
89
|
-
def __init__(self):
|
|
89
|
+
def __init__(self) -> None:
|
|
90
90
|
self.temp_files: List[str] = []
|
|
91
91
|
|
|
92
92
|
def generate_dockerfile_content(self, config: DockerfileConfig) -> str:
|