Assemble a generic llm node's provider request from its config and a runtime environment — as a pure function, shared by execution and preview.
Baton.Flow.Workers.LLM.request/1 calls this at run time; a host's preview
surface (a prompt workbench, a definition linter) calls it with the same
config and a reconstructed environment. Because both go through the one
function, what a preview shows and what a worker sends cannot drift — and
every intermediate the preview wants to display (resolved bindings, merged
assigns, interpolated prompt bodies, the wire opts) is exposed in the result
instead of being worker-internal.
Assembly itself performs no I/O. The one collaborator that may (a prompt resolver backed by a database registry) is passed in by the caller, so a preview can substitute its own — or reuse the production resolver with a preview-shaped runtime.
Errors
Malformed configs return typed errors — never raise, never half-assemble:
{:invalid_node_config, value}— config is not a map{:invalid_bindings, value}—"bindings"is not a map{:invalid_binding, expr}/{:unknown_binding_root, root}/{:binding_not_found, expr}— fromBaton.Flow.Binding:missing_prompt_resolver— a prompt spec is present but no resolver was given{:unsupported_prompt_spec, spec}— from the resolver{:unknown_prompt_variables, :system | :user, missing}— the resolver's unknown-variables error, tagged with which prompt failed{:invalid_prompt_result, slot, value}— the resolver returned something other than{:ok, %{body: binary | list}} | {:error, reason}:invalid_model/{:invalid_model, value}— model missing, or resolved to a non-string{:unsupported_response_mode, mode}— caught here, before tokens are spent, instead of at decode time after the call
Summary
Types
A resolved prompt. body is the rendered text, or a list of content parts
for a host whose wire wants structure the text cannot carry — an Anthropic
cache_control breakpoint, say. Baton neither builds nor inspects the
parts: what a part is is between the host's resolver and the client it
ends up at, so the list is passed through whole.
Functions
Assemble the request for one node config against environment.
Types
A resolved prompt. body is the rendered text, or a list of content parts
for a host whose wire wants structure the text cannot carry — an Anthropic
cache_control breakpoint, say. Baton neither builds nor inspects the
parts: what a part is is between the host's resolver and the client it
ends up at, so the list is passed through whole.
Functions
Assemble the request for one node config against environment.
environment is the five-root binding environment
(Baton.Flow.Runtime.environment/1 at run time; reconstructed from stored
state in a preview).
Options
:resolver— aBaton.Flow.PromptResolvermodule or afun(spec, assigns, runtime)with the same contract. Required whenever the config declares asystem_promptoruser_prompt.:runtime— the opaque runtime map handed to the resolver (Baton.Flow.Runtime.runtime/2at run time). Defaults to%{}.