Files
hermes-hub/app/routers/api.py
T

96 lines
3.3 KiB
Python

from fastapi import APIRouter, HTTPException, Depends, Body
from typing import Dict, Any, List, Optional
import asyncio
from app.config import UNIVERSES, UniverseConfig, get_universe
from app.personas import load_persona, save_persona, clone_persona, list_clones
from app.proxy import check_backend_health
router = APIRouter(prefix="/api", tags=["Hub Management"])
@router.get("/universes")
async def list_universes():
"""
Returns the list of universes with live connectivity status and persona summaries.
"""
results = []
# Run health checks concurrently
health_tasks = [check_backend_health(u.backend_url) for u in UNIVERSES.values()]
health_results = await asyncio.gather(*health_tasks, return_exceptions=True)
for (u_id, u_cfg), health in zip(UNIVERSES.items(), health_results):
persona = load_persona(u_id)
health_data = health if isinstance(health, dict) else {"status": "error", "error": str(health)}
results.append({
"id": u_cfg.id,
"name": u_cfg.name,
"tagline": u_cfg.tagline,
"description": u_cfg.description,
"scope": u_cfg.scope,
"accent_token": u_cfg.accent_token,
"icon": u_cfg.icon,
"backend_url": u_cfg.backend_url,
"health": health_data,
"persona": {
"tone": persona.get("tone", ""),
"style": persona.get("style", ""),
"principles_count": len(persona.get("principles", [])),
"version": persona.get("version", 1),
"updated_at": persona.get("updated_at", "")
}
})
return results
@router.get("/universes/{universe_id}")
async def get_universe_details(universe_id: str):
if universe_id not in UNIVERSES:
raise HTTPException(status_code=404, detail="Universe not found")
u_cfg = UNIVERSES[universe_id]
health = await check_backend_health(u_cfg.backend_url)
persona = load_persona(universe_id)
return {
"config": u_cfg.dict(),
"health": health,
"persona": persona
}
@router.get("/universes/{universe_id}/persona")
async def get_universe_persona(universe_id: str):
if universe_id not in UNIVERSES:
raise HTTPException(status_code=404, detail="Universe not found")
return load_persona(universe_id)
@router.put("/universes/{universe_id}/persona")
async def update_universe_persona(universe_id: str, data: Dict[str, Any] = Body(...)):
if universe_id not in UNIVERSES:
raise HTTPException(status_code=404, detail="Universe not found")
save_persona(universe_id, data)
return {"status": "saved", "persona": load_persona(universe_id)}
@router.post("/universes/{universe_id}/clone")
async def clone_universe_profile(
universe_id: str,
clone_name: str = Body(..., embed=True),
overrides: Optional[Dict[str, Any]] = Body(None, embed=True)
):
if universe_id not in UNIVERSES:
raise HTTPException(status_code=404, detail="Universe not found")
cloned = clone_persona(universe_id, clone_name, overrides)
return {"status": "cloned", "clone": cloned}
@router.get("/clones")
async def get_clones():
return list_clones()
@router.get("/health")
async def hub_health():
return {
"status": "healthy",
"universes_configured": len(UNIVERSES)
}