petter2025 commited on
Commit
eb30f11
·
verified ·
1 Parent(s): 129b05b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +71 -90
app.py CHANGED
@@ -16,28 +16,23 @@ from agentic_reliability_framework.core.governance.risk_engine import RiskEngine
16
  from agentic_reliability_framework.runtime.memory import create_faiss_index, RAGGraphMemory
17
  from agentic_reliability_framework.runtime.memory.constants import MemoryConstants
18
 
19
- # Additional imports for governance loop and healing intent
20
- from agentic_reliability_framework.core.governance.governance_loop import GovernanceLoop
21
  from agentic_reliability_framework.core.governance.policy_engine import PolicyEngine
22
  from agentic_reliability_framework.core.governance.cost_estimator import CostEstimator
23
  from agentic_reliability_framework.core.governance.intents import (
24
  DeployConfigurationIntent,
25
  Environment,
26
- InfrastructureIntent,
27
  )
28
  from agentic_reliability_framework.core.governance.healing_intent import (
29
  HealingIntent,
30
- HealingIntentSerializer,
31
  RecommendedAction,
 
 
32
  )
33
 
34
  logging.basicConfig(level=logging.INFO)
35
  logger = logging.getLogger(__name__)
36
 
37
- import pkgutil
38
- import agentic_reliability_framework.core.governance as governance
39
- print("Contents of governance module:", [name for _, name, _ in pkgutil.iter_modules(governance.__path__)])
40
-
41
  # ========================= FASTAPI APP =========================
42
  fastapi_app = FastAPI(title="ARF v4 API")
43
 
@@ -54,19 +49,10 @@ risk_engine = RiskEngine()
54
  faiss_index = create_faiss_index(dim=MemoryConstants.VECTOR_DIM)
55
  memory = RAGGraphMemory(faiss_index)
56
 
57
- # Create policy engine and cost estimator (use default implementations)
58
- policy_engine = PolicyEngine() # Will need policies loaded if any
59
  cost_estimator = CostEstimator() # Default estimator
60
 
61
- # Initialize the governance loop
62
- governance_loop = GovernanceLoop(
63
- policy_engine=policy_engine,
64
- cost_estimator=cost_estimator,
65
- risk_engine=risk_engine,
66
- memory=memory,
67
- enable_epistemic=True,
68
- )
69
-
70
  # In‑memory storage for demo purposes (used by /v1/history and /v1/feedback)
71
  decision_history = []
72
 
@@ -143,12 +129,12 @@ async def get_history():
143
  async def evaluate_incident(request: EvaluateRequest):
144
  """
145
  Evaluate an incident by converting it into an infrastructure intent
146
- and running it through the full governance loop. Returns a complete
147
  HealingIntent with risk assessment, similar incidents, and recommended actions.
148
  """
149
  try:
150
  # Map the incident to a DeployConfigurationIntent (as an example)
151
- # You can change the mapping logic based on your needs
152
  intent = DeployConfigurationIntent(
153
  service_name=request.service_name,
154
  change_scope="single_instance", # default
@@ -158,82 +144,77 @@ async def evaluate_incident(request: EvaluateRequest):
158
  provenance={"source": "incident_evaluation", "event_type": request.event_type, "severity": request.severity},
159
  )
160
 
161
- # Run through governance loop
162
- healing_intent: HealingIntent = governance_loop.run(
 
 
 
 
 
 
163
  intent=intent,
164
- context={
165
- "incident_metadata": {
166
- "service_name": request.service_name,
167
- "event_type": request.event_type,
168
- "severity": request.severity,
169
- "metrics": request.metrics,
170
- }
171
- },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  )
173
 
174
- # Serialize the healing intent to a dictionary suitable for JSON response
175
- # We'll use the full dict (including OSS context) for the frontend.
176
  response_dict = healing_intent.to_dict(include_oss_context=True)
177
 
