cloudbase-agent-server 0.1.9__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.
- cloudbase_agent/__init__.py +8 -0
- cloudbase_agent/server/__init__.py +91 -0
- cloudbase_agent/server/app.py +371 -0
- cloudbase_agent/server/healthz/__init__.py +14 -0
- cloudbase_agent/server/healthz/handler.py +203 -0
- cloudbase_agent/server/healthz/models.py +132 -0
- cloudbase_agent/server/openai/__init__.py +14 -0
- cloudbase_agent/server/openai/converter.py +69 -0
- cloudbase_agent/server/openai/models.py +57 -0
- cloudbase_agent/server/openai/server.py +46 -0
- cloudbase_agent/server/send_message/__init__.py +20 -0
- cloudbase_agent/server/send_message/handler.py +146 -0
- cloudbase_agent/server/send_message/models.py +62 -0
- cloudbase_agent/server/send_message/server.py +93 -0
- cloudbase_agent/server/utils/__init__.py +21 -0
- cloudbase_agent/server/utils/converters.py +25 -0
- cloudbase_agent/server/utils/sse.py +32 -0
- cloudbase_agent/server/utils/types.py +73 -0
- cloudbase_agent_server-0.1.9.dist-info/METADATA +45 -0
- cloudbase_agent_server-0.1.9.dist-info/RECORD +21 -0
- cloudbase_agent_server-0.1.9.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Cloudbase Agent Server Package.
|
|
2
|
+
|
|
3
|
+
This package provides server components for the Cloudbase Agent Python SDK,
|
|
4
|
+
including FastAPI integration, request handling, streaming responses,
|
|
5
|
+
and resource cleanup support.
|
|
6
|
+
|
|
7
|
+
Core Capabilities (Primary Exports):
|
|
8
|
+
- create_send_message_adapter: Create adapter for Cloudbase Agent native send_message endpoint
|
|
9
|
+
- create_openai_adapter: Create adapter for OpenAI-compatible chat/completions endpoint
|
|
10
|
+
|
|
11
|
+
Convenience Tools (Secondary Exports):
|
|
12
|
+
- AgentServiceApp: FastAPI application wrapper for quick server setup
|
|
13
|
+
|
|
14
|
+
Data Models:
|
|
15
|
+
- RunAgentInput: Request model for send_message endpoint
|
|
16
|
+
- OpenAIChatCompletionRequest: Request model for OpenAI-compatible endpoint
|
|
17
|
+
- AgentCreatorResult: TypedDict for agent creator return type
|
|
18
|
+
- AgentCreator: Type alias for agent creator functions
|
|
19
|
+
|
|
20
|
+
Example:
|
|
21
|
+
Using core capabilities (advanced users)::
|
|
22
|
+
|
|
23
|
+
from fastapi import FastAPI
|
|
24
|
+
from cloudbase_agent.server import create_send_message_adapter, create_openai_adapter
|
|
25
|
+
from cloudbase_agent.server import RunAgentInput, OpenAIChatCompletionRequest
|
|
26
|
+
|
|
27
|
+
def create_agent():
|
|
28
|
+
return {"agent": MyAgent()}
|
|
29
|
+
|
|
30
|
+
app = FastAPI()
|
|
31
|
+
|
|
32
|
+
@app.post("/custom/send-message")
|
|
33
|
+
async def send_message(request: RunAgentInput):
|
|
34
|
+
return await create_send_message_adapter(create_agent, request)
|
|
35
|
+
|
|
36
|
+
@app.post("/custom/chat/completions")
|
|
37
|
+
async def chat_completions(request: OpenAIChatCompletionRequest):
|
|
38
|
+
return await create_openai_adapter(create_agent, request)
|
|
39
|
+
|
|
40
|
+
Using convenience tool (quick start)::
|
|
41
|
+
|
|
42
|
+
from cloudbase_agent.server import AgentServiceApp
|
|
43
|
+
|
|
44
|
+
def create_agent():
|
|
45
|
+
return {"agent": MyAgent()}
|
|
46
|
+
|
|
47
|
+
AgentServiceApp().run(create_agent, port=8000)
|
|
48
|
+
|
|
49
|
+
With resource cleanup::
|
|
50
|
+
|
|
51
|
+
from cloudbase_agent.server import AgentServiceApp, AgentCreatorResult
|
|
52
|
+
|
|
53
|
+
def create_agent() -> AgentCreatorResult:
|
|
54
|
+
db = connect_database()
|
|
55
|
+
agent = MyAgent(db)
|
|
56
|
+
|
|
57
|
+
def cleanup():
|
|
58
|
+
db.close()
|
|
59
|
+
print("Resources cleaned up")
|
|
60
|
+
|
|
61
|
+
return {"agent": agent, "cleanup": cleanup}
|
|
62
|
+
|
|
63
|
+
AgentServiceApp().run(create_agent, port=8000)
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
# Core capabilities (primary exports)
|
|
67
|
+
# Convenience tool (secondary export)
|
|
68
|
+
from .app import AgentServiceApp
|
|
69
|
+
from .healthz.models import HealthzConfig, HealthzResponse
|
|
70
|
+
from .openai.models import OpenAIChatCompletionRequest
|
|
71
|
+
from .openai.server import create_adapter as create_openai_adapter
|
|
72
|
+
|
|
73
|
+
# Data models
|
|
74
|
+
from .send_message.models import RunAgentInput
|
|
75
|
+
from .send_message.server import create_adapter as create_send_message_adapter
|
|
76
|
+
from .utils.types import AgentCreator, AgentCreatorResult
|
|
77
|
+
|
|
78
|
+
__all__ = [
|
|
79
|
+
# Core capabilities (primary)
|
|
80
|
+
"create_send_message_adapter",
|
|
81
|
+
"create_openai_adapter",
|
|
82
|
+
# Convenience tool (secondary)
|
|
83
|
+
"AgentServiceApp",
|
|
84
|
+
# Data models
|
|
85
|
+
"RunAgentInput",
|
|
86
|
+
"OpenAIChatCompletionRequest",
|
|
87
|
+
"HealthzConfig",
|
|
88
|
+
"HealthzResponse",
|
|
89
|
+
"AgentCreatorResult",
|
|
90
|
+
"AgentCreator",
|
|
91
|
+
]
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Cloudbase Agent API Application.
|
|
4
|
+
|
|
5
|
+
This module provides a convenient FastAPI application wrapper for Cloudbase Agent agents,
|
|
6
|
+
offering both quick one-line startup and advanced customization options.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
from typing import Any, Optional
|
|
11
|
+
|
|
12
|
+
from fastapi import FastAPI
|
|
13
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
14
|
+
|
|
15
|
+
from .healthz.handler import create_healthz_handler
|
|
16
|
+
from .healthz.models import HealthzConfig
|
|
17
|
+
from .openai.models import OpenAIChatCompletionRequest
|
|
18
|
+
from .openai.server import create_adapter as create_openai_adapter
|
|
19
|
+
from .send_message.models import RunAgentInput
|
|
20
|
+
from .send_message.server import create_adapter as create_send_message_adapter
|
|
21
|
+
from .utils.types import AgentCreator
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class AgentServiceApp:
|
|
25
|
+
r"""FastAPI Application Wrapper for Cloudbase Agent Agents.
|
|
26
|
+
|
|
27
|
+
This class provides a simple and flexible way to deploy Cloudbase Agent agents
|
|
28
|
+
as web services. It supports both quick one-line startup and advanced
|
|
29
|
+
customization through the build() method.
|
|
30
|
+
|
|
31
|
+
Key Features:
|
|
32
|
+
- One-line server startup with run()
|
|
33
|
+
- Flexible configuration with method chaining
|
|
34
|
+
- Advanced customization with build()
|
|
35
|
+
- Automatic environment detection (e.g., Tencent Cloud SCF)
|
|
36
|
+
- Resource cleanup support
|
|
37
|
+
|
|
38
|
+
Example:
|
|
39
|
+
Quick start (one line)::
|
|
40
|
+
|
|
41
|
+
AgentServiceApp().run(create_agent, port=8000)
|
|
42
|
+
|
|
43
|
+
With configuration (method chaining)::
|
|
44
|
+
|
|
45
|
+
AgentServiceApp() \
|
|
46
|
+
.set_cors_config(allow_origins=["*"]) \
|
|
47
|
+
.run(create_agent, port=8000, reload=True)
|
|
48
|
+
|
|
49
|
+
Advanced usage (build method)::
|
|
50
|
+
|
|
51
|
+
app = AgentServiceApp()
|
|
52
|
+
fastapi_app = app.build(create_agent, base_path="/api")
|
|
53
|
+
|
|
54
|
+
# Add custom routes
|
|
55
|
+
@fastapi_app.get("/custom")
|
|
56
|
+
def custom_route():
|
|
57
|
+
return {"custom": "data"}
|
|
58
|
+
|
|
59
|
+
# Run manually
|
|
60
|
+
import uvicorn
|
|
61
|
+
uvicorn.run(fastapi_app, port=8000)
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
def __init__(self, auto_detect_env: bool = True):
|
|
65
|
+
"""Initialize the Cloudbase Agent API application.
|
|
66
|
+
|
|
67
|
+
:param auto_detect_env: Automatically detect runtime environment
|
|
68
|
+
(e.g., Tencent Cloud SCF) and configure accordingly
|
|
69
|
+
:type auto_detect_env: bool
|
|
70
|
+
"""
|
|
71
|
+
self._cors_config: Optional[dict[str, Any]] = None
|
|
72
|
+
self._base_path: str = ""
|
|
73
|
+
|
|
74
|
+
# Auto-detect environment if enabled
|
|
75
|
+
if auto_detect_env:
|
|
76
|
+
self._detect_environment()
|
|
77
|
+
|
|
78
|
+
def _detect_environment(self) -> None:
|
|
79
|
+
"""Detect runtime environment and apply environment-specific configuration."""
|
|
80
|
+
# Tencent Cloud SCF
|
|
81
|
+
if os.getenv("TENCENTCLOUD_RUNENV") == "SCF":
|
|
82
|
+
self._base_path = "/v1/aibot/bots"
|
|
83
|
+
|
|
84
|
+
def set_cors_config(
|
|
85
|
+
self,
|
|
86
|
+
allow_origins: Optional[list[str]] = None,
|
|
87
|
+
allow_credentials: bool = True,
|
|
88
|
+
allow_methods: Optional[list[str]] = None,
|
|
89
|
+
allow_headers: Optional[list[str]] = None,
|
|
90
|
+
**kwargs: Any,
|
|
91
|
+
) -> "AgentServiceApp":
|
|
92
|
+
r"""Set CORS configuration for the application.
|
|
93
|
+
|
|
94
|
+
:param allow_origins: List of allowed origins, defaults to ["*"]
|
|
95
|
+
:type allow_origins: Optional[list[str]]
|
|
96
|
+
:param allow_credentials: Whether to allow credentials, defaults to True
|
|
97
|
+
:type allow_credentials: bool
|
|
98
|
+
:param allow_methods: List of allowed HTTP methods, defaults to ["*"]
|
|
99
|
+
:type allow_methods: Optional[list[str]]
|
|
100
|
+
:param allow_headers: List of allowed headers, defaults to ["*"]
|
|
101
|
+
:type allow_headers: Optional[list[str]]
|
|
102
|
+
:param kwargs: Additional CORS configuration options
|
|
103
|
+
:type kwargs: Any
|
|
104
|
+
:return: Self for method chaining
|
|
105
|
+
:rtype: AgentServiceApp
|
|
106
|
+
|
|
107
|
+
Example:
|
|
108
|
+
Method chaining::
|
|
109
|
+
|
|
110
|
+
AgentServiceApp() \
|
|
111
|
+
.set_cors_config(
|
|
112
|
+
allow_origins=["https://example.com"],
|
|
113
|
+
allow_credentials=True
|
|
114
|
+
) \
|
|
115
|
+
.run(create_agent, port=8000)
|
|
116
|
+
"""
|
|
117
|
+
self._cors_config = {
|
|
118
|
+
"allow_origins": allow_origins or ["*"],
|
|
119
|
+
"allow_credentials": allow_credentials,
|
|
120
|
+
"allow_methods": allow_methods or ["*"],
|
|
121
|
+
"allow_headers": allow_headers or ["*"],
|
|
122
|
+
**kwargs,
|
|
123
|
+
}
|
|
124
|
+
return self
|
|
125
|
+
|
|
126
|
+
def build(
|
|
127
|
+
self,
|
|
128
|
+
create_agent: AgentCreator,
|
|
129
|
+
base_path: str = "",
|
|
130
|
+
enable_cors: bool = True,
|
|
131
|
+
enable_openai_endpoint: bool = False,
|
|
132
|
+
enable_healthz: bool = True,
|
|
133
|
+
healthz_config: Optional[HealthzConfig] = None,
|
|
134
|
+
**fastapi_kwargs: Any,
|
|
135
|
+
) -> FastAPI:
|
|
136
|
+
"""Build and return a configured FastAPI application.
|
|
137
|
+
|
|
138
|
+
This method creates a FastAPI instance with all routes and middleware
|
|
139
|
+
configured. Use this when you need to customize the application before
|
|
140
|
+
running it (e.g., adding custom routes, middleware, or event handlers).
|
|
141
|
+
|
|
142
|
+
:param create_agent: Function that creates and returns agent with optional cleanup
|
|
143
|
+
:type create_agent: AgentCreator
|
|
144
|
+
:param base_path: Base path for agent routes (overrides environment-detected path)
|
|
145
|
+
:type base_path: str
|
|
146
|
+
:param enable_cors: Whether to enable CORS middleware
|
|
147
|
+
:type enable_cors: bool
|
|
148
|
+
:param enable_openai_endpoint: Whether to enable OpenAI-compatible /chat/completions endpoint
|
|
149
|
+
:type enable_openai_endpoint: bool
|
|
150
|
+
:param enable_healthz: Whether to enable health check endpoint (default: True)
|
|
151
|
+
:type enable_healthz: bool
|
|
152
|
+
:param healthz_config: Optional health check configuration
|
|
153
|
+
:type healthz_config: Optional[HealthzConfig]
|
|
154
|
+
:param fastapi_kwargs: Additional keyword arguments to pass to FastAPI constructor
|
|
155
|
+
(e.g., title, description, version)
|
|
156
|
+
:type fastapi_kwargs: Any
|
|
157
|
+
:return: Configured FastAPI application
|
|
158
|
+
:rtype: FastAPI
|
|
159
|
+
|
|
160
|
+
Example:
|
|
161
|
+
Build and customize::
|
|
162
|
+
|
|
163
|
+
app = AgentServiceApp()
|
|
164
|
+
fastapi_app = app.build(
|
|
165
|
+
create_agent,
|
|
166
|
+
base_path="/api",
|
|
167
|
+
title="My Agent API",
|
|
168
|
+
version="1.0.0"
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# Add custom routes
|
|
172
|
+
@fastapi_app.get("/custom")
|
|
173
|
+
def custom_route():
|
|
174
|
+
return {"custom": "data"}
|
|
175
|
+
|
|
176
|
+
# Add custom middleware
|
|
177
|
+
@fastapi_app.middleware("http")
|
|
178
|
+
async def add_custom_header(request, call_next):
|
|
179
|
+
response = await call_next(request)
|
|
180
|
+
response.headers["X-Custom-Header"] = "value"
|
|
181
|
+
return response
|
|
182
|
+
|
|
183
|
+
# Run the application
|
|
184
|
+
import uvicorn
|
|
185
|
+
uvicorn.run(fastapi_app, host="0.0.0.0", port=8000)
|
|
186
|
+
|
|
187
|
+
With custom health check::
|
|
188
|
+
|
|
189
|
+
from cloudbase_agent.server import HealthzConfig
|
|
190
|
+
|
|
191
|
+
def check_database():
|
|
192
|
+
# Perform database health check
|
|
193
|
+
if not db.is_connected():
|
|
194
|
+
raise Exception("Database not connected")
|
|
195
|
+
return {"database": "connected"}
|
|
196
|
+
|
|
197
|
+
config = HealthzConfig(
|
|
198
|
+
service_name="my-agent-service",
|
|
199
|
+
version="2.0.0",
|
|
200
|
+
custom_checks=check_database
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
fastapi_app = AgentServiceApp().build(
|
|
204
|
+
create_agent,
|
|
205
|
+
healthz_config=config
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
Disable health check::
|
|
209
|
+
|
|
210
|
+
fastapi_app = AgentServiceApp().build(
|
|
211
|
+
create_agent,
|
|
212
|
+
enable_healthz=False # No /healthz endpoint
|
|
213
|
+
)
|
|
214
|
+
"""
|
|
215
|
+
# Create FastAPI instance
|
|
216
|
+
app = FastAPI(**fastapi_kwargs)
|
|
217
|
+
|
|
218
|
+
# Apply CORS middleware if enabled
|
|
219
|
+
if enable_cors:
|
|
220
|
+
cors_config = self._cors_config or {
|
|
221
|
+
"allow_origins": ["*"],
|
|
222
|
+
"allow_credentials": True,
|
|
223
|
+
"allow_methods": ["*"],
|
|
224
|
+
"allow_headers": ["*"],
|
|
225
|
+
}
|
|
226
|
+
app.add_middleware(CORSMiddleware, **cors_config)
|
|
227
|
+
|
|
228
|
+
# Determine final path (environment base path + user base path)
|
|
229
|
+
final_path = self._base_path + base_path
|
|
230
|
+
|
|
231
|
+
# Register send_message endpoint
|
|
232
|
+
@app.post(f"{final_path}/{{agent_id}}/send-message")
|
|
233
|
+
async def send_message_endpoint(agent_id: str, request: RunAgentInput):
|
|
234
|
+
"""Main agent endpoint for processing messages with Cloudbase Agent native format.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
agent_id: Agent identifier (reserved for future use)
|
|
238
|
+
request: Message request payload
|
|
239
|
+
"""
|
|
240
|
+
# agent_id parameter is reserved for future use
|
|
241
|
+
return await create_send_message_adapter(create_agent, request)
|
|
242
|
+
|
|
243
|
+
# Register health check endpoint if enabled
|
|
244
|
+
if enable_healthz:
|
|
245
|
+
healthz_handler = create_healthz_handler(
|
|
246
|
+
config=healthz_config,
|
|
247
|
+
base_path=final_path,
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
@app.get(f"{final_path}/healthz")
|
|
251
|
+
def healthz_endpoint() -> dict[str, Any]:
|
|
252
|
+
"""Health check endpoint.
|
|
253
|
+
|
|
254
|
+
Returns server status and metadata for monitoring and diagnostics.
|
|
255
|
+
This endpoint is automatically added to all Cloudbase Agent servers and can
|
|
256
|
+
be used by load balancers, monitoring systems, and orchestration
|
|
257
|
+
platforms to verify service health.
|
|
258
|
+
|
|
259
|
+
The response includes:
|
|
260
|
+
- Service status (healthy/unhealthy)
|
|
261
|
+
- Timestamp of the check
|
|
262
|
+
- Service name and version
|
|
263
|
+
- Python runtime version
|
|
264
|
+
- Base path configuration
|
|
265
|
+
- Optional custom check results
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
dict: Health check response with status and metadata
|
|
269
|
+
|
|
270
|
+
Example Response:
|
|
271
|
+
{
|
|
272
|
+
"status": "healthy",
|
|
273
|
+
"timestamp": "2024-01-01T00:00:00.000Z",
|
|
274
|
+
"service": "Cloudbase Agent-python-server",
|
|
275
|
+
"version": "1.0.0",
|
|
276
|
+
"python_version": "3.11.0",
|
|
277
|
+
"base_path": "/"
|
|
278
|
+
}
|
|
279
|
+
"""
|
|
280
|
+
return healthz_handler()
|
|
281
|
+
|
|
282
|
+
# Register OpenAI-compatible endpoint if enabled
|
|
283
|
+
if enable_openai_endpoint:
|
|
284
|
+
|
|
285
|
+
@app.post(f"{final_path}/chat/completions")
|
|
286
|
+
async def chat_completions_endpoint(request: OpenAIChatCompletionRequest):
|
|
287
|
+
"""OpenAI-compatible chat completions endpoint.
|
|
288
|
+
|
|
289
|
+
This endpoint provides compatibility with OpenAI's chat completion API,
|
|
290
|
+
allowing Cloudbase Agent agents to be used as drop-in replacements for OpenAI models.
|
|
291
|
+
"""
|
|
292
|
+
return await create_openai_adapter(create_agent, request)
|
|
293
|
+
|
|
294
|
+
return app
|
|
295
|
+
|
|
296
|
+
def run(
|
|
297
|
+
self,
|
|
298
|
+
create_agent: AgentCreator,
|
|
299
|
+
base_path: str = "",
|
|
300
|
+
host: str = "0.0.0.0",
|
|
301
|
+
port: int = 9000,
|
|
302
|
+
enable_openai_endpoint: bool = False,
|
|
303
|
+
enable_healthz: bool = True,
|
|
304
|
+
healthz_config: Optional[HealthzConfig] = None,
|
|
305
|
+
**uvicorn_kwargs: Any,
|
|
306
|
+
) -> None:
|
|
307
|
+
r"""Build and run the FastAPI application (one-line startup).
|
|
308
|
+
|
|
309
|
+
This is the simplest way to start an Cloudbase Agent server. It builds the
|
|
310
|
+
FastAPI application and immediately starts the uvicorn server.
|
|
311
|
+
|
|
312
|
+
:param create_agent: Function that creates and returns agent with optional cleanup
|
|
313
|
+
:type create_agent: AgentCreator
|
|
314
|
+
:param base_path: Base path for agent routes
|
|
315
|
+
:type base_path: str
|
|
316
|
+
:param host: Server host address
|
|
317
|
+
:type host: str
|
|
318
|
+
:param port: Server port number
|
|
319
|
+
:type port: int
|
|
320
|
+
:param enable_openai_endpoint: Whether to enable OpenAI-compatible /chat/completions endpoint
|
|
321
|
+
:type enable_openai_endpoint: bool
|
|
322
|
+
:param enable_healthz: Whether to enable health check endpoint (default: True)
|
|
323
|
+
:type enable_healthz: bool
|
|
324
|
+
:param healthz_config: Optional health check configuration
|
|
325
|
+
:type healthz_config: Optional[HealthzConfig]
|
|
326
|
+
:param uvicorn_kwargs: Additional keyword arguments to pass to uvicorn.run
|
|
327
|
+
Examples: reload=True, workers=4, log_level="debug"
|
|
328
|
+
:type uvicorn_kwargs: Any
|
|
329
|
+
|
|
330
|
+
Example:
|
|
331
|
+
Simplest usage::
|
|
332
|
+
|
|
333
|
+
AgentServiceApp().run(create_agent, port=8000)
|
|
334
|
+
|
|
335
|
+
With configuration::
|
|
336
|
+
|
|
337
|
+
AgentServiceApp() \
|
|
338
|
+
.set_cors_config(allow_origins=["https://example.com"]) \
|
|
339
|
+
.run(create_agent, port=8000, reload=True)
|
|
340
|
+
|
|
341
|
+
Development mode::
|
|
342
|
+
|
|
343
|
+
AgentServiceApp().run(
|
|
344
|
+
create_agent,
|
|
345
|
+
port=8000,
|
|
346
|
+
reload=True,
|
|
347
|
+
log_level="debug"
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
Production mode::
|
|
351
|
+
|
|
352
|
+
AgentServiceApp().run(
|
|
353
|
+
create_agent,
|
|
354
|
+
port=8000,
|
|
355
|
+
workers=4,
|
|
356
|
+
access_log=False
|
|
357
|
+
)
|
|
358
|
+
"""
|
|
359
|
+
# Build the FastAPI application
|
|
360
|
+
app = self.build(
|
|
361
|
+
create_agent,
|
|
362
|
+
base_path,
|
|
363
|
+
enable_openai_endpoint=enable_openai_endpoint,
|
|
364
|
+
enable_healthz=enable_healthz,
|
|
365
|
+
healthz_config=healthz_config,
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
# Run the server
|
|
369
|
+
import uvicorn
|
|
370
|
+
|
|
371
|
+
uvicorn.run(app, host=host, port=port, **uvicorn_kwargs)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Health Check Module.
|
|
2
|
+
|
|
3
|
+
This module provides health check functionality for Cloudbase Agent servers,
|
|
4
|
+
automatically integrated into AgentServiceApp.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .handler import create_healthz_handler
|
|
8
|
+
from .models import HealthzConfig, HealthzResponse
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"HealthzConfig",
|
|
12
|
+
"HealthzResponse",
|
|
13
|
+
"create_healthz_handler",
|
|
14
|
+
]
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Health Check Handler.
|
|
4
|
+
|
|
5
|
+
This module provides the handler function for health check endpoints.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import platform
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
from typing import Any, Callable, Optional
|
|
11
|
+
|
|
12
|
+
from .models import HealthzConfig
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def create_healthz_handler(
|
|
16
|
+
config: Optional[HealthzConfig] = None,
|
|
17
|
+
base_path: str = "",
|
|
18
|
+
agent_name: Optional[str] = None,
|
|
19
|
+
) -> Callable[[], dict[str, Any]]:
|
|
20
|
+
"""Create a health check handler function.
|
|
21
|
+
|
|
22
|
+
This function creates a handler that can be used as a FastAPI route handler
|
|
23
|
+
for health check endpoints. The handler performs basic health checks and
|
|
24
|
+
optionally executes custom health check logic.
|
|
25
|
+
|
|
26
|
+
:param config: Health check configuration
|
|
27
|
+
:type config: Optional[HealthzConfig]
|
|
28
|
+
:param base_path: Base path of the service
|
|
29
|
+
:type base_path: str
|
|
30
|
+
:param agent_name: Optional agent name to include in response
|
|
31
|
+
:type agent_name: Optional[str]
|
|
32
|
+
:return: Handler function that returns health check response
|
|
33
|
+
:rtype: Callable[[], dict[str, Any]]
|
|
34
|
+
|
|
35
|
+
Example:
|
|
36
|
+
Basic usage::
|
|
37
|
+
|
|
38
|
+
handler = create_healthz_handler()
|
|
39
|
+
|
|
40
|
+
@app.get("/healthz")
|
|
41
|
+
def healthz():
|
|
42
|
+
return handler()
|
|
43
|
+
|
|
44
|
+
With configuration::
|
|
45
|
+
|
|
46
|
+
config = HealthzConfig(
|
|
47
|
+
service_name="my-service",
|
|
48
|
+
version="2.0.0"
|
|
49
|
+
)
|
|
50
|
+
handler = create_healthz_handler(config, base_path="/api")
|
|
51
|
+
|
|
52
|
+
@app.get("/api/healthz")
|
|
53
|
+
def healthz():
|
|
54
|
+
return handler()
|
|
55
|
+
|
|
56
|
+
With custom checks::
|
|
57
|
+
|
|
58
|
+
async def check_redis():
|
|
59
|
+
if not redis.ping():
|
|
60
|
+
raise Exception("Redis not available")
|
|
61
|
+
return {"redis": "connected"}
|
|
62
|
+
|
|
63
|
+
config = HealthzConfig(custom_checks=check_redis)
|
|
64
|
+
handler = create_healthz_handler(config)
|
|
65
|
+
"""
|
|
66
|
+
# Use default config if not provided
|
|
67
|
+
if config is None:
|
|
68
|
+
config = HealthzConfig()
|
|
69
|
+
|
|
70
|
+
def handler() -> dict[str, Any]:
|
|
71
|
+
"""Health check handler function.
|
|
72
|
+
|
|
73
|
+
This function performs health checks and returns a structured response.
|
|
74
|
+
If custom checks are configured and fail, it returns an unhealthy status.
|
|
75
|
+
|
|
76
|
+
:return: Health check response as dictionary
|
|
77
|
+
:rtype: dict[str, Any]
|
|
78
|
+
"""
|
|
79
|
+
# Build base response
|
|
80
|
+
response_data = {
|
|
81
|
+
"status": "healthy",
|
|
82
|
+
"timestamp": datetime.utcnow().isoformat() + "Z",
|
|
83
|
+
"service": config.service_name,
|
|
84
|
+
"version": config.version,
|
|
85
|
+
"python_version": platform.python_version(),
|
|
86
|
+
"base_path": base_path or "/",
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# Add agent info if enabled
|
|
90
|
+
if config.include_agent_info and agent_name:
|
|
91
|
+
response_data["agent_info"] = {
|
|
92
|
+
"name": agent_name,
|
|
93
|
+
"endpoints": [
|
|
94
|
+
f"{base_path}/send-message",
|
|
95
|
+
f"{base_path}/healthz",
|
|
96
|
+
],
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
# Execute custom checks if provided
|
|
100
|
+
if config.custom_checks:
|
|
101
|
+
try:
|
|
102
|
+
custom_results = config.custom_checks()
|
|
103
|
+
if custom_results:
|
|
104
|
+
response_data["custom"] = custom_results
|
|
105
|
+
except Exception as e:
|
|
106
|
+
# Custom check failed, mark as unhealthy
|
|
107
|
+
response_data["status"] = "unhealthy"
|
|
108
|
+
response_data["error"] = str(e)
|
|
109
|
+
|
|
110
|
+
return response_data
|
|
111
|
+
|
|
112
|
+
return handler
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def create_async_healthz_handler(
|
|
116
|
+
config: Optional[HealthzConfig] = None,
|
|
117
|
+
base_path: str = "",
|
|
118
|
+
agent_name: Optional[str] = None,
|
|
119
|
+
) -> Callable[[], dict[str, Any]]:
|
|
120
|
+
"""Create an async health check handler function.
|
|
121
|
+
|
|
122
|
+
This is the async version of create_healthz_handler, supporting
|
|
123
|
+
async custom health check functions.
|
|
124
|
+
|
|
125
|
+
:param config: Health check configuration
|
|
126
|
+
:type config: Optional[HealthzConfig]
|
|
127
|
+
:param base_path: Base path of the service
|
|
128
|
+
:type base_path: str
|
|
129
|
+
:param agent_name: Optional agent name to include in response
|
|
130
|
+
:type agent_name: Optional[str]
|
|
131
|
+
:return: Async handler function that returns health check response
|
|
132
|
+
:rtype: Callable[[], dict[str, Any]]
|
|
133
|
+
|
|
134
|
+
Example:
|
|
135
|
+
With async custom checks::
|
|
136
|
+
|
|
137
|
+
async def check_database():
|
|
138
|
+
if not await db.is_connected():
|
|
139
|
+
raise Exception("Database not connected")
|
|
140
|
+
return {"database": "connected"}
|
|
141
|
+
|
|
142
|
+
config = HealthzConfig(custom_checks=check_database)
|
|
143
|
+
handler = create_async_healthz_handler(config)
|
|
144
|
+
|
|
145
|
+
@app.get("/healthz")
|
|
146
|
+
async def healthz():
|
|
147
|
+
return await handler()
|
|
148
|
+
"""
|
|
149
|
+
# Use default config if not provided
|
|
150
|
+
if config is None:
|
|
151
|
+
config = HealthzConfig()
|
|
152
|
+
|
|
153
|
+
async def handler() -> dict[str, Any]:
|
|
154
|
+
"""Async health check handler function.
|
|
155
|
+
|
|
156
|
+
This function performs health checks asynchronously and returns
|
|
157
|
+
a structured response. If custom checks are configured and fail,
|
|
158
|
+
it returns an unhealthy status.
|
|
159
|
+
|
|
160
|
+
:return: Health check response as dictionary
|
|
161
|
+
:rtype: dict[str, Any]
|
|
162
|
+
"""
|
|
163
|
+
# Build base response
|
|
164
|
+
response_data = {
|
|
165
|
+
"status": "healthy",
|
|
166
|
+
"timestamp": datetime.utcnow().isoformat() + "Z",
|
|
167
|
+
"service": config.service_name,
|
|
168
|
+
"version": config.version,
|
|
169
|
+
"python_version": platform.python_version(),
|
|
170
|
+
"base_path": base_path or "/",
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
# Add agent info if enabled
|
|
174
|
+
if config.include_agent_info and agent_name:
|
|
175
|
+
response_data["agent_info"] = {
|
|
176
|
+
"name": agent_name,
|
|
177
|
+
"endpoints": [
|
|
178
|
+
f"{base_path}/send-message",
|
|
179
|
+
f"{base_path}/healthz",
|
|
180
|
+
],
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
# Execute custom checks if provided
|
|
184
|
+
if config.custom_checks:
|
|
185
|
+
try:
|
|
186
|
+
# Support both sync and async custom checks
|
|
187
|
+
import inspect
|
|
188
|
+
|
|
189
|
+
if inspect.iscoroutinefunction(config.custom_checks):
|
|
190
|
+
custom_results = await config.custom_checks()
|
|
191
|
+
else:
|
|
192
|
+
custom_results = config.custom_checks()
|
|
193
|
+
|
|
194
|
+
if custom_results:
|
|
195
|
+
response_data["custom"] = custom_results
|
|
196
|
+
except Exception as e:
|
|
197
|
+
# Custom check failed, mark as unhealthy
|
|
198
|
+
response_data["status"] = "unhealthy"
|
|
199
|
+
response_data["error"] = str(e)
|
|
200
|
+
|
|
201
|
+
return response_data
|
|
202
|
+
|
|
203
|
+
return handler
|