One message of a chat (phoenix_kit_agent_messages): what the user wrote, a
model answer (with the tool calls it asked for), a tool result, or a notice
(a limit, an error, a refusal). The table is also the assistant's journal of
tool calls: who, what, when, and the outcome.
conversation_uuid, ai_request_uuid, assistant_message_uuid and
confirmation_uuid are set by the caller, never cast. tool_name is the
registry name of the tool, not the name shown to the model; tool_result is
the truncated result, without confirmation tokens or other control fields.
A write the user is asked to confirm (V2 of the migrations) is a tool
message with tool_outcome: "needs_confirmation", the uuid of core's
confirmation in confirmation_uuid and the assistant message whose tool
call it answers in assistant_message_uuid; how it ended is a notice with
the same confirmation_uuid and its outcome (confirmed, rejected,
expired, changed, failed). One without such a notice is still waiting.
changeset/2 is the full set of fields, for the turn loop
(PhoenixKitAgent.Turns) only; user_changeset/2 is what a person writes —
the text of a user message and nothing else. Both cut NUL characters from
every text they keep (PostgreSQL refuses them in text and jsonb).
tool_summary is virtual: the read functions of
PhoenixKitAgent.Conversations fill it for a tool message in place of
the result (see there). So is card: the chat panel puts there what it
shows of a confirmation (PhoenixKitAgent.Confirmations.cards/4).
Summary
Functions
Builds a message from all its content fields — for the turn loop only, never from what a client sent.
The message roles: user, assistant, tool, notice.
The outcomes of a tool call.
A message the user writes: role user and the non-blank content; every
other attribute is ignored.
Types
@type t() :: %PhoenixKitAgent.Schemas.Message{ __meta__: term(), ai_request_uuid: term(), assistant_message_uuid: term(), card: term(), confirmation_uuid: term(), content: term(), conversation: term(), conversation_uuid: term(), cost_micro_usd: term(), error: term(), input_tokens: term(), inserted_at: term(), latency_ms: term(), model: term(), output_tokens: term(), role: term(), tool_call_id: term(), tool_calls: term(), tool_name: term(), tool_outcome: term(), tool_result: term(), tool_summary: term(), turn_ref: term(), uuid: term() }
Functions
@spec changeset(t(), map()) :: Ecto.Changeset.t()
Builds a message from all its content fields — for the turn loop only, never from what a client sent.
@spec roles() :: [String.t()]
The message roles: user, assistant, tool, notice.
@spec tool_outcomes() :: [String.t()]
The outcomes of a tool call.
@spec user_changeset(t(), map()) :: Ecto.Changeset.t()
A message the user writes: role user and the non-blank content; every
other attribute is ignored.