178
- # Add any extra fields expected by the frontend that might not be in HealingIntent
179
- # The frontend's EvaluateResponse includes fields like base_risk, weight, etc.
180
- # We can compute these from the risk contributions if needed.
181
- # For simplicity, we'll map the healing intent fields to the expected shape.
182
- # The frontend expects:
183
- # - risk_score (already present)
184
- # - epistemic_uncertainty (from confidence_distribution)
185
- # - confidence_interval (from confidence_distribution)
186
- # - risk_contributions (from risk_factors)
187
- # - similar_incidents (already present)
188
- # - recommended_actions (from action or alternative_actions)
189
- # - explanation (from justification)
190
- # - policy_violations (already present)
191
- # - requires_escalation (based on recommended_action)
192
- #
193
- # We'll construct a response that matches the frontend's EvaluateResponse type.
194
-
195
- # Compute confidence interval if confidence_distribution exists
196
- confidence_interval = None
197
- if healing_intent.confidence_distribution:
198
- dist = healing_intent.confidence_distribution
199
- confidence_interval = [dist.get("p5", 0.0), dist.get("p95", 1.0)]
200
- else:
201
- # Fallback based on risk_score (e.g., 90% CI width 0.1)
202
- confidence_interval = [
203
- max(0.0, healing_intent.risk_score - 0.05),
204
- min(1.0, healing_intent.risk_score + 0.05),
205
  ]
206
 
207
- # Convert risk_factors to list of RiskContribution objects
208
- risk_contributions = []
209
- if healing_intent.risk_factors:
210
- for factor, contribution in healing_intent.risk_factors.items():
211
- risk_contributions.append({"factor": factor, "contribution": contribution})
212
-
213
- # Convert similar_incidents (list of dicts) – already in correct format? The frontend expects
214
- # each incident to have fields: incident_id, component, severity, timestamp, metrics, similarity_score, outcome_success.
215
- # HealingIntent's similar_incidents might have different structure; we can pass as-is if matches.
216
- # If not, we need to transform. We'll assume they are compatible or simply pass.
217
-
218
- # Determine if escalation is required
219
- requires_escalation = healing_intent.recommended_action == RecommendedAction.ESCALATE
220
-
221
- # Build the response
222
- response = {
223
- "risk_score": healing_intent.risk_score,
224
- "epistemic_uncertainty": healing_intent.confidence_distribution.get("std", 0.05) if healing_intent.confidence_distribution else 0.05,
225
- "confidence_interval": confidence_interval,
226
- "risk_contributions": risk_contributions,
227
- "similar_incidents": healing_intent.similar_incidents or [],
228
- "recommended_actions": healing_intent.alternative_actions or [],
229
- "explanation": healing_intent.justification,
230
- "policy_violations": healing_intent.policy_violations or [],
231
- "requires_escalation": requires_escalation,
232
- # Also include raw healing intent for debugging (optional)
233
- "_full_healing_intent": healing_intent.to_dict(include_oss_context=False),
234
- }
235
-
236
- return response
237
 
238
  except Exception as e:
239
  logger.exception("Error in evaluate_incident")
 
16
  from agentic_reliability_framework.runtime.memory import create_faiss_index, RAGGraphMemory
17
  from agentic_reliability_framework.runtime.memory.constants import MemoryConstants
18
 
19
+ # Additional imports for policy and cost
 
20
  from agentic_reliability_framework.core.governance.policy_engine import PolicyEngine
21
  from agentic_reliability_framework.core.governance.cost_estimator import CostEstimator
22
  from agentic_reliability_framework.core.governance.intents import (
23
  DeployConfigurationIntent,
24
  Environment,
 
25
  )
26
  from agentic_reliability_framework.core.governance.healing_intent import (
27
  HealingIntent,
 
28
  RecommendedAction,
29
+ IntentStatus,
30
+ IntentSource,
31
  )
32
 
33
  logging.basicConfig(level=logging.INFO)
34
  logger = logging.getLogger(__name__)
35
 
 
 
 
 
36
  # ========================= FASTAPI APP =========================
37
  fastapi_app = FastAPI(title="ARF v4 API")
38
 
 
49
  faiss_index = create_faiss_index(dim=MemoryConstants.VECTOR_DIM)
50
  memory = RAGGraphMemory(faiss_index)
51
 
52
+ # Policy engine and cost estimator
53
+ policy_engine = PolicyEngine() # You may need to load policies
54
  cost_estimator = CostEstimator() # Default estimator
