Skip to main content
doc0blade47/mem0documentation home
Sign in

Vercel AI SDK Integration

Last updated Oct 11, 2026100% grounded
Relevant source files

The following files were used as context for generating this wiki page:

Overview

The Vercel AI SDK integration provides a specialized provider interface that bridges Mem0 long-term memory management directly into AI applications built with the Vercel AI SDK and the Version 3 language model specification. It exposes a configurable provider factory via [[createMem0]] that handles base URL resolution, headers, custom fetch wrappers, and API key management across multiple underlying LLM vendors.

Sources: integrations/vercel-ai-sdk/src/mem0-provider.ts:1-140, integrations/vercel-ai-sdk/src/mem0-facade.ts:7-42

The architecture encapsulates generation and streaming calls within a generic language model wrapper (Mem0GenericLanguageModel) that automatically flattens prompts, queries relevant historical memories, and injects retrieved context as system messages prior to invocation. It dynamically routes requests through selected backend providers while capturing assistant completions to persist conversational turns back into Mem0.

Sources: integrations/vercel-ai-sdk/src/mem0-generic-language-model.ts:20-170, integrations/vercel-ai-sdk/src/mem0-utils.ts:309-390

Provider Architecture and Client Factory

Provider Configuration Options

The public API surface revolves around the [[createMem0]] factory function and the Mem0 class facade, which initialize provider instances conforming to the Vercel AI SDK ProviderV3 specification.

The Mem0ProviderSettings interface defines the configuration properties accepted by createMem0() and the Mem0 class constructor.

PropertyTypeDefault ValueDescription
baseURLstring"https://api.openai.com"Base URL for API requests, normalized via withoutTrailingSlash.
fetchtypeof fetchundefinedCustom fetch implementation for request interception or testing.
generateId() => stringundefinedInternal identifier generator function.
headersRecord<string, string | undefined>undefinedCustom headers included in outgoing requests.
namestringundefinedProvider or model identifier name.
mem0ApiKeystringundefinedAPI key specific to Mem0 services.
apiKeystringundefinedGeneral API key for the underlying model vendor.
providerstring"openai"Underlying LLM provider identifier.
modelType"completion" | "chat"undefinedTarget model type constraint.
mem0ConfigMem0ConfigundefinedConfiguration object for memory extraction and retrieval.
configLLMProviderSettingsundefinedProvider-specific configuration options passed to language models.

Sources: integrations/vercel-ai-sdk/src/mem0-provider.ts:20-46

Provider Instance Initialization

The createMem0 function instantiates a callable Mem0Provider function augmented with helper methods for constructing language models. When invoked directly, the provider checks new.target to guard against construction via the new keyword and defaults to creating a generic language model via createGenericModel.

