Baton.Flow.RequestAssembly (Baton v0.27.4)

Copy Markdown View Source

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} — from Baton.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

assembled()

@type assembled() :: %{
  messages: [%{role: String.t(), content: String.t() | [term()]}],
  opts: keyword(),
  model: String.t(),
  bindings: map(),
  assigns: map(),
  prompts: %{system: prompt() | nil, user: prompt() | nil}
}

prompt()

@type prompt() :: %{:body => String.t() | [term()], optional(:provenance) => map()}

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(config, environment, opts \\ [])

@spec assemble(map(), map(), keyword()) :: {:ok, assembled()} | {:error, term()}

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 — a Baton.Flow.PromptResolver module or a fun(spec, assigns, runtime) with the same contract. Required whenever the config declares a system_prompt or user_prompt.
  • :runtime — the opaque runtime map handed to the resolver (Baton.Flow.Runtime.runtime/2 at run time). Defaults to %{}.