cloud-dog-api-kit 0.13.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.
- cloud_dog_api_kit/__init__.py +170 -0
- cloud_dog_api_kit/a2a/__init__.py +53 -0
- cloud_dog_api_kit/a2a/card.py +138 -0
- cloud_dog_api_kit/a2a/events.py +1123 -0
- cloud_dog_api_kit/a2a/gateway.py +105 -0
- cloud_dog_api_kit/a2a/skill_audit.py +107 -0
- cloud_dog_api_kit/auth/__init__.py +35 -0
- cloud_dog_api_kit/auth/dependency.py +121 -0
- cloud_dog_api_kit/auth/rbac.py +107 -0
- cloud_dog_api_kit/auth/service_auth.py +54 -0
- cloud_dog_api_kit/clients/__init__.py +29 -0
- cloud_dog_api_kit/clients/circuit_breaker.py +39 -0
- cloud_dog_api_kit/clients/http_client.py +127 -0
- cloud_dog_api_kit/clients/retry.py +83 -0
- cloud_dog_api_kit/compat/__init__.py +37 -0
- cloud_dog_api_kit/compat/envelope.py +120 -0
- cloud_dog_api_kit/compat/profile.py +102 -0
- cloud_dog_api_kit/compat/routes.py +90 -0
- cloud_dog_api_kit/config.py +54 -0
- cloud_dog_api_kit/correlation/__init__.py +50 -0
- cloud_dog_api_kit/correlation/context.py +118 -0
- cloud_dog_api_kit/correlation/middleware.py +133 -0
- cloud_dog_api_kit/envelopes/__init__.py +37 -0
- cloud_dog_api_kit/envelopes/error.py +87 -0
- cloud_dog_api_kit/envelopes/success.py +84 -0
- cloud_dog_api_kit/errors/__init__.py +51 -0
- cloud_dog_api_kit/errors/exceptions.py +184 -0
- cloud_dog_api_kit/errors/handler.py +102 -0
- cloud_dog_api_kit/errors/taxonomy.py +62 -0
- cloud_dog_api_kit/factory.py +157 -0
- cloud_dog_api_kit/idempotency/__init__.py +28 -0
- cloud_dog_api_kit/idempotency/middleware.py +118 -0
- cloud_dog_api_kit/idempotency/store.py +100 -0
- cloud_dog_api_kit/lifecycle/__init__.py +39 -0
- cloud_dog_api_kit/lifecycle/hooks.py +75 -0
- cloud_dog_api_kit/lifecycle/shutdown.py +178 -0
- cloud_dog_api_kit/mcp/__init__.py +122 -0
- cloud_dog_api_kit/mcp/async_jobs.py +126 -0
- cloud_dog_api_kit/mcp/client_sdk.py +235 -0
- cloud_dog_api_kit/mcp/client_transport/__init__.py +47 -0
- cloud_dog_api_kit/mcp/client_transport/base.py +98 -0
- cloud_dog_api_kit/mcp/client_transport/exceptions.py +37 -0
- cloud_dog_api_kit/mcp/client_transport/http_jsonrpc.py +405 -0
- cloud_dog_api_kit/mcp/client_transport/legacy_sse.py +320 -0
- cloud_dog_api_kit/mcp/client_transport/stdio.py +322 -0
- cloud_dog_api_kit/mcp/client_transport/streamable_http.py +748 -0
- cloud_dog_api_kit/mcp/contract.py +113 -0
- cloud_dog_api_kit/mcp/error_mapper.py +84 -0
- cloud_dog_api_kit/mcp/gateway.py +117 -0
- cloud_dog_api_kit/mcp/legacy_sse.py +129 -0
- cloud_dog_api_kit/mcp/session.py +96 -0
- cloud_dog_api_kit/mcp/sync_handler.py +269 -0
- cloud_dog_api_kit/mcp/tool_audit.py +136 -0
- cloud_dog_api_kit/mcp/tool_router.py +180 -0
- cloud_dog_api_kit/mcp/transport.py +1041 -0
- cloud_dog_api_kit/middleware/__init__.py +39 -0
- cloud_dog_api_kit/middleware/cors.py +74 -0
- cloud_dog_api_kit/middleware/logging.py +98 -0
- cloud_dog_api_kit/middleware/request_size_limit.py +86 -0
- cloud_dog_api_kit/middleware/timeout.py +78 -0
- cloud_dog_api_kit/middleware/timing.py +52 -0
- cloud_dog_api_kit/openapi/__init__.py +30 -0
- cloud_dog_api_kit/openapi/customise.py +69 -0
- cloud_dog_api_kit/openapi/route.py +46 -0
- cloud_dog_api_kit/routers/__init__.py +41 -0
- cloud_dog_api_kit/routers/crud.py +173 -0
- cloud_dog_api_kit/routers/health.py +160 -0
- cloud_dog_api_kit/routers/jobs.py +69 -0
- cloud_dog_api_kit/routers/version.py +46 -0
- cloud_dog_api_kit/schemas/__init__.py +36 -0
- cloud_dog_api_kit/schemas/envelopes.py +37 -0
- cloud_dog_api_kit/schemas/filters.py +103 -0
- cloud_dog_api_kit/schemas/pagination.py +148 -0
- cloud_dog_api_kit/streaming/__init__.py +28 -0
- cloud_dog_api_kit/streaming/events.py +47 -0
- cloud_dog_api_kit/streaming/jsonl.py +68 -0
- cloud_dog_api_kit/streaming/sse.py +102 -0
- cloud_dog_api_kit/testing/__init__.py +46 -0
- cloud_dog_api_kit/testing/conformance.py +156 -0
- cloud_dog_api_kit/testing/fixtures.py +90 -0
- cloud_dog_api_kit/testing/flows/__init__.py +32 -0
- cloud_dog_api_kit/testing/flows/auth_flow.py +41 -0
- cloud_dog_api_kit/testing/flows/crud_flow.py +50 -0
- cloud_dog_api_kit/testing/flows/job_flow.py +42 -0
- cloud_dog_api_kit/testing/flows/streaming_flow.py +42 -0
- cloud_dog_api_kit/traceability_ids.py +84 -0
- cloud_dog_api_kit/versioning/__init__.py +30 -0
- cloud_dog_api_kit/versioning/header.py +52 -0
- cloud_dog_api_kit/web/__init__.py +7 -0
- cloud_dog_api_kit/web/proxy.py +222 -0
- cloud_dog_api_kit/webhook/__init__.py +29 -0
- cloud_dog_api_kit/webhook/signature.py +149 -0
- cloud_dog_api_kit-0.13.0.dist-info/METADATA +27 -0
- cloud_dog_api_kit-0.13.0.dist-info/RECORD +98 -0
- cloud_dog_api_kit-0.13.0.dist-info/WHEEL +4 -0
- cloud_dog_api_kit-0.13.0.dist-info/licenses/LICENCE +190 -0
- cloud_dog_api_kit-0.13.0.dist-info/licenses/LICENSE +176 -0
- cloud_dog_api_kit-0.13.0.dist-info/licenses/NOTICE +7 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Copyright 2026 Cloud-Dog, Viewdeck Engineering Limited
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# cloud_dog_api_kit — Public API
|
|
16
|
+
#
|
|
17
|
+
# Licence: Proprietary — Cloud-Dog AI Platform
|
|
18
|
+
# Owner: Cloud-Dog AI
|
|
19
|
+
# Description: PS-20 API toolkit for all Cloud-Dog Python services. Provides
|
|
20
|
+
# standard envelopes, error taxonomy, auth, CRUD, pagination, health,
|
|
21
|
+
# streaming, HTTP client, correlation, idempotency, CORS, timeout,
|
|
22
|
+
# OpenAPI, MCP/A2A gateways, test scaffolding, and an app factory.
|
|
23
|
+
# Related requirements: SV1.1, SV1.2, FR17.1
|
|
24
|
+
# Related architecture: SA1
|
|
25
|
+
|
|
26
|
+
"""cloud_dog_api_kit — PS-20 API toolkit for Cloud-Dog services.
|
|
27
|
+
|
|
28
|
+
Public API:
|
|
29
|
+
create_app(...) — FastAPI app factory wiring all components.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
# ruff: noqa: E402
|
|
33
|
+
|
|
34
|
+
from __future__ import annotations
|
|
35
|
+
|
|
36
|
+
__version__ = "0.12.1"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def create_app(*args, **kwargs): # type: ignore[no-untyped-def]
|
|
40
|
+
"""Import the app factory lazily so optional dependencies remain optional."""
|
|
41
|
+
try:
|
|
42
|
+
from cloud_dog_api_kit.factory import create_app as _create_app
|
|
43
|
+
except ModuleNotFoundError as exc:
|
|
44
|
+
if exc.name != "cloud_dog_logging":
|
|
45
|
+
raise
|
|
46
|
+
raise ModuleNotFoundError("create_app requires the optional 'cloud-dog-logging' dependency") from exc
|
|
47
|
+
return _create_app(*args, **kwargs)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
from cloud_dog_api_kit.a2a.events import (
|
|
51
|
+
ConfigChangeEvent,
|
|
52
|
+
EventBroadcaster,
|
|
53
|
+
HTTPIngestAdapter,
|
|
54
|
+
InMemoryEventBroadcaster,
|
|
55
|
+
PersistentEventBroadcaster,
|
|
56
|
+
RESTPollAdapter,
|
|
57
|
+
WebSocketAdapter,
|
|
58
|
+
create_a2a_events_router,
|
|
59
|
+
)
|
|
60
|
+
from cloud_dog_api_kit.compat import (
|
|
61
|
+
LegacyEnvelopeMiddleware,
|
|
62
|
+
LegacyRouteAdapter,
|
|
63
|
+
LegacyRouteAdapterMiddleware,
|
|
64
|
+
ProfileContextMiddleware,
|
|
65
|
+
legacy_envelope_route,
|
|
66
|
+
)
|
|
67
|
+
from cloud_dog_api_kit.correlation import CorrelationMiddleware
|
|
68
|
+
from cloud_dog_api_kit.middleware import configure_cors
|
|
69
|
+
from cloud_dog_api_kit.lifecycle import (
|
|
70
|
+
GracefulShutdownManager,
|
|
71
|
+
LifecycleHooks,
|
|
72
|
+
ShutdownDrainMiddleware,
|
|
73
|
+
install_shutdown_signal_handlers,
|
|
74
|
+
)
|
|
75
|
+
from cloud_dog_api_kit.mcp import (
|
|
76
|
+
MCPContractRegistration,
|
|
77
|
+
McpSessionManager,
|
|
78
|
+
ToolContract,
|
|
79
|
+
map_legacy_mcp_payload,
|
|
80
|
+
register_mcp_contract,
|
|
81
|
+
register_mcp_routes,
|
|
82
|
+
register_tool_router,
|
|
83
|
+
)
|
|
84
|
+
from cloud_dog_api_kit.envelopes import (
|
|
85
|
+
ErrorDetail,
|
|
86
|
+
ErrorResponse,
|
|
87
|
+
Meta,
|
|
88
|
+
SuccessResponse,
|
|
89
|
+
error_envelope,
|
|
90
|
+
success_envelope,
|
|
91
|
+
)
|
|
92
|
+
from cloud_dog_api_kit.schemas.pagination import PageInfo, PaginatedData, paginated_envelope
|
|
93
|
+
from cloud_dog_api_kit.errors import (
|
|
94
|
+
APIError,
|
|
95
|
+
ConflictError,
|
|
96
|
+
InternalError,
|
|
97
|
+
NotFoundError,
|
|
98
|
+
RateLimitError,
|
|
99
|
+
TimeoutError,
|
|
100
|
+
UnauthenticatedError,
|
|
101
|
+
UnauthorisedError,
|
|
102
|
+
UpstreamError,
|
|
103
|
+
ValidationError,
|
|
104
|
+
register_error_handlers,
|
|
105
|
+
)
|
|
106
|
+
from cloud_dog_api_kit.routers.health import HealthCheck, create_health_router
|
|
107
|
+
from cloud_dog_api_kit.middleware import RequestLoggingMiddleware, RequestSizeLimitMiddleware
|
|
108
|
+
from cloud_dog_api_kit.openapi import configure_openapi
|
|
109
|
+
from cloud_dog_api_kit.versioning import VersionHeaderMiddleware
|
|
110
|
+
from cloud_dog_api_kit.webhook import WebhookSignatureMiddleware, compute_webhook_signature
|
|
111
|
+
from cloud_dog_api_kit.web.proxy import WebApiProxy
|
|
112
|
+
|
|
113
|
+
__all__ = [
|
|
114
|
+
"create_app",
|
|
115
|
+
"APIError",
|
|
116
|
+
"ConfigChangeEvent",
|
|
117
|
+
"ConflictError",
|
|
118
|
+
"EventBroadcaster",
|
|
119
|
+
"HTTPIngestAdapter",
|
|
120
|
+
"InMemoryEventBroadcaster",
|
|
121
|
+
"PersistentEventBroadcaster",
|
|
122
|
+
"RESTPollAdapter",
|
|
123
|
+
"WebSocketAdapter",
|
|
124
|
+
"create_a2a_events_router",
|
|
125
|
+
"InternalError",
|
|
126
|
+
"NotFoundError",
|
|
127
|
+
"RateLimitError",
|
|
128
|
+
"TimeoutError",
|
|
129
|
+
"UnauthenticatedError",
|
|
130
|
+
"UnauthorisedError",
|
|
131
|
+
"UpstreamError",
|
|
132
|
+
"ValidationError",
|
|
133
|
+
"GracefulShutdownManager",
|
|
134
|
+
"ErrorDetail",
|
|
135
|
+
"ErrorResponse",
|
|
136
|
+
"LegacyEnvelopeMiddleware",
|
|
137
|
+
"LegacyRouteAdapter",
|
|
138
|
+
"LegacyRouteAdapterMiddleware",
|
|
139
|
+
"LifecycleHooks",
|
|
140
|
+
"MCPContractRegistration",
|
|
141
|
+
"Meta",
|
|
142
|
+
"McpSessionManager",
|
|
143
|
+
"PageInfo",
|
|
144
|
+
"PaginatedData",
|
|
145
|
+
"ProfileContextMiddleware",
|
|
146
|
+
"RequestSizeLimitMiddleware",
|
|
147
|
+
"ShutdownDrainMiddleware",
|
|
148
|
+
"SuccessResponse",
|
|
149
|
+
"ToolContract",
|
|
150
|
+
"WebhookSignatureMiddleware",
|
|
151
|
+
"compute_webhook_signature",
|
|
152
|
+
"error_envelope",
|
|
153
|
+
"install_shutdown_signal_handlers",
|
|
154
|
+
"legacy_envelope_route",
|
|
155
|
+
"map_legacy_mcp_payload",
|
|
156
|
+
"paginated_envelope",
|
|
157
|
+
"register_mcp_contract",
|
|
158
|
+
"register_mcp_routes",
|
|
159
|
+
"success_envelope",
|
|
160
|
+
"register_tool_router",
|
|
161
|
+
"register_error_handlers",
|
|
162
|
+
"HealthCheck",
|
|
163
|
+
"create_health_router",
|
|
164
|
+
"CorrelationMiddleware",
|
|
165
|
+
"RequestLoggingMiddleware",
|
|
166
|
+
"VersionHeaderMiddleware",
|
|
167
|
+
"configure_cors",
|
|
168
|
+
"configure_openapi",
|
|
169
|
+
"WebApiProxy",
|
|
170
|
+
]
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Copyright 2026 Cloud-Dog, Viewdeck Engineering Limited
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# cloud_dog_api_kit — A2A gateway
|
|
16
|
+
#
|
|
17
|
+
# Licence: Proprietary — Cloud-Dog AI Platform
|
|
18
|
+
# Owner: Cloud-Dog AI
|
|
19
|
+
# Description: REST-to-A2A gateway helpers.
|
|
20
|
+
# Related requirements: FR15.1
|
|
21
|
+
# Related architecture: SA1
|
|
22
|
+
|
|
23
|
+
"""A2A gateway helpers for cloud_dog_api_kit."""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
from cloud_dog_api_kit.a2a.card import A2ASkill, create_a2a_card_router
|
|
28
|
+
from cloud_dog_api_kit.a2a.events import (
|
|
29
|
+
ConfigChangeEvent,
|
|
30
|
+
EventBroadcaster,
|
|
31
|
+
HTTPIngestAdapter,
|
|
32
|
+
InMemoryEventBroadcaster,
|
|
33
|
+
PersistentEventBroadcaster,
|
|
34
|
+
RESTPollAdapter,
|
|
35
|
+
WebSocketAdapter,
|
|
36
|
+
create_a2a_events_router,
|
|
37
|
+
)
|
|
38
|
+
from cloud_dog_api_kit.a2a.gateway import A2AHandler, create_a2a_handler_from_endpoint
|
|
39
|
+
|
|
40
|
+
__all__ = [
|
|
41
|
+
"A2AHandler",
|
|
42
|
+
"A2ASkill",
|
|
43
|
+
"ConfigChangeEvent",
|
|
44
|
+
"EventBroadcaster",
|
|
45
|
+
"HTTPIngestAdapter",
|
|
46
|
+
"InMemoryEventBroadcaster",
|
|
47
|
+
"PersistentEventBroadcaster",
|
|
48
|
+
"RESTPollAdapter",
|
|
49
|
+
"WebSocketAdapter",
|
|
50
|
+
"create_a2a_card_router",
|
|
51
|
+
"create_a2a_events_router",
|
|
52
|
+
"create_a2a_handler_from_endpoint",
|
|
53
|
+
]
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Copyright 2026 Cloud-Dog, Viewdeck Engineering Limited
|
|
2
|
+
# Licensed under the Apache License, Version 2.0
|
|
3
|
+
|
|
4
|
+
"""A2A agent card and task submission router.
|
|
5
|
+
|
|
6
|
+
Provides ``create_a2a_card_router`` which adds:
|
|
7
|
+
- ``GET /.well-known/agent.json`` — agent card per A2A protocol spec
|
|
8
|
+
- ``POST /a2a/tasks`` — task submission that routes to skill handlers
|
|
9
|
+
|
|
10
|
+
Usage in any service's A2A server::
|
|
11
|
+
|
|
12
|
+
from cloud_dog_api_kit.a2a.card import create_a2a_card_router, A2ASkill
|
|
13
|
+
|
|
14
|
+
skills = [
|
|
15
|
+
A2ASkill(id="search", name="Search", description="Semantic search",
|
|
16
|
+
handler=lambda text: service.search(query=text)),
|
|
17
|
+
]
|
|
18
|
+
router = create_a2a_card_router(
|
|
19
|
+
name="index-retriever",
|
|
20
|
+
description="Vector database search and document ingestion",
|
|
21
|
+
url="https://example.invalid/a2a",
|
|
22
|
+
skills=skills,
|
|
23
|
+
)
|
|
24
|
+
app.include_router(router)
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
from dataclasses import dataclass, field
|
|
30
|
+
from typing import Any, Callable
|
|
31
|
+
from uuid import uuid4
|
|
32
|
+
|
|
33
|
+
from fastapi import APIRouter, Request
|
|
34
|
+
from fastapi.responses import JSONResponse
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class A2ASkill:
|
|
39
|
+
"""A skill exposed via the A2A agent card."""
|
|
40
|
+
|
|
41
|
+
id: str
|
|
42
|
+
name: str
|
|
43
|
+
description: str
|
|
44
|
+
handler: Callable[[str], Any] | None = None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def create_a2a_card_router(
|
|
48
|
+
*,
|
|
49
|
+
name: str,
|
|
50
|
+
description: str,
|
|
51
|
+
url: str = "",
|
|
52
|
+
version: str = "1.0.0",
|
|
53
|
+
skills: list[A2ASkill] | None = None,
|
|
54
|
+
) -> APIRouter:
|
|
55
|
+
"""Create a FastAPI router with A2A agent card and task submission.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
name: Service name for the agent card.
|
|
59
|
+
description: Human-readable service description.
|
|
60
|
+
url: Base URL for the A2A endpoint.
|
|
61
|
+
version: Service version string.
|
|
62
|
+
skills: List of skills to expose. Each skill can have a handler
|
|
63
|
+
function that accepts a text input and returns a result.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
A FastAPI APIRouter with agent card and task routes.
|
|
67
|
+
"""
|
|
68
|
+
_skills = skills or []
|
|
69
|
+
_skill_map: dict[str, A2ASkill] = {s.id: s for s in _skills}
|
|
70
|
+
|
|
71
|
+
card = {
|
|
72
|
+
"name": name,
|
|
73
|
+
"description": description,
|
|
74
|
+
"url": url,
|
|
75
|
+
"version": version,
|
|
76
|
+
"capabilities": {"streaming": False, "pushNotifications": False},
|
|
77
|
+
"skills": [
|
|
78
|
+
{"id": s.id, "name": s.name, "description": s.description}
|
|
79
|
+
for s in _skills
|
|
80
|
+
],
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
router = APIRouter()
|
|
84
|
+
|
|
85
|
+
@router.get("/.well-known/agent.json")
|
|
86
|
+
async def agent_card() -> JSONResponse:
|
|
87
|
+
"""Return the A2A agent card as JSON."""
|
|
88
|
+
return JSONResponse(card)
|
|
89
|
+
|
|
90
|
+
@router.post("/a2a/tasks")
|
|
91
|
+
@router.post("/tasks")
|
|
92
|
+
async def submit_task(request: Request) -> JSONResponse:
|
|
93
|
+
"""Accept an A2A task submission and dispatch to the matching skill."""
|
|
94
|
+
body = await request.json()
|
|
95
|
+
task_id = body.get("id", str(uuid4()))
|
|
96
|
+
skill_id = body.get("skill_id", "")
|
|
97
|
+
input_data = body.get("input", {})
|
|
98
|
+
input_text = input_data.get("text", "") if isinstance(input_data, dict) else str(input_data)
|
|
99
|
+
|
|
100
|
+
skill = _skill_map.get(skill_id)
|
|
101
|
+
if skill is None:
|
|
102
|
+
# If no specific skill, try a generic "health" skill
|
|
103
|
+
if skill_id == "health":
|
|
104
|
+
return JSONResponse({
|
|
105
|
+
"id": task_id,
|
|
106
|
+
"status": "completed",
|
|
107
|
+
"output": {"type": "text", "text": f"{name} is healthy"},
|
|
108
|
+
})
|
|
109
|
+
return JSONResponse(
|
|
110
|
+
{"id": task_id, "status": "failed",
|
|
111
|
+
"error": f"Unknown skill: {skill_id}. Available: {list(_skill_map.keys())}"},
|
|
112
|
+
status_code=404,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
if skill.handler is not None:
|
|
117
|
+
result = skill.handler(input_text)
|
|
118
|
+
# Handle async handlers
|
|
119
|
+
import asyncio
|
|
120
|
+
if asyncio.iscoroutine(result):
|
|
121
|
+
result = await result
|
|
122
|
+
result_text = str(result)
|
|
123
|
+
else:
|
|
124
|
+
result_text = f"Skill '{skill_id}' acknowledged (no handler configured)"
|
|
125
|
+
except Exception as exc:
|
|
126
|
+
return JSONResponse({
|
|
127
|
+
"id": task_id,
|
|
128
|
+
"status": "failed",
|
|
129
|
+
"error": str(exc),
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
return JSONResponse({
|
|
133
|
+
"id": task_id,
|
|
134
|
+
"status": "completed",
|
|
135
|
+
"output": {"type": "text", "text": result_text},
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
return router
|