saap-deployment / backend /api /hybrid_endpoints.py
Hwandji's picture
feat: initial HuggingFace Space deployment
4343907
"""
Hybrid API Endpoints for SAAP OpenRouter Integration
Additional endpoints to support multi-provider functionality
"""
from fastapi import APIRouter, HTTPException, Depends
from typing import Dict, Optional, Any
import logging
from datetime import datetime
from services.agent_manager_hybrid import HybridAgentManagerService
logger = logging.getLogger(__name__)
# Router for hybrid endpoints
hybrid_router = APIRouter(prefix="/api/v1/hybrid", tags=["hybrid"])
def get_hybrid_manager() -> HybridAgentManagerService:
"""Dependency to get hybrid agent manager (if available)"""
# This will be injected by main.py if hybrid mode is enabled
return None
# =====================================================
# PROVIDER COMPARISON & PERFORMANCE ENDPOINTS
# =====================================================
@hybrid_router.post("/agents/{agent_id}/compare")
async def compare_providers(
agent_id: str,
message_data: Dict[str, str],
hybrid_manager: HybridAgentManagerService = Depends(get_hybrid_manager)
):
"""
πŸ†š Send same message to both colossus and OpenRouter for comparison
Useful for benchmarking performance and cost analysis
"""
if not hybrid_manager:
raise HTTPException(status_code=503, detail="Hybrid mode not enabled")
try:
message = message_data.get("message", "")
if not message:
raise HTTPException(status_code=400, detail="Message content required")
logger.info(f"πŸ“Š Provider comparison requested for {agent_id}")
# Send to both providers
comparison = await hybrid_manager.compare_providers(agent_id, message)
if "error" in comparison:
return {
"success": False,
"error": comparison["error"],
"timestamp": datetime.utcnow().isoformat()
}
logger.info(f"βœ… Provider comparison completed for {agent_id}")
return {
"success": True,
"comparison": comparison,
"timestamp": datetime.utcnow().isoformat()
}
except Exception as e:
logger.error(f"❌ Provider comparison error: {e}")
raise HTTPException(status_code=500, detail=f"Comparison failed: {str(e)}")
@hybrid_router.get("/stats/providers")
async def get_provider_statistics(
hybrid_manager: HybridAgentManagerService = Depends(get_hybrid_manager)
):
"""
πŸ“Š Get comprehensive provider performance statistics
Returns success rates, response times, and cost data
"""
if not hybrid_manager:
raise HTTPException(status_code=503, detail="Hybrid mode not enabled")
try:
stats = hybrid_manager.get_provider_stats()
return {
"success": True,
"statistics": stats,
"timestamp": datetime.utcnow().isoformat()
}
except Exception as e:
logger.error(f"❌ Provider stats error: {e}")
raise HTTPException(status_code=500, detail=f"Statistics failed: {str(e)}")
@hybrid_router.get("/costs/openrouter")
async def get_openrouter_costs(
hybrid_manager: HybridAgentManagerService = Depends(get_hybrid_manager)
):
"""
πŸ’° Get OpenRouter cost summary and budget status
"""
if not hybrid_manager:
raise HTTPException(status_code=503, detail="Hybrid mode not enabled")
if not hybrid_manager.openrouter_client:
raise HTTPException(status_code=503, detail="OpenRouter client not available")
try:
cost_summary = hybrid_manager.openrouter_client.get_cost_summary()
return {
"success": True,
"costs": cost_summary,
"timestamp": datetime.utcnow().isoformat()
}
except Exception as e:
logger.error(f"❌ OpenRouter cost error: {e}")
raise HTTPException(status_code=500, detail=f"Cost summary failed: {str(e)}")
# =====================================================
# PROVIDER SWITCHING & CONFIGURATION
# =====================================================
@hybrid_router.post("/config/primary-provider")
async def set_primary_provider(
config_data: Dict[str, str],
hybrid_manager: HybridAgentManagerService = Depends(get_hybrid_manager)
):
"""
πŸ”„ Switch primary provider (colossus/openrouter)
"""
if not hybrid_manager:
raise HTTPException(status_code=503, detail="Hybrid mode not enabled")
try:
provider = config_data.get("provider", "")
if provider not in ["colossus", "openrouter"]:
raise HTTPException(status_code=400, detail="Provider must be 'colossus' or 'openrouter'")
success = await hybrid_manager.set_primary_provider(provider)
if success:
return {
"success": True,
"message": f"Primary provider set to {provider}",
"provider": provider,
"timestamp": datetime.utcnow().isoformat()
}
else:
raise HTTPException(status_code=400, detail=f"Failed to switch to {provider}")
except HTTPException:
raise
except Exception as e:
logger.error(f"❌ Provider switch error: {e}")
raise HTTPException(status_code=500, detail=f"Provider switch failed: {str(e)}")
@hybrid_router.get("/config/status")
async def get_hybrid_status(
hybrid_manager: HybridAgentManagerService = Depends(get_hybrid_manager)
):
"""
ℹ️ Get hybrid system configuration and status
"""
if not hybrid_manager:
return {
"hybrid_enabled": False,
"message": "Hybrid mode not available",
"timestamp": datetime.utcnow().isoformat()
}
try:
# Check provider availability
providers_status = {
"colossus": {
"available": hybrid_manager.colossus_client is not None,
"status": hybrid_manager.colossus_connection_status if hasattr(hybrid_manager, 'colossus_connection_status') else "unknown"
},
"openrouter": {
"available": hybrid_manager.openrouter_client is not None,
"status": "unknown"
}
}
# Test OpenRouter if available
if hybrid_manager.openrouter_client:
try:
or_health = await hybrid_manager.openrouter_client.health_check()
providers_status["openrouter"]["status"] = or_health.get("status", "unknown")
providers_status["openrouter"]["daily_cost"] = or_health.get("daily_cost", 0)
providers_status["openrouter"]["budget_remaining"] = or_health.get("budget_remaining", 0)
except Exception as e:
providers_status["openrouter"]["status"] = f"error: {e}"
return {
"hybrid_enabled": True,
"primary_provider": hybrid_manager.primary_provider,
"failover_enabled": hybrid_manager.enable_failover,
"cost_comparison_enabled": hybrid_manager.enable_cost_comparison,
"providers": providers_status,
"loaded_agents": len(hybrid_manager.agents),
"timestamp": datetime.utcnow().isoformat()
}
except Exception as e:
logger.error(f"❌ Hybrid status error: {e}")
raise HTTPException(status_code=500, detail=f"Status check failed: {str(e)}")
# =====================================================
# OPTIONAL: DIRECT PROVIDER ENDPOINTS
# =====================================================
@hybrid_router.post("/agents/{agent_id}/chat/colossus")
async def chat_with_colossus(
agent_id: str,
message_data: Dict[str, str],
hybrid_manager: HybridAgentManagerService = Depends(get_hybrid_manager)
):
"""
πŸ€– Direct chat with agent via colossus (bypass primary provider setting)
"""
if not hybrid_manager:
raise HTTPException(status_code=503, detail="Hybrid mode not enabled")
try:
message = message_data.get("message", "")
if not message:
raise HTTPException(status_code=400, detail="Message content required")
# Force colossus provider
response = await hybrid_manager.send_message_to_agent(agent_id, message, "colossus")
if "error" in response:
return {
"success": False,
"error": response["error"],
"provider": "colossus",
"timestamp": datetime.utcnow().isoformat()
}
return {
"success": True,
"agent_id": agent_id,
"message": message,
"response": response,
"provider": "colossus",
"timestamp": datetime.utcnow().isoformat()
}
except Exception as e:
logger.error(f"❌ colossus chat error: {e}")
raise HTTPException(status_code=500, detail=f"colossus chat failed: {str(e)}")
@hybrid_router.post("/agents/{agent_id}/chat/openrouter")
async def chat_with_openrouter(
agent_id: str,
message_data: Dict[str, str],
hybrid_manager: HybridAgentManagerService = Depends(get_hybrid_manager)
):
"""
🌐 Direct chat with agent via OpenRouter (bypass primary provider setting)
"""
if not hybrid_manager:
raise HTTPException(status_code=503, detail="Hybrid mode not enabled")
if not hybrid_manager.openrouter_client:
raise HTTPException(status_code=503, detail="OpenRouter client not available")
try:
message = message_data.get("message", "")
if not message:
raise HTTPException(status_code=400, detail="Message content required")
# Force OpenRouter provider
response = await hybrid_manager.send_message_to_agent(agent_id, message, "openrouter")
if "error" in response:
return {
"success": False,
"error": response["error"],
"provider": "openrouter",
"timestamp": datetime.utcnow().isoformat()
}
return {
"success": True,
"agent_id": agent_id,
"message": message,
"response": response,
"provider": "openrouter",
"timestamp": datetime.utcnow().isoformat()
}
except Exception as e:
logger.error(f"❌ OpenRouter chat error: {e}")
raise HTTPException(status_code=500, detail=f"OpenRouter chat failed: {str(e)}")
# =====================================================
# HEALTH CHECK FOR HYBRID SYSTEM
# =====================================================
@hybrid_router.get("/health")
async def hybrid_health_check(
hybrid_manager: HybridAgentManagerService = Depends(get_hybrid_manager)
):
"""
πŸ₯ Comprehensive health check for hybrid system
"""
if not hybrid_manager:
return {
"status": "hybrid_disabled",
"message": "Hybrid mode not enabled - using standard mode",
"timestamp": datetime.utcnow().isoformat()
}
try:
health_status = {
"status": "healthy",
"providers": {},
"agents_loaded": len(hybrid_manager.agents),
"primary_provider": hybrid_manager.primary_provider,
"timestamp": datetime.utcnow().isoformat()
}
# Check colossus
if hybrid_manager.colossus_client:
try:
# Test colossus connection if method available
if hasattr(hybrid_manager, '_test_colossus_connection'):
await hybrid_manager._test_colossus_connection()
health_status["providers"]["colossus"] = {
"status": getattr(hybrid_manager, 'colossus_connection_status', 'unknown'),
"available": True
}
except Exception as e:
health_status["providers"]["colossus"] = {
"status": f"error: {e}",
"available": False
}
else:
health_status["providers"]["colossus"] = {
"status": "not_configured",
"available": False
}
# Check OpenRouter
if hybrid_manager.openrouter_client:
try:
or_health = await hybrid_manager.openrouter_client.health_check()
health_status["providers"]["openrouter"] = {
"status": or_health.get("status", "unknown"),
"available": or_health.get("status") == "healthy",
"daily_cost": or_health.get("daily_cost", 0),
"budget_remaining": or_health.get("budget_remaining", 0)
}
except Exception as e:
health_status["providers"]["openrouter"] = {
"status": f"error: {e}",
"available": False
}
else:
health_status["providers"]["openrouter"] = {
"status": "not_configured",
"available": False
}
# Overall health status
provider_count = sum(1 for p in health_status["providers"].values() if p["available"])
if provider_count == 0:
health_status["status"] = "unhealthy"
health_status["message"] = "No providers available"
elif provider_count == 1:
health_status["status"] = "degraded"
health_status["message"] = "Only one provider available"
else:
health_status["status"] = "healthy"
health_status["message"] = "All providers operational"
return health_status
except Exception as e:
logger.error(f"❌ Hybrid health check error: {e}")
return {
"status": "error",
"error": str(e),
"timestamp": datetime.utcnow().isoformat()
}
# Export router for main.py integration
__all__ = ["hybrid_router", "get_hybrid_manager"]