agentscope-runtime 0.2.0b1__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.
Files changed (185) hide show
  1. agentscope_runtime/adapters/__init__.py +0 -0
  2. agentscope_runtime/adapters/agentscope/__init__.py +0 -0
  3. agentscope_runtime/adapters/agentscope/long_term_memory/__init__.py +6 -0
  4. agentscope_runtime/adapters/agentscope/long_term_memory/_long_term_memory_adapter.py +258 -0
  5. agentscope_runtime/adapters/agentscope/memory/__init__.py +6 -0
  6. agentscope_runtime/adapters/agentscope/memory/_memory_adapter.py +152 -0
  7. agentscope_runtime/adapters/agentscope/message.py +535 -0
  8. agentscope_runtime/adapters/agentscope/stream.py +506 -0
  9. agentscope_runtime/adapters/agentscope/tool/__init__.py +9 -0
  10. agentscope_runtime/adapters/agentscope/tool/sandbox_tool.py +69 -0
  11. agentscope_runtime/adapters/agentscope/tool/tool.py +233 -0
  12. agentscope_runtime/adapters/autogen/__init__.py +0 -0
  13. agentscope_runtime/adapters/autogen/tool/__init__.py +7 -0
  14. agentscope_runtime/adapters/autogen/tool/tool.py +211 -0
  15. agentscope_runtime/adapters/text/__init__.py +0 -0
  16. agentscope_runtime/adapters/text/stream.py +29 -0
  17. agentscope_runtime/common/collections/redis_mapping.py +4 -1
  18. agentscope_runtime/common/container_clients/fc_client.py +855 -0
  19. agentscope_runtime/common/container_clients/kubernetes_client.py +6 -13
  20. agentscope_runtime/common/utils/__init__.py +0 -0
  21. agentscope_runtime/common/utils/lazy_loader.py +57 -0
  22. agentscope_runtime/engine/__init__.py +25 -18
  23. agentscope_runtime/engine/app/agent_app.py +161 -91
  24. agentscope_runtime/engine/app/base_app.py +4 -118
  25. agentscope_runtime/engine/constant.py +8 -0
  26. agentscope_runtime/engine/deployers/__init__.py +8 -0
  27. agentscope_runtime/engine/deployers/adapter/__init__.py +2 -0
  28. agentscope_runtime/engine/deployers/adapter/a2a/a2a_adapter_utils.py +0 -21
  29. agentscope_runtime/engine/deployers/adapter/a2a/a2a_protocol_adapter.py +28 -9
  30. agentscope_runtime/engine/deployers/adapter/responses/__init__.py +2 -0
  31. agentscope_runtime/engine/deployers/adapter/responses/response_api_adapter_utils.py +5 -2
  32. agentscope_runtime/engine/deployers/adapter/responses/response_api_protocol_adapter.py +1 -1
  33. agentscope_runtime/engine/deployers/agentrun_deployer.py +2541 -0
  34. agentscope_runtime/engine/deployers/cli_fc_deploy.py +1 -1
  35. agentscope_runtime/engine/deployers/kubernetes_deployer.py +9 -21
  36. agentscope_runtime/engine/deployers/local_deployer.py +47 -74
  37. agentscope_runtime/engine/deployers/modelstudio_deployer.py +216 -50
  38. agentscope_runtime/engine/deployers/utils/app_runner_utils.py +29 -0
  39. agentscope_runtime/engine/deployers/utils/detached_app.py +510 -0
  40. agentscope_runtime/engine/deployers/utils/docker_image_utils/__init__.py +1 -1
  41. agentscope_runtime/engine/deployers/utils/docker_image_utils/dockerfile_generator.py +1 -1
  42. agentscope_runtime/engine/deployers/utils/docker_image_utils/{runner_image_factory.py → image_factory.py} +121 -61
  43. agentscope_runtime/engine/deployers/utils/package.py +693 -0
  44. agentscope_runtime/engine/deployers/utils/service_utils/__init__.py +0 -5
  45. agentscope_runtime/engine/deployers/utils/service_utils/fastapi_factory.py +301 -282
  46. agentscope_runtime/engine/deployers/utils/service_utils/fastapi_templates.py +2 -4
  47. agentscope_runtime/engine/deployers/utils/service_utils/process_manager.py +23 -1
  48. agentscope_runtime/engine/deployers/utils/templates/app_main.py.j2 +84 -0
  49. agentscope_runtime/engine/deployers/utils/templates/runner_main.py.j2 +95 -0
  50. agentscope_runtime/engine/deployers/utils/{service_utils → templates}/standalone_main.py.j2 +0 -45
  51. agentscope_runtime/engine/deployers/utils/wheel_packager.py +119 -18
  52. agentscope_runtime/engine/helpers/runner.py +40 -0
  53. agentscope_runtime/engine/runner.py +171 -130
  54. agentscope_runtime/engine/schemas/agent_schemas.py +114 -3
  55. agentscope_runtime/engine/schemas/modelstudio_llm.py +4 -2
  56. agentscope_runtime/engine/schemas/oai_llm.py +23 -23
  57. agentscope_runtime/engine/schemas/response_api.py +65 -0
  58. agentscope_runtime/engine/schemas/session.py +24 -0
  59. agentscope_runtime/engine/services/__init__.py +0 -9
  60. agentscope_runtime/engine/services/agent_state/__init__.py +16 -0
  61. agentscope_runtime/engine/services/agent_state/redis_state_service.py +113 -0
  62. agentscope_runtime/engine/services/agent_state/state_service.py +179 -0
  63. agentscope_runtime/engine/services/memory/__init__.py +24 -0
  64. agentscope_runtime/engine/services/{mem0_memory_service.py → memory/mem0_memory_service.py} +17 -13
  65. agentscope_runtime/engine/services/{memory_service.py → memory/memory_service.py} +28 -7
  66. agentscope_runtime/engine/services/{redis_memory_service.py → memory/redis_memory_service.py} +1 -1
  67. agentscope_runtime/engine/services/{reme_personal_memory_service.py → memory/reme_personal_memory_service.py} +9 -6
  68. agentscope_runtime/engine/services/{reme_task_memory_service.py → memory/reme_task_memory_service.py} +2 -2
  69. agentscope_runtime/engine/services/{tablestore_memory_service.py → memory/tablestore_memory_service.py} +16 -19
  70. agentscope_runtime/engine/services/sandbox/__init__.py +13 -0
  71. agentscope_runtime/engine/services/{sandbox_service.py → sandbox/sandbox_service.py} +86 -71
  72. agentscope_runtime/engine/services/session_history/__init__.py +23 -0
  73. agentscope_runtime/engine/services/{redis_session_history_service.py → session_history/redis_session_history_service.py} +3 -2
  74. agentscope_runtime/engine/services/{session_history_service.py → session_history/session_history_service.py} +44 -34
  75. agentscope_runtime/engine/services/{tablestore_session_history_service.py → session_history/tablestore_session_history_service.py} +14 -19
  76. agentscope_runtime/engine/services/utils/tablestore_service_utils.py +2 -2
  77. agentscope_runtime/engine/tracing/base.py +10 -9
  78. agentscope_runtime/engine/tracing/message_util.py +1 -1
  79. agentscope_runtime/engine/tracing/tracing_util.py +7 -2
  80. agentscope_runtime/engine/tracing/wrapper.py +49 -31
  81. agentscope_runtime/sandbox/__init__.py +10 -2
  82. agentscope_runtime/sandbox/box/agentbay/__init__.py +4 -0
  83. agentscope_runtime/sandbox/box/agentbay/agentbay_sandbox.py +559 -0
  84. agentscope_runtime/sandbox/box/base/base_sandbox.py +12 -0
  85. agentscope_runtime/sandbox/box/browser/browser_sandbox.py +115 -11
  86. agentscope_runtime/sandbox/box/cloud/__init__.py +4 -0
  87. agentscope_runtime/sandbox/box/cloud/cloud_sandbox.py +254 -0
  88. agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +66 -0
  89. agentscope_runtime/sandbox/box/gui/gui_sandbox.py +42 -0
  90. agentscope_runtime/sandbox/box/mobile/__init__.py +4 -0
  91. agentscope_runtime/sandbox/box/mobile/box/__init__.py +0 -0
  92. agentscope_runtime/sandbox/box/mobile/mobile_sandbox.py +216 -0
  93. agentscope_runtime/sandbox/box/training_box/training_box.py +2 -44
  94. agentscope_runtime/sandbox/client/http_client.py +1 -0
  95. agentscope_runtime/sandbox/enums.py +2 -1
  96. agentscope_runtime/sandbox/manager/sandbox_manager.py +15 -2
  97. agentscope_runtime/sandbox/manager/server/app.py +12 -0
  98. agentscope_runtime/sandbox/manager/server/config.py +19 -0
  99. agentscope_runtime/sandbox/model/manager_config.py +79 -2
  100. agentscope_runtime/sandbox/utils.py +0 -18
  101. agentscope_runtime/tools/RAGs/__init__.py +0 -0
  102. agentscope_runtime/tools/RAGs/modelstudio_rag.py +377 -0
  103. agentscope_runtime/tools/RAGs/modelstudio_rag_lite.py +219 -0
  104. agentscope_runtime/tools/__init__.py +119 -0
  105. agentscope_runtime/tools/_constants.py +18 -0
  106. agentscope_runtime/tools/alipay/__init__.py +4 -0
  107. agentscope_runtime/tools/alipay/base.py +334 -0
  108. agentscope_runtime/tools/alipay/payment.py +835 -0
  109. agentscope_runtime/tools/alipay/subscribe.py +551 -0
  110. agentscope_runtime/tools/base.py +264 -0
  111. agentscope_runtime/tools/cli/__init__.py +0 -0
  112. agentscope_runtime/tools/cli/modelstudio_mcp_server.py +78 -0
  113. agentscope_runtime/tools/generations/__init__.py +75 -0
  114. agentscope_runtime/tools/generations/async_image_to_video.py +350 -0
  115. agentscope_runtime/tools/generations/async_image_to_video_wan25.py +366 -0
  116. agentscope_runtime/tools/generations/async_speech_to_video.py +422 -0
  117. agentscope_runtime/tools/generations/async_text_to_video.py +320 -0
  118. agentscope_runtime/tools/generations/async_text_to_video_wan25.py +334 -0
  119. agentscope_runtime/tools/generations/image_edit.py +208 -0
  120. agentscope_runtime/tools/generations/image_edit_wan25.py +193 -0
  121. agentscope_runtime/tools/generations/image_generation.py +202 -0
  122. agentscope_runtime/tools/generations/image_generation_wan25.py +201 -0
  123. agentscope_runtime/tools/generations/image_style_repaint.py +208 -0
  124. agentscope_runtime/tools/generations/image_to_video.py +233 -0
  125. agentscope_runtime/tools/generations/qwen_image_edit.py +205 -0
  126. agentscope_runtime/tools/generations/qwen_image_generation.py +214 -0
  127. agentscope_runtime/tools/generations/qwen_text_to_speech.py +154 -0
  128. agentscope_runtime/tools/generations/speech_to_text.py +260 -0
  129. agentscope_runtime/tools/generations/speech_to_video.py +314 -0
  130. agentscope_runtime/tools/generations/text_to_video.py +221 -0
  131. agentscope_runtime/tools/mcp_wrapper.py +215 -0
  132. agentscope_runtime/tools/realtime_clients/__init__.py +13 -0
  133. agentscope_runtime/tools/realtime_clients/asr_client.py +27 -0
  134. agentscope_runtime/tools/realtime_clients/azure_asr_client.py +195 -0
  135. agentscope_runtime/tools/realtime_clients/azure_tts_client.py +383 -0
  136. agentscope_runtime/tools/realtime_clients/modelstudio_asr_client.py +151 -0
  137. agentscope_runtime/tools/realtime_clients/modelstudio_tts_client.py +199 -0
  138. agentscope_runtime/tools/realtime_clients/realtime_tool.py +55 -0
  139. agentscope_runtime/tools/realtime_clients/tts_client.py +33 -0
  140. agentscope_runtime/tools/searches/__init__.py +3 -0
  141. agentscope_runtime/tools/searches/modelstudio_search.py +877 -0
  142. agentscope_runtime/tools/searches/modelstudio_search_lite.py +310 -0
  143. agentscope_runtime/tools/utils/__init__.py +0 -0
  144. agentscope_runtime/tools/utils/api_key_util.py +45 -0
  145. agentscope_runtime/tools/utils/crypto_utils.py +99 -0
  146. agentscope_runtime/tools/utils/mcp_util.py +35 -0
  147. agentscope_runtime/version.py +1 -1
  148. {agentscope_runtime-0.2.0b1.dist-info → agentscope_runtime-1.0.0.dist-info}/METADATA +244 -168
  149. agentscope_runtime-1.0.0.dist-info/RECORD +240 -0
  150. {agentscope_runtime-0.2.0b1.dist-info → agentscope_runtime-1.0.0.dist-info}/entry_points.txt +1 -0
  151. agentscope_runtime/engine/agents/__init__.py +0 -2
  152. agentscope_runtime/engine/agents/agentscope_agent.py +0 -488
  153. agentscope_runtime/engine/agents/agno_agent.py +0 -222
  154. agentscope_runtime/engine/agents/autogen_agent.py +0 -250
  155. agentscope_runtime/engine/agents/base_agent.py +0 -29
  156. agentscope_runtime/engine/agents/langgraph_agent.py +0 -59
  157. agentscope_runtime/engine/agents/utils.py +0 -53
  158. agentscope_runtime/engine/deployers/utils/package_project_utils.py +0 -1163
  159. agentscope_runtime/engine/deployers/utils/service_utils/service_config.py +0 -75
  160. agentscope_runtime/engine/deployers/utils/service_utils/service_factory.py +0 -220
  161. agentscope_runtime/engine/helpers/helper.py +0 -179
  162. agentscope_runtime/engine/schemas/context.py +0 -54
  163. agentscope_runtime/engine/services/context_manager.py +0 -164
  164. agentscope_runtime/engine/services/environment_manager.py +0 -50
  165. agentscope_runtime/engine/services/manager.py +0 -174
  166. agentscope_runtime/engine/services/rag_service.py +0 -195
  167. agentscope_runtime/engine/services/tablestore_rag_service.py +0 -143
  168. agentscope_runtime/sandbox/tools/__init__.py +0 -12
  169. agentscope_runtime/sandbox/tools/base/__init__.py +0 -8
  170. agentscope_runtime/sandbox/tools/base/tool.py +0 -52
  171. agentscope_runtime/sandbox/tools/browser/__init__.py +0 -57
  172. agentscope_runtime/sandbox/tools/browser/tool.py +0 -597
  173. agentscope_runtime/sandbox/tools/filesystem/__init__.py +0 -32
  174. agentscope_runtime/sandbox/tools/filesystem/tool.py +0 -319
  175. agentscope_runtime/sandbox/tools/function_tool.py +0 -321
  176. agentscope_runtime/sandbox/tools/gui/__init__.py +0 -7
  177. agentscope_runtime/sandbox/tools/gui/tool.py +0 -77
  178. agentscope_runtime/sandbox/tools/mcp_tool.py +0 -195
  179. agentscope_runtime/sandbox/tools/sandbox_tool.py +0 -104
  180. agentscope_runtime/sandbox/tools/tool.py +0 -238
  181. agentscope_runtime/sandbox/tools/utils.py +0 -68
  182. agentscope_runtime-0.2.0b1.dist-info/RECORD +0 -183
  183. {agentscope_runtime-0.2.0b1.dist-info → agentscope_runtime-1.0.0.dist-info}/WHEEL +0 -0
  184. {agentscope_runtime-0.2.0b1.dist-info → agentscope_runtime-1.0.0.dist-info}/licenses/LICENSE +0 -0
  185. {agentscope_runtime-0.2.0b1.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
@@ -1,5 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
- from .runner_image_factory import RunnerImageFactory
2
+ from .image_factory import ImageFactory
3
3
  from .docker_image_builder import (
4
4
  RegistryConfig,
5
5
  BuildConfig,
@@ -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: