Executes routed handlers without crossing action boundaries accidentally.
The runner translates a selected route into a result, but protected side effects remain staged until a policy approves them. This is the main safety boundary in Spectre: prompts may propose actions, and deterministic DSL routes may stage actions, but execution is separate.
Summary
Functions
Handles a deterministic action without calling the LLM.
Renders a prompt, calls the LLM, cleans visible replies, and lets the configured planner stage provider-neutral actions.
Renders a no-LLM reply handler.
Runs the handler selected by a route.
Calls an agent-local function declared through a run handler.
Functions
@spec action( Spectre.Action.ref(), Spectre.Input.t(), Spectre.Context.t() | map(), keyword() ) :: {:ok, Spectre.Result.t()} | {:error, term()}
Handles a deterministic action without calling the LLM.
If the action is protected, Spectre stores it as a pending action effect and
opens the configured policy awaitable. Pass reply: plus normal reply renderer options to
use a no-LLM confirmation message; otherwise Spectre renders the policy
request prompt through the normal ask path.
{:ok, result} = Spectre.Runner.action(:delete_account, input, ctx)
@spec ask( atom() | String.t(), Spectre.Input.t(), Spectre.Context.t() | map(), keyword() ) :: {:ok, Spectre.Result.t()} | {:error, term()}
Renders a prompt, calls the LLM, cleans visible replies, and lets the configured planner stage provider-neutral actions.
{:ok, result} = Spectre.Runner.ask(:support_answer, input, ctx)Policy prompts use the same rendering/LLM path but skip action planning so a confirmation question cannot accidentally stage another action.
@spec reply( atom() | String.t(), Spectre.Input.t(), Spectre.Context.t() | map(), keyword() ) :: {:ok, Spectre.Result.t()} | {:error, term()}
Renders a no-LLM reply handler.
By default reply :some_prompt renders a prompt file under the agent prompt
root. A host application may instead pass renderer: {Module, :function}.
Renderer callbacks can use arity 3 (prompt, input, ctx), arity 2
(prompt, assigns), or arity 1 (assigns).
reply :fallback, renderer: {MyApp.Replies, :render}
@spec run(Spectre.Route.t(), Spectre.Context.t()) :: {:ok, Spectre.Result.t()} | {:error, term()}
Runs the handler selected by a route.
{:ok, result} = Spectre.Runner.run(route, ctx)
@spec run_function(atom(), Spectre.Input.t(), Spectre.Context.t() | map()) :: {:ok, Spectre.Result.t()} | {:error, term()}
Calls an agent-local function declared through a run handler.
{:ok, result} = Spectre.Runner.run_function(:prepare_case, input, ctx)