Spectre.Runtime (Spectre v0.3.0)

Copy Markdown View Source

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:

  1. Merge agent/runtime options.
  2. Normalize input through the configured input pipeline.
  3. Load state and memory adapters.
  4. Resume an active policy, or consult ordered turn handlers.
  5. Route unclaimed input and run the selected handler.
  6. 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

step_result()

@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

advance(run, opts \\ [])

@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}

execute(agent, result, opts \\ [])

@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.

handle(agent, input, opts)

@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"
  )

load_context(agent, input, opts)

@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, [])

resolve_policy(agent, result, resolution, opts \\ [])

@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}
  )

restore_state(agent, opts)

@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")

resume(run, command, opts \\ [])

@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.

start(agent, input, opts \\ [])

@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.