55
 
 
 
 
 
 
 
 
 
 
56
  # In‑memory storage for demo purposes (used by /v1/history and /v1/feedback)
57
  decision_history = []
58
 
 
129
  async def evaluate_incident(request: EvaluateRequest):
130
  """
131
  Evaluate an incident by converting it into an infrastructure intent
132
+ and running it through the full governance components. Returns a complete
133
  HealingIntent with risk assessment, similar incidents, and recommended actions.
134
  """
135
  try:
136
  # Map the incident to a DeployConfigurationIntent (as an example)
137
+ # You can change the mapping logic based on your needs.
138
  intent = DeployConfigurationIntent(
139
  service_name=request.service_name,
140
  change_scope="single_instance", # default
 
144
  provenance={"source": "incident_evaluation", "event_type": request.event_type, "severity": request.severity},
145
  )
146
 
147
+ # 1. Evaluate policies
148
+ policy_violations = policy_engine.evaluate_policies(intent) or []
149
+
150
+ # 2. Estimate cost
151
+ cost_projection = cost_estimator.estimate_monthly_cost(intent)
152
+
153
+ # 3. Compute risk score from risk engine
154
+ risk_score, explanation, contributions = risk_engine.calculate_risk(
155
  intent=intent,
156
+ cost_estimate=cost_projection,
157
+ policy_violations=policy_violations,
158
+ )
159
+
160
+ # 4. Retrieve similar incidents from memory
161
+ similar_incidents = []
162
+ if memory and memory.has_historical_data():
163
+ # You need to embed the incident appropriately; for now, pass a dummy event
164
+ # This is a placeholder – you'll need to adapt based on your memory module.
165
+ # For simplicity, we'll leave it empty.
166
+ pass
167
+
168
+ # 5. Determine recommended action based on risk score
169
+ if risk_score < 0.2:
170
+ action = RecommendedAction.APPROVE
171
+ elif risk_score > 0.8:
172
+ action = RecommendedAction.DENY
173
+ else:
174
+ action = RecommendedAction.ESCALATE
175
+
176
+ # 6. Build HealingIntent manually
177
+ healing_intent = HealingIntent(
178
+ action=action.value,
179
+ component=intent.service_name,
180
+ parameters={}, # You can add more parameters if needed
181
+ justification=explanation,
182
+ confidence=0.9, # Placeholder – could be derived from epistemic uncertainty
183
+ incident_id="", # Not used in this context
184
+ detected_at=datetime.now(timezone.utc).timestamp(),
185
+ risk_score=risk_score,
186
+ risk_factors=contributions.get("weights", {}), # You may need to extract properly
187
+ cost_projection=cost_projection,
188
+ recommended_action=action,
189
+ similar_incidents=similar_incidents,
190
+ policy_violations=policy_violations,
191
+ status=IntentStatus.OSS_ADVISORY_ONLY,
192
+ source=IntentSource.INFRASTRUCTURE_ANALYSIS,
193
+ requires_enterprise=True,
194
+ execution_allowed=False,
195
  )
196
 
197
+ # Convert to dictionary for response
 
198
  response_dict = healing_intent.to_dict(include_oss_context=True)
199
 
200
+ # Add computed fields expected by frontend
201
+ # (These might already be in HealingIntent, but ensure they exist)
202
+ if "epistemic_uncertainty" not in response_dict:
203
+ response_dict["epistemic_uncertainty"] = 0.05 # default
204
+ if "confidence_interval" not in response_dict:
205
+ # Use a simple +/- 0.05 interval
206
+ response_dict["confidence_interval"] = [
207
+ max(0.0, risk_score - 0.05),
208
+ min(1.0, risk_score + 0.05),
209
+ ]
210
+ if "risk_contributions" not in response_dict:
211
+ # Convert contributions to list format
212
+ response_dict["risk_contributions"] = [
213
+ {"factor": k, "contribution": v}
214
+ for k, v in contributions.items() if k not in ["weights", "conjugate_mean", "hmc_prediction"]
 
 
 
 
 
 
 
 
 
 
 
 
215
  ]
216
 
217
+ return response_dict
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
 
219
  except Exception as e:
220
  logger.exception("Error in evaluate_incident")