220 lines
5.7 KiB
Python
220 lines
5.7 KiB
Python
"""
|
|
AI Metrics Proxy Controller
|
|
|
|
Provides proxy endpoints to Core-AI service metrics.
|
|
Allows external access to AI performance stats via core-api.
|
|
"""
|
|
from fastapi import APIRouter, HTTPException
|
|
from typing import Dict, List, Any
|
|
from src.clients.ai_client import get_ai_client
|
|
from src.logging_config import get_logger
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
# Create router
|
|
router = APIRouter(
|
|
prefix="/ai",
|
|
tags=["AI Metrics"]
|
|
)
|
|
|
|
|
|
@router.get(
|
|
"/health",
|
|
summary="Check Core-AI service health",
|
|
description="Verify that the Core-AI service is accessible and responding"
|
|
)
|
|
async def ai_health_check():
|
|
"""
|
|
Check if Core-AI service is healthy
|
|
|
|
Returns:
|
|
Health status and availability
|
|
"""
|
|
try:
|
|
ai_client = get_ai_client()
|
|
is_healthy = await ai_client.health_check()
|
|
|
|
return {
|
|
"service": "core-ai",
|
|
"status": "healthy" if is_healthy else "unhealthy",
|
|
"accessible": is_healthy
|
|
}
|
|
|
|
except Exception as e:
|
|
logger.error(f"AI health check failed: {e}")
|
|
return {
|
|
"service": "core-ai",
|
|
"status": "error",
|
|
"accessible": False,
|
|
"error": str(e)
|
|
}
|
|
|
|
|
|
@router.get(
|
|
"/metrics",
|
|
response_model=Dict[str, Any],
|
|
summary="Get comprehensive AI performance metrics",
|
|
description="Returns detailed metrics including agent performance, tool execution stats, memory system metrics, and user activity"
|
|
)
|
|
async def get_ai_metrics():
|
|
"""
|
|
Proxy endpoint for Core-AI metrics
|
|
|
|
Returns comprehensive AI performance data:
|
|
- Agent request statistics (total, by type, response times)
|
|
- Response time percentiles (p50, p95, p99)
|
|
- Tool execution metrics (calls, success rates, durations)
|
|
- Memory system statistics (cache hits, consolidations)
|
|
- User activity tracking
|
|
- Concurrency metrics
|
|
|
|
Returns:
|
|
Dict with all collected metrics
|
|
|
|
Raises:
|
|
HTTPException: If Core-AI is unreachable or returns error
|
|
"""
|
|
try:
|
|
ai_client = get_ai_client()
|
|
metrics = await ai_client.get_metrics()
|
|
return metrics
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to fetch AI metrics: {e}")
|
|
raise HTTPException(
|
|
status_code=503,
|
|
detail=f"Core-AI service unavailable: {str(e)}"
|
|
)
|
|
|
|
|
|
@router.get(
|
|
"/metrics/errors",
|
|
response_model=Dict[str, Any],
|
|
summary="Get recent request errors",
|
|
description="Returns recent AI agent request errors with timestamps and details"
|
|
)
|
|
async def get_ai_errors(limit: int = 20):
|
|
"""
|
|
Get recent AI request errors
|
|
|
|
Args:
|
|
limit: Maximum number of errors to return (default: 20)
|
|
|
|
Returns:
|
|
Dict with error list and total count
|
|
|
|
Example response:
|
|
{
|
|
"errors": [
|
|
{
|
|
"timestamp": "2025-12-03T19:45:12Z",
|
|
"agent_type": "pydantic",
|
|
"error": "Connection timeout",
|
|
"duration_ms": 5000
|
|
}
|
|
],
|
|
"total": 1
|
|
}
|
|
"""
|
|
try:
|
|
ai_client = get_ai_client()
|
|
errors = await ai_client.get_recent_errors(limit=limit)
|
|
|
|
return {
|
|
"errors": errors,
|
|
"total": len(errors)
|
|
}
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to fetch AI errors: {e}")
|
|
raise HTTPException(
|
|
status_code=503,
|
|
detail=f"Core-AI service unavailable: {str(e)}"
|
|
)
|
|
|
|
|
|
@router.get(
|
|
"/metrics/tool-failures",
|
|
response_model=Dict[str, Any],
|
|
summary="Get recent tool execution failures",
|
|
description="Returns recent tool execution failures with error details"
|
|
)
|
|
async def get_ai_tool_failures(limit: int = 20):
|
|
"""
|
|
Get recent tool execution failures
|
|
|
|
Args:
|
|
limit: Maximum number of failures to return (default: 20)
|
|
|
|
Returns:
|
|
Dict with failure list and total count
|
|
|
|
Example response:
|
|
{
|
|
"failures": [
|
|
{
|
|
"timestamp": "2025-12-03T19:50:30Z",
|
|
"tool_name": "list_containers",
|
|
"error": "Connection refused",
|
|
"duration_ms": 150
|
|
}
|
|
],
|
|
"total": 1
|
|
}
|
|
"""
|
|
try:
|
|
ai_client = get_ai_client()
|
|
failures = await ai_client.get_tool_failures(limit=limit)
|
|
|
|
return {
|
|
"failures": failures,
|
|
"total": len(failures)
|
|
}
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to fetch tool failures: {e}")
|
|
raise HTTPException(
|
|
status_code=503,
|
|
detail=f"Core-AI service unavailable: {str(e)}"
|
|
)
|
|
|
|
|
|
@router.post(
|
|
"/metrics/reset",
|
|
summary="Reset all AI metrics (admin)",
|
|
description="Clear all collected metrics. This is an administrative operation that resets all counters and history."
|
|
)
|
|
async def reset_ai_metrics():
|
|
"""
|
|
Reset all AI metrics (admin operation)
|
|
|
|
Clears all collected metrics including:
|
|
- Request history
|
|
- Tool execution stats
|
|
- Memory system metrics
|
|
- Error logs
|
|
|
|
Returns:
|
|
Success confirmation
|
|
|
|
Note:
|
|
This is an administrative operation that should be used carefully.
|
|
All historical data will be lost.
|
|
"""
|
|
try:
|
|
ai_client = get_ai_client()
|
|
await ai_client.reset_metrics()
|
|
|
|
logger.info("AI metrics reset successfully")
|
|
return {
|
|
"success": True,
|
|
"message": "AI metrics reset successfully"
|
|
}
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to reset AI metrics: {e}")
|
|
raise HTTPException(
|
|
status_code=503,
|
|
detail=f"Core-AI service unavailable: {str(e)}"
|
|
)
|