The Engine
A KnowledgeEngine collects @Rule(...) methods defined on the class and
evaluates them top-to-bottom against an input fact. The first matching rule
wins; its method is called with the matched fact and its return value is
returned from run(...).
from airules import KnowledgeEngine, Rule, Default
class TrafficAdvice(KnowledgeEngine[Light, str]):
@Rule(Light.color.eq("green"))
def green(self, light: Light):
return "go"
@Rule(Light.color.eq("yellow") & Light.remaining_time.gt(5))
def yellow_safe(self, light: Light):
return f"still {light.remaining_time}s"
@Rule(Light.color.eq("yellow") | Light.color.eq("red"))
def stop(self, light: Light):
return "stop"
@Default
def fallback(self, light: Light):
return "unknown signal"
Priority
Rules are ordered by an explicit priority= argument when provided, otherwise
by declaration order (earlier declarations win). @Default-decorated methods
are always tried last, after every regular rule has failed, regardless of
where they appear in the class body.
@Rule(some_predicate, priority=100) # checked before priority=10
def high_priority(self, fact): ...
If no rule matches and there is no @Default, run returns None.
Async support
The engine handles async @Default (or @Rule) methods automatically. Use
run_async and evaluate_async when your action needs to await:
@Default
async def llm_fallback(self, fact: MyFact) -> str:
result = await some_llm_call(fact)
return result
# Synchronous @Rule methods don't need to change
result = await engine.run_async(fact)
Union fact types
The engine type parameter accepts a union, which is useful when several fact shapes can be fed to the same rule set:
class MyEngine(KnowledgeEngine[Light | Car, str]):
...