""" OpenRouter Chat Endpoints for SAAP Frontend Separate endpoints for OpenRouter-specific chat functionality """ from fastapi import APIRouter, HTTPException, Depends from typing import Dict, Any import logging import os from datetime import datetime from services.agent_manager import AgentManagerService from agents.openrouter_saap_agent import OpenRouterSAAPAgent logger = logging.getLogger(__name__) # Create router for OpenRouter endpoints openrouter_router = APIRouter(prefix="/api/v1/agents", tags=["OpenRouter"]) def get_agent_manager() -> AgentManagerService: """Dependency injection for agent manager""" from main import saap_app if not saap_app.agent_manager: raise HTTPException(status_code=503, detail="Agent Manager not initialized") return saap_app.agent_manager @openrouter_router.post("/{agent_id}/chat/openrouter") async def chat_with_agent_via_openrouter( agent_id: str, message_data: Dict[str, Any], agent_manager: AgentManagerService = Depends(get_agent_manager) ): """ 🚀 NEW: Chat with agent using OpenRouter (Fast, Cost-efficient) Endpoint: POST /api/v1/agents/{agent_id}/chat/openrouter """ try: message = message_data.get("message", "") if not message: raise HTTPException(status_code=400, detail="Message content required") logger.info(f"🌐 OpenRouter Chat request: {agent_id} - {message[:50]}...") # Get agent from manager agent = agent_manager.get_agent(agent_id) if not agent: raise HTTPException(status_code=404, detail=f"Agent '{agent_id}' not found") # Get OpenRouter API key from environment api_key = os.getenv("OPENROUTER_API_KEY") if not api_key: raise HTTPException( status_code=500, detail="OpenRouter API key not configured" ) # Create OpenRouter agent openrouter_agent = OpenRouterSAAPAgent( agent_id, agent.type.value if agent.type else "Assistant", api_key ) # Get agent-specific model configuration model_map = { "jane_alesi": os.getenv("JANE_ALESI_MODEL", "openai/gpt-4o-mini"), "john_alesi": os.getenv("JOHN_ALESI_MODEL", "deepseek/deepseek-coder"), "lara_alesi": os.getenv("LARA_ALESI_MODEL", "anthropic/claude-3-haiku") } preferred_model = model_map.get(agent_id, "openai/gpt-4o-mini") openrouter_agent.model_name = preferred_model # Send request to OpenRouter response = await openrouter_agent.send_request_to_openrouter( message, max_tokens=1000 ) if response.get("success"): logger.info(f"✅ OpenRouter chat successful: {agent_id}") return { "success": True, "agent_id": agent_id, "provider": "OpenRouter", "model": preferred_model, "message": message, "response": { "content": response.get("response", ""), "provider": f"OpenRouter ({preferred_model})", "response_time": response.get("response_time", 0), "tokens_used": response.get("token_count", 0), "cost_estimate": response.get("cost_estimate", 0.0) }, "timestamp": datetime.utcnow().isoformat() } else: logger.error(f"❌ OpenRouter chat failed: {response.get('error')}") return { "success": False, "agent_id": agent_id, "provider": "OpenRouter", "error": response.get("error", "Unknown OpenRouter error"), "timestamp": datetime.utcnow().isoformat() } except HTTPException: raise except Exception as e: logger.error(f"❌ OpenRouter endpoint error: {e}") return { "success": False, "agent_id": agent_id, "provider": "OpenRouter", "error": f"OpenRouter endpoint error: {str(e)}", "timestamp": datetime.utcnow().isoformat() } @openrouter_router.post("/{agent_id}/chat/compare") async def compare_providers( agent_id: str, message_data: Dict[str, Any], agent_manager: AgentManagerService = Depends(get_agent_manager) ): """ 🆚 Compare colossus vs OpenRouter performance side-by-side """ try: message = message_data.get("message", "") if not message: raise HTTPException(status_code=400, detail="Message content required") logger.info(f"🆚 Provider comparison request: {agent_id}") # Send to both providers concurrently import asyncio # Colossus request async def colossus_request(): try: return await agent_manager.send_message_to_agent(agent_id, message) except Exception as e: return {"error": f"colossus error: {str(e)}", "provider": "colossus"} # OpenRouter request async def openrouter_request(): try: agent = agent_manager.get_agent(agent_id) if not agent: return {"error": "Agent not found", "provider": "OpenRouter"} api_key = os.getenv("OPENROUTER_API_KEY") if not api_key: return {"error": "API key not configured", "provider": "OpenRouter"} openrouter_agent = OpenRouterSAAPAgent(agent_id, "Assistant", api_key) response = await openrouter_agent.send_request_to_openrouter(message) return { "provider": "OpenRouter", "content": response.get("response", ""), "response_time": response.get("response_time", 0), "success": response.get("success", False), "error": response.get("error") if not response.get("success") else None } except Exception as e: return {"error": f"OpenRouter error: {str(e)}", "provider": "OpenRouter"} # Run both concurrently with timeout colossus_result, openrouter_result = await asyncio.gather( colossus_request(), openrouter_request(), return_exceptions=True ) return { "success": True, "comparison": { "colossus": colossus_result, "openrouter": openrouter_result, "performance_winner": ( "OpenRouter" if ( openrouter_result.get("response_time", float('inf')) < colossus_result.get("response_time", float('inf')) ) else "colossus" ) }, "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)}") @openrouter_router.get("/{agent_id}/openrouter/status") async def openrouter_status(agent_id: str): """ â„šī¸ Get OpenRouter availability status for specific agent """ try: api_key = os.getenv("OPENROUTER_API_KEY") if not api_key: return { "available": False, "error": "OpenRouter API key not configured", "timestamp": datetime.utcnow().isoformat() } # Test OpenRouter connection test_agent = OpenRouterSAAPAgent(agent_id, "Test", api_key) health = await test_agent.health_check() return { "available": health["status"] == "healthy", "model": test_agent.model_name, "response_time": health.get("response_time"), "error": health.get("error"), "timestamp": datetime.utcnow().isoformat() } except Exception as e: return { "available": False, "error": str(e), "timestamp": datetime.utcnow().isoformat() }