Skip to content

Messages

Messages build the conversation context for agent interactions. Each message has a role (user, assistant, system, or tool) and content (text, images, or documents). ActiveAgent supports both native provider formats and a unified common format that works across all providers.

Message Roles

Understanding roles helps you structure conversations correctly:

  • User - Input from the user to the agent (text, images, documents)
  • Assistant - Responses from the agent, including tool call requests
  • System - Instructions that guide agent behavior (set via instructions option)
  • Tool - Results from tool executions (handled automatically)

Most of the time you'll send user messages and inspect assistant/tool responses.

Sending Messages

Single Message

The simplest way to send a message:

ruby
class SingleMessageAgent < ApplicationAgent
  generate_with :openai, model: "gpt-4o-mini"

  def chat
    prompt("What is the capital of France?")
  end
end

Use the message: keyword for clarity:

ruby
class MessageKeywordAgent < ApplicationAgent
  generate_with :anthropic, model: "claude-3-5-haiku-20241022"

  def chat
    prompt(message: "Explain quantum computing")
  end
end

Multiple Messages

Send multiple strings as separate user messages in a single prompt:

ruby
class MultipleMessagesAgent < ApplicationAgent
  generate_with :open_router, model: "openai/gpt-4o-mini"

  def chat_inline
    prompt(
      "Tell me a fun fact about Ruby.",
      "Now explain why that's interesting."
    )
  end

  def chat_array
    prompt(messages: [
      "Tell me a fun fact about Ruby.",
      "Now explain why that's interesting."
    ])
  end
end
ruby
class MultipleMessagesAgent < ApplicationAgent
  generate_with :open_router, model: "openai/gpt-4o-mini"

  def chat_inline
    prompt(
      "Tell me a fun fact about Ruby.",
      "Now explain why that's interesting."
    )
  end

  def chat_array
    prompt(messages: [
      "Tell me a fun fact about Ruby.",
      "Now explain why that's interesting."
    ])
  end
end

Messages with Roles

Set explicit roles using hashes. The default role is :user:

ruby
class MessagesWithRolesAgent < ApplicationAgent
  generate_with :openai, model: "gpt-4o-mini"

  def chat_multiple
    prompt(messages: [
      { role: "assistant", text: "I can help with programming questions." },
      { text: "What are the benefits of ActiveRecord?" }
    ])
  end

  def chat_single
    prompt(message: { role: "assistant", text: "Previous response..." })
  end
end

Note: Use the instructions option for system messages. System role messages are dropped in common format and replaced by instructions. Learn about instructions →

Images and Documents

ActiveAgent provides a unified interface for multimodal inputs. Pass HTTP URLs or Base64 data URIs - the framework converts them to the provider's native format.

ActiveStorage Support: Direct attachment support for ActiveStorage files is coming soon.

Images

ruby
class ImageAgent < ApplicationAgent
  generate_with :anthropic, model: "claude-3-5-haiku-20241022"

  def analyze_url
    prompt(
      "What's in this image?",
      image: "https://framerusercontent.com/images/oEx786EYW2ZVL4Xf9hparOVLjHI.png?scale-down-to=64"
    )
  end

  def analyze_base64
    prompt(
      "Describe this image",
      image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
    )
  end

  def analyze_message_hash
    prompt(message: {
      text: "Analyze this",
      image: "https://framerusercontent.com/images/oEx786EYW2ZVL4Xf9hparOVLjHI.png?scale-down-to=64"
    })
  end

  def analyze_messages_array
    prompt(messages: [
      { text: "What's in this image?" },
      { image: "https://framerusercontent.com/images/oEx786EYW2ZVL4Xf9hparOVLjHI.png?scale-down-to=64" }
    ])
  end
end

Documents

Same interface for PDFs and other documents:

ruby
class DocumentAgent < ApplicationAgent
  generate_with :openai, model: "gpt-4o-mini"

  def summarize_url
    prompt(
      "Summarize this document",
      document: "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
    )
  end
end

Supported formats:

  • Images: JPEG, PNG, GIF, WebP
  • Documents: PDF (provider-dependent)

Inspecting Responses

After generation, access messages from the response:

ruby
response = InspectMessagesAgent.with(message: "Hello").chat.generate_now

response.message
response.messages

Grouping by Role

Filter messages to find specific types:

ruby
system_messages = response.messages.select { |m| m.role == :system }
user_messages = response.messages.select { |m| m.role == :user }
assistant_messages = response.messages.select { |m| m.role == :assistant }
tool_messages = response.messages.select { |m| m.role == :tool }

System Messages

System messages come from the instructions option:

ruby
class SystemMessagesAgent < ApplicationAgent
  generate_with :anthropic, model: "claude-3-5-haiku-20241022"

  def chat
    prompt(
      instructions: "You are a travel booking assistant.",
      message: "Help me book a hotel"
    )
  end
end
ruby
system_message = response.messages.find { |m| m.role == :system }

Assistant Messages

Assistant messages contain the agent's responses. Provide conversation history by including previous assistant messages:

ruby
class AssistantHistoryAgent < ApplicationAgent
  generate_with :open_router, model: "openai/gpt-4o-mini"

  def continue_conversation
    prompt(messages: [
      { role: "assistant", text: "I can help you with that." },
      { text: "Great! I need help with X" }
    ])
  end
end

Tool Messages

Tool messages contain results from tool executions. ActiveAgent handles tool calls and their results automatically. Learn about tools →

ruby
# Tool messages contain execution results
tool_messages.first.content
# => "https://cataas.com/cat/5e9..."

Common vs Native Format

ActiveAgent provides two ways to work with messages:

Use the unified prompt() interface. ActiveAgent normalizes messages across providers:

ruby
class CommonFormatAgent < ApplicationAgent
  generate_with :openai, model: "gpt-4o-mini"

  def multimodal
    prompt("Hello", image: "https://framerusercontent.com/images/oEx786EYW2ZVL4Xf9hparOVLjHI.png?scale-down-to=64")
  end
end

Benefits:

  • Switch providers without changing code
  • Consistent API across all providers
  • Automatic format conversion

Native Format

For provider-specific features, use native message structures:

ruby
class NativeFormatAgent < ApplicationAgent
  generate_with :openai, model: "gpt-4o-mini"

  def multimodal_native
    # Use common format - the native format is provider-specific
    prompt("What's in this image?", image: "https://framerusercontent.com/images/oEx786EYW2ZVL4Xf9hparOVLjHI.png?scale-down-to=64")
  end
end

Both formats work with all providers, but common format is simpler and more portable.