# `Nous.Messages`
[🔗](https://github.com/nyo16/nous/blob/v0.17.1/lib/nous/messages.ex#L1)

Utilities for working with conversations and message lists.

This module provides functions to:
- Work with lists of messages (conversations)
- Convert between internal format and provider-specific formats
- Extract data from conversations
- Parse provider responses into internal format

## Message Format

We use `Nous.Message` structs with standard roles:
- `%Message{role: :system}` - System instructions
- `%Message{role: :user}` - User input (text or multi-modal)
- `%Message{role: :assistant}` - AI responses (with optional tool calls)
- `%Message{role: :tool}` - Tool execution results

## Example

    # Build conversation
    conversation = [
      Message.system("You are a helpful assistant"),
      Message.user("What is 2+2?"),
      Message.assistant("2+2 equals 4")
    ]

    # Convert to provider format
    openai_messages = Messages.to_openai_format(conversation)
    anthropic_messages = Messages.to_anthropic_format(conversation)

    # Parse provider response
    response = Messages.from_openai_response(openai_response)
    # => %Message{role: :assistant, content: "4"}

# `count_by_role`

```elixir
@spec count_by_role([Nous.Message.t()]) :: map()
```

Count messages by role.

## Examples

    iex> conversation = [Message.system("Hi"), Message.user("Hello"), Message.user("World")]
    iex> Messages.count_by_role(conversation)
    %{system: 1, user: 2, assistant: 0, tool: 0}

# `extract_text`

```elixir
@spec extract_text([Nous.Message.t()] | Nous.Message.t()) :: [String.t()] | String.t()
```

Extract text content from messages in a conversation.

## Examples

    iex> conversation = [Message.system("Be helpful"), Message.user("Hello")]
    iex> Messages.extract_text(conversation)
    ["Be helpful", "Hello"]

    iex> message = Message.user("Hi there")
    iex> Messages.extract_text(message)
    "Hi there"

# `extract_tool_calls`

```elixir
@spec extract_tool_calls([Nous.Message.t()]) :: [map()]
```

Extract tool calls from a conversation.

Returns all tool calls found in assistant messages.

## Examples

    iex> conversation = [
    ...>   Message.assistant("Let me search", tool_calls: [%{id: "call_1", name: "search", arguments: %{}}])
    ...> ]
    iex> Messages.extract_tool_calls(conversation)
    [%{id: "call_1", name: "search", arguments: %{}}]

# `find_by_role`

```elixir
@spec find_by_role([Nous.Message.t()], atom()) :: [Nous.Message.t()]
```

Find messages by role in a conversation.

## Examples

    iex> conversation = [Message.system("Be helpful"), Message.user("Hello")]
    iex> [system] = Messages.find_by_role(conversation, :system)
    iex> {system.role, system.content}
    {:system, "Be helpful"}

# `from_anthropic_response`

```elixir
@spec from_anthropic_response(map()) :: Nous.Message.t()
```

Parse Anthropic response into a Message.

## Examples

    iex> anthropic_response = %{
    ...>   "content" => [%{"type" => "text", "text" => "Hello"}],
    ...>   "model" => "claude-3-sonnet"
    ...> }
    iex> message = Messages.from_anthropic_response(anthropic_response)
    iex> {message.role, message.content}
    {:assistant, "Hello"}

# `from_gemini_response`

```elixir
@spec from_gemini_response(map()) :: Nous.Message.t()
```

Parse Gemini response into a Message.

## Examples

    iex> gemini_response = %{
    ...>   "candidates" => [%{"content" => %{"parts" => [%{"text" => "Hello"}]}}]
    ...> }
    iex> message = Messages.from_gemini_response(gemini_response)
    iex> {message.role, message.content}
    {:assistant, "Hello"}

# `from_openai_response`

```elixir
@spec from_openai_response(map()) :: Nous.Message.t()
```

Parse OpenAI response into a Message.

## Examples

    iex> openai_response = %{
    ...>   "choices" => [%{"message" => %{"role" => "assistant", "content" => "Hello"}}],
    ...>   "usage" => %{"total_tokens" => 10}
    ...> }
    iex> message = Messages.from_openai_response(openai_response)
    iex> {message.role, message.content}
    {:assistant, "Hello"}

# `from_provider_response`

```elixir
@spec from_provider_response(map(), atom()) :: Nous.Message.t()
```

Parse provider response into a Message.

Dispatches to appropriate provider-specific parser.

## Examples

    iex> openai_response = %{
    ...>   "choices" => [%{"message" => %{"role" => "assistant", "content" => "Hello"}}],
    ...>   "usage" => %{"total_tokens" => 10}
    ...> }
    iex> message = Messages.from_provider_response(openai_response, :openai)
    iex> {message.role, message.content}
    {:assistant, "Hello"}

# `last_message`

```elixir
@spec last_message([Nous.Message.t()]) :: Nous.Message.t() | nil
```

Get the last message from a conversation.

## Examples

    iex> conversation = [Message.user("Hi"), Message.assistant("Hello")]
    iex> last = Messages.last_message(conversation)
    iex> {last.role, last.content}
    {:assistant, "Hello"}

# `normalize_format`

```elixir
@spec normalize_format(any()) :: [Nous.Message.t()]
```

Normalize any message format to internal Message representation.

Attempts to detect format and convert to Message structs.

## Examples

    iex> [message] = Messages.normalize_format([%{"role" => "user", "content" => "Hi"}])
    iex> {message.role, message.content}
    {:user, "Hi"}

# `to_anthropic_format`

```elixir
@spec to_anthropic_format([Nous.Message.t()]) :: {String.t() | nil, [map()]}
```

Convert messages to Anthropic format.

Returns `{system_prompt, messages}` where system prompt is extracted
and combined, and messages are converted to Anthropic format.

## Examples

    iex> conversation = [Message.system("Be helpful"), Message.user("Hello")]
    iex> Messages.to_anthropic_format(conversation)
    {"Be helpful", [%{"role" => "user", "content" => "Hello"}]}

# `to_gemini_format`

```elixir
@spec to_gemini_format([Nous.Message.t()]) :: {String.t() | nil, [map()]}
```

Convert messages to Gemini format.

Returns `{system_prompt, contents}` where system prompt is extracted
and messages are converted to Gemini contents format.

## Examples

    iex> conversation = [Message.system("Be helpful"), Message.user("Hello")]
    iex> Messages.to_gemini_format(conversation)
    {"Be helpful", [%{"role" => "user", "parts" => [%{"text" => "Hello"}]}]}

# `to_openai_format`

```elixir
@spec to_openai_format([Nous.Message.t()]) :: [map()]
```

Convert messages to OpenAI format.

## Examples

    iex> conversation = [Message.system("Be helpful"), Message.user("Hello")]
    iex> Messages.to_openai_format(conversation)
    [
      %{"role" => "system", "content" => "Be helpful"},
      %{"role" => "user", "content" => "Hello"}
    ]

# `to_provider_format`

```elixir
@spec to_provider_format([Nous.Message.t()], atom()) :: any()
```

Convert messages to provider-specific format.

Dispatches to the appropriate provider-specific conversion function.

## Examples

    iex> conversation = [Message.system("Be helpful"), Message.user("Hello")]
    iex> Messages.to_provider_format(conversation, :openai)
    [%{"role" => "system", "content" => "Be helpful"}, %{"role" => "user", "content" => "Hello"}]

    iex> conversation = [Message.system("Be helpful"), Message.user("Hello")]
    iex> Messages.to_provider_format(conversation, :anthropic)
    {"Be helpful", [%{"role" => "user", "content" => "Hello"}]}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
