"""governed_function decorator — wraps async functions as FunctionPlugins.""" from __future__ import annotations import functools from typing import Any, Callable, Awaitable from .base import FunctionContext, FunctionPlugin, FunctionResult def governed_function( function_id: str, corpus_entry_cid: str, capability_mask: int = 1, trigger_events: list[str] | None = None, accord_template: str = "", gsap_required: bool = True, chronicle_enabled: bool = True, max_duration_seconds: int = 30, display_name: str = "", description: str = "", version: str = "0.1.0", registry: Any = None, ) -> Callable: """Decorator that wraps an async function as a governed FunctionPlugin. Usage:: @governed_function( function_id="my-func", corpus_entry_cid="sha256:abc...", ) async def my_func(event, context): return FunctionResult(success=True, data=event) """ def decorator( fn: Callable[[dict[str, Any], FunctionContext], Awaitable[FunctionResult]], ) -> FunctionPlugin: class WrappedFunction(FunctionPlugin): pass instance = WrappedFunction.__new__(WrappedFunction) instance.function_id = function_id instance.corpus_entry_cid = corpus_entry_cid instance.capability_mask = capability_mask instance.trigger_events = trigger_events or [] instance.accord_template = accord_template instance.gsap_required = gsap_required instance.chronicle_enabled = chronicle_enabled instance.max_duration_seconds = max_duration_seconds instance.display_name = display_name or function_id instance.description = description instance.version = version async def handle(event: dict[str, Any], context: FunctionContext) -> FunctionResult: return await fn(event, context) instance.handle = handle # type: ignore[assignment] instance.health_check = lambda: True # type: ignore[assignment] # Auto-register if a registry is provided if registry is not None: registry.register(instance) # Preserve original function metadata functools.update_wrapper(instance, fn) return instance return decorator