supervaizer 0.10.5__py3-none-any.whl → 0.10.15__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 +7 -3
- supervaizer/__version__.py +1 -1
- supervaizer/account.py +18 -4
- supervaizer/account_service.py +13 -3
- supervaizer/admin/routes.py +84 -34
- supervaizer/admin/static/favicon.ico +0 -0
- supervaizer/admin/templates/index.html +63 -0
- supervaizer/admin/templates/server.html +50 -4
- supervaizer/agent.py +2 -1
- supervaizer/deploy/cli.py +2 -3
- supervaizer/deploy/templates/index.html +57 -0
- supervaizer/examples/controller_template.py +21 -23
- supervaizer/server.py +51 -13
- {supervaizer-0.10.5.dist-info → supervaizer-0.10.15.dist-info}/METADATA +1 -1
- {supervaizer-0.10.5.dist-info → supervaizer-0.10.15.dist-info}/RECORD +18 -15
- {supervaizer-0.10.5.dist-info → supervaizer-0.10.15.dist-info}/WHEEL +0 -0
- {supervaizer-0.10.5.dist-info → supervaizer-0.10.15.dist-info}/entry_points.txt +0 -0
- {supervaizer-0.10.5.dist-info → supervaizer-0.10.15.dist-info}/licenses/LICENSE.md +0 -0
supervaizer/__init__.py
CHANGED
|
@@ -13,6 +13,8 @@ from supervaizer.agent import (
|
|
|
13
13
|
AgentMethod,
|
|
14
14
|
AgentMethodParams,
|
|
15
15
|
AgentMethods,
|
|
16
|
+
AgentMethodField,
|
|
17
|
+
FieldTypeEnum,
|
|
16
18
|
)
|
|
17
19
|
from supervaizer.case import (
|
|
18
20
|
Case,
|
|
@@ -50,6 +52,7 @@ __all__ = [
|
|
|
50
52
|
"Agent",
|
|
51
53
|
"AgentCustomMethodParams",
|
|
52
54
|
"AgentMethod",
|
|
55
|
+
"AgentMethodField",
|
|
53
56
|
"AgentMethodParams",
|
|
54
57
|
"AgentMethods",
|
|
55
58
|
"AgentRegisterEvent",
|
|
@@ -57,11 +60,11 @@ __all__ = [
|
|
|
57
60
|
"ApiResult",
|
|
58
61
|
"ApiSuccess",
|
|
59
62
|
"Case",
|
|
60
|
-
"CaseNodeUpdate",
|
|
61
|
-
"CaseNodeType",
|
|
62
|
-
"Cases",
|
|
63
63
|
"CaseNode",
|
|
64
64
|
"CaseNodes",
|
|
65
|
+
"CaseNodeType",
|
|
66
|
+
"CaseNodeUpdate",
|
|
67
|
+
"Cases",
|
|
65
68
|
"CaseStartEvent",
|
|
66
69
|
"CaseUpdateEvent",
|
|
67
70
|
"create_error_response",
|
|
@@ -75,6 +78,7 @@ __all__ = [
|
|
|
75
78
|
"ErrorType",
|
|
76
79
|
"Event",
|
|
77
80
|
"EventType",
|
|
81
|
+
"FieldTypeEnum",
|
|
78
82
|
"Job",
|
|
79
83
|
"JobContext",
|
|
80
84
|
"JobFinishedEvent",
|
supervaizer/__version__.py
CHANGED
supervaizer/account.py
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
from typing import TYPE_CHECKING, Any, ClassVar, Dict, Optional, Union
|
|
9
9
|
|
|
10
10
|
import httpx
|
|
11
|
-
from pydantic import Field
|
|
11
|
+
from pydantic import Field, field_validator
|
|
12
12
|
|
|
13
13
|
from supervaizer.__version__ import VERSION
|
|
14
14
|
from supervaizer.common import ApiError, ApiResult, ApiSuccess, SvBaseModel
|
|
@@ -55,6 +55,14 @@ class AccountAbstract(SvBaseModel):
|
|
|
55
55
|
description="The URL of the Supervaize SaaS API provided by Supervaize.com"
|
|
56
56
|
)
|
|
57
57
|
|
|
58
|
+
@field_validator("workspace_id", "api_key", "api_url", mode="before")
|
|
59
|
+
@classmethod
|
|
60
|
+
def strip_whitespace(cls, v: Any) -> Any:
|
|
61
|
+
"""Strip leading/trailing whitespace (e.g. newlines from env vars)."""
|
|
62
|
+
if isinstance(v, str):
|
|
63
|
+
return v.strip()
|
|
64
|
+
return v
|
|
65
|
+
|
|
58
66
|
model_config = {
|
|
59
67
|
"reference_group": "Core",
|
|
60
68
|
"json_schema_extra": {
|
|
@@ -62,7 +70,7 @@ class AccountAbstract(SvBaseModel):
|
|
|
62
70
|
{
|
|
63
71
|
"workspace_id": "ws_1234567890abcdef",
|
|
64
72
|
"api_key": "sk_1234567890abcdef",
|
|
65
|
-
"api_url": "https://
|
|
73
|
+
"api_url": "https://app.supervaize.com",
|
|
66
74
|
}
|
|
67
75
|
]
|
|
68
76
|
},
|
|
@@ -121,7 +129,7 @@ class Account(AccountAbstract):
|
|
|
121
129
|
"""URL for the Supervaize Control API.
|
|
122
130
|
Tested in tests/test_account.py
|
|
123
131
|
"""
|
|
124
|
-
return f"{self.api_url_w_v1}/ctrl-events/"
|
|
132
|
+
return f"{self.api_url_w_v1}/ctrl-events/".strip()
|
|
125
133
|
|
|
126
134
|
def get_url(self, pattern_name: str, **kwargs: Any) -> str:
|
|
127
135
|
"""Generate a URL using the predefined patterns.
|
|
@@ -191,7 +199,13 @@ class Account(AccountAbstract):
|
|
|
191
199
|
from supervaizer.event import ServerRegisterEvent
|
|
192
200
|
|
|
193
201
|
event = ServerRegisterEvent(server=server, account=self)
|
|
194
|
-
|
|
202
|
+
result = self.send_event(sender=server, event=event)
|
|
203
|
+
if isinstance(result, ApiSuccess):
|
|
204
|
+
log.success(result.message)
|
|
205
|
+
# TODO: Update server with the server ID from the response. store this ID in env variable.
|
|
206
|
+
else:
|
|
207
|
+
log.error(result.message)
|
|
208
|
+
return result
|
|
195
209
|
|
|
196
210
|
def _create_api_result(
|
|
197
211
|
self,
|
supervaizer/account_service.py
CHANGED
|
@@ -59,14 +59,17 @@ def send_event(
|
|
|
59
59
|
|
|
60
60
|
headers = account.api_headers
|
|
61
61
|
payload = event.payload
|
|
62
|
+
url_event = (
|
|
63
|
+
account.url_event.strip()
|
|
64
|
+
) # defensive: env vars often have trailing newline
|
|
62
65
|
|
|
63
66
|
# Generate curl equivalent for debugging
|
|
64
67
|
|
|
65
68
|
curl_headers = " ".join([f'-H "{k}: {v}"' for k, v in headers.items()])
|
|
66
|
-
curl_cmd = f"curl -X 'GET' '{
|
|
69
|
+
curl_cmd = f"curl -X 'GET' '{url_event}' {curl_headers}"
|
|
67
70
|
|
|
68
71
|
try:
|
|
69
|
-
response = _httpx_client.post(
|
|
72
|
+
response = _httpx_client.post(url_event, headers=headers, json=payload)
|
|
70
73
|
|
|
71
74
|
# Log response details before raising for status
|
|
72
75
|
|
|
@@ -76,6 +79,13 @@ def send_event(
|
|
|
76
79
|
)
|
|
77
80
|
|
|
78
81
|
log.success(result.log_message)
|
|
82
|
+
except (httpx.ConnectError, httpx.ConnectTimeout) as e:
|
|
83
|
+
log.error(
|
|
84
|
+
f"Supervaize controller is not available at {url_event}. "
|
|
85
|
+
"Connection refused or timed out. Is the controller server running?"
|
|
86
|
+
)
|
|
87
|
+
log.error(f"❌ Error sending event {event.type.name}: {e!s}")
|
|
88
|
+
raise e
|
|
79
89
|
except httpx.HTTPError as e:
|
|
80
90
|
# Enhanced error logging
|
|
81
91
|
log.error("[Send event] HTTP Error occurred")
|
|
@@ -83,7 +93,7 @@ def send_event(
|
|
|
83
93
|
|
|
84
94
|
error_result = ApiError(
|
|
85
95
|
message=f"Error sending event {event.type.name}",
|
|
86
|
-
url=
|
|
96
|
+
url=url_event,
|
|
87
97
|
payload=event.payload,
|
|
88
98
|
exception=e,
|
|
89
99
|
)
|
supervaizer/admin/routes.py
CHANGED
|
@@ -20,8 +20,8 @@ from pathlib import Path
|
|
|
20
20
|
from typing import Any, AsyncGenerator, Dict, List, Optional
|
|
21
21
|
|
|
22
22
|
import psutil
|
|
23
|
-
from fastapi import APIRouter, HTTPException, Query, Request, Security
|
|
24
|
-
from fastapi.responses import HTMLResponse, Response
|
|
23
|
+
from fastapi import APIRouter, Depends, HTTPException, Query, Request, Security
|
|
24
|
+
from fastapi.responses import HTMLResponse, JSONResponse, Response
|
|
25
25
|
from fastapi.security import APIKeyHeader
|
|
26
26
|
from fastapi.templating import Jinja2Templates
|
|
27
27
|
from pydantic import BaseModel
|
|
@@ -267,6 +267,7 @@ def create_admin_routes() -> APIRouter:
|
|
|
267
267
|
"db_name": "TinyDB",
|
|
268
268
|
"data_storage_path": str(storage.db_path.absolute()),
|
|
269
269
|
"api_key": os.getenv("SUPERVAIZER_API_KEY"),
|
|
270
|
+
"server_id": os.getenv("SUPERVAIZER_SERVER_ID"),
|
|
270
271
|
},
|
|
271
272
|
)
|
|
272
273
|
except Exception as e:
|
|
@@ -413,6 +414,59 @@ def create_admin_routes() -> APIRouter:
|
|
|
413
414
|
log.error(f"Get server status API error: {e}")
|
|
414
415
|
raise HTTPException(status_code=500, detail=str(e))
|
|
415
416
|
|
|
417
|
+
@router.post("/api/server/register")
|
|
418
|
+
async def register_server_with_supervisor(
|
|
419
|
+
request: Request,
|
|
420
|
+
_: bool = Depends(verify_admin_access),
|
|
421
|
+
) -> JSONResponse:
|
|
422
|
+
"""Trigger SERVER_REGISTER to the supervaizer supervisor."""
|
|
423
|
+
try:
|
|
424
|
+
from supervaizer.common import ApiSuccess
|
|
425
|
+
from supervaizer.routes import get_server
|
|
426
|
+
|
|
427
|
+
get_current = request.app.dependency_overrides.get(get_server)
|
|
428
|
+
if get_current is None:
|
|
429
|
+
raise HTTPException(
|
|
430
|
+
status_code=503,
|
|
431
|
+
detail="Server instance not available (admin not running with live server)",
|
|
432
|
+
)
|
|
433
|
+
try:
|
|
434
|
+
server = await get_current()
|
|
435
|
+
except (NotImplementedError, TypeError):
|
|
436
|
+
raise HTTPException(
|
|
437
|
+
status_code=503,
|
|
438
|
+
detail="Server instance not available (admin not running with live server)",
|
|
439
|
+
)
|
|
440
|
+
if not getattr(server, "supervisor_account", None):
|
|
441
|
+
raise HTTPException(
|
|
442
|
+
status_code=503,
|
|
443
|
+
detail="No supervisor account configured",
|
|
444
|
+
)
|
|
445
|
+
result = server.supervisor_account.register_server(server=server)
|
|
446
|
+
if isinstance(result, ApiSuccess):
|
|
447
|
+
return JSONResponse(
|
|
448
|
+
status_code=200,
|
|
449
|
+
content={
|
|
450
|
+
"success": True,
|
|
451
|
+
"message": result.message,
|
|
452
|
+
"detail": result.detail,
|
|
453
|
+
},
|
|
454
|
+
)
|
|
455
|
+
# ApiError
|
|
456
|
+
return JSONResponse(
|
|
457
|
+
status_code=502,
|
|
458
|
+
content={
|
|
459
|
+
"success": False,
|
|
460
|
+
"message": result.message,
|
|
461
|
+
"detail": getattr(result, "detail", None),
|
|
462
|
+
},
|
|
463
|
+
)
|
|
464
|
+
except HTTPException:
|
|
465
|
+
raise
|
|
466
|
+
except Exception as e:
|
|
467
|
+
log.error(f"Server register API error: {e}")
|
|
468
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
469
|
+
|
|
416
470
|
@router.get("/api/agents")
|
|
417
471
|
async def get_agents_api(
|
|
418
472
|
request: Request,
|
|
@@ -872,28 +926,24 @@ def create_admin_routes() -> APIRouter:
|
|
|
872
926
|
# Combine and sort by created_at
|
|
873
927
|
activities = []
|
|
874
928
|
for job in recent_jobs:
|
|
875
|
-
activities.append(
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
}
|
|
884
|
-
)
|
|
929
|
+
activities.append({
|
|
930
|
+
"type": "job",
|
|
931
|
+
"id": job.get("id"),
|
|
932
|
+
"name": job.get("name"),
|
|
933
|
+
"status": job.get("status"),
|
|
934
|
+
"created_at": job.get("created_at"),
|
|
935
|
+
"agent_name": job.get("agent_name"),
|
|
936
|
+
})
|
|
885
937
|
|
|
886
938
|
for case in recent_cases:
|
|
887
|
-
activities.append(
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
}
|
|
896
|
-
)
|
|
939
|
+
activities.append({
|
|
940
|
+
"type": "case",
|
|
941
|
+
"id": case.get("id"),
|
|
942
|
+
"name": case.get("name"),
|
|
943
|
+
"status": case.get("status"),
|
|
944
|
+
"created_at": case.get("created_at"),
|
|
945
|
+
"job_id": case.get("job_id"),
|
|
946
|
+
})
|
|
897
947
|
|
|
898
948
|
# Sort by created_at descending
|
|
899
949
|
activities.sort(key=lambda x: str(x.get("created_at", "")), reverse=True)
|
|
@@ -1150,23 +1200,23 @@ def get_dashboard_stats(storage: StorageManager) -> AdminStats:
|
|
|
1150
1200
|
|
|
1151
1201
|
# Calculate job stats
|
|
1152
1202
|
job_total = len(all_jobs)
|
|
1153
|
-
job_running = len(
|
|
1154
|
-
|
|
1155
|
-
)
|
|
1203
|
+
job_running = len([
|
|
1204
|
+
j for j in all_jobs if j.get("status") in ["in_progress", "awaiting"]
|
|
1205
|
+
])
|
|
1156
1206
|
job_completed = len([j for j in all_jobs if j.get("status") == "completed"])
|
|
1157
|
-
job_failed = len(
|
|
1158
|
-
|
|
1159
|
-
)
|
|
1207
|
+
job_failed = len([
|
|
1208
|
+
j for j in all_jobs if j.get("status") in ["failed", "cancelled"]
|
|
1209
|
+
])
|
|
1160
1210
|
|
|
1161
1211
|
# Calculate case stats
|
|
1162
1212
|
case_total = len(all_cases)
|
|
1163
|
-
case_running = len(
|
|
1164
|
-
|
|
1165
|
-
)
|
|
1213
|
+
case_running = len([
|
|
1214
|
+
c for c in all_cases if c.get("status") in ["in_progress", "awaiting"]
|
|
1215
|
+
])
|
|
1166
1216
|
case_completed = len([c for c in all_cases if c.get("status") == "completed"])
|
|
1167
|
-
case_failed = len(
|
|
1168
|
-
|
|
1169
|
-
)
|
|
1217
|
+
case_failed = len([
|
|
1218
|
+
c for c in all_cases if c.get("status") in ["failed", "cancelled"]
|
|
1219
|
+
])
|
|
1170
1220
|
|
|
1171
1221
|
# TinyDB collections count (tables)
|
|
1172
1222
|
collections_count = len(storage._db.tables())
|
|
Binary file
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Supervaizer API</title>
|
|
7
|
+
<!-- Tailwind CSS -->
|
|
8
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
9
|
+
</head>
|
|
10
|
+
<body class="bg-gray-50 min-h-screen">
|
|
11
|
+
<main class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
|
|
12
|
+
<div class="px-4 py-6 sm:px-0">
|
|
13
|
+
<h1 class="text-2xl font-bold leading-7 text-gray-900 sm:truncate sm:text-3xl sm:tracking-tight">
|
|
14
|
+
Supervaizer API
|
|
15
|
+
</h1>
|
|
16
|
+
<p class="mt-2 text-sm text-gray-500">
|
|
17
|
+
Controller version {{ version }} · API version {{ api_version }}
|
|
18
|
+
</p>
|
|
19
|
+
<p class="mt-1 text-xs text-gray-400 font-mono">Server ID: {{ server_id }}</p>
|
|
20
|
+
|
|
21
|
+
<div class="mt-8">
|
|
22
|
+
<h2 class="text-lg font-medium text-gray-900 mb-4">Links</h2>
|
|
23
|
+
<ul class="space-y-2">
|
|
24
|
+
<li>
|
|
25
|
+
<a href="{{ base }}/docs" class="text-blue-600 hover:text-blue-800 font-medium">
|
|
26
|
+
Swagger UI
|
|
27
|
+
</a>
|
|
28
|
+
</li>
|
|
29
|
+
<li>
|
|
30
|
+
<a href="{{ base }}/redoc" class="text-blue-600 hover:text-blue-800 font-medium">
|
|
31
|
+
ReDoc
|
|
32
|
+
</a>
|
|
33
|
+
</li>
|
|
34
|
+
<li>
|
|
35
|
+
<a href="{{ base }}/openapi.json" class="text-blue-600 hover:text-blue-800 font-medium">
|
|
36
|
+
OpenAPI
|
|
37
|
+
</a>
|
|
38
|
+
</li>
|
|
39
|
+
<li><strong>BASE:</strong> {{ base }}
|
|
40
|
+
<br>
|
|
41
|
+
<strong>PUBLIC_URL:</strong> {{ public_url }}
|
|
42
|
+
<br>
|
|
43
|
+
<strong>FULL_URL:</strong> {{ full_url }}
|
|
44
|
+
<br>
|
|
45
|
+
</li>
|
|
46
|
+
|
|
47
|
+
{% if show_admin %}
|
|
48
|
+
<li>
|
|
49
|
+
<a href="{{ base }}/admin" class="text-blue-600 hover:text-blue-800 font-medium">
|
|
50
|
+
Admin
|
|
51
|
+
</a>
|
|
52
|
+
</li>
|
|
53
|
+
{% endif %}
|
|
54
|
+
</ul>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
<hr>
|
|
58
|
+
<div class="mt-8">
|
|
59
|
+
TO REPLACE THIS FILE, create an index.html at the root of the project and it will be served as the home page.
|
|
60
|
+
</div>
|
|
61
|
+
</main>
|
|
62
|
+
</body>
|
|
63
|
+
</html>
|
|
@@ -12,7 +12,15 @@
|
|
|
12
12
|
</h2>
|
|
13
13
|
<p class="mt-1 text-sm text-gray-500">Monitor server health and configuration</p>
|
|
14
14
|
</div>
|
|
15
|
-
<div class="mt-4 flex md:mt-0">
|
|
15
|
+
<div class="mt-4 flex md:mt-0 gap-2">
|
|
16
|
+
<button
|
|
17
|
+
id="register-supervisor-btn"
|
|
18
|
+
type="button"
|
|
19
|
+
class="inline-flex items-center px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
|
20
|
+
>
|
|
21
|
+
<span id="register-indicator" class="htmx-indicator -ml-1 mr-2 h-4 w-4 border-2 border-white border-t-transparent rounded-full animate-spin"></span>
|
|
22
|
+
Register with supervisor
|
|
23
|
+
</button>
|
|
16
24
|
<button
|
|
17
25
|
hx-get="/admin/api/server/status"
|
|
18
26
|
hx-target="#server-status-container"
|
|
@@ -26,6 +34,7 @@
|
|
|
26
34
|
Refresh
|
|
27
35
|
</button>
|
|
28
36
|
</div>
|
|
37
|
+
<div id="register-result" class="mt-2 text-sm hidden" role="alert"></div>
|
|
29
38
|
</div>
|
|
30
39
|
|
|
31
40
|
<!-- Server Status Cards -->
|
|
@@ -91,15 +100,52 @@
|
|
|
91
100
|
</div>
|
|
92
101
|
|
|
93
102
|
<script>
|
|
94
|
-
// Auto-refresh server status every 30 seconds
|
|
95
103
|
document.addEventListener('DOMContentLoaded', function() {
|
|
96
|
-
//
|
|
104
|
+
// Auto-refresh server status every 30 seconds
|
|
97
105
|
setInterval(function() {
|
|
98
106
|
const refreshButton = document.querySelector('[hx-get="/admin/api/server/status"]');
|
|
99
107
|
if (refreshButton) {
|
|
100
108
|
htmx.trigger(refreshButton, 'click');
|
|
101
109
|
}
|
|
102
|
-
}, 30000);
|
|
110
|
+
}, 30000);
|
|
111
|
+
|
|
112
|
+
// Register with supervisor button
|
|
113
|
+
const registerBtn = document.getElementById('register-supervisor-btn');
|
|
114
|
+
const registerIndicator = document.getElementById('register-indicator');
|
|
115
|
+
const registerResult = document.getElementById('register-result');
|
|
116
|
+
if (registerBtn) {
|
|
117
|
+
registerBtn.addEventListener('click', async function() {
|
|
118
|
+
const params = new URLSearchParams(window.location.search);
|
|
119
|
+
const key = params.get('key');
|
|
120
|
+
const url = key ? '/admin/api/server/register?key=' + encodeURIComponent(key) : '/admin/api/server/register';
|
|
121
|
+
registerResult.classList.add('hidden');
|
|
122
|
+
registerIndicator.classList.remove('htmx-indicator');
|
|
123
|
+
registerBtn.disabled = true;
|
|
124
|
+
try {
|
|
125
|
+
const res = await fetch(url, { method: 'POST' });
|
|
126
|
+
const data = await res.json().catch(function() { return {}; });
|
|
127
|
+
registerResult.classList.remove('hidden');
|
|
128
|
+
if (res.ok && data.success) {
|
|
129
|
+
registerResult.className = 'mt-2 text-sm text-green-700';
|
|
130
|
+
registerResult.textContent = data.message || 'Registered successfully.';
|
|
131
|
+
} else {
|
|
132
|
+
registerResult.className = 'mt-2 text-sm text-red-700';
|
|
133
|
+
if (res.status === 403) {
|
|
134
|
+
registerResult.textContent = 'Authentication required. Open this page with ?key=...';
|
|
135
|
+
} else {
|
|
136
|
+
registerResult.textContent = (data.detail && typeof data.detail === 'object' && data.detail.message) ? data.detail.message : (data.message || 'Registration failed.');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
} catch (e) {
|
|
140
|
+
registerResult.classList.remove('hidden');
|
|
141
|
+
registerResult.className = 'mt-2 text-sm text-red-700';
|
|
142
|
+
registerResult.textContent = 'Request failed: ' + (e.message || String(e));
|
|
143
|
+
} finally {
|
|
144
|
+
registerIndicator.classList.add('htmx-indicator');
|
|
145
|
+
registerBtn.disabled = false;
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
103
149
|
});
|
|
104
150
|
</script>
|
|
105
151
|
{% endblock %}
|
supervaizer/agent.py
CHANGED
|
@@ -78,7 +78,7 @@ class AgentMethodField(BaseModel):
|
|
|
78
78
|
type: Any = Field(
|
|
79
79
|
description="Python type of the field for pydantic validation - note , ChoiceField and MultipleChoiceField are a list[str]"
|
|
80
80
|
)
|
|
81
|
-
field_type: FieldTypeEnum = Field(
|
|
81
|
+
field_type: FieldTypeEnum | str = Field(
|
|
82
82
|
default=FieldTypeEnum.CHAR, description="Field type for persistence"
|
|
83
83
|
)
|
|
84
84
|
description: str | None = Field(
|
|
@@ -185,6 +185,7 @@ class AgentMethodAbstract(BaseModel):
|
|
|
185
185
|
default=None,
|
|
186
186
|
description="A list of field specifications for generating forms/UI, following the django.forms.fields definition",
|
|
187
187
|
)
|
|
188
|
+
|
|
188
189
|
description: str | None = Field(
|
|
189
190
|
default=None, description="Optional description of what the method does"
|
|
190
191
|
)
|
supervaizer/deploy/cli.py
CHANGED
|
@@ -10,6 +10,7 @@ Deployment CLI Commands
|
|
|
10
10
|
This module contains the main CLI commands for the deploy subcommand.
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
|
+
import importlib.util
|
|
13
14
|
import typer
|
|
14
15
|
from pathlib import Path
|
|
15
16
|
from rich.console import Console
|
|
@@ -168,9 +169,7 @@ def plan(
|
|
|
168
169
|
) -> None:
|
|
169
170
|
"""Plan deployment changes without applying them."""
|
|
170
171
|
# Check if deploy extras are installed (e.g., docker, cloud SDKs)
|
|
171
|
-
|
|
172
|
-
import docker
|
|
173
|
-
except ImportError:
|
|
172
|
+
if importlib.util.find_spec("docker") is None:
|
|
174
173
|
console.print(
|
|
175
174
|
"[bold red]Error:[/] 'deploy' extra requirements are not installed. "
|
|
176
175
|
"Install them with: [bold]pip install supervaizer[deploy][/]"
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Supervaizer API</title>
|
|
7
|
+
<!-- Tailwind CSS -->
|
|
8
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
9
|
+
</head>
|
|
10
|
+
<body class="bg-gray-50 min-h-screen">
|
|
11
|
+
<main class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
|
|
12
|
+
<div class="px-4 py-6 sm:px-0">
|
|
13
|
+
<h1 class="text-2xl font-bold leading-7 text-gray-900 sm:truncate sm:text-3xl sm:tracking-tight">
|
|
14
|
+
Supervaizer API
|
|
15
|
+
</h1>
|
|
16
|
+
<p class="mt-2 text-sm text-gray-500">
|
|
17
|
+
Controller version {{ version }} · API version {{ api_version }}
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<div class="mt-8">
|
|
21
|
+
<h2 class="text-lg font-medium text-gray-900 mb-4">Links</h2>
|
|
22
|
+
<ul class="space-y-2">
|
|
23
|
+
<li>
|
|
24
|
+
<a href="/docs" class="text-blue-600 hover:text-blue-800 font-medium">
|
|
25
|
+
Swagger UI
|
|
26
|
+
</a>
|
|
27
|
+
</li>
|
|
28
|
+
<li>
|
|
29
|
+
<a href="/redoc" class="text-blue-600 hover:text-blue-800 font-medium">
|
|
30
|
+
ReDoc
|
|
31
|
+
</a>
|
|
32
|
+
</li>
|
|
33
|
+
<li>
|
|
34
|
+
<a href="/openapi.json" class="text-blue-600 hover:text-blue-800 font-medium">
|
|
35
|
+
OpenAPI
|
|
36
|
+
</a>
|
|
37
|
+
</li>
|
|
38
|
+
{% if show_admin %}
|
|
39
|
+
<li>
|
|
40
|
+
<a href="/admin" class="text-blue-600 hover:text-blue-800 font-medium">
|
|
41
|
+
Admin
|
|
42
|
+
</a>
|
|
43
|
+
</li>
|
|
44
|
+
{% endif %}
|
|
45
|
+
<li>
|
|
46
|
+
<a href="/console" class="text-blue-600 hover:text-blue-800 font-medium">
|
|
47
|
+
Console
|
|
48
|
+
</a>
|
|
49
|
+
</li>
|
|
50
|
+
<li> BASE: {{ base }}
|
|
51
|
+
</li>
|
|
52
|
+
</ul>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</main>
|
|
56
|
+
</body>
|
|
57
|
+
</html>
|
|
@@ -34,28 +34,26 @@ DEV_PUBLIC_URL = "https://myagent-dev.loca.lt"
|
|
|
34
34
|
PROD_PUBLIC_URL = "https://myagent.cloud-hosting.net:8001"
|
|
35
35
|
|
|
36
36
|
# Define the parameters and secrets expected by the agent
|
|
37
|
-
agent_parameters: ParametersSetup | None = ParametersSetup.from_list(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
]
|
|
58
|
-
)
|
|
37
|
+
agent_parameters: ParametersSetup | None = ParametersSetup.from_list([
|
|
38
|
+
Parameter(
|
|
39
|
+
name="OPEN_API_KEY",
|
|
40
|
+
description="OpenAPI Key",
|
|
41
|
+
is_environment=True,
|
|
42
|
+
is_secret=True,
|
|
43
|
+
),
|
|
44
|
+
Parameter(
|
|
45
|
+
name="SERPER_API",
|
|
46
|
+
description="Server API key updated",
|
|
47
|
+
is_environment=True,
|
|
48
|
+
is_secret=True,
|
|
49
|
+
),
|
|
50
|
+
Parameter(
|
|
51
|
+
name="COMPETITOR_SUMMARY_URL",
|
|
52
|
+
description="Competitor Summary URL",
|
|
53
|
+
is_environment=True,
|
|
54
|
+
is_secret=False,
|
|
55
|
+
),
|
|
56
|
+
])
|
|
59
57
|
|
|
60
58
|
# Define the method used to start a job
|
|
61
59
|
job_start_method: AgentMethod = AgentMethod(
|
|
@@ -180,7 +178,7 @@ agent: Agent = Agent(
|
|
|
180
178
|
account: Account = Account(
|
|
181
179
|
workspace_id=os.getenv("SUPERVAIZE_WORKSPACE_ID") or "dummy_workspace_id",
|
|
182
180
|
api_key=os.getenv("SUPERVAIZE_API_KEY") or "dummy_api_key",
|
|
183
|
-
api_url=os.getenv("SUPERVAIZE_API_URL") or "https://
|
|
181
|
+
api_url=os.getenv("SUPERVAIZE_API_URL") or "https://app.supervaize.com",
|
|
184
182
|
)
|
|
185
183
|
|
|
186
184
|
# Define the supervaizer server capabilities
|
supervaizer/server.py
CHANGED
|
@@ -10,6 +10,7 @@ import sys
|
|
|
10
10
|
import time
|
|
11
11
|
import uuid
|
|
12
12
|
from datetime import datetime
|
|
13
|
+
from pathlib import Path
|
|
13
14
|
from typing import Any, ClassVar, Dict, List, Optional, TypeVar
|
|
14
15
|
from urllib.parse import urlunparse
|
|
15
16
|
|
|
@@ -19,8 +20,9 @@ from cryptography.hazmat.primitives.asymmetric import rsa
|
|
|
19
20
|
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey, RSAPublicKey
|
|
20
21
|
from fastapi import FastAPI, HTTPException, Request, Security, status
|
|
21
22
|
from fastapi.exceptions import RequestValidationError
|
|
22
|
-
from fastapi.responses import JSONResponse
|
|
23
|
+
from fastapi.responses import HTMLResponse, JSONResponse
|
|
23
24
|
from fastapi.security import APIKeyHeader
|
|
25
|
+
from fastapi.templating import Jinja2Templates
|
|
24
26
|
from pydantic import BaseModel, field_validator, Field
|
|
25
27
|
from rich import inspect
|
|
26
28
|
|
|
@@ -53,6 +55,16 @@ T = TypeVar("T")
|
|
|
53
55
|
# Additional imports for server persistence
|
|
54
56
|
|
|
55
57
|
|
|
58
|
+
def _get_or_create_server_id() -> str:
|
|
59
|
+
"""Use SUPERVAIZER_SERVER_ID from env if set; else create uuid and set env."""
|
|
60
|
+
existing = os.getenv("SUPERVAIZER_SERVER_ID")
|
|
61
|
+
if existing:
|
|
62
|
+
return existing
|
|
63
|
+
new_id = str(uuid.uuid4())
|
|
64
|
+
os.environ["SUPERVAIZER_SERVER_ID"] = new_id
|
|
65
|
+
return new_id
|
|
66
|
+
|
|
67
|
+
|
|
56
68
|
class ServerInfo(BaseModel):
|
|
57
69
|
"""Complete server information for storage."""
|
|
58
70
|
|
|
@@ -76,21 +88,20 @@ def save_server_info_to_storage(server_instance: "Server") -> None:
|
|
|
76
88
|
agents = []
|
|
77
89
|
if hasattr(server_instance, "agents") and server_instance.agents:
|
|
78
90
|
for agent in server_instance.agents:
|
|
79
|
-
agents.append(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
)
|
|
91
|
+
agents.append({
|
|
92
|
+
"name": agent.name,
|
|
93
|
+
"description": agent.description,
|
|
94
|
+
"version": agent.version,
|
|
95
|
+
"api_path": agent.path,
|
|
96
|
+
"slug": agent.slug,
|
|
97
|
+
"instructions_path": agent.instructions_path,
|
|
98
|
+
})
|
|
89
99
|
|
|
90
100
|
# Create server info
|
|
91
101
|
server_info = ServerInfo(
|
|
92
|
-
|
|
93
|
-
|
|
102
|
+
id=getattr(server_instance, "server_id", "N/A"),
|
|
103
|
+
host=getattr(server_instance, "host", "N/A"),
|
|
104
|
+
port=getattr(server_instance, "port", "N/A"),
|
|
94
105
|
api_version=API_VERSION,
|
|
95
106
|
environment=os.getenv("SUPERVAIZER_ENVIRONMENT", "development"),
|
|
96
107
|
agents=agents,
|
|
@@ -148,6 +159,10 @@ class ServerAbstract(SvBaseModel):
|
|
|
148
159
|
"""
|
|
149
160
|
|
|
150
161
|
supervaizer_VERSION: ClassVar[str] = VERSION
|
|
162
|
+
server_id: str = Field(
|
|
163
|
+
default_factory=_get_or_create_server_id,
|
|
164
|
+
description="Unique server id (SUPERVAIZER_SERVER_ID env or persisted uuid)",
|
|
165
|
+
)
|
|
151
166
|
scheme: str = Field(description="URL scheme (http or https)")
|
|
152
167
|
host: str = Field(
|
|
153
168
|
description="Host to bind the server to (e.g., 0.0.0.0 for all interfaces)"
|
|
@@ -354,6 +369,8 @@ class Server(ServerAbstract):
|
|
|
354
369
|
**kwargs,
|
|
355
370
|
)
|
|
356
371
|
|
|
372
|
+
log.info(f"[Server launch] Server ID: {self.server_id}")
|
|
373
|
+
|
|
357
374
|
# Create routes
|
|
358
375
|
if self.supervisor_account:
|
|
359
376
|
log.info(
|
|
@@ -377,6 +394,26 @@ class Server(ServerAbstract):
|
|
|
377
394
|
# Save server info to storage for admin interface
|
|
378
395
|
save_server_info_to_storage(self)
|
|
379
396
|
|
|
397
|
+
# Home page (template in admin/templates)
|
|
398
|
+
_home_templates = Jinja2Templates(
|
|
399
|
+
directory=str(Path(__file__).parent / "admin" / "templates")
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
@self.app.get("/", response_class=HTMLResponse)
|
|
403
|
+
async def home_page(request: Request) -> HTMLResponse:
|
|
404
|
+
base = self.public_url or f"{self.scheme}://{self.host}:{self.port}"
|
|
405
|
+
return _home_templates.TemplateResponse(
|
|
406
|
+
"index.html",
|
|
407
|
+
{
|
|
408
|
+
"request": request,
|
|
409
|
+
"base": base,
|
|
410
|
+
"version": VERSION,
|
|
411
|
+
"api_version": API_VERSION,
|
|
412
|
+
"show_admin": bool(self.api_key and admin_interface),
|
|
413
|
+
"server_id": self.server_id,
|
|
414
|
+
},
|
|
415
|
+
)
|
|
416
|
+
|
|
380
417
|
# Load running entities from storage into memory
|
|
381
418
|
try:
|
|
382
419
|
load_running_entities_on_startup()
|
|
@@ -444,6 +481,7 @@ class Server(ServerAbstract):
|
|
|
444
481
|
"""Get registration info for the server."""
|
|
445
482
|
assert self.public_key is not None, "Public key not initialized"
|
|
446
483
|
return {
|
|
484
|
+
"server_id": self.server_id,
|
|
447
485
|
"url": self.public_url,
|
|
448
486
|
"uri": self.uri,
|
|
449
487
|
"api_version": API_VERSION,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
supervaizer/__init__.py,sha256=
|
|
2
|
-
supervaizer/__version__.py,sha256=
|
|
3
|
-
supervaizer/account.py,sha256
|
|
4
|
-
supervaizer/account_service.py,sha256=
|
|
5
|
-
supervaizer/agent.py,sha256=
|
|
1
|
+
supervaizer/__init__.py,sha256=UNFcgJT-2708tLRFXohWr3320LVAzh3_WZZhrU9j1Iw,2427
|
|
2
|
+
supervaizer/__version__.py,sha256=Oe_Vfg1WOw027ZNCTKD35vUMGykGwCa00Szf8CAsyS8,349
|
|
3
|
+
supervaizer/account.py,sha256=POChw9c2ZjBNvesz6JmvBzYmMD40M5oxtz5IupuMqsw,11683
|
|
4
|
+
supervaizer/account_service.py,sha256=ZgZ0fhsbSVA076c-35ZZoYJBrQZsAwfFS7namVeoD3s,3459
|
|
5
|
+
supervaizer/agent.py,sha256=EtmqBH9fsO4k8YcHnjj55_4uOmb5URZwLlIIJReWg7A,36516
|
|
6
6
|
supervaizer/case.py,sha256=dOgRujyf4MFcZ-937zxJbqLIPduKg6ZspHuhnWiq13Q,14385
|
|
7
7
|
supervaizer/cli.py,sha256=3KH4gZXTiJ9GtY375kGm5HaKCGV2V8WEbcWdF_sWWEc,13936
|
|
8
8
|
supervaizer/common.py,sha256=6ygNS1YxliP-e6OEVX7vDuC8YAaT2rYhjqQ_8txnWlg,10066
|
|
@@ -13,11 +13,12 @@ supervaizer/job_service.py,sha256=22Qe7Z5_u3R28tcNH_21YMIYciWFtJaM7I-MXtIhBMU,46
|
|
|
13
13
|
supervaizer/lifecycle.py,sha256=5CunJN7MsM5blyNiFMJMLFDUBmTmmAsPE24QC-gSbYA,13958
|
|
14
14
|
supervaizer/parameter.py,sha256=sYDuGof_w6mlix0oxjB6odV0sO0QSBL1KwFZa3Y2cOA,8157
|
|
15
15
|
supervaizer/routes.py,sha256=o3u7pGGLE0MQzWtQNdd5xk1M0G9Y_BR_JiLVmCFtdC4,34319
|
|
16
|
-
supervaizer/server.py,sha256=
|
|
16
|
+
supervaizer/server.py,sha256=JLavzhd8PVTDtqfupaHGnshnY5GCi5rxTC4ThGcml9M,22270
|
|
17
17
|
supervaizer/server_utils.py,sha256=FMglpADQBJynkR2v-pfwANu6obsaPvR9j0BQc5Otpac,1590
|
|
18
18
|
supervaizer/storage.py,sha256=WLX8ggwt1AGF07DrfD1K6PyP2-N45c_Ep4CL0iPLVbI,15332
|
|
19
19
|
supervaizer/telemetry.py,sha256=XSYw8ZwoY8W6C7mhwHU67t7trJzWd7CBkkSNdsDT_HA,2596
|
|
20
|
-
supervaizer/admin/routes.py,sha256=
|
|
20
|
+
supervaizer/admin/routes.py,sha256=utXv4Agn9Cz9V6IG8XCKSJnRPK4qi7Ge7Ti9ZUlSB4w,47694
|
|
21
|
+
supervaizer/admin/static/favicon.ico,sha256=wFyXw96AplZoEcW45dJBeC1pHTcPSH07HGWbtrc49mI,5558
|
|
21
22
|
supervaizer/admin/static/js/job-start-form.js,sha256=s--AGVYzgc9mE20POYeM0BNm0Wy41aBZVv99tc0cSPU,11938
|
|
22
23
|
supervaizer/admin/templates/agent_detail.html,sha256=DFOGfjuQNC39FOLYUW_jD0A01WpBY1umatGCslyJ0_c,7581
|
|
23
24
|
supervaizer/admin/templates/agents.html,sha256=orB_z1iMFE2MKhFm9XejwZjmzMC1PVT69oB-F9YZPHQ,12678
|
|
@@ -28,17 +29,18 @@ supervaizer/admin/templates/cases_list.html,sha256=UV4SfULzxNiOpG8aNddablpwf6hVN
|
|
|
28
29
|
supervaizer/admin/templates/cases_table.html,sha256=VyL5mEF003FTNHym1UYBD8JkvhA9wR328ciTKNKxdb8,6619
|
|
29
30
|
supervaizer/admin/templates/console.html,sha256=tLGGf8vHjGK77Il6SYlgparoU_xz3nbvNpGVQRkVNCc,13966
|
|
30
31
|
supervaizer/admin/templates/dashboard.html,sha256=3Pu5bR78QUcPNp5MyXkyibfp-wxYdJyyf77v3O_f_hU,7873
|
|
32
|
+
supervaizer/admin/templates/index.html,sha256=3MFAQ53gptvUgBBfzQoCLOFLAd7JYOV5Ak4NEPsU1f4,2500
|
|
31
33
|
supervaizer/admin/templates/job_detail.html,sha256=LDTMWLURyVCp7SMTxQ4M8AFqNpbbUVUx253negp9JNA,10790
|
|
32
34
|
supervaizer/admin/templates/job_start_test.html,sha256=eAogAit0JfuMU4N5YR7N03w0nD_Bi9mtiX8uJ7dHLPg,4270
|
|
33
35
|
supervaizer/admin/templates/jobs_list.html,sha256=VJ2VYe62dHXvjQQgUAVyKcn58rO5919UuP3VKgxLVhM,9136
|
|
34
36
|
supervaizer/admin/templates/jobs_table.html,sha256=BCOI_7QlxJ5XOra7WKou48a2lNwQYASCMFTtgzHNotw,5974
|
|
35
37
|
supervaizer/admin/templates/navigation.html,sha256=Ci_CMLqBuIKRt3JCFtn9Vjz1AAkqC75WMT6IQUiByFI,11724
|
|
36
38
|
supervaizer/admin/templates/recent_activity.html,sha256=hL06GXF1a-C_tkj3pRLrDTTDqG0KplcWMZFengFMuEc,4843
|
|
37
|
-
supervaizer/admin/templates/server.html,sha256=
|
|
39
|
+
supervaizer/admin/templates/server.html,sha256=CScvNTNdc0Wi2entmzZHSnqrBjqIOZUsbQrWD58pBYM,8527
|
|
38
40
|
supervaizer/admin/templates/server_status_cards.html,sha256=yJ36hkfgQpscYkiaodFDQPnmJWeb2W7gey09Z3T6JsY,7882
|
|
39
41
|
supervaizer/admin/templates/supervaize_instructions.html,sha256=LTLla1xgIeLpFf7bond_lxH5qdQQ2ak52Fd7hqChi1I,10225
|
|
40
42
|
supervaizer/deploy/__init__.py,sha256=DvngGQu8tS_Yz5FU4kKCvPpod11IGCtZWkUNeB5aVHI,557
|
|
41
|
-
supervaizer/deploy/cli.py,sha256=
|
|
43
|
+
supervaizer/deploy/cli.py,sha256=6najlZXh_3kSY_sfJdilf-iW5BqaudI2bKKrhzXN09A,10201
|
|
42
44
|
supervaizer/deploy/docker.py,sha256=FLMKHOnbnjMFTcULdRdgwKJwT-q8JtVwbN1iSemh21w,13810
|
|
43
45
|
supervaizer/deploy/driver_factory.py,sha256=Qm6DYVUfV3mlRHUglk5YlslGg6JYZ754uKeoiyxXw10,1487
|
|
44
46
|
supervaizer/deploy/health.py,sha256=vh4SMOxy43QXi1fanQjWfWqoGTy_z1VXwwfy4Fq2bHg,13764
|
|
@@ -61,7 +63,8 @@ supervaizer/deploy/templates/debug_env.py,sha256=WFlxfiCAlkxM1NybNvtmmG5zJnoSvjW
|
|
|
61
63
|
supervaizer/deploy/templates/docker-compose.yml.template,sha256=ZcW8WyhmqMElaxBpokuZG12n0tFJL8BY7k7Tvdz6tdw,1100
|
|
62
64
|
supervaizer/deploy/templates/dockerignore.template,sha256=bYFRn6QGsjtRDH-Y7vzWk3-u3jIp90FajV2Ed94ah5M,515
|
|
63
65
|
supervaizer/deploy/templates/entrypoint.sh,sha256=z079VUotu6DJX92fJiBB3eVwCEgcP6B9D9Fvwv_FL9w,463
|
|
64
|
-
supervaizer/
|
|
66
|
+
supervaizer/deploy/templates/index.html,sha256=z2ocEOYbWbl1Rz3Toc5JZkN7OAoW_GFV1yKKhdyC3vw,2160
|
|
67
|
+
supervaizer/examples/controller_template.py,sha256=bQRtZdq9Z8Pg0b3bRy4oVy6YIIM_e5DzhXVPOr1gFvk,6337
|
|
65
68
|
supervaizer/protocol/__init__.py,sha256=00GHbUsLNsf0a1rQrUPpVN2Uy-7rDz72Ps6TUVD91tE,389
|
|
66
69
|
supervaizer/protocol/a2a/__init__.py,sha256=1ACfPGLzS6XdZPiFxn1nVamvbasqtJJ7U1BBbSmT-nI,625
|
|
67
70
|
supervaizer/protocol/a2a/model.py,sha256=sWzatlA_fcva_fdtM8Yh4cioRq0KbwV5AXpNCnsOtQo,7198
|
|
@@ -69,8 +72,8 @@ supervaizer/protocol/a2a/routes.py,sha256=rkQTNBD1NTYimKCb8iOk4bVf9ldDP1LqHfOsyh
|
|
|
69
72
|
supervaizer/utils/__init__.py,sha256=fd0NFwN_cen3QPms2SOnuz4jcetay3f_31dit2As7EA,458
|
|
70
73
|
supervaizer/utils/version_check.py,sha256=-tsOURpHVh0LNTbpQsyJDJENKszC-NzXDSO_EToEQPE,1893
|
|
71
74
|
supervaizer/py.typed,sha256=bHhvLx7c6MqrzXVPbdK3qAOcSxzp4wDtTx4QifMC2EY,74
|
|
72
|
-
supervaizer-0.10.
|
|
73
|
-
supervaizer-0.10.
|
|
74
|
-
supervaizer-0.10.
|
|
75
|
-
supervaizer-0.10.
|
|
76
|
-
supervaizer-0.10.
|
|
75
|
+
supervaizer-0.10.15.dist-info/METADATA,sha256=-c3Opx2tY7d8zsKm14IRFJFE3ELjquXaPEFGYrGHhtQ,12648
|
|
76
|
+
supervaizer-0.10.15.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
77
|
+
supervaizer-0.10.15.dist-info/entry_points.txt,sha256=vL_IBR_AeEI2u2-6YL4PY9k2Mar4-gprG8-UxERWjmg,52
|
|
78
|
+
supervaizer-0.10.15.dist-info/licenses/LICENSE.md,sha256=dmdnt1vfpxNPr8Lt0BnxKE5uzUwK3CWTthTUStgOXjY,15327
|
|
79
|
+
supervaizer-0.10.15.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|