Skip to main content

Advanced Usage

Info
Last Updated: 2026-01-09 | Version: v0.29.0+

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"
},
});

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:

  1. Slot Matching: Checks if the new fact matches an existing fact's subject-predicate structure
  2. Semantic Matching: Uses embeddings to find semantically similar facts
  3. LLM Resolution: For nuanced conflicts, uses an LLM to decide the appropriate action

Revision Actions

ActionDescriptionExample
ADDNew fact with no conflictsFirst time mentioning favorite color
UPDATEExisting fact refined with new details"I like blue" → "I love dark blue"
SUPERSEDEOld fact replaced by contradicting new information"I like blue" → "I prefer purple now"
NONEDuplicate or irrelevant, no storage neededSaying "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);
}
}
},
},
Info

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

  1. Always provide embeddings - Semantic matching is crucial for detecting non-obvious conflicts
  2. Enable LLM resolution - Catches edge cases that slot/semantic matching might miss
  3. Use structured facts - Facts with clear subject-predicate-object structure work best with slot matching
  4. 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,
});

Next Steps