feat: initialisation Hermes Hub — interface multi-univers securisee (FastAPI, proxy async, design tokens)
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
# Routers module
|
||||
@@ -0,0 +1,95 @@
|
||||
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)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
from fastapi import APIRouter, Request, HTTPException
|
||||
from app.config import UNIVERSES
|
||||
from app.proxy import proxy_request
|
||||
|
||||
router = APIRouter(prefix="/u", tags=["Universe Proxy"])
|
||||
|
||||
@router.api_route("/{universe_id}", methods=["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"])
|
||||
@router.api_route("/{universe_id}/", methods=["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"])
|
||||
@router.api_route("/{universe_id}/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"])
|
||||
async def dynamic_universe_proxy(universe_id: str, request: Request, path: str = ""):
|
||||
if universe_id not in UNIVERSES:
|
||||
raise HTTPException(status_code=404, detail=f"Universe '{universe_id}' not found.")
|
||||
|
||||
universe = UNIVERSES[universe_id]
|
||||
return await proxy_request(
|
||||
request=request,
|
||||
backend_url=universe.backend_url,
|
||||
path=path
|
||||
)
|
||||
Reference in New Issue
Block a user