Current section
Files
Jump to
Current section
Files
priv/templates/display_message_persistence.ex.eex
defmodule <%= module %> do
@moduledoc """
Implements `Sagents.DisplayMessagePersistence` for display messages.
Persists user-facing message representations to PostgreSQL and handles
tool execution lifecycle status updates. Called from within the AgentServer
process for exactly-once semantics.
"""
@behaviour Sagents.DisplayMessagePersistence
require Logger
alias Sagents.Message.DisplayHelpers
alias LangChain.Message
@impl true
def save_message(conversation_id, %Message{} = message) do
display_items = DisplayHelpers.extract_display_items(message)
if Enum.empty?(display_items) do
{:ok, []}
else
Enum.reduce_while(display_items, {:ok, []}, fn item, {:ok, acc} ->
attrs = %{
"message_type" => Atom.to_string(item.message_type),
"content_type" => Atom.to_string(item.type),
"content" => item.content
}
# Set status to "pending" for tool calls
attrs =
if item.type == :tool_call do
Map.put(attrs, "status", "pending")
else
attrs
end
case <%= conversations_module %>.append_display_message(conversation_id, attrs) do
{:ok, display_msg} ->
{:cont, {:ok, acc ++ [display_msg]}}
{:error, reason} ->
Logger.error(
"Failed to persist DisplayMessage (#{attrs["content_type"]}): #{inspect(reason)}"
)
{:halt, {:error, reason}}
end
end)
end
end
@impl true
def update_tool_status(:executing, %{call_id: call_id}) do
<%= conversations_module %>.mark_tool_executing(call_id)
end
def update_tool_status(:completed, %{call_id: call_id, result: result} = tool_info) do
metadata = %{"result" => result}
metadata =
case Map.get(tool_info, :display_text) do
nil -> metadata
text -> Map.put(metadata, "display_text", text)
end
<%= conversations_module %>.complete_tool_call(call_id, metadata)
end
def update_tool_status(:failed, %{call_id: call_id, error: error}) do
<%= conversations_module %>.fail_tool_call(call_id, %{"error" => error})
end
def update_tool_status(:interrupted, %{call_id: call_id, display_text: display_text}) do
<%= conversations_module %>.interrupt_tool_call(call_id, %{"display_text" => display_text})
end
@doc """
Resolves an interrupted tool result display message with the actual result content.
Called after a sub-agent resumes and completes.
"""
@impl true
def resolve_tool_result(tool_call_id, result_content) do
<%= conversations_module %>.resolve_interrupted_tool_result(tool_call_id, result_content)
end
end