Skip to main content

Overview

Messages are the fundamental unit of communication in T3Router. Each message has a role (User or Assistant), content, and metadata that determines how it’s processed by the API.

Message Structure

The Message struct contains the following fields:
pub struct Message {
    pub id: String,
    pub role: Type,
    pub content: String,
    pub content_type: ContentType,
    pub image_url: Option<String>,
    pub base64_data: Option<String>,
}

Fields

  • id: Unique identifier (UUID) for the message
  • role: Either Type::User or Type::Assistant
  • content: The text content or image URL
  • content_type: Either ContentType::Text or ContentType::Image
  • image_url: Optional URL for generated images
  • base64_data: Optional base64-encoded image data

Type Enum

The Type enum represents the role of a message:
pub enum Type {
    Assistant,
    User,
}
  • User: Messages sent by the user to the API
  • Assistant: Responses from the AI model

ContentType Enum

The ContentType enum indicates what kind of content the message contains:
pub enum ContentType {
    Text,
    Image,
}
  • Text: Standard text content
  • Image: Generated image (URL and/or base64 data)

Creating Messages

Text Messages

Create a standard text message:
use t3router::t3::message::{Message, Type};

let user_message = Message::new(
    Type::User,
    "What is the capital of France?".to_string()
);
Method Signature:
pub fn new(role: Type, content: String) -> Self
This creates a text message with:
  • A randomly generated UUID as the ID
  • ContentType::Text
  • No image data

Image Messages

Create a message containing an image:
let image_message = Message::new_image(
    Type::Assistant,
    "https://example.com/image.png".to_string(),
    Some(base64_data)
);
Method Signature:
pub fn new_image(role: Type, url: String, base64: Option<String>) -> Self
This creates an image message with:
  • A randomly generated UUID as the ID
  • ContentType::Image
  • The URL stored in both content and image_url
  • Optional base64 data

Messages with Custom IDs

Create a message with a specific ID (useful for message reconstruction):
let message = Message::with_id(
    "custom-id-123".to_string(),
    Type::User,
    "Hello".to_string()
);
Method Signature:
pub fn with_id(id: String, role: Type, content: String) -> Self

Working with Messages

Sending Messages

Messages can be sent immediately:
use t3router::t3::client::Client;
use t3router::t3::config::Config;

let mut client = Client::new(cookies, session_id);
let config = Config::new();

let response = client.send(
    "gemini-2.5-flash-lite",
    Some(Message::new(Type::User, "Hello!".to_string())),
    Some(config),
).await?;

Building Conversation History

Messages can be appended to build context before sending:
client.append_message(Message::new(
    Type::User,
    "I'm planning a trip".to_string()
));

// Later, send without a new message to use existing history
let response = client.send("gemini-2.5-flash-lite", None, Some(config)).await?;

Handling Different Content Types

Always check the content type when processing responses:
match response.content_type {
    ContentType::Text => {
        println!("Text response: {}", response.content);
    },
    ContentType::Image => {
        if let Some(url) = response.image_url {
            println!("Image URL: {}", url);
        }
        if let Some(data) = response.base64_data {
            println!("Base64 data length: {}", data.len());
        }
    }
}

Message Examples

Simple Q&A

let question = Message::new(
    Type::User,
    "Explain quantum computing in simple terms".to_string()
);

let response = client.send("claude-4-sonnet", Some(question), Some(config)).await?;
println!("Answer: {}", response.content);

Image Generation

let prompt = Message::new(
    Type::User,
    "Create a serene mountain landscape at sunset".to_string()
);

let response = client.send("gemini-imagen-4", Some(prompt), Some(config)).await?;

if matches!(response.content_type, ContentType::Image) {
    println!("Image generated successfully!");
}

Pre-populated Context

client.new_conversation();

// Set up context
client.append_message(Message::new(
    Type::User,
    "You are a helpful coding assistant".to_string()
));

client.append_message(Message::new(
    Type::Assistant,
    "I'll help you with your coding questions!".to_string()
));

// Now ask your question
let response = client.send(
    "claude-4-sonnet",
    Some(Message::new(Type::User, "How do I implement a binary search?".to_string())),
    Some(config),
).await?;

Message Validation

Ensure messages contain actual content. The Client will return an error message if you attempt to send with an empty message queue.
// Bad: No messages
let response = client.send("model", None, Some(config)).await?;
// Returns: Message { content: "Error: No messages to send", ... }

// Good: At least one message
client.append_message(Message::new(Type::User, "Hello".to_string()));
let response = client.send("model", None, Some(config)).await?;

Best Practices

Use Type::User for all user inputs and Type::Assistant for AI responses. Don’t mix these up as it affects conversation context.
Always match on content_type when handling responses, especially with image generation models that may return either text or images.
Message IDs are automatically generated and should be preserved. Use with_id() only when reconstructing conversation history.
For image messages, prefer using send_with_image_download() to automatically populate base64_data for offline access.
  • Client - Learn about the Client interface
  • Conversations - Manage multi-turn conversations
  • Models - Choose the right model for your messages

Build docs developers (and LLMs) love