import json import logging import os from app.services.supabase import get_supabase from app.config import settings logger = logging.getLogger(__name__) AUDIT_MODEL = "groq/llama-3.3-70b-versatile" ANALYSIS_PROMPT = """ You are an intelligent observability engine for BioNexus, a bioinformatics SaaS platform. Below is the ordered sequence of events from a user session. Your job: 1. Identify what the user is trying to accomplish 2. Find any steps that failed, produced unexpected output, or took unusually long 3. Detect patterns — e.g. user retried the same step 3 times, or a tool returned 0 results silently 4. Output a JSON object with this exact shape: { "severity": "info" | "warning" | "critical", "insight": "Plain-language summary of what happened in this session", "affected_steps": ["step_name_1", "step_name_2"], "suggestion": "What should be fixed or what the user should try next", "anomalies": ["list of specific anomalies detected"] } Session events: {events_json} Return ONLY the JSON object. No markdown, no preamble. """ def run_audit(session_id: str, triggered_by: str | None = None) -> None: sb = get_supabase() resp = sb.table("audit_events") \ .select("*") \ .eq("session_id", session_id) \ .order("timestamp") \ .execute() events = resp.data if not events: return try: import litellm response = litellm.completion( model=AUDIT_MODEL, messages=[{ "role": "user", "content": ANALYSIS_PROMPT.format( events_json=json.dumps(events, indent=2, default=str) ), }], max_tokens=1000, temperature=0.1, api_key=settings.GROQ_API_KEY, ) raw = response.choices[0].message.content.strip() insight_data = json.loads(raw) sb.table("audit_insights").insert({ "session_id": session_id, "triggered_by": triggered_by, "severity": insight_data.get("severity", "info"), "insight": insight_data.get("insight", ""), "affected_steps": insight_data.get("affected_steps", []), "suggestion": insight_data.get("suggestion", ""), "raw_audit": {"events": events, "anomalies": insight_data.get("anomalies", [])}, }).execute() logger.info(f"Audit insight stored for session {session_id[:8]}...") except Exception as e: logger.warning(f"Audit engine failed for session {session_id[:8]}...: {e}")