Turn-level orchestration for Spectre agents.
Runtime owns the per-turn workflow, but it deliberately does not own the domain decisions inside an agent. It coordinates boundaries in this order:
- Merge agent/runtime options.
- Normalize input through the configured input pipeline.
- Load state and memory adapters.
- Resume an active policy, or consult ordered turn handlers.
- Route unclaimed input and run the selected handler.
- Record chat history and persist state/memory.
Keeping this flow centralized makes individual adapters simpler and keeps policy gates from being accidentally skipped.
Summary
Functions
Advances a Run until it must await work, exposes a public boundary, or completes.
Executes a staged effect using the durable two-commit workflow.
Handles one normalized input turn for an agent module.
Builds the per-turn context by loading state and memory adapters.
Resolves a currently open policy from a trusted host decision and persists the state transition before returning it.
Restores initial session state from the configured state adapter.
Resumes a revision-fenced policy boundary or effect invocation.
Creates a resumable Run and loads only its logical input and state.
Types
@type step_result() :: {:continue, Spectre.Run.t()} | {:await, Spectre.Invocation.t(), Spectre.Run.t()} | {:boundary, Spectre.Run.Boundary.t(), Spectre.Run.t()} | {:complete, Spectre.Result.t(), Spectre.Run.t()} | {:error, term(), Spectre.Run.t()}
Functions
@spec advance( Spectre.Run.t(), keyword() ) :: step_result()
Advances a Run until it must await work, exposes a public boundary, or completes.
The return vocabulary is closed:
{:continue, run}
{:await, invocation, run}
{:boundary, observable, run}
{:complete, result, run}
{:error, reason, run}
@spec execute(module(), Spectre.Result.t(), keyword()) :: {:ok, Spectre.Result.t()} | {:error, term()}
Executes a staged effect using the durable two-commit workflow.
The executable state is persisted before the capability is invoked, and the completed/failed state is persisted before the terminal result is returned. Adapters receive the effect idempotency key through the action context.
@spec handle(module(), Spectre.Input.t(), keyword()) :: {:ok, Spectre.Result.t()} | {:error, term()}
Handles one normalized input turn for an agent module.
{:ok, result} =
Spectre.Runtime.handle(
MyApp.Agent,
Spectre.Input.new("delete my account"),
conversation_id: "conv-123"
)
@spec load_context(module(), Spectre.Input.t(), keyword()) :: {:ok, Spectre.Context.t()} | {:error, term()}
Builds the per-turn context by loading state and memory adapters.
{:ok, ctx} = Spectre.Runtime.load_context(MyApp.Agent, input, [])
@spec resolve_policy( module(), Spectre.Result.t(), Spectre.Policy.resolution(), keyword() ) :: {:ok, Spectre.Result.t()} | {:error, term()}
Resolves a currently open policy from a trusted host decision and persists the state transition before returning it.
Unlike a user turn, this does not route synthetic text, append chat history, or invoke the memory adapter.
{:ok, approved} =
Spectre.Runtime.resolve_policy(
MyApp.Agent,
awaiting_result,
{:accept, :terms_accepted},
assigns: %{user: user}
)
@spec restore_state( module(), keyword() ) :: {:ok, Spectre.State.t()} | {:error, term()}
Restores initial session state from the configured state adapter.
{:ok, state} = Spectre.Runtime.restore_state(MyApp.Agent, conversation_id: "conv-123")
@spec resume(Spectre.Run.t(), term(), keyword()) :: step_result()
Resumes a revision-fenced policy boundary or effect invocation.
Policy responses use {:policy, ref, resolution}. Effect work uses
{:execute, invocation} (or {:execute, invocation_id}). Stale, foreign,
and already-consumed references are rejected before lifecycle state changes.
@spec start(module(), Spectre.Input.t() | String.t() | map() | term(), keyword()) :: step_result()
Creates a resumable Run and loads only its logical input and state.
Runtime options and memory are intentionally not stored on the Run. They are re-resolved on every subsequent step.