Sagents.Persistence.Hooks behaviour (Sagents v0.7.0)

Copy Markdown

Optional behavior for hooking into agent state persistence events.

Implement this behavior to automatically save state at key points in the agent lifecycle without explicit calls.

Usage

Define a module implementing this behavior:

defmodule MyApp.Conversations.Hooks do
  @behaviour Sagents.Persistence.Hooks

  @impl true
  def after_message_received(conversation_id, message) do
    MyApp.Conversations.append_display_message(conversation_id, message)
  end

  @impl true
  def after_agent_response(conversation_id, agent_state) do
    MyApp.Conversations.save_agent_state(conversation_id, agent_state)
  end

  @impl true
  def after_status_change(conversation_id, status, data) do
    # Optional: track status changes
    :ok
  end
end

Then configure it in your application:

# config/config.exs
config :sagents, :persistence,
  adapter: MyApp.Conversations,
  hooks: MyApp.Conversations.Hooks,
  auto_save: true

Hook Callbacks

All callbacks are optional. If a callback is not defined, the hook will be skipped silently.

Error Handling

Hook callbacks should return :ok or {:ok, term()} on success. Errors will be logged but won't interrupt the agent execution.

Summary

Callbacks

Called after the agent produces a response.

Called after a user message is received.

Called when the agent status changes.

Functions

Check if hooks are enabled.

Get the configured hooks module.

Invoke a hook callback if hooks are configured.

Callbacks

after_agent_response(conversation_id, agent_state)

(optional)
@callback after_agent_response(conversation_id :: binary(), agent_state :: map()) ::
  :ok | {:ok, term()} | {:error, term()}

Called after the agent produces a response.

This is typically used to:

  • Save the agent's response message to display messages
  • Save the updated agent state

Parameters

  • conversation_id - The conversation identifier
  • agent_state - The complete agent state (map with string keys from export_state/1)

Returns

:ok or {:ok, term()} on success. Errors are logged but don't interrupt execution.

after_message_received(conversation_id, message)

(optional)
@callback after_message_received(conversation_id :: binary(), message :: term()) ::
  :ok | {:ok, term()} | {:error, term()}

Called after a user message is received.

This is typically used to save the user's message to the display messages table.

Parameters

  • conversation_id - The conversation identifier
  • message - The message struct

Returns

:ok or {:ok, term()} on success. Errors are logged but don't interrupt execution.

after_status_change(conversation_id, status, data)

(optional)
@callback after_status_change(
  conversation_id :: binary(),
  status :: atom(),
  data :: term()
) :: :ok | {:ok, term()} | {:error, term()}

Called when the agent status changes.

This can be used to track agent lifecycle events like:

  • :idle - Ready for work
  • :running - Executing
  • :interrupted - Awaiting human decision
  • :completed - Execution finished
  • :error - Execution failed

Parameters

  • conversation_id - The conversation identifier
  • status - The new status (:idle, :running, :interrupted, :completed, :error)
  • data - Additional data (interrupt_data for :interrupted, error for :error, state for :completed)

Returns

:ok or {:ok, term()} on success. Errors are logged but don't interrupt execution.

Functions

enabled?()

Check if hooks are enabled.

Returns true if a hooks module is configured, false otherwise.

get_hooks_module()

Get the configured hooks module.

Returns the module or nil if not configured.

invoke(callback_name, args)

Invoke a hook callback if hooks are configured.

This is a convenience function for the framework to call hooks without requiring the hooks module to be defined.

Examples

# In AgentServer
Sagents.Persistence.Hooks.invoke(:after_message_received, [conversation_id, message])