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
@@ -1,22 +1,95 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # pylint:disable=too-many-branches, unused-argument, too-many-return-statements
3
-
3
+ # pylint:disable=protected-access
4
4
 
5
5
  import asyncio
6
+ import functools
6
7
  import inspect
7
8
  import json
9
+ import logging
8
10
  from contextlib import asynccontextmanager
11
+ from dataclasses import asdict, is_dataclass
9
12
  from typing import Optional, Callable, Type, Any, List, Dict
10
13
 
14
+ from a2a.types import A2ARequest
11
15
  from fastapi import FastAPI, Request
12
16
  from fastapi.middleware.cors import CORSMiddleware
13
17
  from fastapi.responses import StreamingResponse, JSONResponse
14
18
  from pydantic import BaseModel
15
19
 
16
- from .service_config import ServicesConfig, DEFAULT_SERVICES_CONFIG
17
- from .service_factory import ServiceFactory
20
+ from agentscope_runtime.engine.schemas.agent_schemas import AgentRequest
21
+ from agentscope_runtime.engine.schemas.response_api import ResponseAPI
18
22
  from ..deployment_modes import DeploymentMode
23
+ from ...adapter.a2a.a2a_protocol_adapter import A2AFastAPIDefaultAdapter
19
24
  from ...adapter.protocol_adapter import ProtocolAdapter
25
+ from ...adapter.responses.response_api_protocol_adapter import (
26
+ ResponseAPIDefaultAdapter,
27
+ )
28
+
29
+ logger = logging.getLogger(__name__)
30
+
31
+
32
+ class _WrappedFastAPI(FastAPI):
33
+ """FastAPI subclass that can dynamically augment OpenAPI schemas."""
34
+
35
+ _REF_TEMPLATE = "#/components/schemas/{model}"
36
+
37
+ def openapi(self) -> dict[str, Any]:
38
+ """Generate OpenAPI schema with protocol-specific components."""
39
+ openapi_schema = super().openapi()
40
+ protocol_adapters = (
41
+ getattr(self.state, "protocol_adapters", None) or []
42
+ )
43
+
44
+ if protocol_adapters:
45
+ if any(
46
+ isinstance(adapter, A2AFastAPIDefaultAdapter)
47
+ for adapter in protocol_adapters
48
+ ):
49
+ self._inject_schema(
50
+ openapi_schema,
51
+ "A2ARequest",
52
+ A2ARequest.model_json_schema(
53
+ ref_template=self._REF_TEMPLATE,
54
+ ),
55
+ )
56
+ if any(
57
+ isinstance(adapter, ResponseAPIDefaultAdapter)
58
+ for adapter in protocol_adapters
59
+ ):
60
+ self._inject_schema(
61
+ openapi_schema,
62
+ "ResponseAPI",
63
+ ResponseAPI.model_json_schema(
64
+ ref_template=self._REF_TEMPLATE,
65
+ ),
66
+ )
67
+
68
+ self._inject_schema(
69
+ openapi_schema,
70
+ "AgentRequest",
71
+ AgentRequest.model_json_schema(
72
+ ref_template=self._REF_TEMPLATE,
73
+ ),
74
+ )
75
+
76
+ return openapi_schema
77
+
78
+ @staticmethod
79
+ def _inject_schema(
80
+ openapi_schema: dict[str, Any],
81
+ schema_name: str,
82
+ schema_definition: dict[str, Any],
83
+ ) -> None:
84
+ """Insert schema definition (and nested defs) into OpenAPI."""
85
+ components = openapi_schema.setdefault("components", {})
86
+ component_schemas = components.setdefault("schemas", {})
87
+
88
+ defs = schema_definition.pop("$defs", {})
89
+ for def_name, def_schema in defs.items():
90
+ component_schemas.setdefault(def_name, def_schema)
91
+
92
+ component_schemas[schema_name] = schema_definition
20
93
 
21
94
 
22
95
  async def error_stream(e):
@@ -40,7 +113,6 @@ class FastAPIAppFactory:
40
113
  before_start: Optional[Callable] = None,
41
114
  after_finish: Optional[Callable] = None,
42
115
  mode: DeploymentMode = DeploymentMode.DAEMON_THREAD,
43
- services_config: Optional[ServicesConfig] = None,
44
116
  protocol_adapters: Optional[list[ProtocolAdapter]] = None,
