supervaizer 0.10.5__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.
- supervaizer/__init__.py +97 -0
- supervaizer/__version__.py +10 -0
- supervaizer/account.py +308 -0
- supervaizer/account_service.py +93 -0
- supervaizer/admin/routes.py +1293 -0
- supervaizer/admin/static/js/job-start-form.js +373 -0
- supervaizer/admin/templates/agent_detail.html +145 -0
- supervaizer/admin/templates/agents.html +249 -0
- supervaizer/admin/templates/agents_grid.html +82 -0
- supervaizer/admin/templates/base.html +233 -0
- supervaizer/admin/templates/case_detail.html +230 -0
- supervaizer/admin/templates/cases_list.html +182 -0
- supervaizer/admin/templates/cases_table.html +134 -0
- supervaizer/admin/templates/console.html +389 -0
- supervaizer/admin/templates/dashboard.html +153 -0
- supervaizer/admin/templates/job_detail.html +192 -0
- supervaizer/admin/templates/job_start_test.html +109 -0
- supervaizer/admin/templates/jobs_list.html +180 -0
- supervaizer/admin/templates/jobs_table.html +122 -0
- supervaizer/admin/templates/navigation.html +163 -0
- supervaizer/admin/templates/recent_activity.html +81 -0
- supervaizer/admin/templates/server.html +105 -0
- supervaizer/admin/templates/server_status_cards.html +121 -0
- supervaizer/admin/templates/supervaize_instructions.html +212 -0
- supervaizer/agent.py +956 -0
- supervaizer/case.py +432 -0
- supervaizer/cli.py +395 -0
- supervaizer/common.py +324 -0
- supervaizer/deploy/__init__.py +16 -0
- supervaizer/deploy/cli.py +305 -0
- supervaizer/deploy/commands/__init__.py +9 -0
- supervaizer/deploy/commands/clean.py +294 -0
- supervaizer/deploy/commands/down.py +119 -0
- supervaizer/deploy/commands/local.py +460 -0
- supervaizer/deploy/commands/plan.py +167 -0
- supervaizer/deploy/commands/status.py +169 -0
- supervaizer/deploy/commands/up.py +281 -0
- supervaizer/deploy/docker.py +377 -0
- supervaizer/deploy/driver_factory.py +42 -0
- supervaizer/deploy/drivers/__init__.py +39 -0
- supervaizer/deploy/drivers/aws_app_runner.py +607 -0
- supervaizer/deploy/drivers/base.py +196 -0
- supervaizer/deploy/drivers/cloud_run.py +570 -0
- supervaizer/deploy/drivers/do_app_platform.py +504 -0
- supervaizer/deploy/health.py +404 -0
- supervaizer/deploy/state.py +210 -0
- supervaizer/deploy/templates/Dockerfile.template +44 -0
- supervaizer/deploy/templates/debug_env.py +69 -0
- supervaizer/deploy/templates/docker-compose.yml.template +37 -0
- supervaizer/deploy/templates/dockerignore.template +66 -0
- supervaizer/deploy/templates/entrypoint.sh +20 -0
- supervaizer/deploy/utils.py +52 -0
- supervaizer/event.py +181 -0
- supervaizer/examples/controller_template.py +196 -0
- supervaizer/instructions.py +145 -0
- supervaizer/job.py +392 -0
- supervaizer/job_service.py +156 -0
- supervaizer/lifecycle.py +417 -0
- supervaizer/parameter.py +233 -0
- supervaizer/protocol/__init__.py +11 -0
- supervaizer/protocol/a2a/__init__.py +21 -0
- supervaizer/protocol/a2a/model.py +227 -0
- supervaizer/protocol/a2a/routes.py +99 -0
- supervaizer/py.typed +1 -0
- supervaizer/routes.py +917 -0
- supervaizer/server.py +553 -0
- supervaizer/server_utils.py +54 -0
- supervaizer/storage.py +462 -0
- supervaizer/telemetry.py +81 -0
- supervaizer/utils/__init__.py +16 -0
- supervaizer/utils/version_check.py +56 -0
- supervaizer-0.10.5.dist-info/METADATA +317 -0
- supervaizer-0.10.5.dist-info/RECORD +76 -0
- supervaizer-0.10.5.dist-info/WHEEL +4 -0
- supervaizer-0.10.5.dist-info/entry_points.txt +2 -0
- supervaizer-0.10.5.dist-info/licenses/LICENSE.md +346 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# Copyright (c) 2024-2025 Alain Prasquier - Supervaize.com. All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
|
4
|
+
# If a copy of the MPL was not distributed with this file, you can obtain one at
|
|
5
|
+
# https://mozilla.org/MPL/2.0/.
|
|
6
|
+
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from typing import Any, Dict, List
|
|
9
|
+
|
|
10
|
+
from supervaizer.agent import Agent
|
|
11
|
+
from supervaizer.job import EntityStatus, Jobs
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def create_agent_card(agent: Agent, base_url: str) -> Dict[str, Any]:
|
|
15
|
+
"""
|
|
16
|
+
Create an A2A agent card for the given agent.
|
|
17
|
+
|
|
18
|
+
This follows the A2A protocol as defined in:
|
|
19
|
+
https://github.com/google/A2A/blob/main/specification/json/a2a.json
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
agent: The Agent instance
|
|
23
|
+
base_url: The base URL of the server
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
A dictionary representing the agent card in A2A format
|
|
27
|
+
"""
|
|
28
|
+
# Construct the agent URL
|
|
29
|
+
agent_url = f"{base_url}{agent.path}"
|
|
30
|
+
|
|
31
|
+
# Build API endpoints object with OpenAPI integration
|
|
32
|
+
api_endpoints = [
|
|
33
|
+
{
|
|
34
|
+
"type": "json",
|
|
35
|
+
"url": agent_url,
|
|
36
|
+
"name": "Supervaize API - A2A protocol support",
|
|
37
|
+
"description": f"RESTful API for {agent.name} agent",
|
|
38
|
+
"openapi_url": f"{base_url}/openapi.json",
|
|
39
|
+
"docs_url": f"{base_url}/docs",
|
|
40
|
+
"examples": [
|
|
41
|
+
{
|
|
42
|
+
"name": "Get agent info",
|
|
43
|
+
"description": "Retrieve information about the agent",
|
|
44
|
+
"request": {"method": "GET", "url": agent_url},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"name": "Start a job",
|
|
48
|
+
"description": "Start a new job with this agent",
|
|
49
|
+
"request": {"method": "POST", "url": f"{agent_url}/jobs"},
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
# Build the tools object based on agent methods
|
|
56
|
+
tools = []
|
|
57
|
+
|
|
58
|
+
# Add basic job tools
|
|
59
|
+
tools.append(
|
|
60
|
+
{
|
|
61
|
+
"name": "job_start",
|
|
62
|
+
"description": (
|
|
63
|
+
agent.methods.job_start.description if agent.methods else None
|
|
64
|
+
)
|
|
65
|
+
or f"Start a job with {agent.name}",
|
|
66
|
+
"input_schema": {
|
|
67
|
+
"type": "object",
|
|
68
|
+
"properties": {
|
|
69
|
+
"job_fields": {"type": "object"},
|
|
70
|
+
"job_context": {"type": "object"},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
tools.append(
|
|
77
|
+
{
|
|
78
|
+
"name": "job_status",
|
|
79
|
+
"description": "Check the status of a job",
|
|
80
|
+
"input_schema": {
|
|
81
|
+
"type": "object",
|
|
82
|
+
"properties": {"job_id": {"type": "string"}},
|
|
83
|
+
},
|
|
84
|
+
}
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Add custom tools if available
|
|
88
|
+
if agent.methods and agent.methods.custom:
|
|
89
|
+
for name, method in agent.methods.custom.items():
|
|
90
|
+
tools.append(
|
|
91
|
+
{
|
|
92
|
+
"name": name,
|
|
93
|
+
"description": method.description
|
|
94
|
+
or f"Execute {name} custom method",
|
|
95
|
+
"input_schema": {
|
|
96
|
+
"type": "object",
|
|
97
|
+
"properties": {
|
|
98
|
+
"method_name": {"type": "string", "const": name},
|
|
99
|
+
"params": {"type": "object"},
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
}
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Build authentication object
|
|
106
|
+
authentication = {
|
|
107
|
+
"type": "none",
|
|
108
|
+
"description": "Authentication is handled at the Supervaize server level",
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Version information
|
|
112
|
+
version_info = {
|
|
113
|
+
"current": agent.version,
|
|
114
|
+
"latest": agent.version,
|
|
115
|
+
"changelog_url": f"{base_url}/changelog/{agent.slug}",
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
# Create the main agent card
|
|
119
|
+
agent_card = {
|
|
120
|
+
"name": agent.name,
|
|
121
|
+
"description": agent.description,
|
|
122
|
+
"developer": {
|
|
123
|
+
"name": agent.developer or agent.author or "Supervaize",
|
|
124
|
+
"url": "https://supervaize.com/",
|
|
125
|
+
"email": "info@supervaize.com",
|
|
126
|
+
},
|
|
127
|
+
"version": agent.version,
|
|
128
|
+
"version_info": version_info,
|
|
129
|
+
"logo_url": f"{base_url}/static/agents/{agent.slug}_logo.png",
|
|
130
|
+
"human_url": f"{base_url}/agents/{agent.slug}",
|
|
131
|
+
"contact_information": {"general": {"email": "support@supervaize.com"}},
|
|
132
|
+
"api_endpoints": api_endpoints,
|
|
133
|
+
"tools": tools,
|
|
134
|
+
"authentication": authentication,
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return agent_card
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def create_agents_list(agents: List[Agent], base_url: str) -> Dict[str, Any]:
|
|
141
|
+
"""
|
|
142
|
+
Create an A2A agents list for all available agents.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
agents: List of Agent instances
|
|
146
|
+
base_url: The base URL of the server
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
A dictionary representing the list of agent cards in A2A format
|
|
150
|
+
"""
|
|
151
|
+
return {
|
|
152
|
+
"schema_version": "a2a_2023_v1",
|
|
153
|
+
"agents": [
|
|
154
|
+
{
|
|
155
|
+
"name": agent.name,
|
|
156
|
+
"description": agent.description,
|
|
157
|
+
"developer": agent.developer or agent.author or "Supervaize",
|
|
158
|
+
"version": agent.version,
|
|
159
|
+
"agent_card_url": f"{base_url}/.well-known/agents/v{agent.version}/{agent.slug}_agent.json",
|
|
160
|
+
}
|
|
161
|
+
for agent in agents
|
|
162
|
+
],
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def create_health_data(agents: List[Agent]) -> Dict[str, Any]:
|
|
167
|
+
"""
|
|
168
|
+
Create health data for all agents according to A2A protocol.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
agents: List of Agent instances
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
A dictionary with health information for all agents
|
|
175
|
+
"""
|
|
176
|
+
jobs_registry = Jobs()
|
|
177
|
+
|
|
178
|
+
agents_health = {}
|
|
179
|
+
for agent in agents:
|
|
180
|
+
# Get agent jobs
|
|
181
|
+
agent_jobs = jobs_registry.get_agent_jobs(agent.name)
|
|
182
|
+
|
|
183
|
+
# Calculate job statistics
|
|
184
|
+
total_jobs = len(agent_jobs)
|
|
185
|
+
completed_jobs = sum(
|
|
186
|
+
1 for j in agent_jobs.values() if j.status == EntityStatus.COMPLETED
|
|
187
|
+
)
|
|
188
|
+
failed_jobs = sum(
|
|
189
|
+
1 for j in agent_jobs.values() if j.status == EntityStatus.FAILED
|
|
190
|
+
)
|
|
191
|
+
in_progress_jobs = sum(
|
|
192
|
+
1 for j in agent_jobs.values() if j.status == EntityStatus.IN_PROGRESS
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# Set agent status based on health indicators
|
|
196
|
+
if total_jobs == 0:
|
|
197
|
+
status = "available"
|
|
198
|
+
elif failed_jobs > total_jobs / 2: # If more than half are failing
|
|
199
|
+
status = "degraded"
|
|
200
|
+
elif in_progress_jobs > 0:
|
|
201
|
+
status = "busy"
|
|
202
|
+
else:
|
|
203
|
+
status = "available"
|
|
204
|
+
|
|
205
|
+
agents_health[agent.id] = {
|
|
206
|
+
"agent_id": agent.id,
|
|
207
|
+
"agent_server_id": agent.server_agent_id,
|
|
208
|
+
"name": agent.name,
|
|
209
|
+
"status": status,
|
|
210
|
+
"version": agent.version,
|
|
211
|
+
"statistics": {
|
|
212
|
+
"total_jobs": total_jobs,
|
|
213
|
+
"completed_jobs": completed_jobs,
|
|
214
|
+
"failed_jobs": failed_jobs,
|
|
215
|
+
"in_progress_jobs": in_progress_jobs,
|
|
216
|
+
"success_rate": (completed_jobs / total_jobs * 100)
|
|
217
|
+
if total_jobs > 0
|
|
218
|
+
else 100,
|
|
219
|
+
},
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
"schema_version": "a2a_2023_v1",
|
|
224
|
+
"status": "operational",
|
|
225
|
+
"timestamp": str(datetime.now()),
|
|
226
|
+
"agents": agents_health,
|
|
227
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Copyright (c) 2024-2025 Alain Prasquier - Supervaize.com. All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
|
4
|
+
# If a copy of the MPL was not distributed with this file, you can obtain one at
|
|
5
|
+
# https://mozilla.org/MPL/2.0/.
|
|
6
|
+
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Dict
|
|
8
|
+
|
|
9
|
+
from fastapi import APIRouter
|
|
10
|
+
|
|
11
|
+
from supervaizer.common import log
|
|
12
|
+
from supervaizer.protocol.a2a.model import (
|
|
13
|
+
create_agent_card,
|
|
14
|
+
create_agents_list,
|
|
15
|
+
create_health_data,
|
|
16
|
+
)
|
|
17
|
+
from supervaizer.routes import handle_route_errors
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from supervaizer.agent import Agent
|
|
21
|
+
from supervaizer.server import Server
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def create_routes(server: "Server") -> APIRouter:
|
|
25
|
+
"""Create A2A protocol routes for the server."""
|
|
26
|
+
router = APIRouter(prefix="/.well-known", tags=["Protocol A2A"])
|
|
27
|
+
base_url = server.public_url or ""
|
|
28
|
+
|
|
29
|
+
@router.get(
|
|
30
|
+
"/agents.json",
|
|
31
|
+
summary="A2A Agents Discovery",
|
|
32
|
+
description="Returns a list of all agents according to A2A protocol specification",
|
|
33
|
+
response_model=Dict[str, Any],
|
|
34
|
+
)
|
|
35
|
+
@handle_route_errors()
|
|
36
|
+
async def get_a2a_agents() -> Dict[str, Any]:
|
|
37
|
+
"""Get a list of all available agents in A2A format."""
|
|
38
|
+
log.info("[A2A] GET /.well-known/agents.json [Agent discovery]")
|
|
39
|
+
return create_agents_list(server.agents, base_url)
|
|
40
|
+
|
|
41
|
+
# Health endpoint
|
|
42
|
+
@router.get(
|
|
43
|
+
"/health",
|
|
44
|
+
summary="A2A Health Status",
|
|
45
|
+
description="Returns health information about the server and agents",
|
|
46
|
+
response_model=Dict[str, Any],
|
|
47
|
+
)
|
|
48
|
+
@handle_route_errors()
|
|
49
|
+
async def get_health() -> Dict[str, Any]:
|
|
50
|
+
"""Get health information for the server and all agents."""
|
|
51
|
+
# log.debug("[A2A] GET /.well-known/health [Health status]")
|
|
52
|
+
return create_health_data(server.agents)
|
|
53
|
+
|
|
54
|
+
# Create explicit routes for each agent in the versioned format
|
|
55
|
+
for agent in server.agents:
|
|
56
|
+
# V1 endpoints (current version)
|
|
57
|
+
def create_agent_route_versioned(current_agent: "Agent") -> None:
|
|
58
|
+
route_path = (
|
|
59
|
+
f"/agents/v{current_agent.version}/{current_agent.slug}_agent.json"
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
@router.get(
|
|
63
|
+
route_path,
|
|
64
|
+
summary=f"A2A Agent Card for {current_agent.name} (v1)",
|
|
65
|
+
description=f"Returns agent card for {current_agent.name} according to A2A protocol specification",
|
|
66
|
+
response_model=Dict[str, Any],
|
|
67
|
+
)
|
|
68
|
+
@handle_route_errors()
|
|
69
|
+
async def get_agent_card() -> Dict[str, Any]:
|
|
70
|
+
"""Get an agent card in A2A format."""
|
|
71
|
+
log.info(
|
|
72
|
+
f"[A2A] GET /.well-known/agents/v{current_agent.version}/"
|
|
73
|
+
f"{current_agent.slug}_agent.json [Agent card]"
|
|
74
|
+
)
|
|
75
|
+
return create_agent_card(current_agent, base_url)
|
|
76
|
+
|
|
77
|
+
# Create routes for backward compatibility to current versions
|
|
78
|
+
def create_agent_route_legacy(current_agent: "Agent") -> None:
|
|
79
|
+
route_path = f"/agents/{current_agent.slug}_agent.json"
|
|
80
|
+
|
|
81
|
+
@router.get(
|
|
82
|
+
route_path,
|
|
83
|
+
summary=f"A2A Agent Card for {current_agent.name} (Legacy)",
|
|
84
|
+
description=f"Legacy endpoint for {current_agent.name} agent card",
|
|
85
|
+
response_model=Dict[str, Any],
|
|
86
|
+
)
|
|
87
|
+
@handle_route_errors()
|
|
88
|
+
async def get_agent_card_legacy() -> Dict[str, Any]:
|
|
89
|
+
"""Get an agent card in A2A format (legacy endpoint)."""
|
|
90
|
+
log.info(
|
|
91
|
+
f"[A2A] GET /.well-known/agents/{current_agent.slug}_agent.json [Legacy Agent card]"
|
|
92
|
+
)
|
|
93
|
+
return create_agent_card(current_agent, base_url)
|
|
94
|
+
|
|
95
|
+
# Call the closure function with the current agent
|
|
96
|
+
create_agent_route_versioned(agent)
|
|
97
|
+
create_agent_route_legacy(agent)
|
|
98
|
+
|
|
99
|
+
return router
|
supervaizer/py.typed
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# This file indicates that the supervaizer package supports type checking
|