Advanced Usage
Advanced patterns and configurations for Cortex Memory Provider with SDK v0.24.0+.
Graph Memory Integration (SDK v0.19.0+)
Sync memories to Neo4j or Memgraph for complex relationship queries.
Environment Variable Configuration
The simplest setup uses environment variables:
# .env.local
CORTEX_GRAPH_SYNC=true
# Neo4j
NEO4J_URI=bolt://localhost:7687
NEO4J_USERNAME=neo4j
NEO4J_PASSWORD=your-password
# Or Memgraph
# MEMGRAPH_URI=bolt://localhost:7687
# MEMGRAPH_USERNAME=
# MEMGRAPH_PASSWORD=
const cortexMemory = createCortexMemory({
convexUrl: process.env.CONVEX_URL!,
memorySpaceId: "my-agent",
userId: "user-123",
agentId: "my-assistant",
// Auto-configured from env vars
enableGraphMemory: process.env.CORTEX_GRAPH_SYNC === "true",
});
Explicit Configuration
For more control, pass graph configuration directly:
const cortexMemory = createCortexMemory({
convexUrl: process.env.CONVEX_URL!,
memorySpaceId: "my-agent",
userId: "user-123",
agentId: "my-assistant",
enableGraphMemory: true,
graphConfig: {
uri: "bolt://localhost:7687",
username: "neo4j",
password: "your-password",
type: "neo4j", // or "memgraph"
},
});
Async Initialization (Recommended)
For automatic graph database connection setup:
import { createCortexMemoryAsync } from "@cortexmemory/vercel-ai-provider";
// Reads graph config from env vars and validates connection
const cortexMemory = await createCortexMemoryAsync({
convexUrl: process.env.CONVEX_URL!,
memorySpaceId: "my-agent",
userId: "user-123",
agentId: "my-assistant",
});
Automatic Fact Extraction (SDK v0.18.0+)
LLM-powered extraction of structured facts from conversations.
Environment Variable Configuration
# .env.local
CORTEX_FACT_EXTRACTION=true
CORTEX_FACT_EXTRACTION_MODEL=gpt-4o-mini
const cortexMemory = createCortexMemory({
convexUrl: process.env.CONVEX_URL!,
memorySpaceId: "my-agent",
userId: "user-123",
agentId: "my-assistant",
// Auto-configured from env vars
enableFactExtraction: process.env.CORTEX_FACT_EXTRACTION === "true",
});
Explicit Configuration
const cortexMemory = createCortexMemory({
convexUrl: process.env.CONVEX_URL!,
memorySpaceId: "my-agent",
userId: "user-123",
agentId: "my-assistant",
enableFactExtraction: true,
factExtractionConfig: {
model: "gpt-4o-mini",
provider: "openai",
},
});
Custom Fact Extraction
For full control over fact extraction logic:
import { generateObject } from "ai";
import { z } from "zod";
const factSchema = z.object({
facts: z.array(
z.object({
fact: z.string(),
factType: z.enum([
"preference",
"identity",
"knowledge",
"relationship",
"event",
"observation",
]),
subject: z.string().optional(),
predicate: z.string().optional(),
object: z.string().optional(),
confidence: z.number(),
tags: z.array(z.string()).optional(),
}),
),
});
const cortexMemory = createCortexMemory({
convexUrl: process.env.CONVEX_URL!,
memorySpaceId: "smart-agent",
userId: "user-123",
agentId: "my-assistant",
enableFactExtraction: true,
extractFacts: async (userMsg, agentResp) => {
const { object } = await generateObject({
model: openai("gpt-4o-mini"),
schema: factSchema,
prompt: `Extract structured facts from this conversation.
User: "${userMsg}"
Assistant: "${agentResp}"
Focus on:
- User preferences (favorite things, likes/dislikes)
- Identity facts (name, job, location)
- Knowledge (things user knows or learned)
- Relationships (people mentioned)
- Events (things that happened)`,
});
return object.facts.map((f) => ({
fact: f.fact,
factType: f.factType,
subject: f.subject,
predicate: f.predicate,
object: f.object,
confidence: f.confidence,
tags: f.tags,
}));
},
});
Belief Revision (SDK v0.24.0+)
Intelligently update or supersede existing facts when information changes, instead of creating duplicates.
How It Works
When a user says "I like blue" and later says "I prefer purple now", without belief revision you'd have two conflicting facts. With belief revision enabled, Cortex:
- Slot Matching: Checks if the new fact matches an existing fact's subject-predicate structure
- Semantic Matching: Uses embeddings to find semantically similar facts
- LLM Resolution: For nuanced conflicts, uses an LLM to decide the appropriate action
Revision Actions
| Action | Description | Example |
|---|---|---|
ADD | New fact with no conflicts | First time mentioning favorite color |
UPDATE | Existing fact refined with new details | "I like blue" → "I love dark blue" |
SUPERSEDE | Old fact replaced by contradicting new information | "I like blue" → "I prefer purple now" |
NONE | Duplicate or irrelevant, no storage needed | Saying "I like blue" twice |
Basic Configuration
const cortexMemory = createCortexMemory({
convexUrl: process.env.CONVEX_URL!,
memorySpaceId: "my-agent",
userId: "user-123",
agentId: "my-assistant",
enableFactExtraction: true,
// Enable belief revision
beliefRevision: {
enabled: true,
slotMatching: true, // Fast detection via subject-predicate matching
llmResolution: true, // LLM resolves nuanced conflicts
},
// Recommended for semantic matching
embeddingProvider: {
generate: async (text) => {
const { embedding } = await embed({
model: openai.embedding("text-embedding-3-small"),
value: text,
});
return embedding;
},
},
});
Disable Specific Features
You can selectively disable parts of the belief revision pipeline:
// Slot matching only (fastest, no embeddings or LLM calls)
beliefRevision: {
enabled: true,
slotMatching: true,
llmResolution: false,
},
// Disable belief revision entirely
beliefRevision: false,
Layer Observer Events
When using the layer observer, facts layer events now include revision information:
layerObserver: {
onLayerUpdate: (event) => {
// revisionAction and supersededFacts are optional properties
// Only present when event.layer === 'facts'
if (event.layer === 'facts' && event.revisionAction) {
console.log(`Fact ${event.revisionAction}: ${event.data?.preview}`);
if (event.revisionAction === 'SUPERSEDE' && event.supersededFacts) {
console.log(`Superseded facts:`, event.supersededFacts);
}
}
},
},
revisionAction and supersededFacts are optional properties that are only present for facts layer events. The revisionAction value will be "ADD", "UPDATE", "SUPERSEDE", or "NONE".
Best Practices
- Always provide embeddings - Semantic matching is crucial for detecting non-obvious conflicts
- Enable LLM resolution - Catches edge cases that slot/semantic matching might miss
- Use structured facts - Facts with clear subject-predicate-object structure work best with slot matching
- Monitor revision actions - Track how often facts are updated vs superseded to understand user behavior
Layer Observation (for Visualization)
Watch memory orchestration in real-time for UI visualization.
const cortexMemory = createCortexMemory({
convexUrl: process.env.CONVEX_URL!,
memorySpaceId: "demo-agent",
userId: "user-123",
agentId: "my-assistant",
layerObserver: {
onOrchestrationStart: (orchestrationId) => {
console.log(`Starting orchestration: ${orchestrationId}`);
setIsOrchestrating(true);
},
onLayerUpdate: (event) => {
// event.layer: 'memorySpace' | 'user' | 'agent' | 'conversation' | 'vector' | 'facts' | 'graph'
// event.status: 'pending' | 'in_progress' | 'complete' | 'error' | 'skipped'
// event.latencyMs: number
// event.data: { id?, preview?, metadata? }
console.log(`${event.layer}: ${event.status} (${event.latencyMs}ms)`);
updateLayerVisualization(event.layer, event);
},
onOrchestrationComplete: (summary) => {
console.log(`Total orchestration: ${summary.totalLatencyMs}ms`);
console.log(`Created IDs:`, summary.createdIds);
setIsOrchestrating(false);
},
},
});
See the quickstart demo for a full implementation of the LayerFlowDiagram component.
Enhanced Streaming
Progressive Storage
Store partial responses during streaming for resumability:
const cortexMemory = createCortexMemory({
convexUrl: process.env.CONVEX_URL!,
memorySpaceId: "demo-chat",
userId: "user-123",
agentId: "my-assistant",
streamingOptions: {
storePartialResponse: true,
partialResponseInterval: 3000, // Update every 3 seconds
},
});
Streaming Hooks
Monitor streaming progress in real-time:
const cortexMemory = createCortexMemory({
convexUrl: process.env.CONVEX_URL!,
memorySpaceId: "demo-chat",
userId: "user-123",
agentId: "my-assistant",
streamingHooks: {
onChunk: (event) => {
console.log(`Chunk ${event.chunkNumber}: ${event.chunk}`);
console.log(`Accumulated: ${event.accumulated.length} chars`);
console.log(`Estimated tokens: ${event.estimatedTokens}`);
},
onProgress: (event) => {
console.log(`Bytes processed: ${event.bytesProcessed}`);
console.log(`Chunks: ${event.chunks}`);
console.log(`Elapsed: ${event.elapsedMs}ms`);
console.log(`Phase: ${event.currentPhase}`);
updateProgressBar(event.bytesProcessed);
},
onError: (error) => {
console.error("Stream error:", error.message);
console.log(`Phase: ${error.phase}`);
console.log(`Recoverable: ${error.recoverable}`);
if (error.resumeToken) {
saveResumeToken(error.resumeToken);
}
},
onComplete: (event) => {
console.log(`Response: ${event.fullResponse.length} chars`);
console.log(`Duration: ${event.durationMs}ms`);
console.log(`Total chunks: ${event.totalChunks}`);
console.log(`Facts extracted: ${event.factsExtracted}`);
},
},
});
Progressive Fact Extraction
Extract facts incrementally during streaming:
const cortexMemory = createCortexMemory({
convexUrl: process.env.CONVEX_URL!,
memorySpaceId: "demo-chat",
userId: "user-123",
agentId: "my-assistant",
enableFactExtraction: true,
streamingOptions: {
progressiveFactExtraction: true,
factExtractionThreshold: 500, // Extract every 500 characters
},
});
Error Recovery
Handle interrupted streams:
const cortexMemory = createCortexMemory({
convexUrl: process.env.CONVEX_URL!,
memorySpaceId: "demo-chat",
userId: "user-123",
agentId: "my-assistant",
streamingOptions: {
partialFailureHandling: "store-partial", // or 'rollback', 'retry', 'best-effort'
maxRetries: 3,
generateResumeToken: true,
streamTimeout: 30000, // 30 seconds
maxResponseLength: 50000, // characters
},
});
Adaptive Processing
Auto-optimize based on stream characteristics:
const cortexMemory = createCortexMemory({
convexUrl: process.env.CONVEX_URL!,
memorySpaceId: "demo-chat",
userId: "user-123",
agentId: "my-assistant",
streamingOptions: {
enableAdaptiveProcessing: true, // Auto-adjust batch sizes, intervals
storePartialResponse: true,
progressiveFactExtraction: true,
progressiveGraphSync: true,
},
});
Custom Embedding Providers
OpenAI Embeddings
import { embed } from "ai";
import { openai } from "@ai-sdk/openai";
const cortexMemory = createCortexMemory({
convexUrl: process.env.CONVEX_URL!,
memorySpaceId: "my-agent",
userId: "user-123",
agentId: "my-assistant",
embeddingProvider: {
generate: async (text) => {
const { embedding } = await embed({
model: openai.embedding("text-embedding-3-large"),
value: text,
});
return embedding;
},
},
});
Local Embeddings (Transformers.js)
import { pipeline } from "@xenova/transformers";
const embedder = await pipeline(
"feature-extraction",
"Xenova/all-MiniLM-L6-v2",
);
const cortexMemory = createCortexMemory({
convexUrl: process.env.CONVEX_URL!,
memorySpaceId: "local-agent",
userId: "user-123",
agentId: "my-assistant",
embeddingProvider: {
generate: async (text) => {
const output = await embedder(text, { pooling: "mean", normalize: true });
return Array.from(output.data);
},
},
});
Custom Context Injection
Control how memory context is added to prompts:
const cortexMemory = createCortexMemory({
convexUrl: process.env.CONVEX_URL!,
memorySpaceId: "custom-agent",
userId: "user-123",
agentId: "my-assistant",
// Custom context builder
customContextBuilder: (memories) => {
const highImportance = memories.filter((m) => m.importance > 70);
const recent = memories.slice(0, 3);
return `## Critical Information
${highImportance.map((m) => `- ${m.content}`).join("\n")}
## Recent Context
${recent.map((m) => `- ${m.content}`).join("\n")}`;
},
// Or use injection strategy
contextInjectionStrategy: "system", // or 'user', 'custom'
});
Performance Optimization
Memory Search Tuning
const cortexMemory = createCortexMemory({
convexUrl: process.env.CONVEX_URL!,
memorySpaceId: "fast-agent",
userId: "user-123",
agentId: "my-assistant",
// Limit search results for faster responses
memorySearchLimit: 3,
// Higher threshold = more relevant results only
minMemoryRelevance: 0.8,
// Filter by importance
defaultImportance: 50,
});
Disable Features for Speed
const cortexMemory = createCortexMemory({
convexUrl: process.env.CONVEX_URL!,
memorySpaceId: "minimal-agent",
userId: "user-123",
agentId: "my-assistant",
// Disable search for write-only scenarios
enableMemorySearch: false,
// Or disable storage for read-only scenarios
enableMemoryStorage: false,
// Disable metrics collection
enableStreamMetrics: false,
});