ExAgent.Server.Snapshot (ExAgent v0.2.0)

Copy Markdown View Source

A serializable checkpoint of an ExAgent.Server's conversational state.

A snapshot captures what is needed to resume a conversation after a crash or restart: the agent_id, the serialized message_history, accumulated token usage, free-form metadata, and an optional serializable provider_state.

By design a snapshot never contains:

  • pids or other live process references,
  • API keys or other secrets,
  • tool closures / function captures,
  • the live model struct (its internal state isn't assumed serializable).

Those live, non-serializable pieces (tools, model, instructions) are provided by the host app as an agent template on restart; the snapshot only carries the conversational state to rehydrate on top of that template.

Snapshots are JSON-serializable (Snapshot.serialize/1 / deserialize/1), so the same contract maps cleanly to a future Postgres/Redis store without redesign. Serialization is strict: a snapshot that somehow carries a non-encodable value (e.g. a closure snuck into metadata) fails to encode rather than being silently stored as a broken term.

Summary

Functions

Decode a JSON binary (from serialize/1) back into a snapshot struct. Returns {:ok, t} or {:error, reason}.

Parse the snapshot's message history back into Message.t() structs. Returns {:ok, [Message.t()]} or {:error, reason}. An empty/absent history yields {:ok, []}.

Build a snapshot from the conversational state of an ExAgent.Server.

Encode a snapshot to a JSON binary. Strict: raises if any field is not JSON-encodable (e.g. a closure or pid), which is how we refuse to persist non-serializable state.

Rebuild the Usage struct from the snapshot's usage map.

Types

t()

@type t() :: %ExAgent.Server.Snapshot{
  agent_id: String.t(),
  message_history: String.t() | nil,
  metadata: map(),
  provider_state: map() | nil,
  saved_at: DateTime.t() | nil,
  usage: map(),
  version: pos_integer()
}

Functions

deserialize(binary)

@spec deserialize(String.t() | binary()) :: {:ok, t()} | {:error, term()}

Decode a JSON binary (from serialize/1) back into a snapshot struct. Returns {:ok, t} or {:error, reason}.

messages(snapshot)

@spec messages(t()) :: {:ok, [ExAgent.Message.t()]} | {:error, term()}

Parse the snapshot's message history back into Message.t() structs. Returns {:ok, [Message.t()]} or {:error, reason}. An empty/absent history yields {:ok, []}.

new(opts)

@spec new(keyword()) :: t()

Build a snapshot from the conversational state of an ExAgent.Server.

Options: :agent_id (required), :history ([Message.t()]), :usage (Usage.t()), :metadata (map), :provider_state (map | nil). message_history is serialized via Message.to_json/1 here, so the snapshot is immediately serializable.

serialize(snapshot)

@spec serialize(t()) :: String.t()

Encode a snapshot to a JSON binary. Strict: raises if any field is not JSON-encodable (e.g. a closure or pid), which is how we refuse to persist non-serializable state.

usage_struct(snapshot)

@spec usage_struct(t()) :: ExAgent.Message.Usage.t()

Rebuild the Usage struct from the snapshot's usage map.