File size: 5,563 Bytes
65646f4
 
 
 
 
 
 
 
 
 
2d521fd
 
 
 
 
 
6d20eab
 
 
 
65646f4
6d20eab
 
2d521fd
 
65646f4
 
 
 
2d521fd
65646f4
 
 
 
 
2d521fd
 
 
 
 
 
 
65646f4
 
 
 
6d20eab
 
65646f4
 
 
2d521fd
65646f4
 
 
2d521fd
 
 
 
 
 
 
 
65646f4
 
 
 
 
 
 
 
 
 
6d20eab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65646f4
6d20eab
 
 
 
 
 
65646f4
6d20eab
 
2d521fd
 
65646f4
 
 
 
 
2d521fd
 
 
 
 
 
 
65646f4
 
 
 
 
2d521fd
 
 
 
 
 
 
65646f4
 
 
 
2d521fd
 
 
 
 
 
65646f4
 
 
 
2d521fd
 
 
 
 
 
65646f4
 
 
 
 
 
 
2d521fd
 
65646f4
6d20eab
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
"""
Dependency injection module for the ARF Agentic Reliability Framework API.

Provides FastAPI dependencies for database sessions, rate limiting, and
singleton instances of the core ARF engines (RiskEngine, DecisionEngine,
LyapunovStabilityController, CausalEffectEstimator, and RAGGraphMemory).
All engine dependencies are lazily initialised and cached for the lifetime
of the application process.
"""

import sys
from app.database.session import SessionLocal
from slowapi import Limiter
from slowapi.util import get_remote_address
from app.core.config import settings

# ARF core engine imports
from agentic_reliability_framework.core.governance.risk_engine import RiskEngine
from agentic_reliability_framework.core.decision.decision_engine import DecisionEngine
from agentic_reliability_framework.core.governance.stability_controller import LyapunovStabilityController
from agentic_reliability_framework.core.governance.causal_effect_estimator import CausalEffectEstimator
from agentic_reliability_framework.runtime.memory.rag_graph import RAGGraphMemory
from agentic_reliability_framework.core.models.event import ReliabilityEvent, HealingAction


# ---------------------------------------------------------------------------
# Database dependency
# ---------------------------------------------------------------------------

def get_db():
    """
    Yield a SQLAlchemy database session and ensure it is closed after use.

    This dependency is intended to be used with FastAPI's `Depends` mechanism.
    """
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()


# ---------------------------------------------------------------------------
# Rate limiter
# ---------------------------------------------------------------------------

limiter = Limiter(
    key_func=get_remote_address,
    default_limits=[settings.RATE_LIMIT],
)


# ---------------------------------------------------------------------------
# Singleton engine instances (lazy, cached)
# ---------------------------------------------------------------------------

_risk_engine = None
_decision_engine = None
_stability_controller = None
_causal_explainer = None
_rag_graph = None


def _seed_rag_graph(rag: RAGGraphMemory) -> None:
    """
    Populate the RAG graph with a small set of synthetic historical
    healing‑action outcomes to provide initial memory for the decision engine.

    Parameters
    ----------
    rag : RAGGraphMemory
        An already‑instantiated RAG graph memory instance.
    """
    seed_data = [
        ("seed_restart_1", "test", HealingAction.RESTART_CONTAINER.value, True, 2),
        ("seed_restart_2", "test", HealingAction.RESTART_CONTAINER.value, True, 3),
        ("seed_restart_3", "test", HealingAction.RESTART_CONTAINER.value, False, 10),
        ("seed_rollback_1", "test", HealingAction.ROLLBACK.value, True, 1),
        ("seed_rollback_2", "test", HealingAction.ROLLBACK.value, True, 2),
        ("seed_rollback_3", "test", HealingAction.ROLLBACK.value, False, 5),
        ("seed_scale_1", "test", HealingAction.SCALE_OUT.value, True, 5),
        ("seed_scale_2", "test", HealingAction.SCALE_OUT.value, False, 15),
        ("seed_cb_1", "test", HealingAction.CIRCUIT_BREAKER.value, True, 1),
        ("seed_cb_2", "test", HealingAction.CIRCUIT_BREAKER.value, True, 2),
        ("seed_ts_1", "test", HealingAction.TRAFFIC_SHIFT.value, True, 4),
        ("seed_ts_2", "test", HealingAction.TRAFFIC_SHIFT.value, False, 8),
    ]
    for inc_id, comp, action, success, res_time in seed_data:
        event = ReliabilityEvent(
            component=comp,
            latency_p99=500,
            error_rate=0.1,
            service_mesh="default",
        )
        rag.record_outcome(
            incident_id=inc_id,
            event=event,
            action_taken=action,
            success=success,
            resolution_time_minutes=res_time,
        )
    print("Seeded RAG graph with historical data", file=sys.stderr)


def get_rag_graph() -> RAGGraphMemory:
    """
    Return a singleton instance of the RAG graph memory, seeded with
    synthetic historical data on first access.
    """
    global _rag_graph
    if _rag_graph is None:
        _rag_graph = RAGGraphMemory()
        _seed_rag_graph(_rag_graph)
    return _rag_graph


def get_decision_engine() -> DecisionEngine:
    """
    Return a singleton DecisionEngine, wiring it to the shared RAG graph
    memory.
    """
    global _decision_engine
    if _decision_engine is None:
        rag = get_rag_graph()
        _decision_engine = DecisionEngine(rag_graph=rag)
    return _decision_engine


def get_risk_engine() -> RiskEngine:
    """
    Return a singleton RiskEngine instance.
    """
    global _risk_engine
    if _risk_engine is None:
        _risk_engine = RiskEngine()
    return _risk_engine


def get_stability_controller() -> LyapunovStabilityController:
    """
    Return a singleton LyapunovStabilityController instance.
    """
    global _stability_controller
    if _stability_controller is None:
        _stability_controller = LyapunovStabilityController()
    return _stability_controller


def get_causal_explainer() -> CausalEffectEstimator:
    """
    Return a singleton CausalEffectEstimator instance.

    The estimator uses Inverse Probability Weighting (IPW) and causal forests
    to provide counterfactual explanations for governance decisions.
    """
    global _causal_explainer
    if _causal_explainer is None:
        _causal_explainer = CausalEffectEstimator()
    return _causal_explainer