Behaviour for Raxol.Agent.Conversation.Item persistence.
Mirrors Raxol.Agent.ThreadLog's pluggable-adapter shape, but for the
conversation item log: the store owns durability and assigns each item a stable
seq/id; live fan-out and the snapshot/tail partition live in
Raxol.Agent.Conversation.Log.
One adapter ships today: Raxol.Agent.Conversation.Store.ETS (in-process,
ordered_set on {conversation_id, seq}). A durable adapter (DETS/Postgrex) is a
deliberate follow-up, matching ThreadLog's Ets/Postgrex split.
Append is the only writer
append/3 assigns consecutive seq values atomically per conversation and
returns the materialized items. Items are never updated or deleted; the log is
append-only.
Cursor pagination
list_items/3 accepts :after/:before sequence cursors (both exclusive),
:limit, :order, and a :type filter. A reconnecting client pages forward by
passing the last seq it has as :after.
Summary
Functions
Dispatch append to the adapter.
Dispatch get_conversation to the adapter.
Dispatch list_conversations to the adapter.
Dispatch list_items to the adapter.
Normalize a store opt into {module, config} form.
Types
@type config() :: map()
@type conversation_id() :: binary()
@type list_opts() :: keyword()
Options for list_items/3:
:after-- return items withseq >this value (exclusive cursor).:before-- return items withseq <this value (exclusive).:limit-- max items, or:all. Default 1000.:order--:asc(default) or:desc.:type-- a type atom or list of types to filter by.
@type new_item() :: %{ :type => Raxol.Agent.Conversation.Item.type(), optional(:data) => map(), optional(:status) => Raxol.Agent.Conversation.Item.status(), optional(:response_id) => binary() | nil, optional(:created_by) => term() }
A new item to append; the store assigns id/seq/created_at.
Callbacks
@callback append(config(), conversation_id(), [new_item()]) :: {:ok, [Raxol.Agent.Conversation.Item.t()]}
@callback get_conversation(config(), conversation_id()) :: {:ok, map()} | {:error, :not_found}
@callback list_conversations(config()) :: {:ok, [conversation_id()]}
@callback list_items(config(), conversation_id(), list_opts()) :: {:ok, [Raxol.Agent.Conversation.Item.t()]}
Functions
@spec append({module(), config()}, conversation_id(), [new_item()]) :: {:ok, [Raxol.Agent.Conversation.Item.t()]}
Dispatch append to the adapter.
@spec get_conversation( {module(), config()}, conversation_id() ) :: {:ok, map()} | {:error, :not_found}
Dispatch get_conversation to the adapter.
@spec list_conversations({module(), config()}) :: {:ok, [conversation_id()]}
Dispatch list_conversations to the adapter.
@spec list_items({module(), config()}, conversation_id(), list_opts()) :: {:ok, [Raxol.Agent.Conversation.Item.t()]}
Dispatch list_items to the adapter.
Normalize a store opt into {module, config} form.