from __future__ import annotations from dataclasses import dataclass, field from typing import Any, Awaitable, Callable, Dict, List, Optional @dataclass class RuleContext: data: Dict[str, Any] = field(default_factory=dict) def get(self, key: str, default: Any = None) -> Any: return self.data.get(key, default) def set(self, key: str, value: Any) -> None: self.data[key] = value @dataclass class RuleResult: matched: bool = False stop: bool = False action: str = "" payload: Dict[str, Any] = field(default_factory=dict) Predicate = Callable[[RuleContext], Awaitable[bool]] Action = Callable[[RuleContext], Awaitable[RuleResult]] @dataclass class Rule: name: str priority: int predicate: Predicate action: Action class RuleEngine: """Priority-ordered async rule chain.""" def __init__(self, rules: Optional[List[Rule]] = None): self._rules: List[Rule] = sorted(rules or [], key=lambda x: x.priority) def add_rule(self, rule: Rule) -> None: self._rules.append(rule) self._rules.sort(key=lambda x: x.priority) async def run(self, ctx: RuleContext) -> RuleResult: for rule in self._rules: if not await rule.predicate(ctx): continue result = await rule.action(ctx) if not result.matched: result.matched = True if not result.action: result.action = rule.name if result.stop: return result return RuleResult(matched=False, stop=False, action="no_match")