petter2025 commited on
Commit
5d54760
·
verified ·
1 Parent(s): 5570429

Create arf_adapter.py

Browse files
Files changed (1) hide show
  1. core/arf_adapter.py +277 -0
core/arf_adapter.py ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ ARF Adapter Pattern for clean integration with real or mock ARF
3
+ """
4
+ from abc import ABC, abstractmethod
5
+ from typing import Dict, Any, List, Optional
6
+ import asyncio
7
+ import logging
8
+ from config.settings import settings, ARFMode
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class ARFAdapter(ABC):
14
+ """Abstract adapter for ARF integration"""
15
+
16
+ @abstractmethod
17
+ async def detect(self, metrics: Dict[str, Any]) -> Dict[str, Any]:
18
+ """Detect anomalies in metrics"""
19
+ pass
20
+
21
+ @abstractmethod
22
+ async def recall(self, incident: Dict[str, Any]) -> List[Dict[str, Any]]:
23
+ """Recall similar incidents from memory"""
24
+ pass
25
+
26
+ @abstractmethod
27
+ async def decide(self, incident: Dict[str, Any], context: Dict[str, Any]) -> Dict[str, Any]:
28
+ """Generate healing intent"""
29
+ pass
30
+
31
+ @abstractmethod
32
+ async def analyze(self, scenario_name: str, scenario_data: Dict[str, Any]) -> Dict[str, Any]:
33
+ """Complete analysis pipeline"""
34
+ pass
35
+
36
+
37
+ class MockARFAdapter(ARFAdapter):
38
+ """Mock ARF implementation for demo mode"""
39
+
40
+ def __init__(self):
41
+ logger.info("Initializing MockARFAdapter")
42
+ # Lazy imports to avoid circular dependencies
43
+ self._simulate_arf_analysis = None
44
+ self._run_rag_similarity_search = None
45
+ self._create_mock_healing_intent = None
46
+ self._calculate_pattern_confidence = None
47
+
48
+ def _import_mock_functions(self):
49
+ """Lazy import of mock functions"""
50
+ if self._simulate_arf_analysis is None:
51
+ from demo.mock_arf import (
52
+ simulate_arf_analysis,
53
+ run_rag_similarity_search,
54
+ create_mock_healing_intent,
55
+ calculate_pattern_confidence
56
+ )
57
+ self._simulate_arf_analysis = simulate_arf_analysis
58
+ self._run_rag_similarity_search = run_rag_similarity_search
59
+ self._create_mock_healing_intent = create_mock_healing_intent
60
+ self._calculate_pattern_confidence = calculate_pattern_confidence
61
+
62
+ async def detect(self, metrics: Dict[str, Any]) -> Dict[str, Any]:
63
+ """Mock anomaly detection"""
64
+ self._import_mock_functions()
65
+
66
+ # Simulate processing time
67
+ await asyncio.sleep(0.1)
68
+
69
+ result = self._simulate_arf_analysis({"metrics": metrics})
70
+ result["detection_method"] = "mock_ml_algorithm"
71
+ result["confidence"] = 0.987 # 98.7%
72
+
73
+ return result
74
+
75
+ async def recall(self, incident: Dict[str, Any]) -> List[Dict[str, Any]]:
76
+ """Mock RAG similarity search"""
77
+ self._import_mock_functions()
78
+
79
+ # Simulate processing time
80
+ await asyncio.sleep(0.2)
81
+
82
+ similar = self._run_rag_similarity_search(incident)
83
+
84
+ # Enhance with additional metadata
85
+ for item in similar:
86
+ item["source"] = "mock_rag_memory"
87
+ item["retrieval_time"] = "45ms"
88
+
89
+ return similar
90
+
91
+ async def decide(self, incident: Dict[str, Any], context: Dict[str, Any]) -> Dict[str, Any]:
92
+ """Mock decision making"""
93
+ self._import_mock_functions()
94
+
95
+ # Get similar incidents from context or recall them
96
+ similar = context.get("similar_incidents")
97
+ if not similar:
98
+ similar = await self.recall(incident)
99
+
100
+ # Calculate confidence
101
+ confidence = self._calculate_pattern_confidence(incident, similar)
102
+
103
+ # Generate healing intent
104
+ intent = self._create_mock_healing_intent(incident, similar, confidence)
105
+
106
+ # Add safety check
107
+ intent["safety_checks"] = {
108
+ "blast_radius": "2 services",
109
+ "business_hours": "compliant",
110
+ "rollback_plan": "available",
111
+ "approval_required": True
112
+ }
113
+
114
+ return intent
115
+
116
+ async def analyze(self, scenario_name: str, scenario_data: Dict[str, Any]) -> Dict[str, Any]:
117
+ """Complete mock analysis pipeline"""
118
+ logger.info(f"Starting mock analysis for: {scenario_name}")
119
+
120
+ # Step 1: Detection
121
+ detection_result = await self.detect(scenario_data.get("metrics", {}))
122
+
123
+ # Step 2: Recall
124
+ recall_result = await self.recall(scenario_data)
125
+
126
+ # Step 3: Decision
127
+ decision_result = await self.decision(
128
+ scenario_data,
129
+ {"similar_incidents": recall_result}
130
+ )
131
+
132
+ return {
133
+ "scenario": scenario_name,
134
+ "detection": detection_result,
135
+ "recall": recall_result,
136
+ "decision": decision_result,
137
+ "overall_confidence": decision_result.get("confidence", 0.85),
138
+ "processing_time_ms": 450,
139
+ "agents_executed": ["detection", "recall", "decision"]
140
+ }
141
+
142
+
143
+ class RealARFAdapter(ARFAdapter):
144
+ """Real ARF integration (requires agentic-reliability-framework package)"""
145
+
146
+ def __init__(self, api_key: Optional[str] = None):
147
+ logger.info("Initializing RealARFAdapter")
148
+
149
+ try:
150
+ from agentic_reliability_framework import ARFClient
151
+ self.client = ARFClient(api_key=api_key or settings.arf_api_key)
152
+ self._available = True
153
+ except ImportError as e:
154
+ logger.error(f"Failed to import ARF package: {e}")
155
+ self._available = False
156
+ raise RuntimeError(
157
+ "Real ARF integration requires 'agentic-reliability-framework' package. "
158
+ "Install with: pip install agentic-reliability-framework"
159
+ )
160
+
161
+ async def detect(self, metrics: Dict[str, Any]) -> Dict[str, Any]:
162
+ """Real anomaly detection"""
163
+ if not self._available:
164
+ raise RuntimeError("ARF client not available")
165
+
166
+ try:
167
+ # Assuming async API
168
+ result = await self.client.detect_anomaly_async(metrics)
169
+ return result
170
+ except AttributeError:
171
+ # Fallback to sync if async not available
172
+ result = self.client.detect_anomaly(metrics)
173
+ return result
174
+
175
+ async def recall(self, incident: Dict[str, Any]) -> List[Dict[str, Any]]:
176
+ """Real RAG similarity search"""
177
+ if not self._available:
178
+ raise RuntimeError("ARF client not available")
179
+
180
+ try:
181
+ # Assuming async API
182
+ result = await self.client.recall_similar_async(incident)
183
+ return result
184
+ except AttributeError:
185
+ # Fallback to sync
186
+ result = self.client.recall_similar(incident)
187
+ return result
188
+
189
+ async def decide(self, incident: Dict[str, Any], context: Dict[str, Any]) -> Dict[str, Any]:
190
+ """Real decision making"""
191
+ if not self._available:
192
+ raise RuntimeError("ARF client not available")
193
+
194
+ try:
195
+ # Assuming async API
196
+ result = await self.client.generate_intent_async(incident, context)
197
+ return result
198
+ except AttributeError:
199
+ # Fallback to sync
200
+ result = self.client.generate_intent(incident, context)
201
+ return result
202
+
203
+ async def analyze(self, scenario_name: str, scenario_data: Dict[str, Any]) -> Dict[str, Any]:
204
+ """Complete real analysis pipeline"""
205
+ logger.info(f"Starting real analysis for: {scenario_name}")
206
+
207
+ # Run agents in parallel where possible
208
+ detection_task = asyncio.create_task(self.detect(scenario_data.get("metrics", {})))
209
+ recall_task = asyncio.create_task(self.recall(scenario_data))
210
+
211
+ detection_result, recall_result = await asyncio.gather(detection_task, recall_task)
212
+
213
+ # Decision depends on recall results
214
+ decision_result = await self.decision(
215
+ scenario_data,
216
+ {"similar_incidents": recall_result}
217
+ )
218
+
219
+ return {
220
+ "scenario": scenario_name,
221
+ "detection": detection_result,
222
+ "recall": recall_result,
223
+ "decision": decision_result,
224
+ "overall_confidence": decision_result.get("confidence", 0.85),
225
+ "processing_time_ms": 250, # Real system should be faster
226
+ "agents_executed": ["detection", "recall", "decision"]
227
+ }
228
+
229
+
230
+ def get_arf_adapter() -> ARFAdapter:
231
+ """
232
+ Factory function to get appropriate ARF adapter based on settings
233
+
234
+ Returns:
235
+ ARFAdapter instance
236
+ """
237
+ if settings.arf_mode == ARFMode.DEMO or settings.use_mock_arf:
238
+ logger.info("Using MockARFAdapter (demo mode)")
239
+ return MockARFAdapter()
240
+ elif settings.arf_mode == ARFMode.OSS:
241
+ logger.info("Using RealARFAdapter (OSS mode)")
242
+ return RealARFAdapter()
243
+ elif settings.arf_mode == ARFMode.ENTERPRISE:
244
+ logger.info("Using RealARFAdapter (Enterprise mode)")
245
+ return RealARFAdapter()
246
+ else:
247
+ logger.warning("Unknown ARF mode, falling back to mock")
248
+ return MockARFAdapter()
249
+
250
+
251
+ # Async helper for easy integration
252
+ async def analyze_scenario_async(scenario_name: str, scenario_data: Dict[str, Any]) -> Dict[str, Any]:
253
+ """Convenience function for async scenario analysis"""
254
+ adapter = get_arf_adapter()
255
+ return await adapter.analyze(scenario_name, scenario_data)
256
+
257
+
258
+ # Sync wrapper for compatibility
259
+ def analyze_scenario_sync(scenario_name: str, scenario_data: Dict[str, Any]) -> Dict[str, Any]:
260
+ """Sync wrapper for scenario analysis"""
261
+ import asyncio
262
+
263
+ async def _analyze():
264
+ return await analyze_scenario_async(scenario_name, scenario_data)
265
+
266
+ try:
267
+ loop = asyncio.get_running_loop()
268
+ # Already in async context, create task
269
+ return asyncio.create_task(_analyze())
270
+ except RuntimeError:
271
+ # Create new event loop
272
+ loop = asyncio.new_event_loop()
273
+ asyncio.set_event_loop(loop)
274
+ try:
275
+ return loop.run_until_complete(_analyze())
276
+ finally:
277
+ loop.close()