agentscope-runtime 0.2.0b2__py3-none-any.whl → 1.0.0b1__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 (183) 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 +474 -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/utils/__init__.py +0 -0
  20. agentscope_runtime/common/utils/lazy_loader.py +57 -0
  21. agentscope_runtime/engine/__init__.py +25 -18
  22. agentscope_runtime/engine/app/agent_app.py +161 -91
  23. agentscope_runtime/engine/app/base_app.py +4 -118
  24. agentscope_runtime/engine/constant.py +8 -0
  25. agentscope_runtime/engine/deployers/__init__.py +8 -0
  26. agentscope_runtime/engine/deployers/adapter/__init__.py +2 -0
  27. agentscope_runtime/engine/deployers/adapter/a2a/a2a_adapter_utils.py +0 -21
  28. agentscope_runtime/engine/deployers/adapter/a2a/a2a_protocol_adapter.py +28 -9
  29. agentscope_runtime/engine/deployers/adapter/responses/__init__.py +2 -0
  30. agentscope_runtime/engine/deployers/adapter/responses/response_api_adapter_utils.py +5 -2
  31. agentscope_runtime/engine/deployers/adapter/responses/response_api_protocol_adapter.py +1 -1
  32. agentscope_runtime/engine/deployers/agentrun_deployer.py +2541 -0
  33. agentscope_runtime/engine/deployers/cli_fc_deploy.py +1 -1
  34. agentscope_runtime/engine/deployers/kubernetes_deployer.py +9 -21
  35. agentscope_runtime/engine/deployers/local_deployer.py +47 -74
  36. agentscope_runtime/engine/deployers/modelstudio_deployer.py +216 -50
  37. agentscope_runtime/engine/deployers/utils/app_runner_utils.py +29 -0
  38. agentscope_runtime/engine/deployers/utils/detached_app.py +510 -0
  39. agentscope_runtime/engine/deployers/utils/docker_image_utils/__init__.py +1 -1
  40. agentscope_runtime/engine/deployers/utils/docker_image_utils/dockerfile_generator.py +1 -1
  41. agentscope_runtime/engine/deployers/utils/docker_image_utils/{runner_image_factory.py → image_factory.py} +121 -61
  42. agentscope_runtime/engine/deployers/utils/package.py +693 -0
  43. agentscope_runtime/engine/deployers/utils/service_utils/__init__.py +0 -5
  44. agentscope_runtime/engine/deployers/utils/service_utils/fastapi_factory.py +256 -282
  45. agentscope_runtime/engine/deployers/utils/service_utils/fastapi_templates.py +2 -4
  46. agentscope_runtime/engine/deployers/utils/service_utils/process_manager.py +23 -1
  47. agentscope_runtime/engine/deployers/utils/templates/app_main.py.j2 +84 -0
  48. agentscope_runtime/engine/deployers/utils/templates/runner_main.py.j2 +95 -0
  49. agentscope_runtime/engine/deployers/utils/{service_utils → templates}/standalone_main.py.j2 +0 -45
  50. agentscope_runtime/engine/deployers/utils/wheel_packager.py +119 -18
  51. agentscope_runtime/engine/helpers/runner.py +40 -0
  52. agentscope_runtime/engine/runner.py +170 -130
  53. agentscope_runtime/engine/schemas/agent_schemas.py +114 -3
  54. agentscope_runtime/engine/schemas/modelstudio_llm.py +4 -2
  55. agentscope_runtime/engine/schemas/oai_llm.py +23 -23
  56. agentscope_runtime/engine/schemas/response_api.py +65 -0
  57. agentscope_runtime/engine/schemas/session.py +24 -0
  58. agentscope_runtime/engine/services/__init__.py +0 -9
  59. agentscope_runtime/engine/services/agent_state/__init__.py +16 -0
  60. agentscope_runtime/engine/services/agent_state/redis_state_service.py +113 -0
  61. agentscope_runtime/engine/services/agent_state/state_service.py +179 -0
  62. agentscope_runtime/engine/services/memory/__init__.py +24 -0
  63. agentscope_runtime/engine/services/{mem0_memory_service.py → memory/mem0_memory_service.py} +17 -13
  64. agentscope_runtime/engine/services/{memory_service.py → memory/memory_service.py} +28 -7
  65. agentscope_runtime/engine/services/{redis_memory_service.py → memory/redis_memory_service.py} +1 -1
  66. agentscope_runtime/engine/services/{reme_personal_memory_service.py → memory/reme_personal_memory_service.py} +9 -6
  67. agentscope_runtime/engine/services/{reme_task_memory_service.py → memory/reme_task_memory_service.py} +2 -2
  68. agentscope_runtime/engine/services/{tablestore_memory_service.py → memory/tablestore_memory_service.py} +12 -18
  69. agentscope_runtime/engine/services/sandbox/__init__.py +13 -0
  70. agentscope_runtime/engine/services/{sandbox_service.py → sandbox/sandbox_service.py} +86 -71
  71. agentscope_runtime/engine/services/session_history/__init__.py +23 -0
  72. agentscope_runtime/engine/services/{redis_session_history_service.py → session_history/redis_session_history_service.py} +3 -2
  73. agentscope_runtime/engine/services/{session_history_service.py → session_history/session_history_service.py} +44 -34
  74. agentscope_runtime/engine/services/{tablestore_session_history_service.py → session_history/tablestore_session_history_service.py} +14 -19
  75. agentscope_runtime/engine/services/utils/tablestore_service_utils.py +2 -2
  76. agentscope_runtime/engine/tracing/base.py +10 -9
  77. agentscope_runtime/engine/tracing/message_util.py +1 -1
  78. agentscope_runtime/engine/tracing/tracing_util.py +7 -2
  79. agentscope_runtime/sandbox/__init__.py +10 -2
  80. agentscope_runtime/sandbox/box/agentbay/__init__.py +4 -0
  81. agentscope_runtime/sandbox/box/agentbay/agentbay_sandbox.py +559 -0
  82. agentscope_runtime/sandbox/box/base/base_sandbox.py +12 -0
  83. agentscope_runtime/sandbox/box/browser/browser_sandbox.py +115 -11
  84. agentscope_runtime/sandbox/box/cloud/__init__.py +4 -0
  85. agentscope_runtime/sandbox/box/cloud/cloud_sandbox.py +254 -0
  86. agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +66 -0
  87. agentscope_runtime/sandbox/box/gui/gui_sandbox.py +42 -0
  88. agentscope_runtime/sandbox/box/mobile/__init__.py +4 -0
  89. agentscope_runtime/sandbox/box/mobile/box/__init__.py +0 -0
  90. agentscope_runtime/sandbox/box/mobile/mobile_sandbox.py +216 -0
  91. agentscope_runtime/sandbox/box/training_box/training_box.py +2 -2
  92. agentscope_runtime/sandbox/client/http_client.py +1 -0
  93. agentscope_runtime/sandbox/enums.py +2 -0
  94. agentscope_runtime/sandbox/manager/sandbox_manager.py +18 -2
  95. agentscope_runtime/sandbox/manager/server/app.py +12 -0
  96. agentscope_runtime/sandbox/manager/server/config.py +19 -0
  97. agentscope_runtime/sandbox/model/manager_config.py +79 -2
  98. agentscope_runtime/sandbox/utils.py +0 -18
  99. agentscope_runtime/tools/RAGs/__init__.py +0 -0
  100. agentscope_runtime/tools/RAGs/modelstudio_rag.py +377 -0
  101. agentscope_runtime/tools/RAGs/modelstudio_rag_lite.py +219 -0
  102. agentscope_runtime/tools/__init__.py +119 -0
  103. agentscope_runtime/tools/_constants.py +18 -0
  104. agentscope_runtime/tools/alipay/__init__.py +4 -0
  105. agentscope_runtime/tools/alipay/base.py +334 -0
  106. agentscope_runtime/tools/alipay/payment.py +835 -0
  107. agentscope_runtime/tools/alipay/subscribe.py +551 -0
  108. agentscope_runtime/tools/base.py +264 -0
  109. agentscope_runtime/tools/cli/__init__.py +0 -0
  110. agentscope_runtime/tools/cli/modelstudio_mcp_server.py +78 -0
  111. agentscope_runtime/tools/generations/__init__.py +75 -0
  112. agentscope_runtime/tools/generations/async_image_to_video.py +350 -0
  113. agentscope_runtime/tools/generations/async_image_to_video_wan25.py +366 -0
  114. agentscope_runtime/tools/generations/async_speech_to_video.py +422 -0
  115. agentscope_runtime/tools/generations/async_text_to_video.py +320 -0
  116. agentscope_runtime/tools/generations/async_text_to_video_wan25.py +334 -0
  117. agentscope_runtime/tools/generations/image_edit.py +208 -0
  118. agentscope_runtime/tools/generations/image_edit_wan25.py +193 -0
  119. agentscope_runtime/tools/generations/image_generation.py +202 -0
  120. agentscope_runtime/tools/generations/image_generation_wan25.py +201 -0
  121. agentscope_runtime/tools/generations/image_style_repaint.py +208 -0
  122. agentscope_runtime/tools/generations/image_to_video.py +233 -0
  123. agentscope_runtime/tools/generations/qwen_image_edit.py +205 -0
  124. agentscope_runtime/tools/generations/qwen_image_generation.py +214 -0
  125. agentscope_runtime/tools/generations/qwen_text_to_speech.py +154 -0
  126. agentscope_runtime/tools/generations/speech_to_text.py +260 -0
  127. agentscope_runtime/tools/generations/speech_to_video.py +314 -0
  128. agentscope_runtime/tools/generations/text_to_video.py +221 -0
  129. agentscope_runtime/tools/mcp_wrapper.py +215 -0
  130. agentscope_runtime/tools/realtime_clients/__init__.py +13 -0
  131. agentscope_runtime/tools/realtime_clients/asr_client.py +27 -0
  132. agentscope_runtime/tools/realtime_clients/azure_asr_client.py +195 -0
  133. agentscope_runtime/tools/realtime_clients/azure_tts_client.py +383 -0
  134. agentscope_runtime/tools/realtime_clients/modelstudio_asr_client.py +151 -0
  135. agentscope_runtime/tools/realtime_clients/modelstudio_tts_client.py +199 -0
  136. agentscope_runtime/tools/realtime_clients/realtime_tool.py +55 -0
  137. agentscope_runtime/tools/realtime_clients/tts_client.py +33 -0
  138. agentscope_runtime/tools/searches/__init__.py +3 -0
  139. agentscope_runtime/tools/searches/modelstudio_search.py +877 -0
  140. agentscope_runtime/tools/searches/modelstudio_search_lite.py +310 -0
  141. agentscope_runtime/tools/utils/__init__.py +0 -0
  142. agentscope_runtime/tools/utils/api_key_util.py +45 -0
  143. agentscope_runtime/tools/utils/crypto_utils.py +99 -0
  144. agentscope_runtime/tools/utils/mcp_util.py +35 -0
  145. agentscope_runtime/version.py +1 -1
  146. {agentscope_runtime-0.2.0b2.dist-info → agentscope_runtime-1.0.0b1.dist-info}/METADATA +234 -165
  147. agentscope_runtime-1.0.0b1.dist-info/RECORD +240 -0
  148. {agentscope_runtime-0.2.0b2.dist-info → agentscope_runtime-1.0.0b1.dist-info}/entry_points.txt +1 -0
  149. agentscope_runtime/engine/agents/__init__.py +0 -2
  150. agentscope_runtime/engine/agents/agentscope_agent.py +0 -488
  151. agentscope_runtime/engine/agents/agno_agent.py +0 -220
  152. agentscope_runtime/engine/agents/autogen_agent.py +0 -250
  153. agentscope_runtime/engine/agents/base_agent.py +0 -29
  154. agentscope_runtime/engine/agents/langgraph_agent.py +0 -59
  155. agentscope_runtime/engine/agents/utils.py +0 -53
  156. agentscope_runtime/engine/deployers/utils/package_project_utils.py +0 -1163
  157. agentscope_runtime/engine/deployers/utils/service_utils/service_config.py +0 -75
  158. agentscope_runtime/engine/deployers/utils/service_utils/service_factory.py +0 -220
  159. agentscope_runtime/engine/helpers/helper.py +0 -179
  160. agentscope_runtime/engine/schemas/context.py +0 -54
  161. agentscope_runtime/engine/services/context_manager.py +0 -164
  162. agentscope_runtime/engine/services/environment_manager.py +0 -50
  163. agentscope_runtime/engine/services/manager.py +0 -174
  164. agentscope_runtime/engine/services/rag_service.py +0 -195
  165. agentscope_runtime/engine/services/tablestore_rag_service.py +0 -143
  166. agentscope_runtime/sandbox/tools/__init__.py +0 -12
  167. agentscope_runtime/sandbox/tools/base/__init__.py +0 -8
  168. agentscope_runtime/sandbox/tools/base/tool.py +0 -52
  169. agentscope_runtime/sandbox/tools/browser/__init__.py +0 -57
  170. agentscope_runtime/sandbox/tools/browser/tool.py +0 -597
  171. agentscope_runtime/sandbox/tools/filesystem/__init__.py +0 -32
  172. agentscope_runtime/sandbox/tools/filesystem/tool.py +0 -319
  173. agentscope_runtime/sandbox/tools/function_tool.py +0 -321
  174. agentscope_runtime/sandbox/tools/gui/__init__.py +0 -7
  175. agentscope_runtime/sandbox/tools/gui/tool.py +0 -77
  176. agentscope_runtime/sandbox/tools/mcp_tool.py +0 -195
  177. agentscope_runtime/sandbox/tools/sandbox_tool.py +0 -104
  178. agentscope_runtime/sandbox/tools/tool.py +0 -238
  179. agentscope_runtime/sandbox/tools/utils.py +0 -68
  180. agentscope_runtime-0.2.0b2.dist-info/RECORD +0 -183
  181. {agentscope_runtime-0.2.0b2.dist-info → agentscope_runtime-1.0.0b1.dist-info}/WHEEL +0 -0
  182. {agentscope_runtime-0.2.0b2.dist-info → agentscope_runtime-1.0.0b1.dist-info}/licenses/LICENSE +0 -0
  183. {agentscope_runtime-0.2.0b2.dist-info → agentscope_runtime-1.0.0b1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,693 @@
1
+ # -*- coding: utf-8 -*-
2
+ # pylint:disable=unused-argument
3
+
4
+ """
5
+ Project-based packaging utilities for AgentApp and Runner deployment.
6
+
7
+ This module provides packaging utilities that support:
8
+ - Function-based AgentApp deployment with decorators
9
+ - Runner-based deployment with entrypoint files
10
+ - Entire project directory packaging
11
+ - Smart dependency caching
12
+ - CLI-style and object-style deployment patterns
13
+ """
14
+
15
+ import inspect
16
+ import logging
17
+ import os
18
+ import shutil
19
+ import tempfile
20
+ import zipfile
21
+ from pathlib import Path
22
+ from typing import Optional, List, Tuple, Union
23
+
24
+ from jinja2 import Environment, FileSystemLoader, TemplateNotFound
25
+ from pydantic import BaseModel
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+ DEPLOYMENT_ZIP = "deployment.zip"
30
+ TEMPLATES_DIR = Path(__file__).parent / "templates"
31
+ DEFAULT_ENTRYPOINT_FILE = "runtime_main.py"
32
+
33
+
34
+ def _get_template_env() -> Environment:
35
+ """
36
+ Get Jinja2 environment for template rendering.
37
+
38
+ Returns:
39
+ Jinja2 Environment configured with the templates directory
40
+ """
41
+ return Environment(
42
+ loader=FileSystemLoader(str(TEMPLATES_DIR)),
43
+ trim_blocks=True,
44
+ lstrip_blocks=True,
45
+ )
46
+
47
+
48
+ # ===== Data Models =====
49
+
50
+
51
+ class RuntimeParameter(BaseModel):
52
+ """Configuration for a runtime parameter."""
53
+
54
+ name: str # Parameter name (e.g., "log_level")
55
+ type: str # Parameter type: "str", "int", "bool", "float"
56
+ default: Union[str, int, bool, float, None] # Default value
57
+ help: Optional[str] = None # Help text for CLI argument
58
+ cli_name: Optional[str] = None # CLI argument name (defaults to --{name})
59
+
60
+
61
+ class EntrypointInfo(BaseModel):
62
+ """Information about the generated entrypoint."""
63
+
64
+ module_name: str # Module to import from (e.g., "app_deploy")
65
+ object_name: str # Object name to import (e.g., "agent_app")
66
+ object_type: str # "app" or "runner"
67
+ host: str = "0.0.0.0" # Default host for the service
68
+ port: int = 8090 # Default port for the service
69
+ extra_parameters: List[
70
+ RuntimeParameter
71
+ ] = [] # Additional runtime parameters
72
+
73
+
74
+ class ProjectInfo(BaseModel):
75
+ """Information about a project to be packaged."""
76
+
77
+ project_dir: str # Absolute path to project root directory
78
+ entrypoint_file: str # Relative path to entrypoint file (if applicable)
79
+ entrypoint_handler: str # actual object name, e.g., "agent_app"
80
+ handler_type: Optional[str] = None # Handler type ("app" or "runner")
81
+ is_directory_entrypoint: bool = False # True if packaging entire directory
82
+
83
+
84
+ # ===== Project Directory Extraction =====
85
+
86
+
87
+ def project_dir_extractor(
88
+ app=None,
89
+ runner=None,
90
+ ) -> ProjectInfo:
91
+ """
92
+ Extract project directory information from app or runner object.
93
+
94
+ This function inspects the call stack to find where the app or runner
95
+ was defined and extracts the project root directory and object name.
96
+
97
+ Args:
98
+ app: AgentApp instance (optional)
99
+ runner: Runner instance (optional)
100
+
101
+ Returns:
102
+ ProjectInfo with project directory, entrypoint file, and handler name
103
+
104
+ Raises:
105
+ ValueError: If neither app nor runner is provided or project dir
106
+ cannot be determined
107
+ """
108
+ if app is None and runner is None:
109
+ raise ValueError("Either app or runner must be provided")
110
+
111
+ target_obj = app if app is not None else runner
112
+ target_type = "app" if app is not None else "runner"
113
+
114
+ # Get the source file where the object was defined
115
+ frame = inspect.currentframe()
116
+ caller_frame = frame.f_back if frame else None
117
+
118
+ project_file = None
119
+ object_name = None # Store the actual object name
120
+
121
+ # Try to find the file where the object was created
122
+ while caller_frame:
123
+ try:
124
+ frame_filename = caller_frame.f_code.co_filename
125
+
126
+ # Skip internal/system files and focus on user code
127
+ if (
128
+ not frame_filename.endswith(".py")
129
+ or "site-packages" in frame_filename
130
+ or "agentscope_runtime" in frame_filename
131
+ ):
132
+ caller_frame = caller_frame.f_back
133
+ continue
134
+
135
+ # Check if this frame contains our target object
136
+ frame_locals = caller_frame.f_locals
137
+ frame_globals = caller_frame.f_globals
138
+
139
+ # Look for the object (by identity) in locals and globals
140
+ for var_name, var_value in list(frame_locals.items()) + list(
141
+ frame_globals.items(),
142
+ ):
143
+ if var_value is target_obj:
144
+ project_file = frame_filename
145
+ object_name = var_name # Capture the actual object name!
146
+ break
147
+
148
+ if project_file:
149
+ break
150
+
151
+ except (AttributeError, TypeError) as e:
152
+ logger.warning(
153
+ f"Ignore Attribute or Type error: {e}",
154
+ )
155
+
156
+ caller_frame = caller_frame.f_back
157
+
158
+ if not project_file or not os.path.exists(project_file):
159
+ raise ValueError(
160
+ f"Unable to locate source file for {target_type} object",
161
+ )
162
+
163
+ # The project directory is the directory containing the file
164
+ project_dir = os.path.dirname(os.path.abspath(project_file))
165
+ entrypoint_file = os.path.basename(project_file)
166
+
167
+ logger.info(
168
+ f"Extracted project dir from {target_type}: {project_dir}",
169
+ )
170
+ logger.info(
171
+ f"Detected {target_type} object name: {object_name}",
172
+ )
173
+
174
+ return ProjectInfo(
175
+ project_dir=project_dir,
176
+ entrypoint_file=entrypoint_file,
177
+ entrypoint_handler=object_name, # Actual object name (e.g.,
178
+ # "agent_app")
179
+ handler_type=target_type, # Type: "app" or "runner"
180
+ is_directory_entrypoint=False,
181
+ )
182
+
183
+
184
+ # ===== Entrypoint Parsing =====
185
+
186
+
187
+ def parse_entrypoint(spec: str) -> ProjectInfo:
188
+ """
189
+ Parse entrypoint specification into ProjectInfo.
190
+
191
+ Supported formats:
192
+ - "app.py" - File with default handler name "app"
193
+ - "app.py:my_handler" - File with specific handler name
194
+ - "project_dir/" - Directory (will auto-detect entrypoint)
195
+
196
+ Args:
197
+ spec: Entrypoint specification string
198
+
199
+ Returns:
200
+ ProjectInfo with parsed information
201
+
202
+ Raises:
203
+ ValueError: If specification format is invalid or file/dir doesn't
204
+ exist
205
+ """
206
+ spec = spec.strip()
207
+
208
+ # Check if it's a directory entrypoint
209
+ if spec.endswith("/") or os.path.isdir(spec):
210
+ project_dir = os.path.abspath(spec.rstrip("/"))
211
+ if not os.path.exists(project_dir):
212
+ raise ValueError(f"Directory not found: {project_dir}")
213
+
214
+ # Auto-detect entrypoint file in directory
215
+ entrypoint_file = _auto_detect_entrypoint(project_dir)
216
+
217
+ return ProjectInfo(
218
+ project_dir=project_dir,
219
+ entrypoint_file=entrypoint_file,
220
+ entrypoint_handler="app", # Default handler name
221
+ handler_type="app", # Default type
222
+ is_directory_entrypoint=True,
223
+ )
224
+
225
+ # Parse file-based entrypoint with optional handler
226
+ if ":" in spec:
227
+ file_part, handler = spec.split(":", 1)
228
+ else:
229
+ file_part = spec
230
+ handler = "app" # Default handler name
231
+
232
+ # Resolve file path
233
+ file_path = os.path.abspath(file_part)
234
+ if not os.path.exists(file_path):
235
+ raise ValueError(f"Entrypoint file not found: {file_path}")
236
+
237
+ project_dir = os.path.dirname(file_path)
238
+ entrypoint_file = os.path.basename(file_path)
239
+
240
+ return ProjectInfo(
241
+ project_dir=project_dir,
242
+ entrypoint_file=entrypoint_file,
243
+ entrypoint_handler=handler, # Handler name
244
+ handler_type="app", # Assume app type for entrypoint-style
245
+ is_directory_entrypoint=False,
246
+ )
247
+
248
+
249
+ def _auto_detect_entrypoint(project_dir: str) -> str:
250
+ """
251
+ Auto-detect entrypoint file in a directory.
252
+
253
+ Looks for common entrypoint file names in priority order:
254
+ - app.py
255
+ - main.py
256
+ - __main__.py
257
+ - run.py
258
+ - runner.py
259
+
260
+ Args:
261
+ project_dir: Directory to search
262
+
263
+ Returns:
264
+ Name of detected entrypoint file (relative to project_dir)
265
+
266
+ Raises:
267
+ ValueError: If no entrypoint file is found
268
+ """
269
+ candidates = [
270
+ "app.py",
271
+ "main.py",
272
+ "__main__.py",
273
+ "run.py",
274
+ "runner.py",
275
+ ]
276
+
277
+ for candidate in candidates:
278
+ candidate_path = os.path.join(project_dir, candidate)
279
+ if os.path.exists(candidate_path):
280
+ logger.info(f"Auto-detected entrypoint: {candidate}")
281
+ return candidate
282
+
283
+ raise ValueError(
284
+ f"No entrypoint file found in {project_dir}. "
285
+ f"Expected one of: {', '.join(candidates)}",
286
+ )
287
+
288
+
289
+ # ===== Main Template Generation =====
290
+ def _generate_app_main_template(entrypoint_info: EntrypointInfo) -> str:
291
+ """
292
+ Generate main.py template for AgentApp using Jinja2.
293
+
294
+ Args:
295
+ entrypoint_info: Information about the entrypoint
296
+
297
+ Returns:
298
+ String content for main.py
299
+
300
+ Raises:
301
+ RuntimeError: If template file not found
302
+ """
303
+ try:
304
+ env = _get_template_env()
305
+ template = env.get_template("app_main.py.j2")
306
+
307
+ # Convert RuntimeParameter objects to dicts for Jinja2
308
+ extra_params_dicts = [
309
+ param.model_dump() for param in entrypoint_info.extra_parameters
310
+ ]
311
+
312
+ return template.render(
313
+ module_name=entrypoint_info.module_name,
314
+ object_name=entrypoint_info.object_name,
315
+ host=entrypoint_info.host,
316
+ port=entrypoint_info.port,
317
+ extra_parameters=extra_params_dicts,
318
+ )
319
+ except TemplateNotFound as e:
320
+ raise RuntimeError(
321
+ f"Template 'app_main.py.j2' not found in {TEMPLATES_DIR}",
322
+ ) from e
323
+
324
+
325
+ def _generate_runner_main_template(entrypoint_info: EntrypointInfo) -> str:
326
+ """
327
+ Generate main.py template for Runner using Jinja2.
328
+
329
+ The template wraps the Runner in an AgentApp so it can be deployed as a
330
+ service.
331
+
332
+ Args:
333
+ entrypoint_info: Information about the entrypoint
334
+
335
+ Returns:
336
+ String content for main.py
337
+
338
+ Raises:
339
+ RuntimeError: If template file not found
340
+ """
341
+ try:
342
+ env = _get_template_env()
343
+ template = env.get_template("runner_main.py.j2")
344
+
345
+ # Use app_name from entrypoint_info or default to object_name
346
+ app_name = (
347
+ entrypoint_info.app_name or f"{entrypoint_info.object_name}_app"
348
+ )
349
+ app_description = (
350
+ entrypoint_info.app_description
351
+ or f"Service for {entrypoint_info.object_name}"
352
+ )
353
+
354
+ # Convert RuntimeParameter objects to dicts for Jinja2
355
+ extra_params_dicts = [
356
+ param.model_dump() for param in entrypoint_info.extra_parameters
357
+ ]
358
+
359
+ return template.render(
360
+ module_name=entrypoint_info.module_name,
361
+ object_name=entrypoint_info.object_name,
362
+ app_name=app_name,
363
+ app_description=app_description,
364
+ host=entrypoint_info.host,
365
+ port=entrypoint_info.port,
366
+ extra_parameters=extra_params_dicts,
367
+ )
368
+ except TemplateNotFound as e:
369
+ raise RuntimeError(
370
+ f"Template 'runner_main.py.j2' not found in {TEMPLATES_DIR}",
371
+ ) from e
372
+
373
+
374
+ def generate_main_template(entrypoint_info: EntrypointInfo) -> str:
375
+ """
376
+ Generate main.py template based on object type using Jinja2 templates.
377
+
378
+ Args:
379
+ entrypoint_info: Information about the entrypoint
380
+
381
+ Returns:
382
+ String content for main.py
383
+
384
+ Raises:
385
+ ValueError: If object_type is not supported
386
+ RuntimeError: If template rendering fails
387
+ """
388
+ if entrypoint_info.object_type == "app":
389
+ return _generate_app_main_template(entrypoint_info)
390
+ elif entrypoint_info.object_type == "runner":
391
+ return _generate_runner_main_template(entrypoint_info)
392
+ else:
393
+ raise ValueError(
394
+ f"Unsupported object type: {entrypoint_info.object_type}. "
395
+ f"Expected 'app' or 'runner'",
396
+ )
397
+
398
+
399
+ # ===== Project Packaging =====
400
+
401
+
402
+ def _get_default_ignore_patterns() -> List[str]:
403
+ """
404
+ Get default ignore patterns for project packaging.
405
+
406
+ Returns:
407
+ List of ignore patterns (similar to .dockerignore)
408
+ """
409
+ return [
410
+ "__pycache__",
411
+ "*.pyc",
412
+ "*.pyo",
413
+ ".git",
414
+ ".gitignore",
415
+ ".pytest_cache",
416
+ ".mypy_cache",
417
+ ".tox",
418
+ "venv",
419
+ "env",
420
+ ".venv",
421
+ ".env",
422
+ "node_modules",
423
+ ".DS_Store",
424
+ "*.egg-info",
425
+ "build",
426
+ "dist",
427
+ ".cache",
428
+ "*.swp",
429
+ "*.swo",
430
+ "*~",
431
+ ".idea",
432
+ ".vscode",
433
+ "*.log",
434
+ "logs",
435
+ ]
436
+
437
+
438
+ def _should_ignore(path: str, patterns: List[str]) -> bool:
439
+ """
440
+ Check if path should be ignored based on patterns.
441
+
442
+ Args:
443
+ path: Path to check (relative)
444
+ patterns: List of ignore patterns
445
+
446
+ Returns:
447
+ True if path should be ignored
448
+ """
449
+ path_parts = Path(path).parts
450
+
451
+ for pattern in patterns:
452
+ # Check if any part of the path matches the pattern
453
+ if pattern in path_parts:
454
+ return True
455
+
456
+ # Check wildcard patterns
457
+ if "*" in pattern:
458
+ import fnmatch
459
+
460
+ if fnmatch.fnmatch(path, pattern):
461
+ return True
462
+
463
+ return False
464
+
465
+
466
+ def package_code(
467
+ source_dir: Path,
468
+ output_zip: Path,
469
+ ignore_patterns: Optional[List[str]] = None,
470
+ ) -> None:
471
+ """
472
+ Package project source code into a zip file.
473
+
474
+ Args:
475
+ source_dir: Source directory to package
476
+ output_zip: Output zip file path
477
+ ignore_patterns: Optional ignore patterns (uses defaults if None)
478
+ """
479
+ if ignore_patterns is None:
480
+ ignore_patterns = _get_default_ignore_patterns()
481
+
482
+ logger.info(f"Packaging source code from {source_dir}")
483
+
484
+ with zipfile.ZipFile(output_zip, "w", zipfile.ZIP_DEFLATED) as zipf:
485
+ for root, dirs, files in os.walk(source_dir):
486
+ # Filter directories
487
+ dirs[:] = [
488
+ d
489
+ for d in dirs
490
+ if not _should_ignore(
491
+ os.path.relpath(os.path.join(root, d), source_dir),
492
+ ignore_patterns,
493
+ )
494
+ ]
495
+
496
+ # Add files
497
+ for file in files:
498
+ file_path = os.path.join(root, file)
499
+ arcname = os.path.relpath(file_path, source_dir)
500
+
501
+ if _should_ignore(arcname, ignore_patterns):
502
+ continue
503
+
504
+ zipf.write(file_path, arcname)
505
+
506
+ logger.info(f"Source code packaged: {output_zip}")
507
+
508
+
509
+ def _merge_zips(
510
+ dependencies_zip: Optional[Path],
511
+ code_zip: Path,
512
+ output_zip: Path,
513
+ ) -> None:
514
+ """
515
+ Merge dependencies and code zips into a deployment package.
516
+
517
+ Args:
518
+ dependencies_zip: Path to dependencies.zip (optional)
519
+ code_zip: Path to code.zip
520
+ output_zip: Path to output deployment.zip
521
+ """
522
+ logger.info("Merging packages into deployment.zip...")
523
+
524
+ with zipfile.ZipFile(output_zip, "w", zipfile.ZIP_DEFLATED) as out:
525
+ # Layer 1: Dependencies
526
+ if dependencies_zip and dependencies_zip.exists():
527
+ with zipfile.ZipFile(dependencies_zip, "r") as dep:
528
+ for item in dep.namelist():
529
+ out.writestr(item, dep.read(item))
530
+
531
+ # Layer 2: Code (overwrites conflicts)
532
+ with zipfile.ZipFile(code_zip, "r") as code:
533
+ for item in code.namelist():
534
+ out.writestr(item, code.read(item))
535
+
536
+ logger.info(f"Deployment package created: {output_zip}")
537
+
538
+
539
+ # ===== Main Package Function =====
540
+
541
+
542
+ def package(
543
+ app=None,
544
+ runner=None,
545
+ entrypoint: Optional[str] = None,
546
+ output_dir: Optional[str] = None,
547
+ host: str = "0.0.0.0",
548
+ port: int = 8090,
549
+ extra_parameters: Optional[List[RuntimeParameter]] = None,
550
+ **kwargs,
551
+ ) -> Tuple[str, ProjectInfo]:
552
+ """
553
+ Package an AgentApp or Runner for deployment.
554
+
555
+ This function supports two deployment patterns:
556
+ 1. Object-style: package(app=my_app) or package(runner=my_runner)
557
+ 2. Entrypoint-style: package(entrypoint="app.py") or package(
558
+ entrypoint="project_dir/")
559
+
560
+ For object-style deployment, this function will:
561
+ 1. Extract the project directory containing the app/runner
562
+ 2. Generate a new main.py that imports and runs the app/runner
563
+ 3. Package the project with the generated main.py as entrypoint
564
+
565
+ Args:
566
+ app: AgentApp instance (for object-style deployment)
567
+ runner: Runner instance (for object-style deployment)
568
+ entrypoint: Entrypoint specification (for CLI-style deployment)
569
+ output_dir: Output directory (creates temp dir if None)
570
+ host: Default host for the service (default: "0.0.0.0")
571
+ port: Default port for the service (default: 8090)
572
+ extra_parameters: Additional runtime parameters to expose via CLI
573
+ **kwargs: Additional keyword arguments (ignored)
574
+
575
+ Returns:
576
+ Tuple of (package_path, project_info)
577
+ - package_path: Path to the deployment package directory
578
+ - project_info: ProjectInfo with project metadata
579
+
580
+ Raises:
581
+ ValueError: If neither app/runner nor entrypoint is provided
582
+ RuntimeError: If packaging fails
583
+
584
+ Example:
585
+ >>> # Package with extra parameters
586
+ >>> extra_params = [
587
+ ... RuntimeParameter(
588
+ ... name="log_level",
589
+ ... type="str",
590
+ ... default="info",
591
+ ... help="Logging level"
592
+ ... ),
593
+ ... RuntimeParameter(
594
+ ... name="workers",
595
+ ... type="int",
596
+ ... default=4,
597
+ ... help="Number of worker threads"
598
+ ... ),
599
+ ... ]
600
+ >>> package(app=my_app, extra_parameters=extra_params)
601
+ """
602
+ # Determine project info and target object
603
+ target_obj = None
604
+ if entrypoint:
605
+ project_info = parse_entrypoint(entrypoint)
606
+ elif app or runner:
607
+ project_info = project_dir_extractor(app=app, runner=runner)
608
+ target_obj = app if app is not None else runner
609
+ else:
610
+ raise ValueError(
611
+ "Either app/runner or entrypoint must be provided",
612
+ )
613
+
614
+ logger.info(f"Packaging project from: {project_info.project_dir}")
615
+
616
+ # Create output directory
617
+ if output_dir is None:
618
+ output_dir = tempfile.mkdtemp(prefix="agentscope_package_")
619
+ else:
620
+ os.makedirs(output_dir, exist_ok=True)
621
+
622
+ output_path = Path(output_dir)
623
+ module_name = project_info.entrypoint_file.split(".", maxsplit=1)[0]
624
+ # For object-style deployment, generate main.py template
625
+ generated_main = False
626
+ if target_obj is not None:
627
+ entrypoint_info = EntrypointInfo(
628
+ module_name=module_name,
629
+ object_type=project_info.handler_type,
630
+ object_name=project_info.entrypoint_handler,
631
+ host=host,
632
+ port=port,
633
+ extra_parameters=extra_parameters or [],
634
+ )
635
+
636
+ # Generate main.py content
637
+ main_content = generate_main_template(entrypoint_info)
638
+
639
+ # Create temporary directory for modified source
640
+ temp_source_dir = output_path / "temp_source"
641
+ temp_source_dir.mkdir(exist_ok=True)
642
+
643
+ # Copy original project to temp directory
644
+ shutil.copytree(
645
+ project_info.project_dir,
646
+ temp_source_dir,
647
+ dirs_exist_ok=True,
648
+ ignore=shutil.ignore_patterns(*_get_default_ignore_patterns()),
649
+ )
650
+
651
+ # Write generated main.py to temp directory
652
+ main_py_path = temp_source_dir / DEFAULT_ENTRYPOINT_FILE
653
+ with open(main_py_path, "w", encoding="utf-8") as f:
654
+ f.write(main_content)
655
+
656
+ # Update project_info to use generated main.py
657
+ project_info.entrypoint_file = DEFAULT_ENTRYPOINT_FILE
658
+ project_info.entrypoint_handler = entrypoint_info.object_name
659
+ # Use object name
660
+ project_info.handler_type = entrypoint_info.object_type # Use type
661
+ project_info.project_dir = str(temp_source_dir)
662
+
663
+ generated_main = True
664
+ logger.info(
665
+ f"Generated main.py template for {entrypoint_info.object_type}: "
666
+ f"{entrypoint_info.object_name}",
667
+ )
668
+ logger.info(
669
+ f"Service will start on {host}:{port} by default",
670
+ )
671
+ if extra_parameters:
672
+ logger.info(
673
+ f"Added {len(extra_parameters)} extra runtime parameters",
674
+ )
675
+
676
+ # Package code
677
+ deployment_zip = output_path / DEPLOYMENT_ZIP
678
+ package_code(
679
+ Path(project_info.project_dir),
680
+ deployment_zip,
681
+ )
682
+
683
+ # Clean up temporary directory if created
684
+ if generated_main:
685
+ temp_source_dir = Path(project_info.project_dir)
686
+ if temp_source_dir.exists() and temp_source_dir.parent == output_path:
687
+ shutil.rmtree(temp_source_dir)
688
+
689
+ # Report size
690
+ size_mb = deployment_zip.stat().st_size / (1024 * 1024)
691
+ logger.info(f"Deployment package ready: {size_mb:.2f} MB")
692
+
693
+ return str(output_path), project_info
@@ -1,9 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  from .fastapi_factory import FastAPIAppFactory
3
- from .service_config import (
4
- ServicesConfig,
5
- ServiceConfig,
6
- ServiceProvider,
7
- )
8
3
  from .fastapi_templates import FastAPITemplateManager
9
4
  from .process_manager import ProcessManager