Messages & Items

Access and manage conversation messages and items.

Overview

  • Messages - Traditional chat messages (ChatCompletions, AssistantsApi)

  • Items - Enhanced conversation items (RealtimeApi) including audio

Messages

Access Messages

// Get all messages
List<Message> messages = agent.Messages;

// Get last message
Message lastMessage = agent.LastMessage;

// Get last user message
Message lastUserMessage = agent.Messages
    .LastOrDefault(m => m.Role == Role.User);

// Get last assistant message
Message lastAssistantMessage = agent.Messages
    .LastOrDefault(m => m.Role == Role.Assistant);

Message Structure

public class Message
{
    public string Id { get; set; }
    public Role Role { get; set; }  // System, User, Assistant, Tool
    public string Content { get; set; }
    public List<ContentPart> Parts { get; set; }
    public DateTime Timestamp { get; set; }
    public Dictionary<string, object> Metadata { get; set; }
}

Message Roles

public enum Role
{
    System,      // System instructions
    User,        // User messages
    Assistant,   // AI responses
    Tool         // Tool outputs
}

Content Parts

// Text message
var message = new Message
{
    Role = Role.User,
    Content = "Hello!",
    Parts = new List<ContentPart>
    {
        new ContentPart { Type = "text", Text = "Hello!" }
    }
};

// Image message
var imageMessage = new Message
{
    Role = Role.User,
    Parts = new List<ContentPart>
    {
        new ContentPart { Type = "text", Text = "What's in this image?" },
        new ContentPart
        {
            Type = "image_url",
            ImageUrl = new ImageUrl
            {
                Url = "data:image/png;base64,...",
                Detail = "high"
            }
        }
    }
};

// Audio message
var audioMessage = new Message
{
    Role = Role.User,
    Parts = new List<ContentPart>
    {
        new ContentPart
        {
            Type = "input_audio",
            InputAudio = new InputAudio
            {
                Data = audioBase64,
                Format = "wav"
            }
        }
    }
};

Items (Realtime API)

Access Items

// Get all conversation items
List<ConversationItem> items = agent.Items;

// Filter by type
var messages = items.Where(i => i.Type == "message").ToList();
var functionCalls = items.Where(i => i.Type == "function_call").ToList();
var functionCallOutputs = items.Where(i => i.Type == "function_call_output").ToList();

Item Structure

public class ConversationItem
{
    public string Id { get; set; }
    public string Type { get; set; }  // message, function_call, function_call_output
    public string Status { get; set; }  // completed, in_progress, incomplete
    public Role Role { get; set; }
    public List<ContentPart> Content { get; set; }
}

Item Types

// Message item
{
    "type": "message",
    "role": "user",
    "content": [
        { "type": "text", "text": "Hello!" }
    ]
}

// Function call item
{
    "type": "function_call",
    "name": "get_weather",
    "call_id": "call_abc123",
    "arguments": "{\"location\":\"Tokyo\"}"
}

// Function call output item
{
    "type": "function_call_output",
    "call_id": "call_abc123",
    "output": "{\"temperature\":22,\"condition\":\"sunny\"}"
}

Adding Messages

Manually Add User Message

var message = new Message
{
    Role = Role.User,
    Content = "Hello!",
    Timestamp = DateTime.UtcNow
};

agent.Conversation.Messages.Add(message);
await agent.SaveConversationAsync();

Manually Add System Message

var systemMessage = new Message
{
    Role = Role.System,
    Content = "You are a Unity development expert.",
    Timestamp = DateTime.UtcNow
};

// Insert at beginning
agent.Conversation.Messages.Insert(0, systemMessage);

Add Tool Response

var toolMessage = new Message
{
    Role = Role.Tool,
    Content = toolOutput,
    Metadata = new Dictionary<string, object>
    {
        ["tool_call_id"] = toolCallId,
        ["tool_name"] = toolName
    }
};

agent.Conversation.Messages.Add(toolMessage);

Modifying Messages

