falaw.backends#

Execution backend registry — where CallPlan.backend dispatches (falaw#15).

Until this module existed, “make the vendor call” meant one hardcoded path: falaw.core.call_fal. That is a budget bypass waiting to happen — the video_gen research programme’s decisions of record (§3.2) put it plainly: “Do not write a ComfyUI Transform before this lands. A flavor without a priceable Plan is a budget bypass.” A backend reachable only by overriding Transform.execute wholesale returns Plan(calls=()), so Plan.total_cost_usd reads $0.00 on a real spend and every downstream consumer of Plan — the cache, the dry-run converter, the cost gate — never sees the call happen.

The fix is the smallest one that closes that gap: CallPlan gains a backend: str field (default falaw.canonical.DFLT_BACKEND, i.e. "fal"), and execute_isolated resolves it through this module’s backends registry instead of calling call_fal directly. Everything else about a CallPlan — its cost estimate, its cache key, its artifact conversion — stays exactly what it already is, because the executor’s contract is narrow: turn (application, arguments) into the vendor’s raw response, in the same shape falaw.core.call_fal() already returns. Converting that raw response into a lacing.Artifact remains execute’s job, uniform across backends.

Nothing above falaw.Plan may know a specific backend exists. A module that imports a backend type, references a vendor node name, or assumes a backend’s execution semantics is an architecture bug regardless of whether it works — this registry is the one seam allowed to know backends exist at all.

Register a second backend with backends.register(name, executor), then build CallPlan(..., backend=name). See docs/comfyui_integration_plan.md (video_gen research programme) for the two-tier ruling this registry is the executor half of: a nw.Transform comfy flavor is the graph template and never opens a socket; a GraphExecutionBackend registered here is the executor.

Module Attributes

BackendExecutor

executor(application, arguments, *, on_event=None) -> dict — the same shape falaw.core.call_fal() returns: the vendor's raw response, ready for the existing artifact converter.

backends

Public registry of execution backends, keyed by CallPlan.backend.

Functions

get_backend_executor(name)

Look up a backend executor by name; raises with the known names.

falaw.backends.BackendExecutor#

executor(application, arguments, *, on_event=None) -> dict — the same shape falaw.core.call_fal() returns: the vendor’s raw response, ready for the existing artifact converter. An executor’s only job is *making the call*; it must not attempt caching (the registry sits below the cache) or artifact conversion (execute owns that, uniformly across backends).

alias of Callable[[…], dict]

falaw.backends.backends: Registry = <Registry falaw.backends>#

Public registry of execution backends, keyed by CallPlan.backend. on_conflict="error" so a misconfigured plugin fails loudly instead of silently shadowing the built-in fal executor.

falaw.backends.get_backend_executor(name)[source]#

Look up a backend executor by name; raises with the known names.

Return type:

Callable[..., dict]