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
`ADD`New fact with no conflictsFirst 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 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​