"""Activity drivers for the orchestrator. Concrete drivers register dispatch in :func:`get_driver_for`. Same lazy-import pattern as :mod:`decnet.canary.factory`: the import-time cost of :mod:`decnet.orchestrator.drivers` stays low for callers that only need :class:`ActivityResult` / :class:`ActivityDriver`. """ from __future__ import annotations from decnet.orchestrator.drivers.base import ( ActivityDriver, ActivityResult, Driver, ) from decnet.orchestrator.scheduler import Action, FileAction, TrafficAction __all__ = [ "ActivityDriver", "ActivityResult", "Driver", "SSHDriver", "get_driver_for", ] def __getattr__(name: str): # pragma: no cover - import passthrough """Lazy access to concrete drivers. Avoids dragging the docker-exec / email-driver code into every consumer that only needs the ABC. """ if name == "SSHDriver": from decnet.orchestrator.drivers.ssh import SSHDriver return SSHDriver if name == "EmailDriver": from decnet.orchestrator.drivers.email import EmailDriver return EmailDriver raise AttributeError(f"module {__name__!r} has no attribute {name!r}") def get_driver_for(action: Action) -> ActivityDriver: """Return the concrete driver that handles *action*. Stage 4 of the realism migration adds this seam so the orchestrator worker can dispatch by action type without an isinstance chain in ``_one_tick``. Stage 5 wires the worker to call this function instead of holding a single ``SSHDriver`` instance. The set of action shapes the orchestrator can plan grows with the migration: * :class:`TrafficAction` / :class:`FileAction` → :class:`SSHDriver` * :class:`EmailAction` (post-stage-5) → ``EmailDriver`` * :class:`EditAction` (post-stage-3b) → :class:`SSHDriver` """ # Lazy imports keep the side-effecting docker-exec / email-driver # modules out of every importer's graph. from decnet.orchestrator.drivers.ssh import SSHDriver if isinstance(action, (TrafficAction, FileAction)): return SSHDriver() # EmailAction lands in stage 5; reachable only after that import is # added to scheduler. Importing inside the branch avoids a cycle # with realism.llm at module load time. try: from decnet.orchestrator.emailgen.scheduler import EmailAction except ImportError: # pragma: no cover - scheduler always exists EmailAction = None # type: ignore[assignment] if EmailAction is not None and isinstance(action, EmailAction): from decnet.orchestrator.drivers.email import EmailDriver return EmailDriver() raise TypeError( f"no driver registered for action type {type(action).__name__}" )