45
117
  custom_endpoints: Optional[
46
118
  List[Dict]
@@ -49,6 +121,7 @@ class FastAPIAppFactory:
49
121
  broker_url: Optional[str] = None,
50
122
  backend_url: Optional[str] = None,
51
123
  enable_embedded_worker: bool = False,
124
+ app_kwargs: Optional[Dict] = None,
52
125
  **kwargs: Any,
53
126
  ) -> FastAPI:
54
127
  """Create a FastAPI application with unified architecture.
@@ -63,20 +136,17 @@ class FastAPIAppFactory:
63
136
  before_start: Callback function called before server starts
64
137
  after_finish: Callback function called after server finishes
65
138
  mode: Deployment mode
66
- services_config: Services configuration
67
139
  protocol_adapters: Protocol adapters
68
140
  custom_endpoints: List of custom endpoint configurations
69
141
  broker_url: Celery broker URL
70
142
  backend_url: Celery backend URL
71
143
  enable_embedded_worker: Whether to run embedded Celery worker
144
+ app_kwargs: Additional keyword arguments for the FastAPI app
72
145
  **kwargs: Additional keyword arguments
73
146
 
74
147
  Returns:
75
148
  FastAPI application instance
76
149
  """
77
- # Use default services config if not provided
78
- if services_config is None:
79
- services_config = DEFAULT_SERVICES_CONFIG
80
150
 
81
151
  # Initialize Celery mixin if broker and backend URLs are provided
82
152
  celery_mixin = None
@@ -101,7 +171,6 @@ class FastAPIAppFactory:
101
171
  await FastAPIAppFactory._handle_startup(
102
172
  app,
103
173
  mode,
104
- services_config,
105
174
  runner,
106
175
  before_start,
107
176
  **kwargs,
@@ -116,15 +185,14 @@ class FastAPIAppFactory:
116
185
  )
117
186
 
118
187
  # Create FastAPI app
119
- app = FastAPI(lifespan=lifespan)
188
+ app = _WrappedFastAPI(lifespan=lifespan, **(app_kwargs or {}))
120
189
 
121
190
  # Store configuration in app state
122
191
  app.state.deployment_mode = mode
123
- app.state.services_config = services_config
124
192
  app.state.stream_enabled = stream
125
- app.state.response_type = response_type
126
193
  app.state.custom_func = func
127
- app.state.external_runner = runner
194
+ app.state.runner = runner
195
+ app.state.response_type = response_type
128
196
  app.state.endpoint_path = endpoint_path
129
197
  app.state.protocol_adapters = protocol_adapters # Store for later use
