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 scopes for chat history vs usage tracking, use the custom identity override methods below.

Custom Identity Overrides

Override identity creation methods to customize how chat history and usage tracking are scoped. This is useful for multi-tenant applications, team-based sharing, or any scenario requiring different storage isolation.

Overriding History Identity

Use createHistoryIdentity() to customize chat history scoping:
use LarAgent\Context\SessionIdentity;

class TeamAgent extends Agent
{
    // Share chat history across team members
    protected function createHistoryIdentity(): SessionIdentity
    {
        return new SessionIdentity(
            agentName: $this->name(),
            chatName: $this->getTeamId(), // Share history across team
        );
    }
    
    private function getTeamId(): string
    {
        return auth()->user()->team_id;
    }
}

Overriding Usage Identity

Use createUsageIdentity() to customize usage tracking scoping:
use LarAgent\Context\SessionIdentity;

class OrganizationAgent extends Agent
{
    // Track usage at organization level
    protected function createUsageIdentity(): SessionIdentity
    {
        return new SessionIdentity(
            agentName: $this->name(),
            chatName: 'org-' . $this->getOrganizationId(),
        );
    }
    
    private function getOrganizationId(): string
    {
        return auth()->user()->organization_id;
    }
}

Dual Identity (Different Scopes)

Use different scopes for history and usage:
use LarAgent\Context\SessionIdentity;

class MultiTenantAgent extends Agent
{
    // Chat history scoped to team
    protected function createHistoryIdentity(): SessionIdentity
    {
        return new SessionIdentity(
            agentName: $this->name(),
            chatName: 'team-' . $this->getTeamId(),
        );
    }
    
    // Usage tracking scoped to organization
    protected function createUsageIdentity(): SessionIdentity
    {
        return new SessionIdentity(
            agentName: $this->name(),
            chatName: 'org-' . $this->getOrganizationId(),
        );
    }
}
Use createHistoryIdentity() and createUsageIdentity() for simple identity customization. For full control over storage creation (including drivers and options), override createChatHistory() or createUsageStorage() instead.
use LarAgent\Context\SessionIdentity;
use LarAgent\Context\Storages\ChatHistoryStorage;

class MyAgent extends Agent
{
    protected $group = 'shared-group'; // Default group for all storages
    
    // Full control over chat history storage creation
    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
        );
    }
}
Use this approach when you need full control over storage configuration, such as custom drivers or storage options.

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