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.
- agentscope_runtime/adapters/__init__.py +0 -0
- agentscope_runtime/adapters/agentscope/__init__.py +0 -0
- agentscope_runtime/adapters/agentscope/long_term_memory/__init__.py +6 -0
- agentscope_runtime/adapters/agentscope/long_term_memory/_long_term_memory_adapter.py +258 -0
- agentscope_runtime/adapters/agentscope/memory/__init__.py +6 -0
- agentscope_runtime/adapters/agentscope/memory/_memory_adapter.py +152 -0
- agentscope_runtime/adapters/agentscope/message.py +535 -0
- agentscope_runtime/adapters/agentscope/stream.py +506 -0
- agentscope_runtime/adapters/agentscope/tool/__init__.py +9 -0
- agentscope_runtime/adapters/agentscope/tool/sandbox_tool.py +69 -0
- agentscope_runtime/adapters/agentscope/tool/tool.py +233 -0
- agentscope_runtime/adapters/autogen/__init__.py +0 -0
- agentscope_runtime/adapters/autogen/tool/__init__.py +7 -0
- agentscope_runtime/adapters/autogen/tool/tool.py +211 -0
- agentscope_runtime/adapters/text/__init__.py +0 -0
- agentscope_runtime/adapters/text/stream.py +29 -0
- agentscope_runtime/common/collections/redis_mapping.py +4 -1
- agentscope_runtime/common/container_clients/fc_client.py +855 -0
- agentscope_runtime/common/container_clients/kubernetes_client.py +6 -13
- agentscope_runtime/common/utils/__init__.py +0 -0
- agentscope_runtime/common/utils/lazy_loader.py +57 -0
- agentscope_runtime/engine/__init__.py +25 -18
- agentscope_runtime/engine/app/agent_app.py +161 -91
- agentscope_runtime/engine/app/base_app.py +4 -118
- agentscope_runtime/engine/constant.py +8 -0
- agentscope_runtime/engine/deployers/__init__.py +8 -0
- agentscope_runtime/engine/deployers/adapter/__init__.py +2 -0
- agentscope_runtime/engine/deployers/adapter/a2a/a2a_adapter_utils.py +0 -21
- agentscope_runtime/engine/deployers/adapter/a2a/a2a_protocol_adapter.py +28 -9
- agentscope_runtime/engine/deployers/adapter/responses/__init__.py +2 -0
- agentscope_runtime/engine/deployers/adapter/responses/response_api_adapter_utils.py +5 -2
- agentscope_runtime/engine/deployers/adapter/responses/response_api_protocol_adapter.py +1 -1
- agentscope_runtime/engine/deployers/agentrun_deployer.py +2541 -0
- agentscope_runtime/engine/deployers/cli_fc_deploy.py +1 -1
- agentscope_runtime/engine/deployers/kubernetes_deployer.py +9 -21
- agentscope_runtime/engine/deployers/local_deployer.py +47 -74
- agentscope_runtime/engine/deployers/modelstudio_deployer.py +216 -50
- agentscope_runtime/engine/deployers/utils/app_runner_utils.py +29 -0
- agentscope_runtime/engine/deployers/utils/detached_app.py +510 -0
- agentscope_runtime/engine/deployers/utils/docker_image_utils/__init__.py +1 -1
- agentscope_runtime/engine/deployers/utils/docker_image_utils/dockerfile_generator.py +1 -1
- agentscope_runtime/engine/deployers/utils/docker_image_utils/{runner_image_factory.py → image_factory.py} +121 -61
- agentscope_runtime/engine/deployers/utils/package.py +693 -0
- agentscope_runtime/engine/deployers/utils/service_utils/__init__.py +0 -5
- agentscope_runtime/engine/deployers/utils/service_utils/fastapi_factory.py +301 -282
- agentscope_runtime/engine/deployers/utils/service_utils/fastapi_templates.py +2 -4
- agentscope_runtime/engine/deployers/utils/service_utils/process_manager.py +23 -1
- agentscope_runtime/engine/deployers/utils/templates/app_main.py.j2 +84 -0
- agentscope_runtime/engine/deployers/utils/templates/runner_main.py.j2 +95 -0
- agentscope_runtime/engine/deployers/utils/{service_utils → templates}/standalone_main.py.j2 +0 -45
- agentscope_runtime/engine/deployers/utils/wheel_packager.py +119 -18
- agentscope_runtime/engine/helpers/runner.py +40 -0
- agentscope_runtime/engine/runner.py +171 -130
- agentscope_runtime/engine/schemas/agent_schemas.py +114 -3
- agentscope_runtime/engine/schemas/modelstudio_llm.py +4 -2
- agentscope_runtime/engine/schemas/oai_llm.py +23 -23
- agentscope_runtime/engine/schemas/response_api.py +65 -0
- agentscope_runtime/engine/schemas/session.py +24 -0
- agentscope_runtime/engine/services/__init__.py +0 -9
- agentscope_runtime/engine/services/agent_state/__init__.py +16 -0
- agentscope_runtime/engine/services/agent_state/redis_state_service.py +113 -0
- agentscope_runtime/engine/services/agent_state/state_service.py +179 -0
- agentscope_runtime/engine/services/memory/__init__.py +24 -0
- agentscope_runtime/engine/services/{mem0_memory_service.py → memory/mem0_memory_service.py} +17 -13
- agentscope_runtime/engine/services/{memory_service.py → memory/memory_service.py} +28 -7
- agentscope_runtime/engine/services/{redis_memory_service.py → memory/redis_memory_service.py} +1 -1
- agentscope_runtime/engine/services/{reme_personal_memory_service.py → memory/reme_personal_memory_service.py} +9 -6
- agentscope_runtime/engine/services/{reme_task_memory_service.py → memory/reme_task_memory_service.py} +2 -2
- agentscope_runtime/engine/services/{tablestore_memory_service.py → memory/tablestore_memory_service.py} +16 -19
- agentscope_runtime/engine/services/sandbox/__init__.py +13 -0
- agentscope_runtime/engine/services/{sandbox_service.py → sandbox/sandbox_service.py} +86 -71
- agentscope_runtime/engine/services/session_history/__init__.py +23 -0
- agentscope_runtime/engine/services/{redis_session_history_service.py → session_history/redis_session_history_service.py} +3 -2
- agentscope_runtime/engine/services/{session_history_service.py → session_history/session_history_service.py} +44 -34
- agentscope_runtime/engine/services/{tablestore_session_history_service.py → session_history/tablestore_session_history_service.py} +14 -19
- agentscope_runtime/engine/services/utils/tablestore_service_utils.py +2 -2
- agentscope_runtime/engine/tracing/base.py +10 -9
- agentscope_runtime/engine/tracing/message_util.py +1 -1
- agentscope_runtime/engine/tracing/tracing_util.py +7 -2
- agentscope_runtime/engine/tracing/wrapper.py +49 -31
- agentscope_runtime/sandbox/__init__.py +10 -2
- agentscope_runtime/sandbox/box/agentbay/__init__.py +4 -0
- agentscope_runtime/sandbox/box/agentbay/agentbay_sandbox.py +559 -0
- agentscope_runtime/sandbox/box/base/base_sandbox.py +12 -0
- agentscope_runtime/sandbox/box/browser/browser_sandbox.py +115 -11
- agentscope_runtime/sandbox/box/cloud/__init__.py +4 -0
- agentscope_runtime/sandbox/box/cloud/cloud_sandbox.py +254 -0
- agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +66 -0
- agentscope_runtime/sandbox/box/gui/gui_sandbox.py +42 -0
- agentscope_runtime/sandbox/box/mobile/__init__.py +4 -0
- agentscope_runtime/sandbox/box/mobile/box/__init__.py +0 -0
- agentscope_runtime/sandbox/box/mobile/mobile_sandbox.py +216 -0
- agentscope_runtime/sandbox/box/training_box/training_box.py +2 -44
- agentscope_runtime/sandbox/client/http_client.py +1 -0
- agentscope_runtime/sandbox/enums.py +2 -1
- agentscope_runtime/sandbox/manager/sandbox_manager.py +15 -2
- agentscope_runtime/sandbox/manager/server/app.py +12 -0
- agentscope_runtime/sandbox/manager/server/config.py +19 -0
- agentscope_runtime/sandbox/model/manager_config.py +79 -2
- agentscope_runtime/sandbox/utils.py +0 -18
- agentscope_runtime/tools/RAGs/__init__.py +0 -0
- agentscope_runtime/tools/RAGs/modelstudio_rag.py +377 -0
- agentscope_runtime/tools/RAGs/modelstudio_rag_lite.py +219 -0
- agentscope_runtime/tools/__init__.py +119 -0
- agentscope_runtime/tools/_constants.py +18 -0
- agentscope_runtime/tools/alipay/__init__.py +4 -0
- agentscope_runtime/tools/alipay/base.py +334 -0
- agentscope_runtime/tools/alipay/payment.py +835 -0
- agentscope_runtime/tools/alipay/subscribe.py +551 -0
- agentscope_runtime/tools/base.py +264 -0
- agentscope_runtime/tools/cli/__init__.py +0 -0
- agentscope_runtime/tools/cli/modelstudio_mcp_server.py +78 -0
- agentscope_runtime/tools/generations/__init__.py +75 -0
- agentscope_runtime/tools/generations/async_image_to_video.py +350 -0
- agentscope_runtime/tools/generations/async_image_to_video_wan25.py +366 -0
- agentscope_runtime/tools/generations/async_speech_to_video.py +422 -0
- agentscope_runtime/tools/generations/async_text_to_video.py +320 -0
- agentscope_runtime/tools/generations/async_text_to_video_wan25.py +334 -0
- agentscope_runtime/tools/generations/image_edit.py +208 -0
- agentscope_runtime/tools/generations/image_edit_wan25.py +193 -0
- agentscope_runtime/tools/generations/image_generation.py +202 -0
- agentscope_runtime/tools/generations/image_generation_wan25.py +201 -0
- agentscope_runtime/tools/generations/image_style_repaint.py +208 -0
- agentscope_runtime/tools/generations/image_to_video.py +233 -0
- agentscope_runtime/tools/generations/qwen_image_edit.py +205 -0
- agentscope_runtime/tools/generations/qwen_image_generation.py +214 -0
- agentscope_runtime/tools/generations/qwen_text_to_speech.py +154 -0
- agentscope_runtime/tools/generations/speech_to_text.py +260 -0
- agentscope_runtime/tools/generations/speech_to_video.py +314 -0
- agentscope_runtime/tools/generations/text_to_video.py +221 -0
- agentscope_runtime/tools/mcp_wrapper.py +215 -0
- agentscope_runtime/tools/realtime_clients/__init__.py +13 -0
- agentscope_runtime/tools/realtime_clients/asr_client.py +27 -0
- agentscope_runtime/tools/realtime_clients/azure_asr_client.py +195 -0
- agentscope_runtime/tools/realtime_clients/azure_tts_client.py +383 -0
- agentscope_runtime/tools/realtime_clients/modelstudio_asr_client.py +151 -0
- agentscope_runtime/tools/realtime_clients/modelstudio_tts_client.py +199 -0
- agentscope_runtime/tools/realtime_clients/realtime_tool.py +55 -0
- agentscope_runtime/tools/realtime_clients/tts_client.py +33 -0
- agentscope_runtime/tools/searches/__init__.py +3 -0
- agentscope_runtime/tools/searches/modelstudio_search.py +877 -0
- agentscope_runtime/tools/searches/modelstudio_search_lite.py +310 -0
- agentscope_runtime/tools/utils/__init__.py +0 -0
- agentscope_runtime/tools/utils/api_key_util.py +45 -0
- agentscope_runtime/tools/utils/crypto_utils.py +99 -0
- agentscope_runtime/tools/utils/mcp_util.py +35 -0
- agentscope_runtime/version.py +1 -1
- {agentscope_runtime-0.2.0b1.dist-info → agentscope_runtime-1.0.0.dist-info}/METADATA +244 -168
- agentscope_runtime-1.0.0.dist-info/RECORD +240 -0
- {agentscope_runtime-0.2.0b1.dist-info → agentscope_runtime-1.0.0.dist-info}/entry_points.txt +1 -0
- agentscope_runtime/engine/agents/__init__.py +0 -2
- agentscope_runtime/engine/agents/agentscope_agent.py +0 -488
- agentscope_runtime/engine/agents/agno_agent.py +0 -222
- agentscope_runtime/engine/agents/autogen_agent.py +0 -250
- agentscope_runtime/engine/agents/base_agent.py +0 -29
- agentscope_runtime/engine/agents/langgraph_agent.py +0 -59
- agentscope_runtime/engine/agents/utils.py +0 -53
- agentscope_runtime/engine/deployers/utils/package_project_utils.py +0 -1163
- agentscope_runtime/engine/deployers/utils/service_utils/service_config.py +0 -75
- agentscope_runtime/engine/deployers/utils/service_utils/service_factory.py +0 -220
- agentscope_runtime/engine/helpers/helper.py +0 -179
- agentscope_runtime/engine/schemas/context.py +0 -54
- agentscope_runtime/engine/services/context_manager.py +0 -164
- agentscope_runtime/engine/services/environment_manager.py +0 -50
- agentscope_runtime/engine/services/manager.py +0 -174
- agentscope_runtime/engine/services/rag_service.py +0 -195
- agentscope_runtime/engine/services/tablestore_rag_service.py +0 -143
- agentscope_runtime/sandbox/tools/__init__.py +0 -12
- agentscope_runtime/sandbox/tools/base/__init__.py +0 -8
- agentscope_runtime/sandbox/tools/base/tool.py +0 -52
- agentscope_runtime/sandbox/tools/browser/__init__.py +0 -57
- agentscope_runtime/sandbox/tools/browser/tool.py +0 -597
- agentscope_runtime/sandbox/tools/filesystem/__init__.py +0 -32
- agentscope_runtime/sandbox/tools/filesystem/tool.py +0 -319
- agentscope_runtime/sandbox/tools/function_tool.py +0 -321
- agentscope_runtime/sandbox/tools/gui/__init__.py +0 -7
- agentscope_runtime/sandbox/tools/gui/tool.py +0 -77
- agentscope_runtime/sandbox/tools/mcp_tool.py +0 -195
- agentscope_runtime/sandbox/tools/sandbox_tool.py +0 -104
- agentscope_runtime/sandbox/tools/tool.py +0 -238
- agentscope_runtime/sandbox/tools/utils.py +0 -68
- agentscope_runtime-0.2.0b1.dist-info/RECORD +0 -183
- {agentscope_runtime-0.2.0b1.dist-info → agentscope_runtime-1.0.0.dist-info}/WHEEL +0 -0
- {agentscope_runtime-0.2.0b1.dist-info → agentscope_runtime-1.0.0.dist-info}/licenses/LICENSE +0 -0
- {agentscope_runtime-0.2.0b1.dist-info → agentscope_runtime-1.0.0.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 .
|
|
17
|
-
from .
|
|
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 =
|
|
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.
|
|
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
|
-
|
|
168
|
-
|
|
169
|
-
#
|
|
170
|
-
app.state.runner
|
|
171
|
-
app.state.
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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(
|
|
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
|
-
#
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
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(
|
|
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":
|
|
402
|
-
|
|
403
|
-
|
|
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,180 @@ class FastAPIAppFactory:
|
|
|
591
621
|
return None
|
|
592
622
|
|
|
593
623
|
@staticmethod
|
|
594
|
-
def
|
|
595
|
-
"""Create a wrapper
|
|
596
|
-
|
|
624
|
+
def _create_handler_wrapper(handler: Callable):
|
|
625
|
+
"""Create a wrapper for a handler that preserves function signature.
|
|
626
|
+
|
|
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.
|
|
597
631
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
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
|
-
|
|
607
|
-
|
|
608
|
-
return handler
|
|
639
|
+
is_awaitable = inspect.iscoroutinefunction(handler)
|
|
640
|
+
if is_awaitable:
|
|
609
641
|
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
642
|
+
@functools.wraps(handler)
|
|
643
|
+
async def wrapped_handler(*args, **kwargs):
|
|
644
|
+
return await handler(*args, **kwargs)
|
|
613
645
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
646
|
+
wrapped_handler.__signature__ = inspect.signature(handler)
|
|
647
|
+
return wrapped_handler
|
|
648
|
+
else:
|
|
617
649
|
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
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
|
-
|
|
641
|
-
|
|
654
|
+
wrapped_handler.__signature__ = inspect.signature(handler)
|
|
655
|
+
return wrapped_handler
|
|
642
656
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
657
|
+
@staticmethod
|
|
658
|
+
def _to_sse_event(item: Any) -> str:
|
|
659
|
+
"""Normalize streaming items into JSON-serializable structures."""
|
|
660
|
+
|
|
661
|
+
def _serialize(value: Any, depth: int = 0):
|
|
662
|
+
if depth > 20:
|
|
663
|
+
return f"<too-deep-level-{depth}-{str(value)}>"
|
|
664
|
+
|
|
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)
|
|
656
677
|
|
|
657
|
-
|
|
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)
|
|
658
683
|
|
|
659
|
-
|
|
660
|
-
return handler
|
|
684
|
+
serialized = _serialize(item, depth=0)
|
|
661
685
|
|
|
662
|
-
|
|
663
|
-
# If anything goes wrong with introspection, fall back to
|
|
664
|
-
# original behavior
|
|
665
|
-
return handler
|
|
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
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
694
|
+
is_async_gen = inspect.isasyncgenfunction(handler)
|
|
695
|
+
|
|
696
|
+
# NOTE:
|
|
697
|
+
# -----
|
|
698
|
+
# FastAPI >= 0.123.5 uses Dependant.is_coroutine_callable, which in
|
|
699
|
+
# turn unwraps callables via inspect.unwrap() and then inspects the
|
|
700
|
+
# unwrapped target to decide whether it is a coroutine function /
|
|
701
|
+
# generator / async generator.
|
|
702
|
+
#
|
|
703
|
+
# If we decorate an async-generator handler with
|
|
704
|
+
# functools.wraps(handler), FastAPI will unwrap back to the original
|
|
705
|
+
# async-generator function and *misclassify* the endpoint as
|
|
706
|
+
# non-coroutine. It will then call our async wrapper *without awaiting
|
|
707
|
+
# it*, and later try to JSON-encode the resulting coroutine object,
|
|
708
|
+
# causing errors like:
|
|
709
|
+
# TypeError("'coroutine' object is not iterable")
|
|
710
|
+
#
|
|
711
|
+
# To avoid that, we deliberately do NOT use functools.wraps() here.
|
|
712
|
+
# Instead, we manually copy the key metadata (name, qualname, doc,
|
|
713
|
+
# module, and signature) from the original handler, but we do NOT set
|
|
714
|
+
# __wrapped__. This ensures:
|
|
715
|
+
# * FastAPI sees the wrapper itself as the callable (an async def),
|
|
716
|
+
# so Dependant.is_coroutine_callable is True, and it is properly
|
|
717
|
+
# awaited.
|
|
718
|
+
# * FastAPI still sees the correct signature for parameter parsing.
|
|
719
|
+
|
|
720
|
+
if is_async_gen:
|
|
721
|
+
|
|
722
|
+
async def wrapped_handler(*args, **kwargs):
|
|
723
|
+
async def generate():
|
|
724
|
+
try:
|
|
725
|
+
async for chunk in handler(*args, **kwargs):
|
|
726
|
+
yield FastAPIAppFactory._to_sse_event(
|
|
727
|
+
chunk,
|
|
728
|
+
)
|
|
729
|
+
except Exception as e:
|
|
730
|
+
logger.error(
|
|
731
|
+
f"Error in streaming handler: {e}",
|
|
732
|
+
exc_info=True,
|
|
703
733
|
)
|
|
734
|
+
err_event = {
|
|
735
|
+
"error": str(e),
|
|
736
|
+
"error_type": e.__class__.__name__,
|
|
737
|
+
"message": "Error in streaming generator",
|
|
738
|
+
}
|
|
739
|
+
yield FastAPIAppFactory._to_sse_event(err_event)
|
|
740
|
+
|
|
741
|
+
return StreamingResponse(
|
|
742
|
+
generate(),
|
|
743
|
+
media_type="text/event-stream",
|
|
744
|
+
)
|
|
704
745
|
|
|
705
|
-
|
|
706
|
-
else:
|
|
707
|
-
|
|
708
|
-
async def sync_no_param_wrapper():
|
|
709
|
-
def generate():
|
|
710
|
-
for chunk in handler():
|
|
711
|
-
yield str(chunk)
|
|
746
|
+
else:
|
|
712
747
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
748
|
+
def wrapped_handler(*args, **kwargs):
|
|
749
|
+
def generate():
|
|
750
|
+
try:
|
|
751
|
+
for chunk in handler(*args, **kwargs):
|
|
752
|
+
yield FastAPIAppFactory._to_sse_event(chunk)
|
|
753
|
+
except Exception as e:
|
|
754
|
+
logger.error(
|
|
755
|
+
f"Error in streaming handler: {e}",
|
|
756
|
+
exc_info=True,
|
|
716
757
|
)
|
|
758
|
+
err_event = {
|
|
759
|
+
"error": str(e),
|
|
760
|
+
"error_type": e.__class__.__name__,
|
|
761
|
+
"message": "Error in streaming generator",
|
|
762
|
+
}
|
|
763
|
+
yield FastAPIAppFactory._to_sse_event(err_event)
|
|
764
|
+
|
|
765
|
+
return StreamingResponse(
|
|
766
|
+
generate(),
|
|
767
|
+
media_type="text/event-stream",
|
|
768
|
+
)
|
|
717
769
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
)
|
|
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)
|
|
757
|
-
|
|
758
|
-
def generate():
|
|
759
|
-
for chunk in handler(parsed_param):
|
|
760
|
-
yield str(chunk)
|
|
761
|
-
|
|
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
|
|
770
|
+
# Manually propagate essential metadata without creating a __wrapped__
|
|
771
|
+
# chain that would confuse FastAPI's unwrap logic.
|
|
772
|
+
wrapped_handler.__name__ = getattr(
|
|
773
|
+
handler,
|
|
774
|
+
"__name__",
|
|
775
|
+
wrapped_handler.__name__,
|
|
776
|
+
)
|
|
777
|
+
wrapped_handler.__qualname__ = getattr(
|
|
778
|
+
handler,
|
|
779
|
+
"__qualname__",
|
|
780
|
+
wrapped_handler.__qualname__,
|
|
781
|
+
)
|
|
782
|
+
wrapped_handler.__doc__ = getattr(
|
|
783
|
+
handler,
|
|
784
|
+
"__doc__",
|
|
785
|
+
wrapped_handler.__doc__,
|
|
786
|
+
)
|
|
787
|
+
wrapped_handler.__module__ = getattr(
|
|
788
|
+
handler,
|
|
789
|
+
"__module__",
|
|
790
|
+
wrapped_handler.__module__,
|
|
791
|
+
)
|
|
792
|
+
wrapped_handler.__signature__ = inspect.signature(handler)
|
|
776
793
|
|
|
777
|
-
|
|
794
|
+
# Make sure FastAPI doesn't see any stale __wrapped__ pointing back to
|
|
795
|
+
# the original async-generator; if present, remove it.
|
|
778
796
|
|
|
779
|
-
|
|
780
|
-
return handler
|
|
797
|
+
return wrapped_handler
|
|
781
798
|
|
|
782
799
|
@staticmethod
|
|
783
800
|
def _add_custom_endpoints(app: FastAPI):
|
|
@@ -808,6 +825,8 @@ class FastAPIAppFactory:
|
|
|
808
825
|
"""Register a single custom endpoint with proper async/sync
|
|
809
826
|
handling."""
|
|
810
827
|
|
|
828
|
+
tags = ["custom"]
|
|
829
|
+
|
|
811
830
|
for method in methods:
|
|
812
831
|
# Check if this is a task endpoint
|
|
813
832
|
if endpoint_config and endpoint_config.get("task_type"):
|
|
@@ -817,7 +836,12 @@ class FastAPIAppFactory:
|
|
|
817
836
|
handler,
|
|
818
837
|
endpoint_config.get("queue", "default"),
|
|
819
838
|
)
|
|
820
|
-
app.add_api_route(
|
|
839
|
+
app.add_api_route(
|
|
840
|
+
path,
|
|
841
|
+
task_handler,
|
|
842
|
+
methods=[method],
|
|
843
|
+
tags=tags,
|
|
844
|
+
)
|
|
821
845
|
|
|
822
846
|
# Add task status endpoint - align with BaseApp pattern
|
|
823
847
|
status_path = f"{path}/{{task_id}}"
|
|
@@ -828,47 +852,42 @@ class FastAPIAppFactory:
|
|
|
828
852
|
status_path,
|
|
829
853
|
status_handler,
|
|
830
854
|
methods=["GET"],
|
|
855
|
+
tags=tags,
|
|
831
856
|
)
|
|
832
857
|
|
|
833
858
|
else:
|
|
834
859
|
# Regular endpoint handling with automatic parameter parsing
|
|
835
860
|
# Check in the correct order: async gen > sync gen > async &
|
|
836
861
|
# sync
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
862
|
+
|
|
863
|
+
if inspect.isasyncgenfunction(
|
|
864
|
+
handler,
|
|
865
|
+
) or inspect.isgeneratorfunction(handler):
|
|
840
866
|
wrapped_handler = (
|
|
841
867
|
FastAPIAppFactory._create_streaming_parameter_wrapper(
|
|
842
868
|
handler,
|
|
843
|
-
is_async_gen=True,
|
|
844
869
|
)
|
|
845
870
|
)
|
|
846
|
-
|
|
847
871
|
app.add_api_route(
|
|
848
872
|
path,
|
|
849
873
|
wrapped_handler,
|
|
850
874
|
methods=[method],
|
|
875
|
+
tags=tags,
|
|
876
|
+
response_model=None,
|
|
851
877
|
)
|
|
852
|
-
|
|
853
|
-
#
|
|
854
|
-
#
|
|
878
|
+
else:
|
|
879
|
+
# Non-streaming endpoint -> wrapper that preserves
|
|
880
|
+
# handler signature
|
|
855
881
|
wrapped_handler = (
|
|
856
|
-
FastAPIAppFactory.
|
|
857
|
-
handler,
|
|
858
|
-
is_async_gen=False,
|
|
859
|
-
)
|
|
882
|
+
FastAPIAppFactory._create_handler_wrapper(handler)
|
|
860
883
|
)
|
|
861
884
|
app.add_api_route(
|
|
862
885
|
path,
|
|
863
886
|
wrapped_handler,
|
|
864
887
|
methods=[method],
|
|
888
|
+
response_model=None,
|
|
889
|
+
tags=tags,
|
|
865
890
|
)
|
|
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
891
|
|
|
873
892
|
@staticmethod
|
|
874
893
|
def _create_task_handler(app: FastAPI, task_func: Callable, queue: str):
|