"""Platform dashboard & analytics (I-DASH, I-COST, I-USE). Provides aggregated metrics for: - Agent status, workflow stats, search metrics, knowledge coverage - LLM cost tracking per agent/workflow/user, budget alerts - Feature usage, search queries, agent runs, workflow executions - Proactive suggestions accepted/rejected """ from __future__ import annotations import logging import uuid from datetime import UTC, datetime, timedelta from typing import Any from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession logger = logging.getLogger(__name__) # ─── I-DASH: Platform Dashboard ───────────────────────────────────────────── async def get_platform_dashboard( db: AsyncSession, tenant_id: uuid.UUID, ) -> dict[str, Any]: """Get aggregated platform metrics for the dashboard (I-DASH). Returns: Agent status, workflow stats, search metrics, knowledge coverage, workstream metrics, system health. """ dashboard: dict[str, Any] = { "agents": {}, "workflows": {}, "search": {}, "knowledge": {}, "workstream": {}, "system_health": {}, "generated_at": datetime.now(UTC).isoformat(), } # Agent metrics try: from app.models.workflow import AgentDefinition, AgentRun active_agents = await db.scalar( select(func.count(AgentDefinition.id)).where( AgentDefinition.tenant_id == tenant_id, AgentDefinition.is_active == True, # noqa: E712 ) ) total_runs = await db.scalar( select(func.count(AgentRun.id)).where( AgentRun.tenant_id == tenant_id, ) ) recent_runs = await db.scalar( select(func.count(AgentRun.id)).where( AgentRun.tenant_id == tenant_id, AgentRun.created_at >= datetime.now(UTC) - timedelta(days=7), ) ) dashboard["agents"] = { "active_agents": active_agents or 0, "total_runs": total_runs or 0, "recent_runs_7d": recent_runs or 0, } except Exception as e: logger.warning("Dashboard agent metrics failed: %s", e) dashboard["agents"] = {"error": str(e)} # Workflow metrics try: from app.models.workflow import WorkflowDefinition, WorkflowInstance active_workflows = await db.scalar( select(func.count(WorkflowDefinition.id)).where( WorkflowDefinition.tenant_id == tenant_id, WorkflowDefinition.is_active == True, # noqa: E712 ) ) running_instances = await db.scalar( select(func.count(WorkflowInstance.id)).where( WorkflowInstance.tenant_id == tenant_id, WorkflowInstance.status.in_(["pending", "running", "waiting"]), ) ) completed_instances = await db.scalar( select(func.count(WorkflowInstance.id)).where( WorkflowInstance.tenant_id == tenant_id, WorkflowInstance.status == "completed", ) ) dashboard["workflows"] = { "active_workflows": active_workflows or 0, "running_instances": running_instances or 0, "completed_instances": completed_instances or 0, } except Exception as e: logger.warning("Dashboard workflow metrics failed: %s", e) dashboard["workflows"] = {"error": str(e)} # Knowledge metrics try: from app.plugins.builtins.wiki.models import WikiArticle wiki_articles = await db.scalar( select(func.count(WikiArticle.id)).where( WikiArticle.tenant_id == tenant_id, WikiArticle.deleted_at.is_(None), ) ) dashboard["knowledge"] = { "wiki_articles": wiki_articles or 0, } except Exception as e: logger.warning("Dashboard knowledge metrics failed: %s", e) dashboard["knowledge"] = {"error": str(e)} # System health (from Redis check) try: from app.core.redis import get_redis redis = await get_redis() if redis: await redis.ping() dashboard["system_health"] = {"redis": "up", "status": "healthy"} else: dashboard["system_health"] = {"redis": "down", "status": "degraded"} except Exception as e: dashboard["system_health"] = {"redis": "error", "status": "degraded", "error": str(e)} return dashboard # ─── I-COST: Cost Tracking Dashboard ───────────────────────────────────────── async def get_cost_dashboard( db: AsyncSession, tenant_id: uuid.UUID, days: int = 30, ) -> dict[str, Any]: """Get LLM cost tracking metrics (I-COST). Returns: Live costs, budget utilization, alert history, cost per tenant/agent/workflow, hard-stop events. """ since = datetime.now(UTC) - timedelta(days=days) cost_data: dict[str, Any] = { "period_days": days, "total_cost_usd": 0.0, "by_agent": {}, "by_workflow": {}, "by_user": {}, "daily_trend": [], "budget": {}, "alerts": [], "generated_at": datetime.now(UTC).isoformat(), } # Aggregate costs from AgentRun try: from app.models.workflow import AgentRun # Total cost total_cost = await db.scalar( select(func.sum(AgentRun.total_cost_usd)).where( AgentRun.tenant_id == tenant_id, AgentRun.created_at >= since, ) ) cost_data["total_cost_usd"] = float(total_cost or 0.0) # Cost by agent agent_costs = await db.execute( select( AgentRun.agent_id, func.sum(AgentRun.total_cost_usd).label("cost"), func.count(AgentRun.id).label("runs"), ) .where( AgentRun.tenant_id == tenant_id, AgentRun.created_at >= since, ) .group_by(AgentRun.agent_id) ) for row in agent_costs: cost_data["by_agent"][str(row.agent_id)] = { "cost_usd": float(row.cost or 0.0), "runs": row.runs, } except Exception as e: logger.warning("Cost dashboard failed: %s", e) cost_data["error"] = str(e) # Budget info from config try: from app.config import get_settings settings = get_settings() monthly_budget = getattr(settings, "llm_monthly_budget_usd", None) if monthly_budget: cost_data["budget"] = { "monthly_limit_usd": monthly_budget, "utilization_pct": (cost_data["total_cost_usd"] / monthly_budget) * 100, } except Exception: pass return cost_data # ─── I-USE: Usage & Collaboration Analytics ───────────────────────────────── async def get_usage_analytics( db: AsyncSession, tenant_id: uuid.UUID, days: int = 30, ) -> dict[str, Any]: """Get feature usage and collaboration analytics (I-USE). Returns: Feature usage, search queries, agent runs, workflow executions, proactive suggestions accepted/rejected. """ since = datetime.now(UTC) - timedelta(days=days) analytics: dict[str, Any] = { "period_days": days, "agent_runs": {}, "workflow_executions": {}, "search_queries": {}, "proactive_suggestions": {}, "generated_at": datetime.now(UTC).isoformat(), } # Agent run stats try: from app.models.workflow import AgentRun total_runs = await db.scalar( select(func.count(AgentRun.id)).where( AgentRun.tenant_id == tenant_id, AgentRun.created_at >= since, ) ) completed_runs = await db.scalar( select(func.count(AgentRun.id)).where( AgentRun.tenant_id == tenant_id, AgentRun.created_at >= since, AgentRun.status == "completed", ) ) failed_runs = await db.scalar( select(func.count(AgentRun.id)).where( AgentRun.tenant_id == tenant_id, AgentRun.created_at >= since, AgentRun.status.in_(["stopped_error", "stopped_timeout"]), ) ) analytics["agent_runs"] = { "total": total_runs or 0, "completed": completed_runs or 0, "failed": failed_runs or 0, "success_rate": (completed_runs / total_runs * 100) if total_runs else 0.0, } except Exception as e: analytics["agent_runs"] = {"error": str(e)} # Workflow execution stats try: from app.models.workflow import WorkflowInstance total_instances = await db.scalar( select(func.count(WorkflowInstance.id)).where( WorkflowInstance.tenant_id == tenant_id, WorkflowInstance.created_at >= since, ) ) completed_instances = await db.scalar( select(func.count(WorkflowInstance.id)).where( WorkflowInstance.tenant_id == tenant_id, WorkflowInstance.created_at >= since, WorkflowInstance.status == "completed", ) ) analytics["workflow_executions"] = { "total": total_instances or 0, "completed": completed_instances or 0, } except Exception as e: analytics["workflow_executions"] = {"error": str(e)} return analytics __all__ = [ "get_platform_dashboard", "get_cost_dashboard", "get_usage_analytics", ]