Chat history is a crucial component that allows your agents to maintain context across multiple interactions, providing a more natural and coherent conversation experience.

Built-in Chat Histories

LarAgent provides several built-in chat history implementations to suit different needs:
Set in your Agent class by the name:
yourAgent.php
// Stores chat history temporarily in memory (lost after request)
protected $history = 'in_memory';  

// Uses Laravel's session storage
protected $history = 'session';    

// Uses Laravel's cache system
protected $history = 'cache';      

// Stores in files (storage/app/chat-histories)
protected $history = 'file';       

// Stores in JSON files (storage/app/chat-histories)
protected $history = 'json';       
Or use it by class:
yourAgent.php
protected $history = \LarAgent\History\SessionChatHistory::class;
Or use it by override method to add custom logic or configuration:
yourAgent.php
  public function createChatHistory($name)
  {
      return new JsonChatHistory($name, ['folder' => __DIR__.'/json_History']);
  }

Chat History Configuration

You can configure how chat history behaves using these properties in your Agent class:

Reinjecting Instructions

/** @var int - Number of messages after which to reinject the agent's instructions */
protected $reinjectInstructionsPer;
Instructions are always injected at the beginning of the chat history. The $reinjectInstructionsPer property defines when to reinject these instructions to ensure the agent stays on track. By default, it’s set to 0 (disabled).
Reinjecting instructions can be useful for long conversations where the agent might drift from its original purpose or forget important constraints.

Managing Context Window Size

/** @var int - Maximum number of tokens to keep in context window */
protected $contextWindowSize;
After the context window is exceeded, the oldest messages are removed until the context window is satisfied or the limit is reached. This helps manage token usage and ensures the conversation stays within the model’s context limits.

Managing chatHistory SessionId

/** @var bool - Whether to include model name in chat session id */
protected $includeModelInChatSessionId;
By default it is set to false (disabled). If you want to include model name in chat session id, set it to true.
Before v0.5 model name was used in chat history key by default: AgentName_ModelName_UserId. To keep old code compatible set it to true in your agent classes.
Agent automatically appends the Agent class basename and model name used on each message’s metadata to keep track of the agent and model used. You can access metadata of message using getMetadata() method or store it in chat history automatically by setting storeMeta property to true in your agent class. Check Storing usage data section for more information.

How chat history works

The flow of information in the chat history process works as follows:
  1. User to Agent: The user sends a prompt to the agent.
  2. Agent to Chat History: The agent processes and adds the user’s message to the chat history.
  3. Chat History to Agent: The agent retrieves all relevant messages from the chat history.
  4. Agent to LLM: The agent sends these messages as context to the language model.
  5. LLM to Agent: The language model generates a response based on the provided context.
  6. Agent to Chat History: The agent processes and adds the LLM’s response to the chat history.
  7. Agent to User: The agent displays the last message from the chat history to the user.
Throughout this process, the Context Window Management system:
  • Tracks all messages in the conversation
  • Counts tokens to ensure they stay within model limits
  • Prunes older messages when necessary to maintain the context window size

Extensibility

You can implement custom logic for context window management using events and the chat history instance inside your agent. Or create custom chat history implementations by implementing the ChatHistoryInterface.

Using Chat History

Per-User Chat History

One of the most common use cases is maintaining separate chat histories for different users:
// Create a chat history for a specific user
$response = MyAgent::forUser(auth()->user())->respond('Hello, how can you help me?');

// Later, the same user continues the conversation
$response = MyAgent::forUser(auth()->user())->respond('Can you explain more about that?');

Named Chat Histories

You can also create named chat histories for specific contexts or topics:
// Start a conversation about weather
$response = MyAgent::for('weather_chat')->respond('What's the weather like today?');

// Start a separate conversation about recipes
$response = MyAgent::for('recipe_chat')->respond('How do I make pasta carbonara?');

// Continue the weather conversation
$response = MyAgent::for('weather_chat')->respond('Will it rain tomorrow?');

Accessing and Managing Chat History

LarAgent provides several methods to access and manage chat history:
// Get the current chat history instance
$history = $agent->chatHistory();

// Get all messages in the chat history
$messages = $history->getMessages();

// Get the last message (MessageInterface)
$lastMessage = $history->getLastMessage();

// Count messages in history
$count = $history->count();

// Get the chat history identifier
$identifier = $history->getIdentifier();

// Convert messages to array
$messagesArray = $history->toArray();

// Convert messages to array with metadata
$messagesWithMeta = $history->toArrayWithMeta();

The addMessage(MessageInterface $message) method adds a new message to the chat history instance, which will be saved automatically by the agent class if you are using it in agent context. In other case, you can save it manually using writeToMemory() method.

Creating Custom Chat Histories

You can create your own chat history by implementing the ChatHistoryInterface and extending the LarAgent\Core\Abstractions\ChatHistory abstract class. Check example implementations in src/History There are two ways to register your custom chat history into an agent. If you use standard constructor only with $name parameter, you can define it by class in $history property or provider configuration: Agent Class
protected $history = \App\ChatHistories\CustomChatHistory::class;
Provider Configuration (config/laragent.php)
'chat_history' => \App\ChatHistories\CustomChatHistory::class,
If you need any configuration other than $name, you can override createChatHistory() method:
public function createChatHistory($name)
{
    return new \App\ChatHistories\CustomChatHistory($name, [
      // Added config
      'folder' => __DIR__.'/history',
      // Default configs used inside Agent class:
      'context_window' => $this->contextWindowSize,
      'store_meta' => $this->storeMeta,
      'save_chat_keys' => $this->saveChatKeys,
    ]);
}

Storing usage data

You can store usage data (if available) automatically in the chat history by setting store_meta config or $storeMeta property to true:
protected $storeMeta = true;
This will store usage data (if available) in the chat history as metadata of message. Each message supports toArrayWithMeta() method to get array with metadata:
// Example
$message = $message->toArrayWithMeta();

// Result
[
  // Other message properties
  'usage' => [
    'prompt_tokens' => 10,
    'completion_tokens' => 20,
    'total_tokens' => 30,
    // Other usage details
  ],
]
Before v0.5 keys was stored as promptTokens (camelCase) instead of prompt_tokens (snake_case), so make sure to update your code if you were using it.
Alternatively, you can store usage data manually using afterResponse hooks in your agent class:
protected function afterResponse($message)
{
    $messageArray = $message->toArrayWithMeta();
    
    // Store usage data
    Usage::create([
        'agent_name' => class_basename($this),
        'user_id' => auth()->user()->id,
        'prompt_tokens' => $messageArray['usage']['prompt_tokens'],
        'completion_tokens' => $messageArray['usage']['completion_tokens'],
        'total_tokens' => $messageArray['usage']['total_tokens'],
    ]);
}

Best Practices

Do choose the appropriate chat history implementation based on your needs (persistence, performance, etc.)
Do set a reasonable context window size to balance coherence and token usage
Do use unique identifiers for chat histories to prevent cross-contamination
Don’t store sensitive information in chat histories without proper encryption Don’t neglect to clear chat histories when they’re no longer needed