Understand the Context and Identity system for managing storage isolation, session tracking, and data scoping in LarAgent
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.
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.
Copy
// 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'
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.
Copy
// 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'
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.
Copy
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...');
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.
For runtime group resolution (e.g., based on current tenant):
Copy
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.
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.
Use createHistoryIdentity() to customize chat history scoping:
Copy
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; }}
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.
Advanced: Full storage override
Copy
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.
You can access the context object directly from an agent:
Copy
// 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.
// 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();
// 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();
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 addedEvent::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()]);});