Nous.Message (nous v0.9.0)

View Source

Represents a message in a conversation with an AI model.

Messages support multi-modal content, tool calls, and various roles following OpenAI's standard message format while providing Elixir-native validation and type safety.

Message Roles

  • :system - System instructions and context
  • :user - User input and queries
  • :assistant - AI model responses
  • :tool - Tool execution results

Examples

# Simple text messages
iex> Message.system("You are a helpful assistant")
%Message{role: :system, content: "You are a helpful assistant"}

iex> Message.user("Hello!")
%Message{role: :user, content: "Hello!"}

# Multi-modal user message
iex> Message.user([
...>   ContentPart.text("What's in this image?"),
...>   ContentPart.image_url("https://example.com/image.jpg")
...> ])
%Message{role: :user, content: [%ContentPart{}, %ContentPart{}]}

# Assistant message with tool calls
iex> Message.assistant("Let me search for that", tool_calls: [
...>   %{id: "call_123", name: "search", arguments: %{"query" => "elixir"}}
...> ])
%Message{role: :assistant, content: "Let me search for that", tool_calls: [...]}

Summary

Functions

Create an assistant message.

Extract text content from a message.

Check if message is from assistant.

Convert from legacy tuple format.

Check if message is from user.

Get message content as ContentPart list.

Get metadata from a message.

Check if message has tool calls.

Check if message is system instruction.

Check if message is tool-related (tool call or tool result).

Create a new message.

Create a new message, raising on validation failure.

Add metadata to a message.

Create a system message.

Convert message content to plain text representation.

Create a tool result message.

Create a user message.

Types

t()

@type t() :: %Nous.Message{
  content: String.t() | nil,
  created_at: DateTime.t(),
  metadata: map(),
  name: String.t() | nil,
  role: atom(),
  tool_call_id: String.t() | nil,
  tool_calls: [map()]
}

Functions

assistant(content, opts \\ [])

@spec assistant(
  String.t() | [Nous.Message.ContentPart.t()],
  keyword()
) :: t()

Create an assistant message.

Assistant messages contain AI model responses, including tool calls.

Examples

iex> Message.assistant("Hello there!")
%Message{role: :assistant, content: "Hello there!"}

iex> Message.assistant("Let me search", tool_calls: [%{...}])
%Message{role: :assistant, content: "Let me search", tool_calls: [%{...}]}

extract_text(message)

@spec extract_text(t()) :: String.t()

Extract text content from a message.

Examples

iex> message = Message.user("Hello world")
iex> Message.extract_text(message)
"Hello world"

iex> message = Message.user([ContentPart.text("Hi"), ContentPart.image_url("...")])
iex> Message.extract_text(message)
"Hi"

from_assistant?(arg1)

@spec from_assistant?(t()) :: boolean()

Check if message is from assistant.

Examples

iex> Message.from_assistant?(Message.assistant("hello"))
true

iex> Message.from_assistant?(Message.user("hi"))
false

from_legacy(response)

@spec from_legacy(tuple() | map()) :: t()

Convert from legacy tuple format.

Examples

iex> Message.from_legacy({:user_prompt, "Hello"})
%Message{role: :user, content: "Hello"}

iex> Message.from_legacy({:system_prompt, "Instructions"})
%Message{role: :system, content: "Instructions"}

from_user?(arg1)

@spec from_user?(t()) :: boolean()

Check if message is from user.

Examples

iex> Message.from_user?(Message.user("hello"))
true

iex> Message.from_user?(Message.assistant("hi"))
false

get_content_parts(message)

@spec get_content_parts(t()) :: [Nous.Message.ContentPart.t()]

Get message content as ContentPart list.

Always returns a list, converting string content to text parts.

Examples

iex> Message.get_content_parts(Message.user("Hello"))
[%ContentPart{type: :text, content: "Hello"}]

get_metadata(message, key, default \\ nil)

@spec get_metadata(t(), atom() | String.t(), any()) :: any()

Get metadata from a message.

Examples

iex> message = Message.user("hello", metadata: %{source: "api"})
iex> Message.get_metadata(message, :source)
"api"

has_tool_calls?(message)

@spec has_tool_calls?(t()) :: boolean()

Check if message has tool calls.

Examples

iex> message = Message.assistant("Hello")
iex> Message.has_tool_calls?(message)
false

iex> message = Message.assistant("Search", tool_calls: [%{id: "call_1", ...}])
iex> Message.has_tool_calls?(message)
true

is_system?(arg1)

@spec is_system?(t()) :: boolean()

Check if message is system instruction.

Examples

iex> Message.is_system?(Message.system("You are helpful"))
true

iex> Message.is_system?(Message.user("hi"))
false

is_tool_related?(message)

@spec is_tool_related?(t()) :: boolean()

Check if message is tool-related (tool call or tool result).

Examples

iex> Message.is_tool_related?(Message.tool("call_1", "result"))
true

iex> Message.is_tool_related?(Message.assistant("text", tool_calls: [%{}]))
true

iex> Message.is_tool_related?(Message.user("hello"))
false

new(attrs)

@spec new(map()) :: {:ok, t()} | {:error, Ecto.Changeset.t()}

Create a new message.

Returns {:ok, message} on success or {:error, changeset} on validation failure.

Examples

iex> Message.new(%{role: :user, content: "Hello"})
{:ok, %Message{role: :user, content: "Hello"}}

iex> Message.new(%{role: :invalid})
{:error, %Ecto.Changeset{}}

new!(attrs)

@spec new!(map()) :: t()

Create a new message, raising on validation failure.

Examples

iex> Message.new!(%{role: :user, content: "Hello"})
%Message{role: :user, content: "Hello"}

put_metadata(message, key, value)

@spec put_metadata(t(), atom() | String.t(), any()) :: t()

Add metadata to a message.

Examples

iex> message = Message.user("hello")
iex> Message.put_metadata(message, :source, "web_ui")
%Message{metadata: %{source: "web_ui"}}

system(content, opts \\ [])

@spec system(
  String.t() | [Nous.Message.ContentPart.t()],
  keyword()
) :: t()

Create a system message.

System messages provide instructions and context for the AI model.

Examples

iex> Message.system("You are a helpful assistant")
%Message{role: :system, content: "You are a helpful assistant"}

to_text(message)

@spec to_text(t()) :: String.t()

Convert message content to plain text representation.

Examples

iex> message = Message.user([
...>   ContentPart.text("Check this out: "),
...>   ContentPart.image_url("https://example.com/img.jpg")
...> ])
iex> Message.to_text(message)
"Check this out: [Image: https://example.com/img.jpg]"

tool(tool_call_id, result, opts \\ [])

@spec tool(String.t(), String.t() | map(), keyword()) :: t()

Create a tool result message.

Tool messages contain the results of tool/function executions.

Examples

iex> Message.tool("call_123", "Search results: ...", name: "search")
%Message{role: :tool, content: "Search results: ...", tool_call_id: "call_123", name: "search"}

user(content, opts \\ [])

@spec user(
  String.t() | [Nous.Message.ContentPart.t()],
  keyword()
) :: t()

Create a user message.

User messages contain input, queries, and multi-modal content.

Examples

iex> Message.user("Hello!")
%Message{role: :user, content: "Hello!"}

iex> Message.user([ContentPart.text("Hi"), ContentPart.image_url("...")])
%Message{role: :user, content: [%ContentPart{}, %ContentPart{}]}