Edit Last Message

// Get last user message
var lastUserMessage = agent.Messages
    .LastOrDefault(m => m.Role == Role.User);

if (lastUserMessage != null)
{
    // Edit content
    lastUserMessage.Content = "Updated message";
    
    // Save changes
    await agent.SaveConversationAsync();
}

Delete Messages

// Remove last message
if (agent.Messages.Count > 0)
{
    agent.Messages.RemoveAt(agent.Messages.Count - 1);
}

// Remove specific message
agent.Messages.RemoveAll(m => m.Id == messageId);

// Clear all except system message
var systemMessage = agent.Messages.FirstOrDefault(m => m.Role == Role.System);
agent.Messages.Clear();
if (systemMessage != null)
{
    agent.Messages.Add(systemMessage);
}

Filtering Messages

By Role

// User messages only
var userMessages = agent.Messages
    .Where(m => m.Role == Role.User)
    .ToList();

// Assistant messages only
var assistantMessages = agent.Messages
    .Where(m => m.Role == Role.Assistant)
    .ToList();

By Date Range

var today = DateTime.Today;
var todayMessages = agent.Messages
    .Where(m => m.Timestamp.Date == today)
    .ToList();

var lastHour = DateTime.UtcNow.AddHours(-1);
var recentMessages = agent.Messages
    .Where(m => m.Timestamp >= lastHour)
    .ToList();

By Content

// Search for keyword
var searchResults = agent.Messages
    .Where(m => m.Content.Contains("Unity", StringComparison.OrdinalIgnoreCase))
    .ToList();

Message Statistics

Count Messages

int totalMessages = agent.Messages.Count;
int userMessages = agent.Messages.Count(m => m.Role == Role.User);
int assistantMessages = agent.Messages.Count(m => m.Role == Role.Assistant);

Debug.Log($"Total: {totalMessages}");
Debug.Log($"User: {userMessages}");
Debug.Log($"Assistant: {assistantMessages}");

Calculate Token Usage

// Rough estimation (4 characters ≈ 1 token)
int EstimateTokens(string text)
{
    return text.Length / 4;
}

int totalTokens = agent.Messages
    .Sum(m => EstimateTokens(m.Content));

Debug.Log($"Estimated tokens: {totalTokens}");

Message Rate

if (agent.Messages.Count >= 2)
{
    var firstMessage = agent.Messages.First();
    var lastMessage = agent.Messages.Last();
    
    var duration = lastMessage.Timestamp - firstMessage.Timestamp;
    var rate = agent.Messages.Count / duration.TotalMinutes;
    
    Debug.Log($"Messages per minute: {rate:F2}");
}

Display Messages in UI

Simple Chat Display

public class ChatDisplay : MonoBehaviour
{
    [SerializeField] private AgentBehaviour agent;
    [SerializeField] private ChatMessageUI messagePrefab;
    [SerializeField] private Transform messagesContainer;
    
    void Start()
    {
        agent.onResponseCompleted.AddListener(OnResponseReceived);
        RefreshMessages();
    }
    
    void RefreshMessages()
    {
        // Clear existing
        foreach (Transform child in messagesContainer)
        {
            Destroy(child.gameObject);
        }
        
        // Create UI for each message
        foreach (var message in agent.Messages)
        {
            if (message.Role == Role.System) continue;  // Skip system messages
            
            var messageUI = Instantiate(messagePrefab, messagesContainer);
            messageUI.Setup(message);
        }
    }
    
    void OnResponseReceived(Response response)
    {
        RefreshMessages();
    }
}

Advanced Chat Display

public class AdvancedChatDisplay : MonoBehaviour
{
    private Dictionary<string, ChatMessageUI> messageUIs = new();
    
    void Start()
    {
        agent.onTextDelta.AddListener(OnTextDelta);
        agent.onResponseCompleted.AddListener(OnResponseCompleted);
    }
    
