from fastapi import APIRouter, Depends from .auth_guard import require_role, AuthRole from pydantic import BaseModel from typing import List, Dict, Optional, Any import time router = APIRouter(prefix="/api/marketplace", tags=["marketplace"], dependencies=[Depends(require_role(AuthRole.MACHINE))]) class WorkerCapability(BaseModel): id: str name: str version: str = "1.0.0" description: Optional[str] = None status: str = "online" last_seen: int = 0 # SLA & Metrics cost: float = 0.0 # Costo per operazione o unitario latency: float = 0.0 # Latenza media in ms region: str = "global" # Regione geografica gpu: bool = False # Disponibilità GPU priority: int = 10 # Priorità (più basso = più prioritario) # Lista di capacità supportate (es. ["browser", "shell", "vision"]) capabilities: List[str] = [] metadata: Dict[str, Any] = {} WORKERS_REGISTRY: Dict[str, WorkerCapability] = {} @router.get("/workers", response_model=List[WorkerCapability]) async def list_workers(): return list(WORKERS_REGISTRY.values()) @router.post("/register") async def register_worker(worker: WorkerCapability): worker.last_seen = int(time.time()) WORKERS_REGISTRY[worker.id] = worker return {"status": "registered", "id": worker.id, "capabilities": worker.capabilities} @router.get("/capabilities") async def get_all_capabilities(): """Ritorna l'elenco consolidato delle capacità disponibili da tutti i worker attivi.""" caps = {} now = int(time.time()) for w in WORKERS_REGISTRY.values(): if now - w.last_seen < 300: # Worker attivo negli ultimi 5 minuti for cap in w.capabilities: if cap not in caps: caps[cap] = [] caps[cap].append({ "worker_id": w.id, "version": w.version, "cost": w.cost, "latency": w.latency, "region": w.region }) return caps @router.post("/resolve") async def resolve_capability(capability: str, constraints: Optional[Dict[str, Any]] = None): """ ARCH-E3.2: Capability Resolver Endpoint per risolvere una capability in un Worker specifico. """ from .resolver import resolver, ResolverConstraints c = ResolverConstraints(**constraints) if constraints else None worker = await resolver.resolve(capability, c) if not worker: return {"status": "error", "message": f"No worker found for capability: {capability}"} return {"status": "resolved", "worker": worker}