52 lines
1.3 KiB
Python
52 lines
1.3 KiB
Python
"""
|
|
Cause graph API — explain why a node/action made its decisions.
|
|
"""
|
|
|
|
from fastapi import APIRouter
|
|
from typing import Optional
|
|
|
|
from backend.api.api import cause_graph
|
|
|
|
router = APIRouter(prefix="/api/cause", tags=["cause"])
|
|
|
|
|
|
@router.get("/explain/{node}")
|
|
def explain_node(node: str, action: Optional[str] = None):
|
|
"""Explain the causal chain for a given node (+ optional action)."""
|
|
chain = cause_graph.explain(node, action)
|
|
return {
|
|
"node": node,
|
|
"action": action,
|
|
"events": len(chain),
|
|
"chain": chain,
|
|
}
|
|
|
|
|
|
@router.get("/trace")
|
|
def full_trace():
|
|
"""Return the entire cause graph as a dict."""
|
|
return {
|
|
"nodes_tracked": len(cause_graph.graph),
|
|
"events_seen": len(cause_graph.events),
|
|
"trace": {str(k): v for k, v in cause_graph.full_trace().items()},
|
|
}
|
|
|
|
|
|
@router.get("/events")
|
|
def recent_events(limit: int = 100):
|
|
"""Return the most recent N ingested events."""
|
|
events = cause_graph.events[-limit:]
|
|
return {
|
|
"count": len(events),
|
|
"events": events,
|
|
}
|
|
|
|
|
|
# Legacy wrappers (kept for api.py facade)
|
|
def explain_node_legacy(cause_graph_instance, node, action=None):
|
|
return cause_graph_instance.explain(node, action)
|
|
|
|
|
|
def full_cause_trace(cause_graph_instance):
|
|
return cause_graph_instance.full_trace()
|