Packages

AI agent framework for Elixir built on OTP. TEA-based agents with crash isolation, inter-agent messaging, team supervision, and real SSE streaming to Anthropic, OpenAI, Ollama, and more.

Current section

Files

Jump to
raxol_agent lib raxol agent thread_event.ex
Raw

lib/raxol/agent/thread_event.ex

defmodule Raxol.Agent.ThreadEvent do
@moduledoc """
One entry in a `Raxol.Agent.ThreadLog`.
Append-only, keyed on `{thread_id, sequence}`. The adapter
assigns `sequence` atomically on `append/4`; callers supply
`thread_id`, `kind`, `payload`, and optional `metadata`.
## Kinds
| Kind | Payload shape | Use |
| --- | --- | --- |
| `:directive` | the Directive struct emitted | record the agent's intent to fire an effect |
| `:tool_call` | `%{name, arguments}` | record an LLM tool invocation request |
| `:tool_result` | `%{name, result}` | record the result of a tool call |
| `:message` | the message string or struct | a raw conversation message preserved before compaction |
| `:state_snapshot` | the agent state map | a periodic snapshot for audit / replay |
| `:summary` | the compactor's summary string | the marker left when `ContextCompactor` summarized older messages |
| `:sandbox_deny` | `%{dimension, reason}` | record a sandbox denial |
| `:policy_result` | `%{policy, decision, ...}` | record a policy outcome (cache hit, retry attempt, timeout, ...) |
Adapters MAY round-trip arbitrary additional kinds; the canonical
set above is what the framework emits.
## Metadata
Arbitrary map. The framework attaches `:causation_id` when
available (chained from the CloudEvents envelope). Callers
may attach anything; adapters preserve it verbatim.
"""
@type kind ::
:directive
| :tool_call
| :tool_result
| :message
| :state_snapshot
| :summary
| :sandbox_deny
| :policy_result
| atom()
@type t :: %__MODULE__{
thread_id: binary(),
sequence: non_neg_integer(),
kind: kind(),
payload: term(),
metadata: map(),
recorded_at: DateTime.t()
}
@enforce_keys [:thread_id, :sequence, :kind, :recorded_at]
defstruct [
:thread_id,
:sequence,
:kind,
:recorded_at,
payload: nil,
metadata: %{}
]
@doc """
Construct a ThreadEvent. Used by adapters when materializing
events from storage; callers use the `ThreadLog.append/4`
dispatcher instead (which produces these via the adapter).
"""
@spec new(keyword()) :: t()
def new(opts) do
%__MODULE__{
thread_id: Keyword.fetch!(opts, :thread_id),
sequence: Keyword.fetch!(opts, :sequence),
kind: Keyword.fetch!(opts, :kind),
payload: Keyword.get(opts, :payload),
metadata: Keyword.get(opts, :metadata, %{}),
recorded_at: Keyword.get_lazy(opts, :recorded_at, &DateTime.utc_now/0)
}
end
end