"""One persistent policy process; no scheduler or agent loop.""" from __future__ import annotations import importlib import inspect import sys from pathlib import Path # Load the SDK before adding editable behavior to the import path. from klbr.hooks import (AttentionDecision, AttentionRequest, DeliveryDecision, DeliveryRequest, HookContext) from .release import fingerprint, manifest class Policy: def __init__(self, root: Path, revision: str): if fingerprint(root) != revision: raise ValueError("behavior content does not match its revision fingerprint") registrations = manifest(root) sys.path.insert(0, str(root.resolve())) self.revision = revision self.handlers = {} for slot, entrypoint in registrations.items(): module, name = entrypoint.split(":") handler = getattr(importlib.import_module(module), name) if not callable(handler): raise ValueError(f"not a callable: {entrypoint}") # Enforce the two-argument use site without evaluating the callback. inspect.signature(handler).bind(object(), object()) self.handlers[slot] = handler async def invoke(self, slot: str, value: dict, context: HookContext) -> dict: match slot: case "delivery.review": request, expected = DeliveryRequest.parse(value), DeliveryDecision case "attention.plan": request, expected = AttentionRequest.parse(value), AttentionDecision case _: raise ValueError(f"unsupported hook slot: {slot}") result = self.handlers[slot](request, context) if inspect.isawaitable(result): result = await result if not isinstance(result, expected): raise TypeError(f"{slot} must return {expected.__name__}, not {type(result).__name__}") return result.to_wire()