klausur-service (11 files): - cv_gutter_repair, ocr_pipeline_regression, upload_api - ocr_pipeline_sessions, smart_spell, nru_worksheet_generator - ocr_pipeline_overlays, mail/aggregator, zeugnis_api - cv_syllable_detect, self_rag backend-lehrer (17 files): - classroom_engine/suggestions, generators/quiz_generator - worksheets_api, llm_gateway/comparison, state_engine_api - classroom/models (→ 4 submodules), services/file_processor - alerts_agent/api/wizard+digests+routes, content_generators/pdf - classroom/routes/sessions, llm_gateway/inference - classroom_engine/analytics, auth/keycloak_auth - alerts_agent/processing/rule_engine, ai_processor/print_versions agent-core (5 files): - brain/memory_store, brain/knowledge_graph, brain/context_manager - orchestrator/supervisor, sessions/session_manager admin-lehrer (5 components): - GridOverlay, StepGridReview, DevOpsPipelineSidebar - DataFlowDiagram, sbom/wizard/page website (2 files): - DependencyMap, lehrer/abitur-archiv Other: nibis_ingestion, grid_detection_service, export-doclayout-onnx Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
139 lines
4.4 KiB
Python
139 lines
4.4 KiB
Python
"""
|
|
Rule Engine für Alerts Agent.
|
|
|
|
Evaluiert Regeln gegen Alert-Items und führt Aktionen aus.
|
|
Batch-Verarbeitung und Action-Anwendung.
|
|
"""
|
|
|
|
import logging
|
|
from typing import List, Dict, Any, Optional
|
|
|
|
from alerts_agent.db.models import AlertItemDB, AlertRuleDB, RuleActionEnum
|
|
|
|
from .rule_models import (
|
|
ConditionOperator,
|
|
RuleCondition,
|
|
RuleMatch,
|
|
get_field_value,
|
|
evaluate_condition,
|
|
evaluate_rule,
|
|
evaluate_rules_for_alert,
|
|
create_keyword_rule,
|
|
create_exclusion_rule,
|
|
create_score_threshold_rule,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Re-export for backward compatibility
|
|
__all__ = [
|
|
"ConditionOperator",
|
|
"RuleCondition",
|
|
"RuleMatch",
|
|
"get_field_value",
|
|
"evaluate_condition",
|
|
"evaluate_rule",
|
|
"evaluate_rules_for_alert",
|
|
"RuleEngine",
|
|
"create_keyword_rule",
|
|
"create_exclusion_rule",
|
|
"create_score_threshold_rule",
|
|
]
|
|
|
|
|
|
class RuleEngine:
|
|
"""Rule Engine für Batch-Verarbeitung von Alerts."""
|
|
|
|
def __init__(self, db_session):
|
|
self.db = db_session
|
|
self._rules_cache: Optional[List[AlertRuleDB]] = None
|
|
|
|
def _get_active_rules(self) -> List[AlertRuleDB]:
|
|
"""Lädt aktive Regeln aus der Datenbank (cached)."""
|
|
if self._rules_cache is None:
|
|
from alerts_agent.db.repository import RuleRepository
|
|
repo = RuleRepository(self.db)
|
|
self._rules_cache = repo.get_active()
|
|
return self._rules_cache
|
|
|
|
def clear_cache(self) -> None:
|
|
"""Leert den Regel-Cache."""
|
|
self._rules_cache = None
|
|
|
|
def process_alert(self, alert: AlertItemDB) -> Optional[RuleMatch]:
|
|
"""Verarbeitet einen Alert mit allen aktiven Regeln."""
|
|
rules = self._get_active_rules()
|
|
return evaluate_rules_for_alert(alert, rules)
|
|
|
|
def process_alerts(self, alerts: List[AlertItemDB]) -> Dict[str, RuleMatch]:
|
|
"""Verarbeitet mehrere Alerts mit allen aktiven Regeln."""
|
|
rules = self._get_active_rules()
|
|
results = {}
|
|
|
|
for alert in alerts:
|
|
match = evaluate_rules_for_alert(alert, rules)
|
|
if match:
|
|
results[alert.id] = match
|
|
|
|
return results
|
|
|
|
def apply_rule_actions(self, alert: AlertItemDB, match: RuleMatch) -> Dict[str, Any]:
|
|
"""Wendet die Regel-Aktion auf einen Alert an."""
|
|
from alerts_agent.db.repository import AlertItemRepository, RuleRepository
|
|
|
|
alert_repo = AlertItemRepository(self.db)
|
|
rule_repo = RuleRepository(self.db)
|
|
|
|
action = match.action
|
|
config = match.action_config
|
|
result = {"action": action.value, "success": False}
|
|
|
|
try:
|
|
if action == RuleActionEnum.KEEP:
|
|
alert_repo.update_scoring(
|
|
alert_id=alert.id, score=1.0, decision="KEEP",
|
|
reasons=["rule_match"], summary=f"Matched rule: {match.rule_name}",
|
|
model="rule_engine",
|
|
)
|
|
result["success"] = True
|
|
|
|
elif action == RuleActionEnum.DROP:
|
|
alert_repo.update_scoring(
|
|
alert_id=alert.id, score=0.0, decision="DROP",
|
|
reasons=["rule_match"], summary=f"Dropped by rule: {match.rule_name}",
|
|
model="rule_engine",
|
|
)
|
|
result["success"] = True
|
|
|
|
elif action == RuleActionEnum.TAG:
|
|
tags = config.get("tags", [])
|
|
if tags:
|
|
existing_tags = alert.user_tags or []
|
|
new_tags = list(set(existing_tags + tags))
|
|
alert_repo.update(alert.id, user_tags=new_tags)
|
|
result["tags_added"] = tags
|
|
result["success"] = True
|
|
|
|
elif action == RuleActionEnum.EMAIL:
|
|
result["email_config"] = config
|
|
result["success"] = True
|
|
result["deferred"] = True
|
|
|
|
elif action == RuleActionEnum.WEBHOOK:
|
|
result["webhook_config"] = config
|
|
result["success"] = True
|
|
result["deferred"] = True
|
|
|
|
elif action == RuleActionEnum.SLACK:
|
|
result["slack_config"] = config
|
|
result["success"] = True
|
|
result["deferred"] = True
|
|
|
|
rule_repo.increment_match_count(match.rule_id)
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error applying rule action: {e}")
|
|
result["error"] = str(e)
|
|
|
|
return result
|