supervaizer 0.10.16__tar.gz → 0.10.18__tar.gz
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-0.10.16 → supervaizer-0.10.18}/PKG-INFO +1 -1
- {supervaizer-0.10.16 → supervaizer-0.10.18}/pyproject.toml +1 -1
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/__version__.py +1 -1
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/routes.py +74 -65
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/base.html +5 -2
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/index.html +7 -2
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/server.html +3 -10
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/templates/index.html +2 -2
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/examples/controller_template.py +22 -20
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/server.py +72 -13
- {supervaizer-0.10.16 → supervaizer-0.10.18}/.gitignore +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/LICENSE.md +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/README.md +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/__init__.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/account.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/account_service.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/static/favicon.ico +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/static/js/job-start-form.js +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/agent_detail.html +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/agents.html +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/agents_grid.html +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/case_detail.html +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/cases_list.html +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/cases_table.html +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/console.html +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/dashboard.html +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/job_detail.html +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/job_start_test.html +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/jobs_list.html +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/jobs_table.html +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/navigation.html +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/recent_activity.html +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/server_status_cards.html +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/supervaize_instructions.html +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/agent.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/case.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/cli.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/common.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/__init__.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/cli.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/commands/__init__.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/commands/clean.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/commands/down.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/commands/local.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/commands/plan.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/commands/status.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/commands/up.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/docker.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/driver_factory.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/drivers/__init__.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/drivers/aws_app_runner.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/drivers/base.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/drivers/cloud_run.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/drivers/do_app_platform.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/health.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/state.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/templates/Dockerfile.template +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/templates/debug_env.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/templates/docker-compose.yml.template +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/templates/dockerignore.template +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/templates/entrypoint.sh +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/utils.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/event.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/instructions.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/job.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/job_service.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/lifecycle.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/parameter.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/protocol/__init__.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/protocol/a2a/__init__.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/protocol/a2a/model.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/protocol/a2a/routes.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/py.typed +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/routes.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/server_utils.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/storage.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/telemetry.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/utils/__init__.py +0 -0
- {supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/utils/version_check.py +0 -0
|
@@ -20,7 +20,7 @@ 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,
|
|
23
|
+
from fastapi import APIRouter, HTTPException, Query, Request, Security
|
|
24
24
|
from fastapi.responses import HTMLResponse, JSONResponse, Response
|
|
25
25
|
from fastapi.security import APIKeyHeader
|
|
26
26
|
from fastapi.templating import Jinja2Templates
|
|
@@ -168,12 +168,26 @@ def format_uptime(seconds: int) -> str:
|
|
|
168
168
|
return f"{minutes}m"
|
|
169
169
|
|
|
170
170
|
|
|
171
|
-
def
|
|
172
|
-
"""Get
|
|
173
|
-
|
|
174
|
-
|
|
171
|
+
def _get_server_info(request: Optional[Request]) -> Optional[Any]:
|
|
172
|
+
"""Get server info from storage, or from live server (app.state.server) when no persistence."""
|
|
173
|
+
from supervaizer.server import (
|
|
174
|
+
get_server_info_from_live,
|
|
175
|
+
get_server_info_from_storage,
|
|
176
|
+
)
|
|
175
177
|
|
|
176
178
|
server_info = get_server_info_from_storage()
|
|
179
|
+
if server_info is not None:
|
|
180
|
+
return server_info
|
|
181
|
+
if request is not None:
|
|
182
|
+
live = getattr(request.app.state, "server", None)
|
|
183
|
+
if live is not None:
|
|
184
|
+
return get_server_info_from_live(live)
|
|
185
|
+
return None
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def get_server_status(request: Optional[Request] = None) -> ServerStatus:
|
|
189
|
+
"""Get current server status and metrics."""
|
|
190
|
+
server_info = _get_server_info(request)
|
|
177
191
|
if not server_info:
|
|
178
192
|
raise HTTPException(
|
|
179
193
|
status_code=503,
|
|
@@ -217,12 +231,11 @@ def get_server_status() -> ServerStatus:
|
|
|
217
231
|
)
|
|
218
232
|
|
|
219
233
|
|
|
220
|
-
def get_server_configuration(
|
|
234
|
+
def get_server_configuration(
|
|
235
|
+
storage: StorageManager, request: Optional[Request] = None
|
|
236
|
+
) -> ServerConfiguration:
|
|
221
237
|
"""Get server configuration details."""
|
|
222
|
-
|
|
223
|
-
from supervaizer.server import get_server_info_from_storage
|
|
224
|
-
|
|
225
|
-
server_info = get_server_info_from_storage()
|
|
238
|
+
server_info = _get_server_info(request)
|
|
226
239
|
if not server_info:
|
|
227
240
|
raise HTTPException(
|
|
228
241
|
status_code=503,
|
|
@@ -304,9 +317,9 @@ def create_admin_routes() -> APIRouter:
|
|
|
304
317
|
async def admin_server_page(request: Request) -> Response:
|
|
305
318
|
"""Server status and configuration page."""
|
|
306
319
|
try:
|
|
307
|
-
# Get initial server data
|
|
308
|
-
server_status = get_server_status()
|
|
309
|
-
server_config = get_server_configuration(storage)
|
|
320
|
+
# Get initial server data (from storage or live when no persistence)
|
|
321
|
+
server_status = get_server_status(request)
|
|
322
|
+
server_config = get_server_configuration(storage, request)
|
|
310
323
|
|
|
311
324
|
return templates.TemplateResponse(
|
|
312
325
|
request,
|
|
@@ -327,9 +340,7 @@ def create_admin_routes() -> APIRouter:
|
|
|
327
340
|
async def admin_agents_page(request: Request) -> Response:
|
|
328
341
|
"""Agents management page."""
|
|
329
342
|
try:
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
server_info = get_server_info_from_storage()
|
|
343
|
+
server_info = _get_server_info(request)
|
|
333
344
|
if not server_info:
|
|
334
345
|
raise HTTPException(
|
|
335
346
|
status_code=503, detail="Server information not available"
|
|
@@ -400,7 +411,7 @@ def create_admin_routes() -> APIRouter:
|
|
|
400
411
|
async def get_server_status_api(request: Request) -> Response:
|
|
401
412
|
"""Get current server status for HTMX refresh."""
|
|
402
413
|
try:
|
|
403
|
-
server_status = get_server_status()
|
|
414
|
+
server_status = get_server_status(request)
|
|
404
415
|
|
|
405
416
|
return templates.TemplateResponse(
|
|
406
417
|
request,
|
|
@@ -415,24 +426,22 @@ def create_admin_routes() -> APIRouter:
|
|
|
415
426
|
raise HTTPException(status_code=500, detail=str(e))
|
|
416
427
|
|
|
417
428
|
@router.post("/api/server/register")
|
|
418
|
-
async def register_server_with_supervisor(
|
|
419
|
-
|
|
420
|
-
_: bool = Depends(verify_admin_access),
|
|
421
|
-
) -> JSONResponse:
|
|
422
|
-
"""Trigger SERVER_REGISTER to the supervaizer supervisor."""
|
|
429
|
+
async def register_server_with_supervisor(request: Request) -> JSONResponse:
|
|
430
|
+
"""Trigger SERVER_REGISTER to the supervaizer supervisor (no frontend API key; backend sends to SUPERVAIZE_API_URL)."""
|
|
423
431
|
try:
|
|
424
432
|
from supervaizer.common import ApiSuccess
|
|
425
433
|
from supervaizer.routes import get_server
|
|
426
434
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
435
|
+
# Prefer app.state.server (set at launch), else dependency override
|
|
436
|
+
server = getattr(request.app.state, "server", None)
|
|
437
|
+
if server is None:
|
|
438
|
+
get_current = request.app.dependency_overrides.get(get_server)
|
|
439
|
+
if get_current is not None:
|
|
440
|
+
try:
|
|
441
|
+
server = await get_current()
|
|
442
|
+
except (NotImplementedError, TypeError):
|
|
443
|
+
pass
|
|
444
|
+
if server is None:
|
|
436
445
|
raise HTTPException(
|
|
437
446
|
status_code=503,
|
|
438
447
|
detail="Server instance not available (admin not running with live server)",
|
|
@@ -477,9 +486,7 @@ def create_admin_routes() -> APIRouter:
|
|
|
477
486
|
) -> Response:
|
|
478
487
|
"""Get agents with filtering for HTMX refresh."""
|
|
479
488
|
try:
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
server_info = get_server_info_from_storage()
|
|
489
|
+
server_info = _get_server_info(request)
|
|
483
490
|
if not server_info:
|
|
484
491
|
raise HTTPException(
|
|
485
492
|
status_code=503, detail="Server information not available"
|
|
@@ -548,9 +555,7 @@ def create_admin_routes() -> APIRouter:
|
|
|
548
555
|
) -> Response:
|
|
549
556
|
"""Get detailed agent information."""
|
|
550
557
|
try:
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
server_info = get_server_info_from_storage()
|
|
558
|
+
server_info = _get_server_info(request)
|
|
554
559
|
if not server_info:
|
|
555
560
|
raise HTTPException(
|
|
556
561
|
status_code=503, detail="Server information not available"
|
|
@@ -926,24 +931,28 @@ def create_admin_routes() -> APIRouter:
|
|
|
926
931
|
# Combine and sort by created_at
|
|
927
932
|
activities = []
|
|
928
933
|
for job in recent_jobs:
|
|
929
|
-
activities.append(
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
934
|
+
activities.append(
|
|
935
|
+
{
|
|
936
|
+
"type": "job",
|
|
937
|
+
"id": job.get("id"),
|
|
938
|
+
"name": job.get("name"),
|
|
939
|
+
"status": job.get("status"),
|
|
940
|
+
"created_at": job.get("created_at"),
|
|
941
|
+
"agent_name": job.get("agent_name"),
|
|
942
|
+
}
|
|
943
|
+
)
|
|
937
944
|
|
|
938
945
|
for case in recent_cases:
|
|
939
|
-
activities.append(
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
946
|
+
activities.append(
|
|
947
|
+
{
|
|
948
|
+
"type": "case",
|
|
949
|
+
"id": case.get("id"),
|
|
950
|
+
"name": case.get("name"),
|
|
951
|
+
"status": case.get("status"),
|
|
952
|
+
"created_at": case.get("created_at"),
|
|
953
|
+
"job_id": case.get("job_id"),
|
|
954
|
+
}
|
|
955
|
+
)
|
|
947
956
|
|
|
948
957
|
# Sort by created_at descending
|
|
949
958
|
activities.sort(key=lambda x: str(x.get("created_at", "")), reverse=True)
|
|
@@ -1200,23 +1209,23 @@ def get_dashboard_stats(storage: StorageManager) -> AdminStats:
|
|
|
1200
1209
|
|
|
1201
1210
|
# Calculate job stats
|
|
1202
1211
|
job_total = len(all_jobs)
|
|
1203
|
-
job_running = len(
|
|
1204
|
-
j for j in all_jobs if j.get("status") in ["in_progress", "awaiting"]
|
|
1205
|
-
|
|
1212
|
+
job_running = len(
|
|
1213
|
+
[j for j in all_jobs if j.get("status") in ["in_progress", "awaiting"]]
|
|
1214
|
+
)
|
|
1206
1215
|
job_completed = len([j for j in all_jobs if j.get("status") == "completed"])
|
|
1207
|
-
job_failed = len(
|
|
1208
|
-
j for j in all_jobs if j.get("status") in ["failed", "cancelled"]
|
|
1209
|
-
|
|
1216
|
+
job_failed = len(
|
|
1217
|
+
[j for j in all_jobs if j.get("status") in ["failed", "cancelled"]]
|
|
1218
|
+
)
|
|
1210
1219
|
|
|
1211
1220
|
# Calculate case stats
|
|
1212
1221
|
case_total = len(all_cases)
|
|
1213
|
-
case_running = len(
|
|
1214
|
-
c for c in all_cases if c.get("status") in ["in_progress", "awaiting"]
|
|
1215
|
-
|
|
1222
|
+
case_running = len(
|
|
1223
|
+
[c for c in all_cases if c.get("status") in ["in_progress", "awaiting"]]
|
|
1224
|
+
)
|
|
1216
1225
|
case_completed = len([c for c in all_cases if c.get("status") == "completed"])
|
|
1217
|
-
case_failed = len(
|
|
1218
|
-
c for c in all_cases if c.get("status") in ["failed", "cancelled"]
|
|
1219
|
-
|
|
1226
|
+
case_failed = len(
|
|
1227
|
+
[c for c in all_cases if c.get("status") in ["failed", "cancelled"]]
|
|
1228
|
+
)
|
|
1220
1229
|
|
|
1221
1230
|
# TinyDB collections count (tables)
|
|
1222
1231
|
collections_count = len(storage._db.tables())
|
|
@@ -35,11 +35,14 @@
|
|
|
35
35
|
// Persist admin API key from URL so it survives navigation (e.g. Register with supervisor)
|
|
36
36
|
(function() {
|
|
37
37
|
var m = /[?&]key=([^&]+)/.exec(window.location.search);
|
|
38
|
-
if (m) try {
|
|
38
|
+
if (m) try {
|
|
39
|
+
var k = decodeURIComponent(m[1]);
|
|
40
|
+
if (k !== 'None' && k !== 'undefined') sessionStorage.setItem('admin_api_key', k);
|
|
41
|
+
} catch (e) {}
|
|
39
42
|
})();
|
|
40
43
|
</script>
|
|
41
44
|
</head>
|
|
42
|
-
<body class="bg-gray-50 min-h-screen">
|
|
45
|
+
<body class="bg-gray-50 min-h-screen" data-admin-key="{{ (api_key or '')|e }}">
|
|
43
46
|
<!-- Navigation -->
|
|
44
47
|
{% include "navigation.html" %}
|
|
45
48
|
|
|
@@ -18,6 +18,11 @@
|
|
|
18
18
|
</p>
|
|
19
19
|
<p class="mt-1 text-xs text-gray-400 font-mono">Server ID: {{ server_id }}</p>
|
|
20
20
|
|
|
21
|
+
<div class="mt-6 p-4 rounded-lg bg-amber-50 border border-amber-200 text-amber-800">
|
|
22
|
+
<p class="font-semibold">⚠️ Do not use in production with network access enabled.</p>
|
|
23
|
+
<p class="mt-1 text-sm">This interface is for development and local use only. Exposing it over the network in production may allow unauthorized access.</p>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
21
26
|
<div class="mt-8">
|
|
22
27
|
<h2 class="text-lg font-medium text-gray-900 mb-4">Links</h2>
|
|
23
28
|
<ul class="space-y-2">
|
|
@@ -36,14 +41,14 @@
|
|
|
36
41
|
OpenAPI
|
|
37
42
|
</a>
|
|
38
43
|
</li>
|
|
39
|
-
<li><strong>BASE:</strong> {{ base }}
|
|
44
|
+
<li><strong>BASE:</strong> {{ base }}
|
|
40
45
|
<br>
|
|
41
46
|
<strong>PUBLIC_URL:</strong> {{ public_url }}
|
|
42
47
|
<br>
|
|
43
48
|
<strong>FULL_URL:</strong> {{ full_url }}
|
|
44
49
|
<br>
|
|
45
50
|
</li>
|
|
46
|
-
|
|
51
|
+
|
|
47
52
|
{% if show_admin %}
|
|
48
53
|
<li>
|
|
49
54
|
<a href="{{ base }}/admin" class="text-blue-600 hover:text-blue-800 font-medium">
|
|
@@ -109,20 +109,17 @@
|
|
|
109
109
|
}
|
|
110
110
|
}, 30000);
|
|
111
111
|
|
|
112
|
-
// Register with supervisor button
|
|
112
|
+
// Register with supervisor button — no API key; backend sends SERVER_REGISTER to SUPERVAIZE_API_URL
|
|
113
113
|
const registerBtn = document.getElementById('register-supervisor-btn');
|
|
114
114
|
const registerIndicator = document.getElementById('register-indicator');
|
|
115
115
|
const registerResult = document.getElementById('register-result');
|
|
116
116
|
if (registerBtn) {
|
|
117
117
|
registerBtn.addEventListener('click', async function() {
|
|
118
|
-
const params = new URLSearchParams(window.location.search);
|
|
119
|
-
const key = params.get('key') || (function() { try { return sessionStorage.getItem('admin_api_key'); } catch (e) { return null; } })();
|
|
120
|
-
const url = key ? '/admin/api/server/register?key=' + encodeURIComponent(key) : '/admin/api/server/register';
|
|
121
118
|
registerResult.classList.add('hidden');
|
|
122
119
|
registerIndicator.classList.remove('htmx-indicator');
|
|
123
120
|
registerBtn.disabled = true;
|
|
124
121
|
try {
|
|
125
|
-
const res = await fetch(
|
|
122
|
+
const res = await fetch('/admin/api/server/register', { method: 'POST' });
|
|
126
123
|
const data = await res.json().catch(function() { return {}; });
|
|
127
124
|
registerResult.classList.remove('hidden');
|
|
128
125
|
if (res.ok && data.success) {
|
|
@@ -130,11 +127,7 @@
|
|
|
130
127
|
registerResult.textContent = data.message || 'Registered successfully.';
|
|
131
128
|
} else {
|
|
132
129
|
registerResult.className = 'mt-2 text-sm text-red-700';
|
|
133
|
-
|
|
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
|
-
}
|
|
130
|
+
registerResult.textContent = (data.detail && typeof data.detail === 'object' && data.detail.message) ? data.detail.message : (data.message || data.detail || 'Registration failed.');
|
|
138
131
|
}
|
|
139
132
|
} catch (e) {
|
|
140
133
|
registerResult.classList.remove('hidden');
|
|
@@ -34,26 +34,28 @@ 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
|
-
|
|
37
|
+
agent_parameters: ParametersSetup | None = ParametersSetup.from_list(
|
|
38
|
+
[
|
|
39
|
+
Parameter(
|
|
40
|
+
name="OPEN_API_KEY",
|
|
41
|
+
description="OpenAPI Key",
|
|
42
|
+
is_environment=True,
|
|
43
|
+
is_secret=True,
|
|
44
|
+
),
|
|
45
|
+
Parameter(
|
|
46
|
+
name="SERPER_API",
|
|
47
|
+
description="Server API key updated",
|
|
48
|
+
is_environment=True,
|
|
49
|
+
is_secret=True,
|
|
50
|
+
),
|
|
51
|
+
Parameter(
|
|
52
|
+
name="COMPETITOR_SUMMARY_URL",
|
|
53
|
+
description="Competitor Summary URL",
|
|
54
|
+
is_environment=True,
|
|
55
|
+
is_secret=False,
|
|
56
|
+
),
|
|
57
|
+
]
|
|
58
|
+
)
|
|
57
59
|
|
|
58
60
|
# Define the method used to start a job
|
|
59
61
|
job_start_method: AgentMethod = AgentMethod(
|
|
@@ -65,6 +65,35 @@ def _get_or_create_server_id() -> str:
|
|
|
65
65
|
return new_id
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
def _get_or_create_private_key() -> RSAPrivateKey:
|
|
69
|
+
"""Use SUPERVAIZER_PRIVATE_KEY from env if set; else create key and set env."""
|
|
70
|
+
pem = os.getenv("SUPERVAIZER_PRIVATE_KEY")
|
|
71
|
+
if pem:
|
|
72
|
+
try:
|
|
73
|
+
return serialization.load_pem_private_key(
|
|
74
|
+
pem.encode("utf-8"),
|
|
75
|
+
password=None,
|
|
76
|
+
backend=default_backend(),
|
|
77
|
+
)
|
|
78
|
+
except Exception as e:
|
|
79
|
+
log.warning(
|
|
80
|
+
f"[Server] Invalid SUPERVAIZER_PRIVATE_KEY, generating new key: {e}"
|
|
81
|
+
)
|
|
82
|
+
private_key = rsa.generate_private_key(
|
|
83
|
+
public_exponent=65537,
|
|
84
|
+
key_size=2048,
|
|
85
|
+
backend=default_backend(),
|
|
86
|
+
)
|
|
87
|
+
pem_bytes = private_key.private_bytes(
|
|
88
|
+
encoding=serialization.Encoding.PEM,
|
|
89
|
+
format=serialization.PrivateFormat.PKCS8,
|
|
90
|
+
encryption_algorithm=serialization.NoEncryption(),
|
|
91
|
+
)
|
|
92
|
+
os.environ["SUPERVAIZER_PRIVATE_KEY"] = pem_bytes.decode("utf-8")
|
|
93
|
+
log.info("[Server] Generated new RSA private key and set SUPERVAIZER_PRIVATE_KEY")
|
|
94
|
+
return private_key
|
|
95
|
+
|
|
96
|
+
|
|
68
97
|
class ServerInfo(BaseModel):
|
|
69
98
|
"""Complete server information for storage."""
|
|
70
99
|
|
|
@@ -88,14 +117,16 @@ def save_server_info_to_storage(server_instance: "Server") -> None:
|
|
|
88
117
|
agents = []
|
|
89
118
|
if hasattr(server_instance, "agents") and server_instance.agents:
|
|
90
119
|
for agent in server_instance.agents:
|
|
91
|
-
agents.append(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
120
|
+
agents.append(
|
|
121
|
+
{
|
|
122
|
+
"name": agent.name,
|
|
123
|
+
"description": agent.description,
|
|
124
|
+
"version": agent.version,
|
|
125
|
+
"api_path": agent.path,
|
|
126
|
+
"slug": agent.slug,
|
|
127
|
+
"instructions_path": agent.instructions_path,
|
|
128
|
+
}
|
|
129
|
+
)
|
|
99
130
|
|
|
100
131
|
# Create server info
|
|
101
132
|
server_info = ServerInfo(
|
|
@@ -131,6 +162,34 @@ def get_server_info_from_storage() -> Optional[ServerInfo]:
|
|
|
131
162
|
return None
|
|
132
163
|
|
|
133
164
|
|
|
165
|
+
def get_server_info_from_live(server_instance: "Server") -> ServerInfo:
|
|
166
|
+
"""Build ServerInfo from a live Server instance (for when storage has no ServerInfo, e.g. no persistence)."""
|
|
167
|
+
agents = []
|
|
168
|
+
if hasattr(server_instance, "agents") and server_instance.agents:
|
|
169
|
+
for agent in server_instance.agents:
|
|
170
|
+
agents.append(
|
|
171
|
+
{
|
|
172
|
+
"name": agent.name,
|
|
173
|
+
"description": agent.description,
|
|
174
|
+
"version": agent.version,
|
|
175
|
+
"api_path": agent.path,
|
|
176
|
+
"slug": agent.slug,
|
|
177
|
+
"instructions_path": agent.instructions_path,
|
|
178
|
+
}
|
|
179
|
+
)
|
|
180
|
+
start_time = getattr(server_instance, "_start_time", time.time())
|
|
181
|
+
return ServerInfo(
|
|
182
|
+
host=getattr(server_instance, "host", "N/A"),
|
|
183
|
+
port=getattr(server_instance, "port", 0),
|
|
184
|
+
api_version=API_VERSION,
|
|
185
|
+
environment=os.getenv("SUPERVAIZER_ENVIRONMENT", "development"),
|
|
186
|
+
agents=agents,
|
|
187
|
+
start_time=start_time,
|
|
188
|
+
created_at=datetime.now().isoformat(),
|
|
189
|
+
updated_at=datetime.now().isoformat(),
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
|
|
134
193
|
class ServerAbstract(SvBaseModel):
|
|
135
194
|
"""
|
|
136
195
|
API Server for the Supervaize Controller.
|
|
@@ -291,11 +350,7 @@ class Server(ServerAbstract):
|
|
|
291
350
|
)
|
|
292
351
|
|
|
293
352
|
if private_key is None:
|
|
294
|
-
private_key =
|
|
295
|
-
public_exponent=65537,
|
|
296
|
-
key_size=2048,
|
|
297
|
-
backend=default_backend(),
|
|
298
|
-
)
|
|
353
|
+
private_key = _get_or_create_private_key()
|
|
299
354
|
|
|
300
355
|
public_key = private_key.public_key()
|
|
301
356
|
|
|
@@ -428,6 +483,10 @@ class Server(ServerAbstract):
|
|
|
428
483
|
# Update the dependency
|
|
429
484
|
self.app.dependency_overrides[get_server] = get_current_server
|
|
430
485
|
|
|
486
|
+
# Expose live server for admin when storage has no ServerInfo (e.g. no persistence)
|
|
487
|
+
self._start_time = time.time()
|
|
488
|
+
self.app.state.server = self
|
|
489
|
+
|
|
431
490
|
if api_key:
|
|
432
491
|
log.info("[Server launch] API Key authentication enabled")
|
|
433
492
|
# Print the API key if it was generated
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/static/js/job-start-form.js
RENAMED
|
File without changes
|
{supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/agent_detail.html
RENAMED
|
File without changes
|
|
File without changes
|
{supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/agents_grid.html
RENAMED
|
File without changes
|
{supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/case_detail.html
RENAMED
|
File without changes
|
|
File without changes
|
{supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/cases_table.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/job_start_test.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/recent_activity.html
RENAMED
|
File without changes
|
{supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/admin/templates/server_status_cards.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/drivers/aws_app_runner.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/drivers/do_app_platform.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/templates/Dockerfile.template
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supervaizer-0.10.16 → supervaizer-0.10.18}/src/supervaizer/deploy/templates/dockerignore.template
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|