export function createMem0(
  options: Mem0ProviderSettings = {
    provider: "openai",
  }
): Mem0Provider {
  const baseURL =
    withoutTrailingSlash(options.baseURL) ?? "https://api.openai.com";
  const getHeaders = () => ({
    ...options.headers,
  });
 
  const createGenericModel = (
    modelId: Mem0ChatModelId,
    settings: Mem0ChatSettings = {}
  ) =>
    new Mem0GenericLanguageModel(
      modelId,
      settings,
      {
        baseURL,
        fetch: options.fetch,
        headers: getHeaders(),
        provider: options.provider || "openai",
        name: options.name,
        mem0ApiKey: options.mem0ApiKey,
        apiKey: options.apiKey,
        mem0Config: options.mem0Config,
      },
      options.config
    );
 
  const createCompletionModel = (
    modelId: Mem0ChatModelId,
    settings: Mem0ChatSettings = {}
  ) =>
    new Mem0GenericLanguageModel(
      modelId,
      settings,
      {
        baseURL,
        fetch: options.fetch,
        headers: getHeaders(),
        provider: options.provider || "openai",
        name: options.name,
        mem0ApiKey: options.mem0ApiKey,
        apiKey: options.apiKey,
        mem0Config: options.mem0Config,
        modelType: "completion",
      },
      options.config
    );
 
  const createChatModel = (
    modelId: Mem0ChatModelId,
    settings: Mem0ChatSettings = {}
  ) =>
    new Mem0GenericLanguageModel(
      modelId,
      settings,
      {
        baseURL,
        fetch: options.fetch,
        headers: getHeaders(),
        provider: options.provider || "openai",
        name: options.name,
        mem0ApiKey: options.mem0ApiKey,
        apiKey: options.apiKey,
        mem0Config: options.mem0Config,
        modelType: "chat",
      },
      options.config
    );
 
  const provider = function (
    modelId: Mem0ChatModelId,
    settings: Mem0ChatSettings = {}
  ) {
    if (new.target) {
      throw new Error(
        "The Mem0 model function cannot be called with the new keyword."

Sources: integrations/vercel-ai-sdk/src/mem0-provider.ts:48-140

Warning

Calling the returned Mem0Provider instance with the new keyword throws an explicit runtime error: "The Mem0 model function cannot be called with the new keyword."

Sources: integrations/vercel-ai-sdk/src/mem0-provider.ts:125-129

The Mem0 Class Facade

In parallel with createMem0, the Mem0 class provides an alternative object-oriented facade wrapping base URL normalization, header aggregation, and model factory methods for chat and completion interfaces.

export class Mem0 {
  readonly baseURL: string
  readonly headers?: any
 
  constructor(options: Mem0ProviderSettings = {
    provider: 'openai',
  }) {
    this.baseURL =
      withoutTrailingSlash(options.baseURL) ?? 'https://api.openai.com'
 
    this.headers = options.headers
  }
 
  private get baseConfig() {
    return {
      baseURL: this.baseURL,
      headers: this.headers,
    }
  }
 
  chat(modelId: Mem0ChatModelId, settings: Mem0ChatSettings = {}) {
    return new Mem0GenericLanguageModel(modelId, settings, {
      provider: 'openai',
      modelType: 'chat',
      ...this.baseConfig,
    })
  }
 
  completion(modelId: Mem0ChatModelId, settings: Mem0ChatSettings = {}) {
    return new Mem0GenericLanguageModel(modelId, settings, {
      provider: 'openai',
      modelType: 'completion',
      ...this.baseConfig,
    })
  }
}

Sources: integrations/vercel-ai-sdk/src/mem0-facade.ts:7-42

Generic Language Model Wrapper Lifecycle

Wrapper Initialization and V3 Specification Conformance

The Mem0GenericLanguageModel class implements the Vercel AI SDK LanguageModelV3 specification, exposing version v3 and supporting wildcard URLs (*) matched by /.*/. The constructor accepts a chat model identifier, chat settings, a configuration object, and optional provider settings, defaulting the underlying provider string to "openai" if unspecified.

export class Mem0GenericLanguageModel implements LanguageModelV3 {
  readonly specificationVersion = "v3";
  readonly supportedUrls: Record<string, RegExp[]> = {
    '*': [/.*/]
  };
 
  constructor(
    public readonly modelId: Mem0ChatModelId,
    public readonly settings: Mem0ChatSettings,
    public readonly config: Mem0ChatConfig,
    public readonly provider_config?: Mem0ProviderSettings
  ) {
    this.provider = config.provider ?? "openai";
  }
 
  provider: string;

Sources: integrations/vercel-ai-sdk/src/mem0-generic-language-model.ts:20-35

Note

The generic language model wrapper assigns specificationVersion = "v3" and exposes a wildcard supportedUrls mapping so that requests targeting any endpoint can be intercepted and enhanced with memory context.

Sources: integrations/vercel-ai-sdk/src/mem0-generic-language-model.ts:21-24

Intercepting Generation and Streaming Calls

When doGenerate or doStream is invoked with LanguageModelV3CallOptions, the wrapper constructs provider and memory configurations, initializes a Mem0ClassSelector, and processes conversational prompts through processMemories. This internal lifecycle method attempts to persist new memories before retrieving relevant historical context, formatting retrieved items into a specialized system prompt prepended to the prompt array.

private async processMemories(messagesPrompts: LanguageModelV3Message[], mem0Config: Mem0ConfigSettings) {
  try {
    // Add new memories — await to ensure writes complete before returning
    try {
      await addMemories(messagesPrompts, mem0Config);
    } catch (e) {
      console.error("Error while adding memories");
    }
 
    // Get memories (always returns an array since graph support is removed)
    const memories: any[] = await getMemories(messagesPrompts, mem0Config) ?? [];
 
    const mySystemPrompt = "These are the memories I have stored. Give more weightage to the question by users and try to answer that first. You have to modify your answer based on the memories I have provided. If the memories are irrelevant you can ignore them. Also don't reply to this section of the prompt, or the memories, they are only for your reference. The System prompt starts after text System Message: \n\n";
 
    let memoriesText = "";
    try {
      memoriesText = memories
        ?.map((memory: any) => `Memory: ${memory?.memory}\n\n`)
        .join("\n\n");
    } catch (e) {
      console.error("Error while parsing memories");
    }
 
    const memoriesPrompt = `System Message: ${mySystemPrompt} ${memoriesText} `;
 
    // Clone the prompt array to avoid mutating the caller's reference on retries
    const updatedPrompts = [...messagesPrompts];
 
    if (memories?.length > 0) {
      const systemPrompt: LanguageModelV3Message = {
        role: "system",
        content: memoriesPrompt
      };
      updatedPrompts.unshift(systemPrompt);
    }
 
    return { memories, messagesPrompts: updatedPrompts };
  } catch (e) {
    console.error("Error while processing memories");
    return { memories: [], messagesPrompts: [...messagesPrompts] };
  }
}

Sources: integrations/vercel-ai-sdk/src/mem0-generic-language-model.ts:37-78

Caution

If memory processing encounters an exception during either persistence or retrieval, the error is caught, logged to console.error, and execution safely falls back to returning the original unmodified prompt array without historical context.

Sources: integrations/vercel-ai-sdk/src/mem0-generic-language-model.ts:38-44, integrations/vercel-ai-sdk/src/mem0-generic-language-model.ts:74-77

Result Augmentation and Stream Handling

In doGenerate, once the underlying provider model generates a response, the wrapper checks if any memories were retrieved. If memories are present, it constructs a LanguageModelV3Source object with a generated random identifier (mem0- followed by randomized alphanumeric characters) and attaches provider metadata containing the raw memories and concatenated memory text before returning the augmented result.

  if (!memories || memories?.length === 0) {
    return ans;
  }
 
  const mem0Source: LanguageModelV3Source = {
    type: "source",
    sourceType: "url",
    id: "mem0-" + generateRandomId(),
    url: "https://app.mem0.ai?utm_source=oss&utm_medium=vercel-ai-sdk-src",
    title: "Mem0 Memories",
    providerMetadata: {
      mem0: {
        memories: memories,
        memoriesText: memories
          ?.map((memory: any) => memory?.memory)
          .join("\n\n"),
      },
    },
  };
 
  return {
    ...ans,
    content: [...(ans.content ?? []), mem0Source],
  };
}

Sources: integrations/vercel-ai-sdk/src/mem0-generic-language-model.ts:108-132

Conversely, doStream delegates to the underlying provider model's doStream method using the updated memory-injected prompts, returning the raw stream response or throwing an error if streaming fails or remains unimplemented.

async doStream(options: LanguageModelV3CallOptions): Promise<LanguageModelV3StreamResult> {
  try {
    const provider = this.config.provider;
    const mem0_api_key = this.config.mem0ApiKey;
 
    const settings: Mem0ProviderSettings = {
      provider: provider,
      mem0ApiKey: mem0_api_key,
      apiKey: this.config.apiKey,
      modelType: this.config.modelType,
    }
 
    const mem0Config: Mem0ConfigSettings = {
      mem0ApiKey: mem0_api_key,
      ...this.config.mem0Config,
      ...this.settings,
    }
 
    const selector = new Mem0ClassSelector(this.modelId, settings, this.provider_config);
 
    const { messagesPrompts: updatedPrompts } = await this.processMemories(options.prompt, mem0Config);
 
    const baseModel = selector.createProvider();
 
    const streamResponse = await baseModel.doStream({
      ...options,
      prompt: updatedPrompts,
    });
 
    // Return the full stream response, preserving all V3 fields (warnings, etc.)
    return streamResponse;
  } catch (error) {
    console.error("Error in doStream:", error);
    throw new Error("Streaming failed or method not implemented.");
  }
}

Sources: integrations/vercel-ai-sdk/src/mem0-generic-language-model.ts:134-169

Provider Selection and Response Generation

Dynamic Provider Selection and Instantiation

The Mem0ClassSelector class validates and instantiates the underlying AI provider. It accepts a modelId, Mem0ProviderSettings, and optional ProviderSettings, defaulting provider_wrapper to "openai" if config.provider is omitted.

Provider IdentifierSupported StatusInitialization Factory Function
"openai"SupportedcreateOpenAI()
"anthropic"SupportedcreateAnthropic()
"cohere"SupportedcreateCohere()
"groq"SupportedcreateGroq()
"google" / "gemini"SupportedcreateGoogleGenerativeAI()
class Mem0ClassSelector {
    modelId: string;
    provider_wrapper: string;
    config: Mem0ProviderSettings;
    provider_config?: ProviderSettings;
    static supportedProviders = ["openai", "anthropic", "cohere", "groq", "google", "gemini"];
 
    constructor(modelId: string, config: Mem0ProviderSettings, provider_config?: ProviderSettings) {
        this.modelId = modelId;
        this.provider_wrapper = config.provider || "openai";
        this.provider_config = provider_config;
        if(config) this.config = config;
        else this.config = {
            provider: this.provider_wrapper,
        };
 
        // Check if provider_wrapper is supported
        if (!Mem0ClassSelector.supportedProviders.includes(this.provider_wrapper)) {
            throw new Error(`Model not supported: ${this.provider_wrapper}`);
        }
    }
 
    createProvider(): LanguageModelV3 {
        return new Mem0AITextGenerator(this.modelId, this.config , this.provider_config || {});
    }
}

Sources: integrations/vercel-ai-sdk/src/mem0-provider-selector.ts:5-30

Warning

If provider_wrapper does not match any entry in Mem0ClassSelector.supportedProviders, the constructor throws an error stating Model not supported: ${this.provider_wrapper}.

Sources: integrations/vercel-ai-sdk/src/mem0-provider-selector.ts:10-10, integrations/vercel-ai-sdk/src/mem0-provider-selector.ts:21-25

Text Generator Dispatch and Execution

The Mem0AITextGenerator class implements the LanguageModelV3 specification, exposing specificationVersion = "v3", a modelId, a fixed provider string "mem0", and supportedUrls matching any URL pattern ('*': [/.*/]). Its constructor uses a switch statement over config.provider to instantiate the appropriate underlying SDK client. For OpenAI, it supports specific model types (completion, chat, or default languageModel).

class Mem0AITextGenerator implements LanguageModelV3 {
    readonly specificationVersion = "v3";
    readonly modelId: string;
    readonly provider = "mem0";
    readonly supportedUrls: Record<string, RegExp[]> = {
        '*': [/.*/]
    };
    private languageModel: any; // Use any type to avoid version conflicts
 
    constructor(modelId: string, config: Mem0ProviderSettings, provider_config: ProviderSettings) {
        this.modelId = modelId;
 
        switch (config.provider) {
            case "openai":
                if(config?.modelType === "completion"){
                    this.languageModel = createOpenAI({
                        apiKey: config?.apiKey,
                        ...provider_config as OpenAIProviderSettings,
                    }).completion(modelId);
                } else if(config?.modelType === "chat"){
                    this.languageModel = createOpenAI({
                        apiKey: config?.apiKey,
                        ...provider_config as OpenAIProviderSettings,
                    }).chat(modelId);
                } else {
                    this.languageModel = createOpenAI({
                        apiKey: config?.apiKey,
                        ...provider_config as OpenAIProviderSettings,
                    }).languageModel(modelId);
                }
                break;
            case "cohere":
                this.languageModel = createCohere({
                    apiKey: config?.apiKey,
                    ...provider_config as CohereProviderSettings,
                })(modelId);
                break;
            case "anthropic":
                this.languageModel = createAnthropic({
                    apiKey: config?.apiKey,
                    ...provider_config as AnthropicProviderSettings,
                }).languageModel(modelId);
                break;
            case "groq":
                this.languageModel = createGroq({
                    apiKey: config?.apiKey,
                    ...provider_config as GroqProviderSettings,
                })(modelId);
                break;
            case "google":
            case "gemini":
                this.languageModel = createGoogleGenerativeAI({
                    apiKey: config?.apiKey,
                    ...provider_config as GoogleGenerativeAIProviderSettings,
                })(modelId);
                break;
            default:
                throw new Error("Invalid provider");
        }
    }

Sources: integrations/vercel-ai-sdk/src/provider-response-provider.ts:10-69

Caution

If an unrecognized provider string is passed to Mem0AITextGenerator, the switch statement triggers its default branch and throws an Error("Invalid provider").

Sources: integrations/vercel-ai-sdk/src/provider-response-provider.ts:66-68

The doGenerate and doStream methods delegate call options directly to the instantiated languageModel instance, returning typed LanguageModelV3GenerateResult and LanguageModelV3StreamResult responses respectively.

    async doGenerate(options: LanguageModelV3CallOptions): Promise<LanguageModelV3GenerateResult> {
        const result = await this.languageModel.doGenerate(options);
        return result as LanguageModelV3GenerateResult;
    }
 
    async doStream(options: LanguageModelV3CallOptions): Promise<LanguageModelV3StreamResult> {
        const result = await this.languageModel.doStream(options);
        return result as LanguageModelV3StreamResult;
    }
}

Sources: integrations/vercel-ai-sdk/src/provider-response-provider.ts:71-80

Prompt Flattening and Memory Retrieval

Multimodal Content Conversion and Flattening

The flattenPrompt utility extracts and flattens user message prompts from a LanguageModelV3Prompt structure. It maps over prompt parts, verifying if the role is "user", and handles string content, text array objects, or specific file and multimodal media types. File attachments mapped by mediaType yield standard text descriptions ([PDF document], [Markdown document], [Image], or [File attachment]), while unhandled types resolve to [multimodal content].

const flattenPrompt = (prompt: LanguageModelV3Prompt) => {
    try {
        return prompt.map((part) => {
            if (part.role === "user") {
                if (typeof part.content === 'string') {
                    return part.content;
                } else if (Array.isArray(part.content)) {
                    return part.content
                        .filter((obj) => obj.type === 'text')
                        .map((obj) => obj.text)
                        .join(" ");
                } else if (part.content && typeof part.content === 'object' && 'type' in part.content) {
                    const content = part.content as any;
                    if (content.type === 'text' && content.text) {
                        return content.text;
                    } else if (content.type === 'file') {
                        if (content.mediaType === 'application/pdf') {
                            return '[PDF document]';
                        } else if (content.mediaType === 'text/markdown' || content.mediaType === 'application/mdx') {
                            return '[Markdown document]';
                        } else if (content.mediaType && content.mediaType.startsWith('image/')) {
                            return '[Image]';
                        } else {
                            return '[File attachment]';
                        }
                    }
                }
                return "[multimodal content]";
            }
            return "";
        }).join(" ");
    } catch (error) {
        console.error("Error in flattenPrompt:", error);
        return "";
    }
}

Sources: integrations/vercel-ai-sdk/src/mem0-utils.ts:36-71

Complementing prompt flattening, convertToMem0Format transforms messages into structures accepted by the backend. It handles string contents, text arrays, and specific attachment types including PDFs (pdf_url), Markdown or MDX documents (mdx_url), and images (image_url), normalizing various schema aliases.

const convertToMem0Format = (messages: LanguageModelV3Prompt) => {
    try {
        return messages.flatMap((message: any) => {
            try {
                if (typeof message.content === 'string') {
                    return {
                        role: message.role,
                        content: message.content,
                    };
                }
                else if (Array.isArray(message.content)) {
                    return message.content.map((obj: any) => {
                        try {
                            if (obj.type === "text") {
                                return {
                                    role: message.role,
                                    content: obj.text,
                                };
                            } else if (obj.type === "file") {
                                if (obj.mediaType === "application/pdf") {
                                    return {
                                        role: message.role,
                                        content: {
                                            type: "pdf_url",
                                            pdf_url: {
                                                url: obj.data
                                            }
                                        }
                                    };
                                } else if (obj.mediaType === "text/markdown" || obj.mediaType === "application/mdx") {
                                    return {
                                        role: message.role,
                                        content: {
                                            type: "mdx_url",
                                            mdx_url: {
                                                url: obj.data
                                            }
                                        }
                                    };
                                } else if (obj.mediaType && obj.mediaType.startsWith("image/")) {
                                    return {
                                        role: message.role,
                                        content: {
                                            type: "image_url",
                                            image_url: {
                                                url: obj.data
                                            }
                                        }
                                    };
                                }
                            } else if (obj.type === "image_url" || obj.type === "image") {
                                return {
                                    role: message.role,
                                    content: {
                                        type: "image_url",
                                        image_url: {
                                            url: obj.image_url?.url || obj.image?.url || obj.url
                                        }
                                    }
                                };
                            } else if (obj.type === "mdx_url" || obj.type === "mdx") {
                                return {
                                    role: message.role,
                                    content: {
                                        type: "mdx_url",
                                        mdx_url: {
                                            url: obj.mdx_url?.url || obj.mdx?.url || obj.url
                                        }
                                    }
                                };
                            } else if (obj.type === "pdf_url" || obj.type === "pdf") {
                                return {
                                    role: message.role,
                                    content: {
                                        type: "pdf_url",
                                        pdf_url: {
                                            url: obj.pdf_url?.url || obj.pdf?.url || obj.url
                                        }
                                    }
                                };

Sources: integrations/vercel-ai-sdk/src/mem0-utils.ts:73-154

Note

flattenPrompt catches internal mapping errors and safely returns an empty string "" rather than crashing the execution pipeline.

Sources: integrations/vercel-ai-sdk/src/mem0-utils.ts:67-70

Memory Search and System Prompt Injection

The processMemories method in Mem0GenericLanguageModel orchestrates persistence and retrieval during generation turns. It invokes addMemories to record conversational turns, queries relevant items via getMemories, and formats the retrieved records into a structured system prompt prefix.

private async processMemories(messagesPrompts: LanguageModelV3Message[], mem0Config: Mem0ConfigSettings) {
  try {
    // Add new memories — await to ensure writes complete before returning
    try {
      await addMemories(messagesPrompts, mem0Config);
    } catch (e) {
      console.error("Error while adding memories");
    }
 
    // Get memories (always returns an array since graph support is removed)
    const memories: any[] = await getMemories(messagesPrompts, mem0Config) ?? [];
 
    const mySystemPrompt = "These are the memories I have stored. Give more weightage to the question by users and try to answer that first. You have to modify your answer based on the memories I have provided. If the memories are irrelevant you can ignore them. Also don't reply to this section of the prompt, or the memories, they are only for your reference. The System prompt starts after text System Message: \n\n";
 
    let memoriesText = "";
    try {
      memoriesText = memories
        ?.map((memory: any) => `Memory: ${memory?.memory}\n\n`)
        .join("\n\n");
    } catch (e) {
      console.error("Error while parsing memories");
    }
 
    const memoriesPrompt = `System Message: ${mySystemPrompt} ${memoriesText} `;
 
    // Clone the prompt array to avoid mutating the caller's reference on retries
    const updatedPrompts = [...messagesPrompts];
 
    if (memories?.length > 0) {
      const systemPrompt: LanguageModelV3Message = {
        role: "system",
        content: memoriesPrompt
      };
      updatedPrompts.unshift(systemPrompt);
    }
 
    return { memories, messagesPrompts: updatedPrompts };
  } catch (e) {
    console.error("Error while processing memories");
    return { memories: [], messagesPrompts: [...messagesPrompts] };
  }
}

Sources: integrations/vercel-ai-sdk/src/mem0-generic-language-model.ts:37-78

StepOperationDescription
1addMemoriesPersists user messages to the backend using updateMemories.
2getMemoriesSearches for contextually relevant past memories based on the prompt.
3System PrefixPrepends guidance instructing the model to weigh user questions against memories.
4Prompt InjectionUnshifts a system message containing the formatted memories to updatedPrompts.
  await addMemories(messagesPrompts, mem0Config);
} catch (e) {
  console.error("Error while adding memories");
}
 
// Get memories (always returns an array since graph support is removed)
const memories: any[] = await getMemories(messagesPrompts, mem0Config) ?? [];
 
const mySystemPrompt = "These are the memories I have stored. Give more weightage to the question by users and try to answer that first. You have to modify your answer based on the memories I have provided. If the memories are irrelevant you can ignore them. Also don't reply to this section of the prompt, or the memories, they are only for your reference. The System prompt starts after text System Message: \n\n";
 
let memoriesText = "";
try {
  memoriesText = memories
    ?.map((memory: any) => `Memory: ${memory?.memory}\n\n`)
    .join("\n\n");
} catch (e) {
  console.error("Error while parsing memories");
}
 
const memoriesPrompt = `System Message: ${mySystemPrompt} ${memoriesText} `;
 
// Clone the prompt array to avoid mutating the caller's reference on retries
const updatedPrompts = [...messagesPrompts];
 
if (memories?.length > 0) {
  const systemPrompt: LanguageModelV3Message = {
    role: "system",
    content: memoriesPrompt
  };
  updatedPrompts.unshift(systemPrompt);
}

Sources: integrations/vercel-ai-sdk/src/mem0-generic-language-model.ts:41-71

Similarly, retrieveMemories flattens the input prompt or string, searches internal memories via searchInternalMemories, and constructs a formatted system instruction string if results exist.

const retrieveMemories = async (prompt: LanguageModelV3Prompt | string, config?: Mem0ConfigSettings) => {
    try {
        const message = typeof prompt === 'string' ? prompt : flattenPrompt(prompt);
        const systemPrompt = "These are the memories I have stored. Give more weightage to the question by users and try to answer that first. You have to modify your answer based on the memories I have provided. If the memories are irrelevant you can ignore them. Also don't reply to this section of the prompt, or the memories, they are only for your reference. The System prompt starts after text System Message: \n\n";
 
        const data = await searchInternalMemories(message, config);
        // The API response may be a flat array or an object with a results key
        const memories: any[] = Array.isArray(data) ? data : (data?.results ?? []);
 
        if (memories.length === 0) {
            return "";
        }
 
        const memoriesText = memories
            .map((memory: any) => `Memory: ${memory.memory}\n\n`)
            .join("\n\n");
 
        return `System Message: ${systemPrompt} ${memoriesText}`;
    } catch (error) {
        console.error("Error in retrieveMemories:", error);
        throw error;
    }
}

Sources: integrations/vercel-ai-sdk/src/mem0-utils.ts:367-389

Warning

If memory retrieval returns an empty array or fails, processMemories clones the original prompt array without unshifting a system message, preventing empty injection blocks.

Sources: integrations/vercel-ai-sdk/src/mem0-generic-language-model.ts:63-76

Memory Persistence and Post-Generation Hooks

Adding Memories and Request Payload Assembly

The addMemories utility formats input prompts into structured message payloads before sending them to the backend via updateMemories. If the input is a plain string, it wraps it in a single user message object; otherwise, it translates the messages using convertToMem0Format.

const addMemories = async (messages: LanguageModelV3Prompt, config?: Mem0ConfigSettings) => {
    try {
        let finalMessages: Array<Message> = [];
        if (typeof messages === "string") {
            finalMessages = [{ role: "user", content: messages }];
        } else {
            finalMessages = convertToMem0Format(messages);
        }
        const response = await updateMemories(finalMessages, config);
        return response;
    } catch (error) {
        console.error("Error in addMemories:", error);
        throw error;
    }
}

Sources: integrations/vercel-ai-sdk/src/mem0-utils.ts:309-323

The updateMemories function loads authentication credentials via loadApiKey checking the MEM0_API_KEY environment variable or configuration settings. It constructs a POST request body containing the messages along with optional identifiers and parameters.

PropertyField TypeDescription
messagesArray<Message>The array of conversation turns to persist.
user_idstringOptional user scope identifier.
app_idstringOptional application scope identifier.
agent_idstringOptional agent scope identifier.
run_idstringOptional execution run identifier.
metadataobjectOptional custom metadata key-value pairs.
inferbooleanOptional flag controlling memory extraction inference.
const updateMemories = async (messages: Array<Message>, config?: Mem0ConfigSettings) => {
    try {
        const apiKey = loadApiKey({
            apiKey: config?.mem0ApiKey,
            environmentVariableName: "MEM0_API_KEY",
            description: "Mem0",
        });
 
        const body: Record<string, any> = { messages };
        if (config?.user_id) body.user_id = config.user_id;
        if (config?.app_id) body.app_id = config.app_id;
        if (config?.agent_id) body.agent_id = config.agent_id;
        if (config?.run_id) body.run_id = config.run_id;
        if (config?.metadata) body.metadata = config.metadata;
        if (config?.infer != null) body.infer = config.infer;
 

Sources: integrations/vercel-ai-sdk/src/mem0-utils.ts:325-340

Note

updateMemories targets the /v3/memories/add/ endpoint on the configured host, defaulting to https://api.mem0.ai when no host setting is provided.

Sources: integrations/vercel-ai-sdk/src/mem0-utils.ts:354-355

HTTP Headers and Version Attribution

When dispatching requests to the Mem0 backend, updateMemories attaches explicit attribution and authorization headers to every outgoing fetch call.

const options = {
    method: 'POST',
    headers: {
        Authorization: `Token ${apiKey}`,
        'Content-Type': 'application/json',
        // Surface attribution. Set-once by contract: this wrapper is the
        // outermost layer on these raw fetch calls.
        'X-Mem0-Source': 'VERCEL_AI_SDK',
        'X-Mem0-Client': `mem0-vercel-ai-provider/${PROVIDER_VERSION}`
    },
    body: JSON.stringify(body),
};

Sources: integrations/vercel-ai-sdk/src/mem0-utils.ts:341-352

Header NameValue / SourcePurpose
AuthorizationToken ${apiKey}Authenticates the API request using the loaded credentials.
Content-Typeapplication/jsonSpecifies the JSON serialization format of the request body.
X-Mem0-SourceVERCEL_AI_SDKSurfaces provider attribution set-once by contract as the outermost layer.
X-Mem0-Clientmem0-vercel-ai-provider/${PROVIDER_VERSION}Identifies the client wrapper version, resolving to dev unbundled or __MEM0_PROVIDER_VERSION__ at build time.
declare const __MEM0_PROVIDER_VERSION__: string | undefined;
 
// Replaced at build time by tsup `define`. The fallback only applies when the
// source is run unbundled, such as in tests.
const PROVIDER_VERSION =
  typeof __MEM0_PROVIDER_VERSION__ !== "undefined" ? __MEM0_PROVIDER_VERSION__ : "dev";
 
…
const options = {
    method: 'POST',
    headers: {
        Authorization: `Token ${apiKey}`,
        'Content-Type': 'application/json',
        // Surface attribution. Set-once by contract: this wrapper is the
        // outermost layer on these raw fetch calls.
        'X-Mem0-Source': 'VERCEL_AI_SDK',
        'X-Mem0-Client': `mem0-vercel-ai-provider/${PROVIDER_VERSION}`
    },
    body: JSON.stringify(body),
};

Sources: integrations/vercel-ai-sdk/src/mem0-utils.ts:1-7, integrations/vercel-ai-sdk/src/mem0-utils.ts:341-352

Warning

If the fetch response status is not successful (!response.ok), updateMemories throws an HTTP error containing the response status code.

Sources: integrations/vercel-ai-sdk/src/mem0-utils.ts:356-358

Streaming Chunk Transformation and Filtering

Stream Interceptor Pipeline

The streaming architecture utilizes filterStream to process and intercept response chunks generated during doStream invocations. The interceptor wraps an original ReadableStream by acquiring its reader and constructing a new stream that reads chunks asynchronously within a continuous loop.

async function filterStream(originalStream: ReadableStream) {
    const reader = originalStream.getReader();
    const filteredStream = new ReadableStream({
        async start(controller) {
            while (true) {
                const { done, value } = await reader.read();
                if (done) {
                    controller.close();
                    break;
                }
                try {
                    const chunk = JSON.parse(value); 
                    if (chunk.type !== "step-finish") {
                        controller.enqueue(value);
                    }
                } catch (error) {
                    if (!(value.type==='step-finish')) {
                        controller.enqueue(value);
                    }
                }
            }
        }
    });
 
    return filteredStream;
}

Sources: integrations/vercel-ai-sdk/src/stream-utils.ts:1-26

Chunk Filtering Logic

As chunks are read from the underlying stream, the transformation pipeline attempts to parse each value as JSON. If parsing succeeds, chunks whose .type property matches "step-finish" are filtered out and omitted from the output controller.

try {
    const chunk = JSON.parse(value); 
    if (chunk.type !== "step-finish") {
        controller.enqueue(value);
    }
} catch (error) {

Sources: integrations/vercel-ai-sdk/src/stream-utils.ts:11-16

Note

If JSON parsing throws an error, the interceptor falls back to checking the raw value object directly, enqueuing the chunk only if its type field is not equal to 'step-finish'.

Sources: integrations/vercel-ai-sdk/src/stream-utils.ts:16-20

Was this page helpful?