    void OnTextDelta(string delta)
    {
        // Update last message in real-time
        var lastMessage = agent.LastMessage;
        
        if (!messageUIs.TryGetValue(lastMessage.Id, out var messageUI))
        {
            messageUI = CreateMessageUI(lastMessage);
            messageUIs[lastMessage.Id] = messageUI;
        }
        
        messageUI.UpdateText(lastMessage.Content);
    }
    
    void OnResponseCompleted(Response response)
    {
        // Finalize message display
        if (messageUIs.TryGetValue(response.Id, out var messageUI))
        {
            messageUI.SetCompleted();
        }
    }
}

Export Messages

Export to Text

public string ExportToText()
{
    var sb = new StringBuilder();
    
    foreach (var message in agent.Messages)
    {
        if (message.Role == Role.System) continue;
        
        sb.AppendLine($"[{message.Timestamp:yyyy-MM-dd HH:mm:ss}] {message.Role}:");
        sb.AppendLine(message.Content);
        sb.AppendLine();
    }
    
    return sb.ToString();
}

Export to Markdown

public string ExportToMarkdown()
{
    var sb = new StringBuilder();
    sb.AppendLine($"# Conversation: {agent.Conversation.Metadata.Title}");
    sb.AppendLine();
    
    foreach (var message in agent.Messages)
    {
        if (message.Role == Role.System) continue;
        
        string role = message.Role == Role.User ? "👤 User" : "🤖 Assistant";
        sb.AppendLine($"## {role}");
        sb.AppendLine($"*{message.Timestamp:yyyy-MM-dd HH:mm:ss}*");
        sb.AppendLine();
        sb.AppendLine(message.Content);
        sb.AppendLine();
    }
    
    return sb.ToString();
}

Complete Example

using UnityEngine;
using Glitch9.AIDevKit.Agents;
using System.Linq;
using System.Text;

public class MessageManager : MonoBehaviour
{
    [SerializeField] private AgentBehaviour agent;
    
    void Start()
    {
        agent.onResponseCompleted.AddListener(OnResponseReceived);
    }
    
    void OnResponseReceived(Response response)
    {
        DisplayMessageStats();
    }
    
    void DisplayMessageStats()
    {
        int total = agent.Messages.Count;
        int user = agent.Messages.Count(m => m.Role == Role.User);
        int assistant = agent.Messages.Count(m => m.Role == Role.Assistant);
        
        Debug.Log($"Messages: {total} (User: {user}, Assistant: {assistant})");
        
        if (agent.LastMessage != null)
        {
            Debug.Log($"Last: {agent.LastMessage.Content.Substring(0, Math.Min(50, agent.LastMessage.Content.Length))}...");
        }
    }
    
    public void ClearOldMessages()
    {
        var cutoff = DateTime.UtcNow.AddDays(-7);
        
        int removed = agent.Messages.RemoveAll(m =>
            m.Role != Role.System &&
            m.Timestamp < cutoff
        );
        
        Debug.Log($"Removed {removed} old messages");
    }
    
    public void ExportConversation()
    {
        string markdown = ExportToMarkdown();
        
        string path = Path.Combine(
            Application.persistentDataPath,
            $"conversation_{DateTime.Now:yyyyMMdd_HHmmss}.md"
        );
        
        File.WriteAllText(path, markdown);
        Debug.Log($"Exported to: {path}");
    }
    
    string ExportToMarkdown()
    {
        var sb = new StringBuilder();
        sb.AppendLine($"# {agent.Conversation.Metadata.Title}");
        sb.AppendLine();
        
        foreach (var message in agent.Messages)
        {
            if (message.Role == Role.System) continue;
            
            string icon = message.Role == Role.User ? "👤" : "🤖";
            sb.AppendLine($"## {icon} {message.Role}");
            sb.AppendLine($"*{message.Timestamp:yyyy-MM-dd HH:mm:ss}*");
            sb.AppendLine();
            sb.AppendLine(message.Content);
            sb.AppendLine();
        }
        
        return sb.ToString();
    }
}

Next Steps

Last updated