Skip to content

MessageBag

The MessagesBag class is a container for managing collections of messages in a conversation. It provides methods to add, retrieve, and manipulate messages within a chat context.

Creating a MessageBag

You can create a new MessageBag in two ways:

php
// Create an empty MessageBag
$messages = MessagesBag::create();

// Create a MessageBag with initial messages
$messages = MessagesBag::create([
    Message::assistant('I\'m doing well! How can I help you today?')
    Message::user('Hello, how are you?')
]);

Adding Messages

You can add new messages to a MessageBag:

php
// Add a user message
$messages->add(Message::user('What is the capital of France?'));

// Add an assistant message
$messages->add(Message::assistant('The capital of France is Paris.'));

Limiting Messages

You can limit the number of messages in a conversation while maintaining context:

php
// Limit to last 5 messages in descending order (newest first)
$messages->limit(5);

// Limit to first 5 messages in ascending order (oldest first)
$messages->limit(5, 'asc');

TIP

When using limit() with function calls, if the last message is a function call, the function response will be automatically included to maintain the conversation's logical flow. This means you might get slightly more messages than the limit if they are function responses.

Example with function calls:

php
// Original conversation with function calls
$messages = MessagesBag::create([
    Message::user('What is the weather?'),
    Message::assistant(null, [
        [
            'id' => 'call_123',
            'type' => 'function',
            'function' => [
                'name' => 'getWeather',
                'arguments' => '{}'
            ]
        ]
    ]),
    Message::tool('Sunny, 25°C', 'call_123'),
]);

// Limit to last 2 messages
$messages->limit(2);
// Result will include all 3 messages because the last message
// is a function response that completes the function call

WARNING

Using limit() reduces the context available to the LLM, which can affect its ability to maintain coherent conversations. It's important to find the right balance between cost (fewer messages = lower costs) and context quality. Consider:

  • Testing different limits to find the optimal number for your use case
  • Being aware that limiting messages might cut conversations in half
  • Monitoring if the reduced context affects the quality of responses
  • Using techniques like summarizing previous context if needed

Removing Tool Calls

You can remove all function calls and their responses from the conversation:

php
// Remove all tool calls and their responses
$messages->removeTools();

This is useful when you want to:

  • Keep only direct LLM responses and user messages
  • Clean up the conversation before applying a limit
  • Focus on the main conversation flow

Example:

php
// Original conversation with tool calls
$messages = MessagesBag::create([
    Message::user('What is the weather?'),
    Message::assistant(null, [
        [
            'id' => 'call_123',
            'type' => 'function',
            'function' => [
                'name' => 'getWeather',
                'arguments' => '{}'
            ]
        ]
    ]),
    Message::tool('Sunny, 25°C', 'call_123'),
    Message::assistant('The weather is sunny today with a temperature of 25°C. It\'s a great day for outdoor activities!'),
    Message::user('Great! What about tomorrow?'),
    Message::assistant('Let me check the forecast for tomorrow.'),
    Message::assistant(null, [
        [
            'id' => 'call_124',
            'type' => 'function',
            'function' => [
                'name' => 'getWeather',
                'arguments' => '{"day": "tomorrow"}'
            ]
        ]
    ]),
    Message::tool('Rainy, 20°C', 'call_124'),
    Message::assistant('For tomorrow, the forecast shows rain and milder temperatures around 20°C. You might want to bring an umbrella if you need to go out.')
]);

// Remove all tool calls and their responses
$messages->removeTools();
// Result will only contain:
// - User: "What is the weather?"
// - Assistant: "The weather is sunny today with a temperature of 25°C. It's a great day for outdoor activities!"
// - User: "Great! What about tomorrow?"
// - Assistant: "Let me check the forecast for tomorrow."
// - Assistant: "For tomorrow, the forecast shows rain and milder temperatures around 20°C. You might want to bring an umbrella if you need to go out."

// You can then apply a limit if needed
$messages->limit(2);

WARNING

In agents with heavy tool interaction, removing tool calls without proper system prompts can potentially bias the agent to respond without using tools. While this is rare, it's important to:

  • Test how your agent behaves after removing tool calls
  • Consider if your use case requires maintaining tool call history
  • Use appropriate system prompts to guide the agent's behavior
  • Monitor if the agent's responses change after removing tool calls

Managing Conversations

MessageBag makes it easy to maintain the state of a conversation:

php
// Start a conversation
$messages = MessagesBag::create([
    Message::assistant('I\'m doing well! How can I help you today?')
]);

// First user question
$messages->add(Message::user('What is quantum computing?'));

// Send to model and get response
$execute = LabsLLM::text()
    ->using(new OpenAI('your-api-key', 'gpt-4o'))
    ->executeChat($messages);

$response = $execute->getResponseData();

// get the updated message bag
$messages = $execute->getMessagesBag();

// User asks a follow-up question
$messages->add(Message::user('How is it used in cryptography?'));

// Send the updated conversation to the model
$execute = LabsLLM::text()
    ->using(new OpenAI('your-api-key', 'gpt-4o'))
    ->executeChat($messages);

// Get the new response
$response = $execute->getResponseData();
echo $response->response;

Converting to Array

You can convert the MessageBag to an array format for inspection or storage:

php
// Get all messages as an array
$messagesArray = $messages->toArray();

// Process or store the messages
foreach ($messagesArray as $message) {
    echo $message['role'] . ': ' . $message['content'] . PHP_EOL;
}

Exporting and Importing Conversations

You can save and restore conversations using JSON:

php
// Export conversation to JSON
$jsonHistory = $messages->asJson();

// Save to file
file_put_contents('conversation_history.json', $jsonHistory);

// Or save to database
// $db->query("INSERT INTO conversations (user_id, history) VALUES (?, ?)", [$userId, $jsonHistory]);

// Later, restore the conversation
$jsonHistory = file_get_contents('conversation_history.json');
// Or from database
// $jsonHistory = $db->query("SELECT history FROM conversations WHERE user_id = ?", [$userId])->fetchColumn();

// Create MessageBag from saved JSON
$messages = MessagesBag::createFromJson($jsonHistory);

// Continue the conversation
$messages->add(Message::user('Tell me more about quantum gates.'));

$execute = LabsLLM::text()
    ->using(new OpenAI('your-api-key', 'gpt-4o'))
    ->executeChat($messages);

$response = $execute->getResponseData();
echo $response->response;

Working with Tools

When using tools in a conversation, the MessageBag helps maintain the tool call context:

php
// Create a conversation with tool calls
$messages = MessagesBag::create([
    Message::assistant('I\'m doing well! How can I help you today?')
]);

$messages->add(Message::user('What is today\'s date?'));

// Model might respond with a tool call
$assistantResponse = Message::assistant(null, [
    [
        'id' => 'call_12345',
        'type' => 'function',
        'function' => [
            'name' => 'getDate',
            'arguments' => '{}'
        ]
    ]
]);
$messages->add($assistantResponse);

// Add the tool response
$messages->add(Message::tool('Today is 2024-05-05', 'call_12345'));

// Continue the conversation
// ...

For more information about the individual message types, see the Messages section.

Released under the MIT License.