130
198
  app.state.custom_endpoints = (
@@ -158,27 +226,20 @@ class FastAPIAppFactory:
158
226
  async def _handle_startup(
159
227
  app: FastAPI,
160
228
  mode: DeploymentMode,
161
- services_config: ServicesConfig,
162
229
  external_runner: Optional[Any],
163
230
  before_start: Optional[Callable],
164
231
  **kwargs,
165
232
  ):
166
233
  """Handle application startup."""
167
- # Mode-specific initialization
168
- if mode == DeploymentMode.DAEMON_THREAD:
169
- # Use external runner
170
- app.state.runner = external_runner
171
- app.state.runner_managed_externally = True
172
-
173
- elif mode in [
174
- DeploymentMode.DETACHED_PROCESS,
175
- DeploymentMode.STANDALONE,
176
- ]:
177
- # Create internal runner
178
- app.state.runner = await FastAPIAppFactory._create_internal_runner(
179
- services_config,
234
+ try:
235
+ # aexit any possible running instances before set up
236
+ # runner
237
+ await app.state.runner.__aexit__(None, None, None)
238
+ await app.state.runner.__aenter__()
239
+ except Exception as e:
240
+ logger.error(
241
+ f"Warning: Error during runner setup: {e}",
180
242
  )
181
- app.state.runner_managed_externally = False
182
243
 
183
244
  # Call custom startup callback
184
245
  if before_start:
@@ -243,9 +304,6 @@ class FastAPIAppFactory:
243
304
  queues=queues,
244
305
  )
245
306
  except Exception as e:
246
- import logging
247
-
248
- logger = logging.getLogger(__name__)
249
307
  logger.error(f"Failed to start Celery worker: {e}")
250
308
 
251
309
  worker_thread = threading.Thread(
@@ -269,39 +327,23 @@ class FastAPIAppFactory:
269
327
  after_finish(app, **kwargs)
270
328
 
271
329
  # Cleanup internal runner
272
- if (
273
- hasattr(app.state, "runner")
274
- and not app.state.runner_managed_externally
275
- ):
276
- runner = app.state.runner
277
- if runner:
278
- try:
279
- # Clean up runner
280
- await runner.__aexit__(None, None, None)
281
- except Exception as e:
282
- print(f"Warning: Error during runner cleanup: {e}")
330
+ runner = app.state.runner
331
+ if runner:
332
+ try:
333
+ # Clean up runner
334
+ await runner.__aexit__(None, None, None)
335
+ except Exception as e:
336
+ logger.error(f"Warning: Error during runner cleanup: {e}")
283
337
 
284
338
  @staticmethod
285
- async def _create_internal_runner(services_config: ServicesConfig):
339
+ async def _create_internal_runner():
286
340
  """Create internal runner with configured services."""
287
341
  from agentscope_runtime.engine import Runner
288
- from agentscope_runtime.engine.services.context_manager import (
289
- ContextManager,
290
- )
291
-
292
- # Create services
293
- services = ServiceFactory.create_services_from_config(services_config)
294
-
295
- # Create context manager
296
- context_manager = ContextManager(
297
- session_history_service=services["session_history"],
298
- memory_service=services["memory"],
299
- )
300
342
 
301
343
  # Create runner (agent will be set later)
302
344
  runner = Runner(
303
- agent=None, # Will be set by the specific deployment
304
- context_manager=context_manager,
345
+ # agent=None, # Will be set by the specific deployment
346
+ # context_manager=context_manager,
305
347
  )
306
348
 
307
349
  # Initialize runner
@@ -364,14 +406,36 @@ class FastAPIAppFactory:
364
406
 
365
407
  return status
366
408
 
367
- # Main processing endpoint
368
- # if stream_enabled:
369
- # Streaming endpoint
370
- @app.post(endpoint_path)
371
- async def stream_endpoint(request: dict):
372
- """Streaming endpoint."""
409
+ # Agent API endpoint
410
+ @app.post(
411
+ endpoint_path,
412
+ openapi_extra={
413
+ "requestBody": {
414
+ "content": {
415
+ "application/json": {
416
+ "schema": {
417
+ "$ref": "#/components/schemas/AgentRequest",
418
+ },
419
+ },
420
+ },
421
+ "required": True,
422
+ "description": "Agent API Request Format."
423
+ "See https://runtime.agentscope.io/en/protocol.html for "
424
+ "more details.",
425
+ },
426
+ },
427
+ tags=["agent-api"],
428
+ )
429
+ async def agent_api(request: dict):
430
+ """
431
+ Agent API endpoint, see
432
+ <https://runtime.agentscope.io/en/protocol.html> for more details.
433
+ """
373
434
  return StreamingResponse(
374
- FastAPIAppFactory._create_stream_generator(app, request),
435
+ FastAPIAppFactory._create_stream_generator(
436
+ app,
437
+ request=request,
438
+ ),
375
439
  media_type="text/event-stream",
376
440
  headers={
377
441
  "Cache-Control": "no-cache",
@@ -398,9 +462,9 @@ class FastAPIAppFactory:
398
462
  "mode": mode.value,
399
463
  "endpoints": {
400
464
  "process": endpoint_path,
401
- "stream": f"{endpoint_path}/stream"
402
- if stream_enabled
403
- else None,
465
+ "stream": (
466
+ f"{endpoint_path}/stream" if stream_enabled else None
467
+ ),
404
468
  "health": "/health",
405
469
  },
406
470
  }
@@ -408,8 +472,6 @@ class FastAPIAppFactory:
408
472
  # Mode-specific endpoints
409
473
  if mode == DeploymentMode.DETACHED_PROCESS:
410
474
  FastAPIAppFactory._add_process_control_endpoints(app)
411
- elif mode == DeploymentMode.STANDALONE:
412
- FastAPIAppFactory._add_configuration_endpoints(app)
413
475
 
414
476
  @staticmethod
415
477
  def _add_process_control_endpoints(app: FastAPI):
@@ -445,38 +507,6 @@ class FastAPIAppFactory:
445
507
  "uptime": process.create_time(),
446
508
  }
447
509
 
448
- @staticmethod
449
- def _add_configuration_endpoints(app: FastAPI):
450
- """Add configuration endpoints for standalone mode."""
451
-
452
- @app.get("/config")
453
- async def get_configuration():
454
- """Get current service configuration."""
455
- return {
456
- "services_config": app.state.services_config.model_dump(),
457
- "deployment_mode": app.state.deployment_mode.value,
458
- "stream_enabled": app.state.stream_enabled,
459
- }
460
-
461
- @app.get("/config/services")
462
- async def get_services_status():
463
- """Get services status."""
464
- status = {}
465
- if hasattr(app.state, "runner") and app.state.runner:
466
- runner = app.state.runner
467
- if hasattr(runner, "context_manager"):
468
- cm = runner.context_manager
469
- status["memory_service"] = (
470
- "connected" if cm.memory_service else "disconnected"
471
- )
472
- status["session_history_service"] = (
473
- "connected"
474
- if cm.session_history_service
475
- else "disconnected"
476
- )
477
-
478
- return {"services": status}
479
-
480
510
  @staticmethod
481
511
  async def _handle_request(
482
512
  app: FastAPI,
@@ -591,193 +621,135 @@ class FastAPIAppFactory:
591
621
  return None
592
622
 
593
623
  @staticmethod
594
- def _create_parameter_wrapper(handler: Callable):
595
- """Create a wrapper that handles parameter parsing based on function
596
- signature.
624
+ def _create_handler_wrapper(handler: Callable):
625
+ """Create a wrapper for a handler that preserves function signature.
597
626
 
598
- This method inspects the handler function's parameters and creates
599
- appropriate wrappers to parse request data into the expected
600
- parameter types.
627
+ This wrapper maintains the handler's signature to enable FastAPI's
628
+ automatic parameter parsing and dependency injection. For async
629
+ handlers, it returns an async wrapper; for sync handlers,
630
+ it returns a sync wrapper.
631
+
632
+ Args:
633
+ handler: The handler function to wrap
634
+
635
+ Returns:
636
+ A wrapped handler that preserves the original function signature
601
637
  """
602
- try:
603
- sig = inspect.signature(handler)
604
- params = list(sig.parameters.values())
605
638
 
606
- if not params:
607
- # No parameters, call function directly
608
- return handler
639
+ is_awaitable = inspect.iscoroutinefunction(handler)
640
+ if is_awaitable:
609
641
 
610
- # Get the first parameter (assuming single parameter for now)
611
- first_param = params[0]
612
- param_annotation = first_param.annotation
642
+ @functools.wraps(handler)
643
+ async def wrapped_handler(*args, **kwargs):
644
+ return await handler(*args, **kwargs)
613
645
 
614
- # If no annotation or annotation is Request, pass Request directly
615
- if param_annotation in [inspect.Parameter.empty, Request]:
616
- return handler
646
+ wrapped_handler.__signature__ = inspect.signature(handler)
647
+ return wrapped_handler
648
+ else:
617
649
 
618
- # Check if the annotation is a Pydantic model
619
- if isinstance(param_annotation, type) and issubclass(
620
- param_annotation,
621
- BaseModel,
622
- ):
623
- # Create wrapper that parses JSON to Pydantic model
624
- if inspect.iscoroutinefunction(handler):
625
-
626
- async def async_pydantic_wrapper(request: Request):
627
- try:
628
- body = await request.json()
629
- parsed_param = param_annotation(**body)
630
- return await handler(parsed_param)
631
- except Exception as e:
632
- return JSONResponse(
633
- status_code=422,
634
- content={
635
- "detail": f"Request parsing error: "
636
- f"{str(e)}",
637
- },
638
- )
650
+ @functools.wraps(handler)
651
+ def wrapped_handler(*args, **kwargs):
652
+ return handler(*args, **kwargs)
639
653
 
640
- return async_pydantic_wrapper
641
- else:
654
+ wrapped_handler.__signature__ = inspect.signature(handler)
655
+ return wrapped_handler
642
656
 
643
- async def sync_pydantic_wrapper(request: Request):
644
- try:
645
- body = await request.json()
646
- parsed_param = param_annotation(**body)
647
- return handler(parsed_param)
648
- except Exception as e:
649
- return JSONResponse(
650
- status_code=422,
651
- content={
652
- "detail": f"Request parsing error: "
653
- f"{str(e)}",
654
- },
655
- )
657
+ @staticmethod
658
+ def _to_sse_event(item: Any) -> str:
659
+ """Normalize streaming items into JSON-serializable structures."""
656
660
 
657
- return sync_pydantic_wrapper
661
+ def _serialize(value: Any, depth: int = 0):
662
+ if depth > 20:
663
+ return f"<too-deep-level-{depth}-{str(value)}>"
658
664
 
659
- # For other types, fall back to original behavior
660
- return handler
665
+ if isinstance(value, (list, tuple, set)):
666
+ return [_serialize(i, depth=depth + 1) for i in value]
667
+ elif isinstance(value, dict):
668
+ return {
669
+ k: _serialize(v, depth=depth + 1) for k, v in value.items()
670
+ }
671
+ elif isinstance(value, (str, int, float, bool, type(None))):
672
+ return value
673
+ elif isinstance(value, BaseModel):
674
+ return value.model_dump()
675
+ elif is_dataclass(value):
676
+ return asdict(value)
661
677
 
662
- except Exception:
663
- # If anything goes wrong with introspection, fall back to
664
- # original behavior
665
- return handler
678
+ for attr in ("to_map", "to_dict"):
679
+ method = getattr(value, attr, None)
680
+ if callable(method):
681
+ return method()
682
+ return str(value)
683
+
684
+ serialized = _serialize(item, depth=0)
685
+
686
+ return f"data: {json.dumps(serialized, ensure_ascii=False)}\n\n"
666
687
 
667
688
  @staticmethod
668
689
  def _create_streaming_parameter_wrapper(
669
690
  handler: Callable,
670
- is_async_gen: bool = False,
671
691
  ):
672
692
  """Create a wrapper for streaming handlers that handles parameter
673
693
  parsing."""
674
- try:
675
- sig = inspect.signature(handler)
676
- params = list(sig.parameters.values())
677
- no_params = False
678
- param_annotation = None
679
-
680
- if not params:
681
- no_params = True
682
- else:
683
- # Get the first parameter
684
- first_param = params[0]
685
- param_annotation = first_param.annotation
686
-
687
- # If no annotation or annotation is Request, goto no params
688
- # logic
689
- if param_annotation in [inspect.Parameter.empty, Request]:
690
- no_params = True
691
-
692
- if no_params:
693
- if is_async_gen:
694
-
695
- async def async_no_param_wrapper():
696
- async def generate():
697
- async for chunk in handler():
698
- yield str(chunk)
699
-
700
- return StreamingResponse(
701
- generate(),
702
- media_type="text/plain",
703
- )
694
+ is_async_gen = inspect.isasyncgenfunction(handler)
704
695
 
705
- return async_no_param_wrapper
706
- else:
707
-
708
- async def sync_no_param_wrapper():
709
- def generate():
710
- for chunk in handler():
711
- yield str(chunk)
712
-
713
- return StreamingResponse(
714
- generate(),
715
- media_type="text/plain",
716
- )
717
-
718
- return sync_no_param_wrapper
696
+ if is_async_gen:
719
697
 
720
- # Check if the annotation is a Pydantic model
721
- if isinstance(param_annotation, type) and issubclass(
722
- param_annotation,
723
- BaseModel,
724
- ):
725
- if is_async_gen:
726
-
727
- async def async_stream_pydantic_wrapper(
728
- request: Request,
729
- ):
730
- try:
731
- body = await request.json()
732
- parsed_param = param_annotation(**body)
733
-
734
- async def generate():
735
- async for chunk in handler(parsed_param):
736
- yield str(chunk)
737
-
738
- return StreamingResponse(
739
- generate(),
740
- media_type="text/plain",
698
+ @functools.wraps(handler)
699
+ async def wrapped_handler(*args, **kwargs):
700
+ async def generate():
701
+ try:
702
+ async for chunk in handler(*args, **kwargs):
703
+ yield FastAPIAppFactory._to_sse_event(
704
+ chunk,
741
705
  )
742
- except Exception as e:
743
- return StreamingResponse(
744
- error_stream(e),
745
- media_type="text/event-stream",
746
- )
747
-
748
- return async_stream_pydantic_wrapper
749
- else:
750
-
751
- async def sync_stream_pydantic_wrapper(
752
- request: Request,
753
- ):
754
- try:
755
- body = await request.json()
756
- parsed_param = param_annotation(**body)
706
+ except Exception as e:
707
+ logger.error(
708
+ f"Error in streaming handler: {e}",
709
+ exc_info=True,
710
+ )
711
+ err_event = {
712
+ "error": str(e),
713
+ "error_type": e.__class__.__name__,
714
+ "message": "Error in streaming generator",
715
+ }
716
+ yield FastAPIAppFactory._to_sse_event(err_event)
717
+
718
+ return StreamingResponse(
719
+ generate(),
720
+ media_type="text/event-stream",
721
+ )
757
722
 
758
- def generate():
759
- for chunk in handler(parsed_param):
760
- yield str(chunk)
723
+ wrapped_handler.__signature__ = inspect.signature(handler)
724
+ return wrapped_handler
761
725
 
762
- return StreamingResponse(
763
- generate(),
764
- media_type="text/plain",
765
- )
766
- except Exception as e:
767
- return JSONResponse(
768
- status_code=422,
769
- content={
770
- "detail": f"Request parsing error:"
771
- f" {str(e)}",
772
- },
773
- )
774
-
775
- return sync_stream_pydantic_wrapper
726
+ else:
776
727
 
777
- return handler
728
+ @functools.wraps(handler)
729
+ def wrapped_handler(*args, **kwargs):
730
+ def generate():
731
+ try:
732
+ for chunk in handler(*args, **kwargs):
733
+ yield FastAPIAppFactory._to_sse_event(chunk)
734
+ except Exception as e:
735
+ logger.error(
736
+ f"Error in streaming handler: {e}",
737
+ exc_info=True,
738
+ )
739
+ err_event = {
740
+ "error": str(e),
741
+ "error_type": e.__class__.__name__,
742
+ "message": "Error in streaming generator",
743
+ }
744
+ yield FastAPIAppFactory._to_sse_event(err_event)
745
+
746
+ return StreamingResponse(
747
+ generate(),
748
+ media_type="text/event-stream",
749
+ )
778
750
 
779
- except Exception:
780
- return handler
751
+ wrapped_handler.__signature__ = inspect.signature(handler)
752
+ return wrapped_handler
781
753
 
782
754
  @staticmethod
783
755
  def _add_custom_endpoints(app: FastAPI):
@@ -808,6 +780,8 @@ class FastAPIAppFactory:
808
780
  """Register a single custom endpoint with proper async/sync
809
781
  handling."""
810
782
 
783
+ tags = ["custom"]
784
+
811
785
  for method in methods:
812
786
  # Check if this is a task endpoint
813
787
  if endpoint_config and endpoint_config.get("task_type"):
@@ -817,7 +791,12 @@ class FastAPIAppFactory:
817
791
  handler,
818
792
  endpoint_config.get("queue", "default"),
819
793
  )
820
- app.add_api_route(path, task_handler, methods=[method])
794
+ app.add_api_route(
795
+ path,
796
+ task_handler,
797
+ methods=[method],
798
+ tags=tags,
799
+ )
821
800
 
822
801
  # Add task status endpoint - align with BaseApp pattern
823
802
  status_path = f"{path}/{{task_id}}"
@@ -828,47 +807,42 @@ class FastAPIAppFactory:
828
807
  status_path,
829
808
  status_handler,
830
809
  methods=["GET"],
810
+ tags=tags,
831
811
  )
832
812
 
833
813
  else:
834
814
  # Regular endpoint handling with automatic parameter parsing
835
815
  # Check in the correct order: async gen > sync gen > async &
836
816
  # sync
837
- if inspect.isasyncgenfunction(handler):
838
- # Async generator -> Streaming response with parameter
839
- # parsing
817
+
818
+ if inspect.isasyncgenfunction(
819
+ handler,
820
+ ) or inspect.isgeneratorfunction(handler):
840
821
  wrapped_handler = (
841
822
  FastAPIAppFactory._create_streaming_parameter_wrapper(
842
823
  handler,
843
- is_async_gen=True,
844
824
  )
845
825
  )
846
-
847
826
  app.add_api_route(
848
827
  path,
849
828
  wrapped_handler,
850
829
  methods=[method],
830
+ tags=tags,
831
+ response_model=None,
851
832
  )
852
- elif inspect.isgeneratorfunction(handler):
853
- # Sync generator -> Streaming response with parameter
854
- # parsing
833
+ else:
834
+ # Non-streaming endpoint -> wrapper that preserves
835
+ # handler signature
855
836
  wrapped_handler = (
856
- FastAPIAppFactory._create_streaming_parameter_wrapper(
857
- handler,
858
- is_async_gen=False,
859
- )
837
+ FastAPIAppFactory._create_handler_wrapper(handler)
860
838
  )
861
839
  app.add_api_route(
862
840
  path,
863
841
  wrapped_handler,
864
842
  methods=[method],
843
+ response_model=None,
844
+ tags=tags,
865
845
  )
866
- else:
867
- # Sync function -> Async wrapper with parameter parsing
868
- wrapped_handler = (
869
- FastAPIAppFactory._create_parameter_wrapper(handler)
870
- )
871
- app.add_api_route(path, wrapped_handler, methods=[method])
872
846
 
873
847
  @staticmethod
874
848
  def _create_task_handler(app: FastAPI, task_func: Callable, queue: str):