Enable agents to share memory, state, and data for seamless collaboration without redundant processing or conflicting information.
Without shared context, each agent operates in isolation. The pricing agent doesn't know what the availability agent found. The communication agent doesn't know what price was calculated. Shared context solves this.
interface SharedContext {
// Unique identifier for this context session
sessionId: string
// Who owns this context
userId: string
organizationId?: string
// Task-specific data
task: {
id: string
type: string
input: Record<string, unknown>
startedAt: Date
}
// Shared memory layers
memory: {
// Short-term: Current task data
shortTerm: Map<string, unknown>
// Working: Intermediate results from agents
working: Map<string, AgentResult>
// Long-term: Persistent user/entity data
longTerm: {
user: UserProfile
entities: Map<string, EntityData>
preferences: Record<string, unknown>
}
}
// Execution trace
trace: {
agentsInvolved: string[]
decisions: Decision[]
timestamps: Record<string, Date>
}
// Access control
permissions: {
readAgents: string[] // Agents that can read
writeAgents: string[] // Agents that can write
sensitiveFields: string[] // Fields requiring extra auth
}
}import { SharedContextManager } from "@/lib/agents/shared-context-manager"
// Create context for a new task
const context = new SharedContextManager({
sessionId: `session_${Date.now()}`,
userId: "user_123",
organizationId: "org_456",
task: {
id: "task_789",
type: "booking_inquiry",
input: { guestMessage, propertyId, dates }
}
})
// Pre-load relevant data
await context.loadEntityData("property", propertyId)
await context.loadUserPreferences(userId)// Agent A writes to context
await context.set("availability", {
isAvailable: true,
blockedDates: [],
minimumStay: 3,
checkedAt: new Date()
}, { agent: "availability-agent" })
// Agent B reads from context
const availability = await context.get("availability")
if (availability.isAvailable) {
// Proceed with pricing calculation
}
// Agent C reads multiple values
const [availability, property, userPrefs] = await context.getMany([
"availability",
"property",
"user.preferences"
])Agents can store intermediate results that other agents can build upon:
// Pricing agent stores calculation
await context.setWorkingMemory("pricing-agent", {
basePrice: 250,
adjustments: [
{ type: "seasonal", modifier: 1.2, reason: "Peak summer" },
{ type: "length", modifier: 0.85, reason: "7-night stay discount" },
{ type: "demand", modifier: 1.1, reason: "High occupancy week" }
],
finalPrice: 280.50,
confidence: 0.92
})
// Communication agent reads and references
const pricingResult = await context.getWorkingMemory("pricing-agent")
const response = `Your stay would be $${pricingResult.finalPrice}/night,
which includes a ${Math.round((1 - pricingResult.adjustments[1].modifier) * 100)}%
discount for your week-long booking!`// Subscribe to context changes
context.subscribe("availability", (newValue, oldValue, agent) => {
console.log(`Availability updated by ${agent}`)
// Trigger re-calculation if needed
if (!newValue.isAvailable && oldValue.isAvailable) {
notifyPricingAgent("availability_changed")
}
})
// Atomic updates with optimistic locking
await context.update("booking_status", (current) => ({
...current,
step: current.step + 1,
lastUpdated: new Date()
}), {
expectedVersion: 3, // Fail if version mismatch
agent: "workflow-coordinator"
})Not all agents should access all data. The SharedContextManager enforces fine-grained permissions:
// Define access control
const context = new SharedContextManager({
// ...
permissions: {
// All agents can read these
publicFields: ["task", "property.basic", "availability"],
// Only specific agents can read
restricted: {
"user.payment_methods": ["payment-agent", "billing-agent"],
"user.personal_info": ["communication-agent", "support-agent"],
"pricing.margins": ["pricing-agent", "coordinator"]
},
// Only specific agents can write
writePermissions: {
"availability": ["availability-agent", "calendar-sync-agent"],
"pricing": ["pricing-agent"],
"final_response": ["coordinator", "communication-agent"]
}
}
})
// Access check happens automatically
try {
// This will fail if content-agent isn't authorized
const paymentMethods = await context.get("user.payment_methods")
} catch (error) {
if (error.code === "ACCESS_DENIED") {
// Handle gracefully
}
}Payment information, personal details, and API keys are automatically encrypted at rest. Access is logged for audit trails.
Context created when task starts. Initial data loaded from databases and user profiles.
Agents read/write during task execution. Working memory accumulates intermediate results.
Important results saved to long-term memory. Execution trace archived for debugging.
Short-term and working memory cleared. Session marked complete. Resources released.
// Complete lifecycle example
const context = new SharedContextManager({ ... })
try {
// Execute task with context
const result = await executeWithContext(context, task)
// Persist important results
await context.persistToLongTerm({
taskResult: result,
learnedPreferences: context.get("learned_preferences")
})
} finally {
// Always cleanup
await context.dispose()
}Load entity data before agents start to minimize wait times
Prefix keys with agent name to avoid collisions: 'pricing.result'
Only store what other agents actually need, not full agent state
Check for existence before using. Data may not be set yet
Always call dispose() to release resources and persist data