Skip to main content
The Context system in LarAgent provides a unified way to manage storage isolation, session tracking, and data scoping across agents and users. It serves as the central orchestration layer that connects agents with their storage backends.

Core Components

The Context system consists of four key components:

SessionIdentity

Uniquely identifies a storage session using agent name, user ID, chat name, group, and scope.

Context

Central orchestration layer that manages multiple storage instances for an agent.

IdentityStorage

Tracks all storage identities registered within a context for discovery and management.

Storage

Abstract base for all storage implementations (chat history, usage, custom).

Session Identity

A SessionIdentity uniquely identifies a storage key using these components:
ComponentDescriptionExample
agentNameName of the agent class'SupportAgent'
chatNameSession/chat identifier'support-ticket-123'
userIdUser identifier (when using forUser())'user-456'
groupGrouping for shared context across agents'FAQ-team'
scopeStorage type scope'chatHistory', 'usage'

Key Generation

The identity key is generated as:
{scope}_{group|agentName}_{userId|chatName|'default'}
  • chatHistory_SupportAgent_user-123 — User-based chat history
  • chatHistory_SupportAgent_session-abc — Session-based chat history
  • usage_sql_user-456 — User usage in SQL group

Creating Agents with Identities

LarAgent provides several ways to create agents with different identity configurations.

Session-based Creation

Use session-based creation when you need to manage conversations by a custom session key rather than user identity. This is ideal for anonymous users, guest sessions, or when you want explicit control over session naming.
// Create agent with a specific session key
$agent = SupportAgent::for('session-123');

// Create agent with random session key
$agent = SupportAgent::make();

// Access identity
$identity = $agent->context()->getIdentity();
echo $identity->getChatName();  // 'session-123'
echo $identity->getAgentName(); // 'SupportAgent'

User-based Creation

Use user-based creation to automatically tie conversations to authenticated users. The identity key will include the user ID, enabling easy querying and management of all conversations for a specific user.
// Create agent for authenticated user
$agent = SupportAgent::forUser($request->user());

// Create agent for specific user ID
$agent = SupportAgent::forUserId('user-123');

// Access identity
$identity = $agent->context()->getIdentity();
echo $identity->getUserId();    // 'user-123'
echo $identity->getAgentName(); // 'SupportAgent'

Reconstructing from Identity

Use fromIdentity() to recreate an agent instance from a previously tracked identity. This is useful for admin panels, background jobs, or any scenario where you need to operate on existing conversations.
use LarAgent\Facades\Context;

// Get an identity from storage
$identity = Context::of(SupportAgent::class)
    ->forUser('user-123')
    ->first();

// Reconstruct the agent from identity
$agent = SupportAgent::fromIdentity($identity);

// The agent is now configured with the same session context
$response = $agent->respond('Continue our conversation...');

Grouping

Groups enable shared context between multiple agents. When a group is set, the storage key uses the group name instead of the agent name.
Key format without group: {scope}_{agentName}_{userId|chatName|'default'}Key format with group: {scope}_{group}_{userId|chatName|'default'}
This is useful for multi-tenant applications where agents should share context within a tenant, or when you want multiple agent types to work with the same conversation history.

Static Group Assignment

class TenantSupportAgent extends Agent
{
    protected $group = 'tenant-123';
}

Dynamic Group Resolution

For runtime group resolution (e.g., based on current tenant):
class TenantSupportAgent extends Agent
{
    public function group(): ?string
    {
        return tenant()->id ?? null;
    }
}
The group setting applies to all storages by default. To use different groups for specific storages (e.g., group usage but not chat history), override createChatHistory() or createUsageStorage() with a custom identity.
use LarAgent\Context\SessionIdentity;
use LarAgent\Context\Storages\ChatHistoryStorage;

class MyAgent extends Agent
{
    protected $group = 'shared-group'; // Default group for all storages
    
    // Override to use agent-specific identity for chat history (no grouping)
    public function createChatHistory()
    {
        $identity = new SessionIdentity(
            agentName: $this->getAgentName(),
            chatName: $this->getChatKey(),
            userId: $this->getUserId(),
            group: null, // No group - uses agentName instead
        );
        
        return new ChatHistoryStorage(
            $identity,
            $this->historyStorageDrivers(),
            $this->storeMeta ?? false
        );
    }
}
Or, alternatively, you can override to set group only for specific storage instead using $group property.

Context Operations

Accessing Context

You can access the context object directly from an agent:
// Get the context instance
$context = $agent->context();

// Get the base identity
$identity = $context->getIdentity();

// Get the context identity (used for IdentityStorage)
$contextIdentity = $context->getContextIdentity();
The contextIdentity is the general identity of the agent. It is stored in IdentityStorage and holds all other storage identities associated with the agent.

Bulk Operations

// Save all dirty storages
$context->save();

// Read all storages from drivers
$context->read();

// Clear all storages (marks as dirty, sets to empty)
$context->clear();

// Remove all storages completely
$context->remove();

Getting Tracked Keys

// Get all tracked storage keys
$keys = $agent->getStorageKeys();
// ['chatHistory_SupportAgent_user-123', 'usage_SupportAgent_user-123', ...]

// Get chat history keys only
$chatKeys = $agent->getChatKeys();

// Get chat history identities
$chatIdentities = $agent->getChatIdentities();

Temporary Sessions

Sessions prefixed with _temp are not tracked in IdentityStorage:
// This session won't be tracked
$agent = SupportAgent::for('_temp_preview');
This is useful for:
  • Preview/demo sessions
  • Test sessions
  • One-time interactions

Context Events

Listen to context lifecycle events for custom behavior:
use LarAgent\Events\Context\ContextCreated;
use LarAgent\Events\Context\ContextSaving;
use LarAgent\Events\Context\ContextSaved;
use LarAgent\Events\Context\ContextReading;
use LarAgent\Events\Context\ContextRead;
use LarAgent\Events\Context\ContextClearing;
use LarAgent\Events\Context\ContextCleared;
use LarAgent\Events\Context\StorageRegistered;

// Context created
Event::listen(ContextCreated::class, function ($event) {
    $context = $event->context;
    Log::info('Context created', ['identity' => $context->getIdentity()->getKey()]);
});

// Storage registered
Event::listen(StorageRegistered::class, function ($event) {
    $context = $event->context;
    $prefix = $event->prefix;
    $storage = $event->storage;
    Log::info('Storage registered', ['prefix' => $prefix]);
});

// Before saving
Event::listen(ContextSaving::class, function ($event) {
    // Last chance to modify before persistence
});

// After saving
Event::listen(ContextSaved::class, function ($event) {
    // Trigger post-save actions
});

Identity Storage Events

use LarAgent\Events\IdentityStorage\IdentityAdding;
use LarAgent\Events\IdentityStorage\IdentityAdded;
use LarAgent\Events\IdentityStorage\IdentityStorageSaving;
use LarAgent\Events\IdentityStorage\IdentityStorageSaved;
use LarAgent\Events\IdentityStorage\IdentityStorageLoaded;

// Before identity is added
Event::listen(IdentityAdding::class, function ($event) {
    $identity = $event->identity;
    // Can modify or validate
});

// After identity is added (only when actually new)
Event::listen(IdentityAdded::class, function ($event) {
    $identity = $event->identity;
    Log::info('New session tracked', ['key' => $identity->getKey()]);
});

Next Steps