Baton.Flow.GuardRunner behaviour (Baton v0.27.4)

Copy Markdown View Source

The host-side contract for a node's guards (see Baton.Flow.NodeSpec).

After Baton.Flow.Workers.LLM has decoded a reply and run the node's handle_response, it hands the outcome — together with the dumped node, whose "guards" list carries the specs — to the runner configured under config :baton, flow_runtime: [guard_runner: MyApp.GuardRunner]. The runner returns a possibly transformed step outcome: pass the result through, rewrite it (degrade a field, mark it partial), or reject the sample with {:error, reason} so the step retries and the model is asked again.

Baton knows nothing about guard kinds. It validates the specs' shape at definition load, refuses to run a guarded node when no runner is configured (a declared check silently skipped is worse than a loud stop), and stays out of the way otherwise. Budget policy — how many fresh samples a rejection is worth — belongs to the runner; Baton.Backoff.deflate/1 gives it the genuine-failure count to build on.

The runner is called on every outcome the response pipeline produces, including {:error, _} — so it can observe rejected samples if it wants to — but a runner that only inspects {:ok, result} and passes everything else through untouched is the expected shape.

Summary

Callbacks

Apply the node's guard specs to a step outcome.

Callbacks

run(outcome, node, job)

@callback run(outcome :: term(), node :: map(), job :: Oban.Job.t()) ::
  Baton.Worker.step_result()

Apply the node's guard specs to a step outcome.

outcome is whatever handle_response returned (before usage attachment); node is the dumped flow node (node["guards"] holds the specs); job is the executing Oban job, for budget and provenance.