from __future__ import annotations import logging from typing import Optional from fastapi import APIRouter, HTTPException, status from pydantic import BaseModel logger = logging.getLogger(__name__) router = APIRouter(prefix='/registry', tags=['registry']) class AgentInfo(BaseModel): name: str domain: str active: bool backend: str = 'ollama' last_seen: Optional[str] = None class BackendOverride(BaseModel): agent_name: str backend: str # ollama | claude set_by: str note: Optional[str] = None @router.get('/agents', response_model=list[AgentInfo]) async def list_agents(): from ..app_state import get_agent_registry, get_llm_router registry = get_agent_registry() llm_router = get_llm_router() if registry is None: raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail='Registry not ready') agents = await registry.get_all() result = [] for agent in agents: backend = 'ollama' if llm_router: try: backend = await llm_router.get_backend(agent['name']) except Exception: pass result.append(AgentInfo( name=agent['name'], domain=agent.get('domain', ''), active=agent.get('active', True), backend=backend, last_seen=agent.get('last_seen'), )) return result @router.post('/sync', status_code=status.HTTP_200_OK) async def sync_registry(): from ..app_state import get_agent_registry registry = get_agent_registry() if registry is None: raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail='Registry not ready') try: count = await registry.sync() return {'synced': count} except Exception as exc: logger.error('registry sync failed: %s', exc) raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc)) @router.post('/backend', status_code=status.HTTP_200_OK) async def set_backend_override(req: BackendOverride): from ..app_state import get_llm_router llm_router = get_llm_router() if llm_router is None: raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail='LLM router not ready') if req.backend not in ('ollama', 'claude'): raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='backend must be ollama or claude') try: await llm_router.set_backend_override( caller=req.agent_name, backend=req.backend, set_by=req.set_by, note=req.note, ) return {'agent': req.agent_name, 'backend': req.backend} except Exception as exc: logger.error('set_backend_override failed: %s', exc) raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc)) @router.delete('/backend/{agent_name}', status_code=status.HTTP_200_OK) async def reset_backend_override(agent_name: str): from ..app_state import get_llm_router llm_router = get_llm_router() if llm_router is None: raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail='LLM router not ready') try: await llm_router.reset_backend_override(caller=agent_name) return {'agent': agent_name, 'reset': True} except Exception as exc: raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc))