agentscope-runtime 0.1.5b2__py3-none-any.whl → 0.1.6__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/engine/agents/agentscope_agent.py +447 -0
- agentscope_runtime/engine/agents/agno_agent.py +19 -18
- agentscope_runtime/engine/agents/autogen_agent.py +13 -8
- agentscope_runtime/engine/agents/utils.py +53 -0
- agentscope_runtime/engine/deployers/__init__.py +0 -13
- agentscope_runtime/engine/deployers/local_deployer.py +501 -356
- agentscope_runtime/engine/helpers/helper.py +60 -41
- agentscope_runtime/engine/runner.py +11 -36
- agentscope_runtime/engine/schemas/agent_schemas.py +2 -70
- agentscope_runtime/engine/services/sandbox_service.py +62 -70
- agentscope_runtime/engine/services/tablestore_memory_service.py +304 -0
- agentscope_runtime/engine/services/tablestore_rag_service.py +143 -0
- agentscope_runtime/engine/services/tablestore_session_history_service.py +293 -0
- agentscope_runtime/engine/services/utils/tablestore_service_utils.py +352 -0
- agentscope_runtime/sandbox/__init__.py +2 -0
- agentscope_runtime/sandbox/box/base/__init__.py +4 -0
- agentscope_runtime/sandbox/box/base/base_sandbox.py +4 -3
- agentscope_runtime/sandbox/box/browser/__init__.py +4 -0
- agentscope_runtime/sandbox/box/browser/browser_sandbox.py +8 -13
- agentscope_runtime/sandbox/box/dummy/__init__.py +4 -0
- agentscope_runtime/sandbox/box/filesystem/__init__.py +4 -0
- agentscope_runtime/sandbox/box/filesystem/filesystem_sandbox.py +8 -6
- agentscope_runtime/sandbox/box/gui/__init__.py +4 -0
- agentscope_runtime/sandbox/box/gui/gui_sandbox.py +80 -0
- agentscope_runtime/sandbox/box/sandbox.py +5 -2
- agentscope_runtime/sandbox/box/shared/routers/generic.py +20 -1
- agentscope_runtime/sandbox/box/training_box/__init__.py +4 -0
- agentscope_runtime/sandbox/box/training_box/training_box.py +10 -15
- agentscope_runtime/sandbox/build.py +143 -58
- agentscope_runtime/sandbox/client/http_client.py +43 -49
- agentscope_runtime/sandbox/client/training_client.py +0 -1
- agentscope_runtime/sandbox/constant.py +24 -1
- agentscope_runtime/sandbox/custom/custom_sandbox.py +5 -5
- agentscope_runtime/sandbox/custom/example.py +2 -2
- agentscope_runtime/sandbox/enums.py +1 -0
- agentscope_runtime/sandbox/manager/collections/in_memory_mapping.py +11 -6
- agentscope_runtime/sandbox/manager/collections/redis_mapping.py +25 -9
- agentscope_runtime/sandbox/manager/container_clients/__init__.py +0 -10
- agentscope_runtime/sandbox/manager/container_clients/agentrun_client.py +1098 -0
- agentscope_runtime/sandbox/manager/container_clients/docker_client.py +33 -205
- agentscope_runtime/sandbox/manager/container_clients/kubernetes_client.py +8 -555
- agentscope_runtime/sandbox/manager/sandbox_manager.py +187 -88
- agentscope_runtime/sandbox/manager/server/app.py +82 -14
- agentscope_runtime/sandbox/manager/server/config.py +50 -3
- agentscope_runtime/sandbox/model/container.py +6 -23
- agentscope_runtime/sandbox/model/manager_config.py +93 -5
- agentscope_runtime/sandbox/tools/gui/__init__.py +7 -0
- agentscope_runtime/sandbox/tools/gui/tool.py +77 -0
- agentscope_runtime/sandbox/tools/mcp_tool.py +6 -2
- agentscope_runtime/sandbox/utils.py +124 -0
- agentscope_runtime/version.py +1 -1
- {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.1.6.dist-info}/METADATA +168 -77
- {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.1.6.dist-info}/RECORD +59 -78
- {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.1.6.dist-info}/entry_points.txt +0 -1
- agentscope_runtime/engine/agents/agentscope_agent/__init__.py +0 -6
- agentscope_runtime/engine/agents/agentscope_agent/agent.py +0 -401
- agentscope_runtime/engine/agents/agentscope_agent/hooks.py +0 -169
- agentscope_runtime/engine/agents/llm_agent.py +0 -51
- agentscope_runtime/engine/deployers/adapter/responses/response_api_adapter_utils.py +0 -2886
- agentscope_runtime/engine/deployers/adapter/responses/response_api_agent_adapter.py +0 -51
- agentscope_runtime/engine/deployers/adapter/responses/response_api_protocol_adapter.py +0 -314
- agentscope_runtime/engine/deployers/cli_fc_deploy.py +0 -184
- agentscope_runtime/engine/deployers/kubernetes_deployer.py +0 -265
- agentscope_runtime/engine/deployers/modelstudio_deployer.py +0 -677
- agentscope_runtime/engine/deployers/utils/deployment_modes.py +0 -14
- agentscope_runtime/engine/deployers/utils/docker_image_utils/__init__.py +0 -8
- agentscope_runtime/engine/deployers/utils/docker_image_utils/docker_image_builder.py +0 -429
- agentscope_runtime/engine/deployers/utils/docker_image_utils/dockerfile_generator.py +0 -240
- agentscope_runtime/engine/deployers/utils/docker_image_utils/runner_image_factory.py +0 -297
- agentscope_runtime/engine/deployers/utils/package_project_utils.py +0 -932
- agentscope_runtime/engine/deployers/utils/service_utils/__init__.py +0 -9
- agentscope_runtime/engine/deployers/utils/service_utils/fastapi_factory.py +0 -504
- agentscope_runtime/engine/deployers/utils/service_utils/fastapi_templates.py +0 -157
- agentscope_runtime/engine/deployers/utils/service_utils/process_manager.py +0 -268
- 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/deployers/utils/wheel_packager.py +0 -389
- agentscope_runtime/engine/helpers/agent_api_builder.py +0 -651
- agentscope_runtime/engine/llms/__init__.py +0 -3
- agentscope_runtime/engine/llms/base_llm.py +0 -60
- agentscope_runtime/engine/llms/qwen_llm.py +0 -47
- agentscope_runtime/engine/schemas/embedding.py +0 -37
- agentscope_runtime/engine/schemas/modelstudio_llm.py +0 -310
- agentscope_runtime/engine/schemas/oai_llm.py +0 -538
- agentscope_runtime/engine/schemas/realtime.py +0 -254
- /agentscope_runtime/engine/{deployers/adapter/responses → services/utils}/__init__.py +0 -0
- /agentscope_runtime/{engine/deployers/utils → sandbox/box/gui/box}/__init__.py +0 -0
- {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.1.6.dist-info}/WHEEL +0 -0
- {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.1.6.dist-info}/licenses/LICENSE +0 -0
- {agentscope_runtime-0.1.5b2.dist-info → agentscope_runtime-0.1.6.dist-info}/top_level.txt +0 -0
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
from .fastapi_factory import FastAPIAppFactory
|
|
3
|
-
from .service_config import (
|
|
4
|
-
ServicesConfig,
|
|
5
|
-
ServiceConfig,
|
|
6
|
-
ServiceProvider,
|
|
7
|
-
)
|
|
8
|
-
from .fastapi_templates import FastAPITemplateManager
|
|
9
|
-
from .process_manager import ProcessManager
|
|
@@ -1,504 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
# pylint:disable=too-many-branches, unused-argument
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import asyncio
|
|
6
|
-
import json
|
|
7
|
-
from contextlib import asynccontextmanager
|
|
8
|
-
from typing import Optional, Callable, Type, Any
|
|
9
|
-
|
|
10
|
-
from fastapi import FastAPI, Request
|
|
11
|
-
from fastapi.middleware.cors import CORSMiddleware
|
|
12
|
-
from fastapi.responses import StreamingResponse, JSONResponse
|
|
13
|
-
|
|
14
|
-
from .service_config import ServicesConfig, DEFAULT_SERVICES_CONFIG
|
|
15
|
-
from .service_factory import ServiceFactory
|
|
16
|
-
from ..deployment_modes import DeploymentMode
|
|
17
|
-
from ...adapter.protocol_adapter import ProtocolAdapter
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class FastAPIAppFactory:
|
|
21
|
-
"""Factory for creating FastAPI applications with unified architecture."""
|
|
22
|
-
|
|
23
|
-
@staticmethod
|
|
24
|
-
def create_app(
|
|
25
|
-
func: Optional[Callable] = None,
|
|
26
|
-
runner: Optional[Any] = None,
|
|
27
|
-
endpoint_path: str = "/process",
|
|
28
|
-
request_model: Optional[Type] = None,
|
|
29
|
-
response_type: str = "sse",
|
|
30
|
-
stream: bool = True,
|
|
31
|
-
before_start: Optional[Callable] = None,
|
|
32
|
-
after_finish: Optional[Callable] = None,
|
|
33
|
-
mode: DeploymentMode = DeploymentMode.DAEMON_THREAD,
|
|
34
|
-
services_config: Optional[ServicesConfig] = None,
|
|
35
|
-
protocol_adapters: Optional[list[ProtocolAdapter]] = None,
|
|
36
|
-
**kwargs: Any,
|
|
37
|
-
) -> FastAPI:
|
|
38
|
-
"""Create a FastAPI application with unified architecture.
|
|
39
|
-
|
|
40
|
-
Args:
|
|
41
|
-
func: Custom processing function
|
|
42
|
-
runner: Runner instance (for DAEMON_THREAD mode)
|
|
43
|
-
endpoint_path: API endpoint path for the processing function
|
|
44
|
-
request_model: Pydantic model for request validation
|
|
45
|
-
response_type: Response type - "json", "sse", or "text"
|
|
46
|
-
stream: Enable streaming responses
|
|
47
|
-
before_start: Callback function called before server starts
|
|
48
|
-
after_finish: Callback function called after server finishes
|
|
49
|
-
mode: Deployment mode
|
|
50
|
-
services_config: Services configuration
|
|
51
|
-
protocol_adapters: Protocol adapters
|
|
52
|
-
**kwargs: Additional keyword arguments
|
|
53
|
-
|
|
54
|
-
Returns:
|
|
55
|
-
FastAPI application instance
|
|
56
|
-
"""
|
|
57
|
-
# Use default services config if not provided
|
|
58
|
-
if services_config is None:
|
|
59
|
-
services_config = DEFAULT_SERVICES_CONFIG
|
|
60
|
-
|
|
61
|
-
# Create lifespan manager
|
|
62
|
-
@asynccontextmanager
|
|
63
|
-
async def lifespan(app: FastAPI):
|
|
64
|
-
"""Application lifespan manager."""
|
|
65
|
-
# Startup
|
|
66
|
-
try:
|
|
67
|
-
await FastAPIAppFactory._handle_startup(
|
|
68
|
-
app,
|
|
69
|
-
mode,
|
|
70
|
-
services_config,
|
|
71
|
-
runner,
|
|
72
|
-
before_start,
|
|
73
|
-
**kwargs,
|
|
74
|
-
)
|
|
75
|
-
yield
|
|
76
|
-
finally:
|
|
77
|
-
# Shutdown
|
|
78
|
-
await FastAPIAppFactory._handle_shutdown(
|
|
79
|
-
app,
|
|
80
|
-
after_finish,
|
|
81
|
-
**kwargs,
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
# Create FastAPI app
|
|
85
|
-
app = FastAPI(lifespan=lifespan)
|
|
86
|
-
|
|
87
|
-
# Store configuration in app state
|
|
88
|
-
app.state.deployment_mode = mode
|
|
89
|
-
app.state.services_config = services_config
|
|
90
|
-
app.state.stream_enabled = stream
|
|
91
|
-
app.state.response_type = response_type
|
|
92
|
-
app.state.custom_func = func
|
|
93
|
-
app.state.external_runner = runner
|
|
94
|
-
app.state.endpoint_path = endpoint_path
|
|
95
|
-
app.state.protocol_adapters = protocol_adapters # Store for later use
|
|
96
|
-
|
|
97
|
-
# Add middleware
|
|
98
|
-
FastAPIAppFactory._add_middleware(app, mode)
|
|
99
|
-
|
|
100
|
-
# Add routes
|
|
101
|
-
FastAPIAppFactory._add_routes(
|
|
102
|
-
app,
|
|
103
|
-
endpoint_path,
|
|
104
|
-
request_model,
|
|
105
|
-
stream,
|
|
106
|
-
mode,
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
# Note: protocol_adapters will be added in _handle_startup
|
|
110
|
-
# after runner is available
|
|
111
|
-
|
|
112
|
-
return app
|
|
113
|
-
|
|
114
|
-
@staticmethod
|
|
115
|
-
async def _handle_startup(
|
|
116
|
-
app: FastAPI,
|
|
117
|
-
mode: DeploymentMode,
|
|
118
|
-
services_config: ServicesConfig,
|
|
119
|
-
external_runner: Optional[Any],
|
|
120
|
-
before_start: Optional[Callable],
|
|
121
|
-
**kwargs,
|
|
122
|
-
):
|
|
123
|
-
"""Handle application startup."""
|
|
124
|
-
# Mode-specific initialization
|
|
125
|
-
if mode == DeploymentMode.DAEMON_THREAD:
|
|
126
|
-
# Use external runner
|
|
127
|
-
app.state.runner = external_runner
|
|
128
|
-
app.state.runner_managed_externally = True
|
|
129
|
-
|
|
130
|
-
elif mode in [
|
|
131
|
-
DeploymentMode.DETACHED_PROCESS,
|
|
132
|
-
DeploymentMode.STANDALONE,
|
|
133
|
-
]:
|
|
134
|
-
# Create internal runner
|
|
135
|
-
app.state.runner = await FastAPIAppFactory._create_internal_runner(
|
|
136
|
-
services_config,
|
|
137
|
-
)
|
|
138
|
-
app.state.runner_managed_externally = False
|
|
139
|
-
|
|
140
|
-
# Call custom startup callback
|
|
141
|
-
if before_start:
|
|
142
|
-
if asyncio.iscoroutinefunction(before_start):
|
|
143
|
-
await before_start(app, **kwargs)
|
|
144
|
-
else:
|
|
145
|
-
before_start(app, **kwargs)
|
|
146
|
-
|
|
147
|
-
# Add protocol adapter endpoints after runner is available
|
|
148
|
-
if (
|
|
149
|
-
hasattr(app.state, "protocol_adapters")
|
|
150
|
-
and app.state.protocol_adapters
|
|
151
|
-
):
|
|
152
|
-
# Determine the effective function to use
|
|
153
|
-
if hasattr(app.state, "custom_func") and app.state.custom_func:
|
|
154
|
-
effective_func = app.state.custom_func
|
|
155
|
-
elif hasattr(app.state, "runner") and app.state.runner:
|
|
156
|
-
# Use stream_query if streaming is enabled, otherwise query
|
|
157
|
-
if (
|
|
158
|
-
hasattr(app.state, "stream_enabled")
|
|
159
|
-
and app.state.stream_enabled
|
|
160
|
-
):
|
|
161
|
-
effective_func = app.state.runner.stream_query
|
|
162
|
-
else:
|
|
163
|
-
effective_func = app.state.runner.query
|
|
164
|
-
else:
|
|
165
|
-
effective_func = None
|
|
166
|
-
|
|
167
|
-
if effective_func:
|
|
168
|
-
for protocol_adapter in app.state.protocol_adapters:
|
|
169
|
-
protocol_adapter.add_endpoint(app=app, func=effective_func)
|
|
170
|
-
|
|
171
|
-
@staticmethod
|
|
172
|
-
async def _handle_shutdown(
|
|
173
|
-
app: FastAPI,
|
|
174
|
-
after_finish: Optional[Callable],
|
|
175
|
-
**kwargs,
|
|
176
|
-
):
|
|
177
|
-
"""Handle application shutdown."""
|
|
178
|
-
# Call custom shutdown callback
|
|
179
|
-
if after_finish:
|
|
180
|
-
if asyncio.iscoroutinefunction(after_finish):
|
|
181
|
-
await after_finish(app, **kwargs)
|
|
182
|
-
else:
|
|
183
|
-
after_finish(app, **kwargs)
|
|
184
|
-
|
|
185
|
-
# Cleanup internal runner
|
|
186
|
-
if (
|
|
187
|
-
hasattr(app.state, "runner")
|
|
188
|
-
and not app.state.runner_managed_externally
|
|
189
|
-
):
|
|
190
|
-
runner = app.state.runner
|
|
191
|
-
if runner and hasattr(runner, "context_manager"):
|
|
192
|
-
try:
|
|
193
|
-
await runner.context_manager.__aexit__(None, None, None)
|
|
194
|
-
except Exception as e:
|
|
195
|
-
print(f"Warning: Error during runner cleanup: {e}")
|
|
196
|
-
|
|
197
|
-
@staticmethod
|
|
198
|
-
async def _create_internal_runner(services_config: ServicesConfig):
|
|
199
|
-
"""Create internal runner with configured services."""
|
|
200
|
-
from agentscope_runtime.engine import Runner
|
|
201
|
-
from agentscope_runtime.engine.services.context_manager import (
|
|
202
|
-
ContextManager,
|
|
203
|
-
)
|
|
204
|
-
|
|
205
|
-
# Create services
|
|
206
|
-
services = ServiceFactory.create_services_from_config(services_config)
|
|
207
|
-
|
|
208
|
-
# Create context manager
|
|
209
|
-
context_manager = ContextManager(
|
|
210
|
-
session_history_service=services["session_history"],
|
|
211
|
-
memory_service=services["memory"],
|
|
212
|
-
)
|
|
213
|
-
|
|
214
|
-
# Initialize context manager
|
|
215
|
-
await context_manager.__aenter__()
|
|
216
|
-
|
|
217
|
-
# Create runner (agent will be set later)
|
|
218
|
-
runner = Runner(
|
|
219
|
-
agent=None, # Will be set by the specific deployment
|
|
220
|
-
context_manager=context_manager,
|
|
221
|
-
)
|
|
222
|
-
|
|
223
|
-
return runner
|
|
224
|
-
|
|
225
|
-
@staticmethod
|
|
226
|
-
def _add_middleware(app: FastAPI, mode: DeploymentMode):
|
|
227
|
-
"""Add middleware based on deployment mode."""
|
|
228
|
-
# Common middleware
|
|
229
|
-
app.add_middleware(
|
|
230
|
-
CORSMiddleware,
|
|
231
|
-
allow_origins=["*"],
|
|
232
|
-
allow_credentials=True,
|
|
233
|
-
allow_methods=["*"],
|
|
234
|
-
allow_headers=["*"],
|
|
235
|
-
)
|
|
236
|
-
|
|
237
|
-
# Mode-specific middleware
|
|
238
|
-
if mode == DeploymentMode.DETACHED_PROCESS:
|
|
239
|
-
# Add process management middleware
|
|
240
|
-
@app.middleware("http")
|
|
241
|
-
async def process_middleware(request: Request, call_next):
|
|
242
|
-
# Add process-specific headers
|
|
243
|
-
response = await call_next(request)
|
|
244
|
-
response.headers["X-Process-Mode"] = "detached"
|
|
245
|
-
return response
|
|
246
|
-
|
|
247
|
-
elif mode == DeploymentMode.STANDALONE:
|
|
248
|
-
# Add configuration middleware
|
|
249
|
-
@app.middleware("http")
|
|
250
|
-
async def config_middleware(request: Request, call_next):
|
|
251
|
-
# Add configuration headers
|
|
252
|
-
response = await call_next(request)
|
|
253
|
-
response.headers["X-Deployment-Mode"] = "standalone"
|
|
254
|
-
return response
|
|
255
|
-
|
|
256
|
-
@staticmethod
|
|
257
|
-
def _add_routes(
|
|
258
|
-
app: FastAPI,
|
|
259
|
-
endpoint_path: str,
|
|
260
|
-
request_model: Optional[Type],
|
|
261
|
-
stream_enabled: bool,
|
|
262
|
-
mode: DeploymentMode,
|
|
263
|
-
):
|
|
264
|
-
"""Add routes to the FastAPI application."""
|
|
265
|
-
|
|
266
|
-
# Health check endpoint
|
|
267
|
-
@app.get("/health")
|
|
268
|
-
async def health_check():
|
|
269
|
-
"""Health check endpoint."""
|
|
270
|
-
status = {"status": "healthy", "mode": mode.value}
|
|
271
|
-
|
|
272
|
-
# Add service health checks
|
|
273
|
-
if hasattr(app.state, "runner") and app.state.runner:
|
|
274
|
-
status["runner"] = "ready"
|
|
275
|
-
else:
|
|
276
|
-
status["runner"] = "not_ready"
|
|
277
|
-
|
|
278
|
-
return status
|
|
279
|
-
|
|
280
|
-
# Main processing endpoint
|
|
281
|
-
# if stream_enabled:
|
|
282
|
-
# Streaming endpoint
|
|
283
|
-
@app.post(endpoint_path)
|
|
284
|
-
async def stream_endpoint(request: dict):
|
|
285
|
-
"""Streaming endpoint."""
|
|
286
|
-
return StreamingResponse(
|
|
287
|
-
FastAPIAppFactory._create_stream_generator(app, request),
|
|
288
|
-
media_type="text/event-stream",
|
|
289
|
-
headers={
|
|
290
|
-
"Cache-Control": "no-cache",
|
|
291
|
-
"Connection": "keep-alive",
|
|
292
|
-
},
|
|
293
|
-
)
|
|
294
|
-
|
|
295
|
-
# # Standard endpoint
|
|
296
|
-
# @app.post(endpoint_path)
|
|
297
|
-
# async def process_endpoint(request: dict):
|
|
298
|
-
# """Main processing endpoint."""
|
|
299
|
-
# return await FastAPIAppFactory._handle_request(
|
|
300
|
-
# app,
|
|
301
|
-
# request,
|
|
302
|
-
# stream_enabled,
|
|
303
|
-
# )
|
|
304
|
-
|
|
305
|
-
# Root endpoint
|
|
306
|
-
@app.get("/")
|
|
307
|
-
async def root():
|
|
308
|
-
"""Root endpoint."""
|
|
309
|
-
return {
|
|
310
|
-
"service": "AgentScope Runtime",
|
|
311
|
-
"mode": mode.value,
|
|
312
|
-
"endpoints": {
|
|
313
|
-
"process": endpoint_path,
|
|
314
|
-
"stream": f"{endpoint_path}/stream"
|
|
315
|
-
if stream_enabled
|
|
316
|
-
else None,
|
|
317
|
-
"health": "/health",
|
|
318
|
-
},
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
# Mode-specific endpoints
|
|
322
|
-
if mode == DeploymentMode.DETACHED_PROCESS:
|
|
323
|
-
FastAPIAppFactory._add_process_control_endpoints(app)
|
|
324
|
-
elif mode == DeploymentMode.STANDALONE:
|
|
325
|
-
FastAPIAppFactory._add_configuration_endpoints(app)
|
|
326
|
-
|
|
327
|
-
@staticmethod
|
|
328
|
-
def _add_process_control_endpoints(app: FastAPI):
|
|
329
|
-
"""Add process control endpoints for detached mode."""
|
|
330
|
-
|
|
331
|
-
@app.post("/admin/shutdown")
|
|
332
|
-
async def shutdown_process():
|
|
333
|
-
"""Gracefully shutdown the process."""
|
|
334
|
-
# Import here to avoid circular imports
|
|
335
|
-
import os
|
|
336
|
-
import signal
|
|
337
|
-
|
|
338
|
-
# Schedule shutdown after response
|
|
339
|
-
async def delayed_shutdown():
|
|
340
|
-
await asyncio.sleep(1)
|
|
341
|
-
os.kill(os.getpid(), signal.SIGTERM)
|
|
342
|
-
|
|
343
|
-
asyncio.create_task(delayed_shutdown())
|
|
344
|
-
return {"message": "Shutdown initiated"}
|
|
345
|
-
|
|
346
|
-
@app.get("/admin/status")
|
|
347
|
-
async def get_process_status():
|
|
348
|
-
"""Get process status information."""
|
|
349
|
-
import os
|
|
350
|
-
import psutil
|
|
351
|
-
|
|
352
|
-
process = psutil.Process(os.getpid())
|
|
353
|
-
return {
|
|
354
|
-
"pid": os.getpid(),
|
|
355
|
-
"status": process.status(),
|
|
356
|
-
"memory_usage": process.memory_info().rss,
|
|
357
|
-
"cpu_percent": process.cpu_percent(),
|
|
358
|
-
"uptime": process.create_time(),
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
@staticmethod
|
|
362
|
-
def _add_configuration_endpoints(app: FastAPI):
|
|
363
|
-
"""Add configuration endpoints for standalone mode."""
|
|
364
|
-
|
|
365
|
-
@app.get("/config")
|
|
366
|
-
async def get_configuration():
|
|
367
|
-
"""Get current service configuration."""
|
|
368
|
-
return {
|
|
369
|
-
"services_config": app.state.services_config.model_dump(),
|
|
370
|
-
"deployment_mode": app.state.deployment_mode.value,
|
|
371
|
-
"stream_enabled": app.state.stream_enabled,
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
@app.get("/config/services")
|
|
375
|
-
async def get_services_status():
|
|
376
|
-
"""Get services status."""
|
|
377
|
-
status = {}
|
|
378
|
-
if hasattr(app.state, "runner") and app.state.runner:
|
|
379
|
-
runner = app.state.runner
|
|
380
|
-
if hasattr(runner, "context_manager"):
|
|
381
|
-
cm = runner.context_manager
|
|
382
|
-
status["memory_service"] = (
|
|
383
|
-
"connected" if cm.memory_service else "disconnected"
|
|
384
|
-
)
|
|
385
|
-
status["session_history_service"] = (
|
|
386
|
-
"connected"
|
|
387
|
-
if cm.session_history_service
|
|
388
|
-
else "disconnected"
|
|
389
|
-
)
|
|
390
|
-
|
|
391
|
-
return {"services": status}
|
|
392
|
-
|
|
393
|
-
@staticmethod
|
|
394
|
-
async def _handle_request(
|
|
395
|
-
app: FastAPI,
|
|
396
|
-
request: dict,
|
|
397
|
-
stream_enabled: bool,
|
|
398
|
-
):
|
|
399
|
-
"""Handle a standard request."""
|
|
400
|
-
try:
|
|
401
|
-
# Get runner instance
|
|
402
|
-
runner = FastAPIAppFactory._get_runner_instance(app)
|
|
403
|
-
if not runner:
|
|
404
|
-
return JSONResponse(
|
|
405
|
-
status_code=503,
|
|
406
|
-
content={
|
|
407
|
-
"error": "Service not ready",
|
|
408
|
-
"message": "Runner not initialized",
|
|
409
|
-
},
|
|
410
|
-
)
|
|
411
|
-
|
|
412
|
-
# Handle custom function vs runner
|
|
413
|
-
if app.state.custom_func:
|
|
414
|
-
# Use custom function
|
|
415
|
-
result = await FastAPIAppFactory._call_custom_function(
|
|
416
|
-
app.state.custom_func,
|
|
417
|
-
request,
|
|
418
|
-
)
|
|
419
|
-
return {"response": result}
|
|
420
|
-
else:
|
|
421
|
-
# Use runner
|
|
422
|
-
if stream_enabled:
|
|
423
|
-
# Collect streaming response
|
|
424
|
-
result = await FastAPIAppFactory._collect_stream_response(
|
|
425
|
-
runner,
|
|
426
|
-
request,
|
|
427
|
-
)
|
|
428
|
-
return {"response": result}
|
|
429
|
-
else:
|
|
430
|
-
# Direct query
|
|
431
|
-
result = await runner.query(request)
|
|
432
|
-
return {"response": result}
|
|
433
|
-
|
|
434
|
-
except Exception as e:
|
|
435
|
-
return JSONResponse(
|
|
436
|
-
status_code=500,
|
|
437
|
-
content={"error": "Internal server error", "message": str(e)},
|
|
438
|
-
)
|
|
439
|
-
|
|
440
|
-
@staticmethod
|
|
441
|
-
async def _create_stream_generator(app: FastAPI, request: dict):
|
|
442
|
-
"""Create streaming response generator."""
|
|
443
|
-
try:
|
|
444
|
-
runner = FastAPIAppFactory._get_runner_instance(app)
|
|
445
|
-
if not runner:
|
|
446
|
-
yield (
|
|
447
|
-
f"data: {json.dumps({'error': 'Runner not initialized'})}"
|
|
448
|
-
f"\n\n"
|
|
449
|
-
)
|
|
450
|
-
return
|
|
451
|
-
|
|
452
|
-
if app.state.custom_func:
|
|
453
|
-
# Handle custom function (convert to stream)
|
|
454
|
-
result = await FastAPIAppFactory._call_custom_function(
|
|
455
|
-
app.state.custom_func,
|
|
456
|
-
request,
|
|
457
|
-
)
|
|
458
|
-
yield f"data: {json.dumps({'text': str(result)})}\n\n"
|
|
459
|
-
else:
|
|
460
|
-
# Use runner streaming
|
|
461
|
-
async for chunk in runner.stream_query(request):
|
|
462
|
-
if hasattr(chunk, "model_dump_json"):
|
|
463
|
-
yield f"data: {chunk.model_dump_json()}\n\n"
|
|
464
|
-
elif hasattr(chunk, "json"):
|
|
465
|
-
yield f"data: {chunk.json()}\n\n"
|
|
466
|
-
else:
|
|
467
|
-
yield f"data: {json.dumps({'text': str(chunk)})}\n\n"
|
|
468
|
-
|
|
469
|
-
except Exception as e:
|
|
470
|
-
yield f"data: {json.dumps({'error': str(e)})}\n\n"
|
|
471
|
-
|
|
472
|
-
@staticmethod
|
|
473
|
-
async def _collect_stream_response(runner, request: dict) -> str:
|
|
474
|
-
"""Collect streaming response into a single string."""
|
|
475
|
-
response_parts = []
|
|
476
|
-
async for chunk in runner.stream_query(request):
|
|
477
|
-
if hasattr(chunk, "text"):
|
|
478
|
-
response_parts.append(chunk.text)
|
|
479
|
-
else:
|
|
480
|
-
response_parts.append(str(chunk))
|
|
481
|
-
return "".join(response_parts)
|
|
482
|
-
|
|
483
|
-
@staticmethod
|
|
484
|
-
async def _call_custom_function(func: Callable, request: dict):
|
|
485
|
-
"""Call custom function with proper parameters."""
|
|
486
|
-
if asyncio.iscoroutinefunction(func):
|
|
487
|
-
return await func(
|
|
488
|
-
user_id="default",
|
|
489
|
-
request=request,
|
|
490
|
-
request_id="generated",
|
|
491
|
-
)
|
|
492
|
-
else:
|
|
493
|
-
return func(
|
|
494
|
-
user_id="default",
|
|
495
|
-
request=request,
|
|
496
|
-
request_id="generated",
|
|
497
|
-
)
|
|
498
|
-
|
|
499
|
-
@staticmethod
|
|
500
|
-
def _get_runner_instance(app: FastAPI):
|
|
501
|
-
"""Get runner instance from app state."""
|
|
502
|
-
if hasattr(app.state, "runner"):
|
|
503
|
-
return app.state.runner
|
|
504
|
-
return None
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
"""FastAPI templates management and rendering."""
|
|
3
|
-
|
|
4
|
-
import os
|
|
5
|
-
from typing import Dict, Any, Optional
|
|
6
|
-
from jinja2 import Template, Environment, FileSystemLoader
|
|
7
|
-
from ..deployment_modes import DeploymentMode
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class FastAPITemplateManager:
|
|
11
|
-
"""Manager for FastAPI deployment templates."""
|
|
12
|
-
|
|
13
|
-
def __init__(self):
|
|
14
|
-
"""Initialize template manager."""
|
|
15
|
-
self.template_dir = os.path.join(
|
|
16
|
-
os.path.dirname(__file__),
|
|
17
|
-
)
|
|
18
|
-
self.env = Environment(
|
|
19
|
-
loader=FileSystemLoader(self.template_dir),
|
|
20
|
-
trim_blocks=True,
|
|
21
|
-
lstrip_blocks=True,
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
def render_standalone_template(
|
|
25
|
-
self,
|
|
26
|
-
agent_name: str,
|
|
27
|
-
endpoint_path: str = "/process",
|
|
28
|
-
deployment_mode: str = DeploymentMode.STANDALONE,
|
|
29
|
-
protocol_adapters: Optional[str] = None,
|
|
30
|
-
**kwargs,
|
|
31
|
-
) -> str:
|
|
32
|
-
"""Render the standalone deployment template.
|
|
33
|
-
|
|
34
|
-
Args:
|
|
35
|
-
agent_name: Name of the agent variable
|
|
36
|
-
endpoint_path: API endpoint path
|
|
37
|
-
deployment_mode: Deployment mode (standalone or detached_process)
|
|
38
|
-
protocol_adapters: Protocol adapters code string
|
|
39
|
-
**kwargs: Additional template variables
|
|
40
|
-
|
|
41
|
-
Returns:
|
|
42
|
-
Rendered template content
|
|
43
|
-
"""
|
|
44
|
-
template = self.env.get_template("standalone_main.py.j2")
|
|
45
|
-
return template.render(
|
|
46
|
-
agent_name=agent_name,
|
|
47
|
-
endpoint_path=endpoint_path,
|
|
48
|
-
deployment_mode=deployment_mode,
|
|
49
|
-
protocol_adapters=protocol_adapters,
|
|
50
|
-
**kwargs,
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
def render_detached_script_template(
|
|
54
|
-
self,
|
|
55
|
-
endpoint_path: str = "/process",
|
|
56
|
-
host: str = "127.0.0.1",
|
|
57
|
-
port: int = 8000,
|
|
58
|
-
stream_enabled: bool = True,
|
|
59
|
-
response_type: str = "sse",
|
|
60
|
-
runner_code: str = "",
|
|
61
|
-
func_code: str = "",
|
|
62
|
-
services_config: str = "",
|
|
63
|
-
protocol_adapters: Optional[str] = None,
|
|
64
|
-
**kwargs,
|
|
65
|
-
) -> str:
|
|
66
|
-
"""Render the detached process script template.
|
|
67
|
-
|
|
68
|
-
Args:
|
|
69
|
-
endpoint_path: API endpoint path
|
|
70
|
-
host: Host to bind to
|
|
71
|
-
port: Port to bind to
|
|
72
|
-
stream_enabled: Enable streaming responses
|
|
73
|
-
response_type: Response type
|
|
74
|
-
runner_code: Code to setup runner
|
|
75
|
-
func_code: Code to setup custom function
|
|
76
|
-
services_config: Services configuration code
|
|
77
|
-
protocol_adapters: Protocol adapters code string
|
|
78
|
-
**kwargs: Additional template variables
|
|
79
|
-
|
|
80
|
-
Returns:
|
|
81
|
-
Rendered template content
|
|
82
|
-
"""
|
|
83
|
-
template = self.env.get_template("detached_script.py.j2")
|
|
84
|
-
return template.render(
|
|
85
|
-
endpoint_path=endpoint_path,
|
|
86
|
-
host=host,
|
|
87
|
-
port=port,
|
|
88
|
-
stream_enabled=str(stream_enabled).lower(),
|
|
89
|
-
response_type=response_type,
|
|
90
|
-
runner_code=runner_code,
|
|
91
|
-
func_code=func_code,
|
|
92
|
-
services_config=services_config,
|
|
93
|
-
protocol_adapters=protocol_adapters,
|
|
94
|
-
**kwargs,
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
def render_template_from_string(
|
|
98
|
-
self,
|
|
99
|
-
template_string: str,
|
|
100
|
-
**variables,
|
|
101
|
-
) -> str:
|
|
102
|
-
"""Render a template from string.
|
|
103
|
-
|
|
104
|
-
Args:
|
|
105
|
-
template_string: Template content as string
|
|
106
|
-
**variables: Template variables
|
|
107
|
-
|
|
108
|
-
Returns:
|
|
109
|
-
Rendered template content
|
|
110
|
-
"""
|
|
111
|
-
template = Template(template_string)
|
|
112
|
-
return template.render(**variables)
|
|
113
|
-
|
|
114
|
-
def get_template_list(self) -> list:
|
|
115
|
-
"""Get list of available templates.
|
|
116
|
-
|
|
117
|
-
Returns:
|
|
118
|
-
List of template filenames
|
|
119
|
-
"""
|
|
120
|
-
if not os.path.exists(self.template_dir):
|
|
121
|
-
return []
|
|
122
|
-
|
|
123
|
-
templates = []
|
|
124
|
-
for filename in os.listdir(self.template_dir):
|
|
125
|
-
if filename.endswith(".j2"):
|
|
126
|
-
templates.append(filename)
|
|
127
|
-
|
|
128
|
-
return templates
|
|
129
|
-
|
|
130
|
-
def validate_template_variables(
|
|
131
|
-
self,
|
|
132
|
-
template_name: str,
|
|
133
|
-
variables: Dict[str, Any],
|
|
134
|
-
) -> Dict[str, list]:
|
|
135
|
-
"""Validate template variables.
|
|
136
|
-
|
|
137
|
-
Args:
|
|
138
|
-
template_name: Name of the template
|
|
139
|
-
variables: Variables to validate
|
|
140
|
-
|
|
141
|
-
Returns:
|
|
142
|
-
Dictionary with 'missing' and 'extra' keys containing lists
|
|
143
|
-
"""
|
|
144
|
-
# This is a basic implementation
|
|
145
|
-
# In practice, you might want to parse the template to find
|
|
146
|
-
# required variables
|
|
147
|
-
required_vars = {
|
|
148
|
-
"standalone_main.py.j2": ["agent_name", "endpoint_path"],
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
required = required_vars.get(template_name, [])
|
|
152
|
-
provided = list(variables.keys())
|
|
153
|
-
|
|
154
|
-
missing = [var for var in required if var not in provided]
|
|
155
|
-
extra = [var for var in provided if var not in required]
|
|
156
|
-
|
|
157
|
-
return {"missing": missing, "extra": extra}
|