Spectre.State (Spectre v0.3.0)

Copy Markdown View Source

Conversation state owned by Spectre.

State is the authoritative machine state for routing and effect safety. It tracks the current flow, pending effects, active awaitables, compact chat history, and trace events.

Summary

Functions

Marks the policy-gated effect identified by an awaitable as approved.

Returns true when the state is waiting for an active policy response.

Returns true when the specified Run owns an open policy response.

Advances the optimistic-concurrency revision exactly once.

Cancels pending effects and appends a trace event.

Clears open awaitables without removing pending effects.

Clears pending effects and open awaitables.

Completes the next pending effect and returns {state, completed_effect}.

Marks the current pending effect as failed and clears it from the execution queue while preserving the failed transition in history.

Normalizes map, keyword, or nil input into a state struct.

Returns the currently open policy awaitable, if one exists.

Returns the open policy awaitable owned by one Run.

Returns the next effect in the execution queue, or nil when it is empty.

Returns the pending effect owned by one Run.

Stores a pending effect and optionally starts a policy gate for it.

Appends a compact chat-history entry under state.data[:chat_history].

Replaces an awaitable through the validated lifecycle transition.

Finds a terminal transition for an effect identifier.

Prepends a compact trace event to the state.

Types

t()

@type t() :: %Spectre.State{
  awaitables: [Spectre.Awaitable.t()],
  conversation_id: term(),
  current_flow: atom() | nil,
  current_scope: Spectre.Definition.scope() | nil,
  data: map(),
  memory_refs: [term()],
  pending_effects: [Spectre.Effect.t()],
  planned_effects: [Spectre.Effect.t()],
  revision: non_neg_integer(),
  state_version: pos_integer(),
  trace: [term()]
}

Functions

approve_pending_effect(state, subject_id)

@spec approve_pending_effect(t(), term()) ::
  {:ok, t(), Spectre.Effect.t()}
  | {:error,
     :pending_effect_not_found | {:effect_not_waiting_policy, term(), atom()}}

Marks the policy-gated effect identified by an awaitable as approved.

The effect remains pending so execution can happen at the explicit host boundary after this state transition has been persisted.

awaiting_policy?(state)

@spec awaiting_policy?(t()) :: boolean()

Returns true when the state is waiting for an active policy response.

awaiting_policy?(state, run_id)

@spec awaiting_policy?(t(), String.t() | nil) :: boolean()

Returns true when the specified Run owns an open policy response.

This scoped form is used by Spectre.Instance. Omitting the Run id retains the conversation-wide compatibility behavior used by stateless calls and Spectre.Session.

bump_revision(state)

@spec bump_revision(t()) :: t()

Advances the optimistic-concurrency revision exactly once.

cancel_pending(state)

@spec cancel_pending(t()) :: t()

Cancels pending effects and appends a trace event.

clear_open_awaitables(state)

@spec clear_open_awaitables(t()) :: t()

Clears open awaitables without removing pending effects.

clear_pending(state)

@spec clear_pending(t()) :: t()

Clears pending effects and open awaitables.

complete_pending_effect(state, result)

@spec complete_pending_effect(t(), term()) :: {t(), Spectre.Effect.t() | nil}

Completes the next pending effect and returns {state, completed_effect}.

If the queue is empty, the effect is nil. If the lifecycle rejects the transition, the original state and nil are returned. Runtime integrations should normally call Spectre.execute/3, which also enforces authorization, persistence, idempotency, and action execution boundaries.

fail_pending_effect(state, reason)

@spec fail_pending_effect(t(), term()) :: {t(), Spectre.Effect.t() | nil}

Marks the current pending effect as failed and clears it from the execution queue while preserving the failed transition in history.

new(state)

@spec new(t() | map() | keyword() | nil) :: t()

Normalizes map, keyword, or nil input into a state struct.

open_policy_awaitable(state)

@spec open_policy_awaitable(t()) :: Spectre.Awaitable.t() | nil

Returns the currently open policy awaitable, if one exists.

Closed, expired, and non-policy awaitables are ignored. Spectre enforces at most one active policy boundary during normal lifecycle transitions.

open_policy_awaitable(state, run_id)

@spec open_policy_awaitable(t(), String.t() | nil) :: Spectre.Awaitable.t() | nil

Returns the open policy awaitable owned by one Run.

pending_effect(state)

@spec pending_effect(t()) :: Spectre.Effect.t() | nil

Returns the next effect in the execution queue, or nil when it is empty.

Hosts normally use Spectre.Result.pending_effect/1 on the value returned by Spectre.ask/3 or Spectre.turn/3. This state-level helper is useful for adapters restoring persisted state.

pending_effect(state, run_id)

@spec pending_effect(t(), String.t() | nil) :: Spectre.Effect.t() | nil

Returns the pending effect owned by one Run.

put_pending_effect(state, effect, policy)

@spec put_pending_effect(t(), Spectre.Effect.t(), term()) :: t()

Stores a pending effect and optionally starts a policy gate for it.

record_turn(state, input, result, limit)

@spec record_turn(
  t(),
  Spectre.Input.t(),
  Spectre.Result.t(),
  pos_integer() | false | nil
) :: t()

Appends a compact chat-history entry under state.data[:chat_history].

replace_awaitable(state, awaitable)

@spec replace_awaitable(t(), Spectre.Awaitable.t()) :: t()

Replaces an awaitable through the validated lifecycle transition.

Matching is performed by awaitable identifier. The function raises if the replacement would violate lifecycle invariants; application code should prefer the higher-level Spectre.Lifecycle operations unless implementing a state adapter or compatibility layer.

resolved_effect(state, effect_id)

@spec resolved_effect(t(), term()) :: Spectre.Effect.t() | nil

Finds a terminal transition for an effect identifier.

This is used as a local idempotency guard when a restored state accidentally contains both a pending copy and an already resolved copy of the same effect.

trace(state, event)

@spec trace(t(), term()) :: t()

Prepends a compact trace event to the state.