Relevant source files
The following files were used as context for generating this wiki page:
- mem0-ts/src/oss/src/utils/factory.ts
- integrations/openclaw/cli/oss-wizard.ts
- integrations/openclaw/providers.ts
- mem0-ts/src/oss/src/memory/index.ts
- integrations/vercel-ai-sdk/src/mem0-provider-selector.ts
- mem0-ts/src/oss/src/llms/aws_bedrock.ts
- integrations/deepseek-plugin/src/index.ts
- integrations/vercel-ai-sdk/src/provider-response-provider.ts
- mem0-ts/src/oss/src/llms/deepseek.ts
- mem0/utils/factory.py
- mem0-ts/src/oss/src/llms/mistral.ts
- mem0-ts/src/oss/src/llms/vllm.ts
- mem0-ts/src/oss/src/llms/groq.ts
- mem0-ts/src/oss/src/llms/ollama.ts
- mem0-ts/src/oss/src/llms/xai.ts
- integrations/vercel-ai-sdk/src/mem0-provider.ts
- mem0-ts/src/oss/src/index.ts
- integrations/vercel-ai-sdk/src/mem0-generic-language-model.ts
- mem0-ts/src/oss/src/llms/lmstudio.ts
- mem0-ts/src/oss/src/llms/anthropic.ts
- mem0-ts/src/oss/src/llms/google.ts
- mem0-ts/src/oss/src/llms/sarvam.ts
- mem0/llms/deepseek.py
- mem0-ts/src/oss/src/llms/openai.ts
- integrations/vercel-ai-sdk/src/mem0-facade.ts
- mem0/llms/aws_bedrock.py
- mem0-ts/src/oss/src/llms/azure.ts
- mem0-ts/src/oss/src/llms/langchain.ts
- integrations/vercel-ai-sdk/config/test-config.ts
- mem0-ts/src/oss/src/llms/base.ts
Overview
The TypeScript core package provides a unified LLM abstraction layer for extracting structured facts, processing memories, and executing chat completions across diverse language model backends. Built around a core LLM interface and standardized LLMResponse structures, the architecture enables modular provider integration and flexible configuration handling via the LLMFactory.
Sources: mem0-ts/src/oss/src/llms/base.ts:1-18, mem0-ts/src/oss/src/utils/factory.ts:108-152
LLM Abstraction and Types
Core Interface and Response Structures
The TypeScript core establishes a standard contract for all language model integrations via the LLM interface. Implementations must provide two primary asynchronous methods: generateResponse, which accepts an array of message objects along with optional response formatting and tools, and generateChat, which takes typed Message arrays and returns a standardized LLMResponse.
export interface LLMResponse {
content: string;
role: string;
toolCalls?: Array<{
name: string;
arguments: string;
}>;
}
export interface LLM {
generateResponse(
messages: Array<{ role: string; content: string }>,
response_format?: { type: string },
tools?: any[],
): Promise<any>;
generateChat(messages: Message[]): Promise<LLMResponse>;
}Sources: mem0-ts/src/oss/src/llms/base.ts:3-19
OpenAI and Compatible Subclasses
Base OpenAI Client and Provider Configurations
The OpenAILLM class serves as the foundational base adapter utilizing the official openai package to execute chat completions and tool calls mem0-ts/src/oss/src/llms/openai.ts:1-75. It maps input messages to valid roles (system, user, or assistant), serializes complex content blocks, and handles response parsing for both direct string outputs and structured tool invocations mem0-ts/src/oss/src/llms/openai.ts:23-53. Several subclassed providers extend OpenAILLM by supplying customized default environment variables, base URLs, and model identifiers mem0-ts/src/oss/src/llms/deepseek.ts:1-43, mem0-ts/src/oss/src/llms/vllm.ts:1-49, mem0-ts/src/oss/src/llms/xai.ts:1-50, mem0-ts/src/oss/src/llms/lmstudio.ts:1-41, mem0-ts/src/oss/src/llms/sarvam.ts:1-52.
| Provider Class | Default Model | Default Base URL | Key Resolution Order |
|---|---|---|---|
OpenAILLM | gpt-5-mini | config.baseURL | config.apiKey |
DeepSeekLLM | deepseek-chat | config.baseURL || DEEPSEEK_API_BASE || https://api.deepseek.com | config.apiKey || DEEPSEEK_API_KEY |
VllmLLM | Qwen/Qwen2.5-32B-Instruct | config.baseURL || config.vllmBaseURL || config.vllm_base_url || config.url || VLLM_BASE_URL || http://localhost:8000/v1 | config.apiKey || VLLM_API_KEY || vllm-api-key |
XAILLM | grok-4.3 | config.baseURL || XAI_API_BASE || https://api.x.ai/v1 | config.apiKey || XAI_API_KEY |
LMStudioLLM | lmstudio-community/Meta-Llama-3.1-70B-Instruct-GGUF/Meta-Llama-3.1-70B-Instruct-IQ2_M.gguf | config.baseURL ?? http://localhost:1234/v1 | config.apiKey || lm-studio |
SarvamLLM | sarvam-m | config.baseURL || SARVAM_API_BASE || https://api.sarvam.ai/v1 | config.apiKey || SARVAM_API_KEY |
Sources: mem0-ts/src/oss/src/llms/deepseek.ts:5-20, mem0-ts/src/oss/src/llms/vllm.ts:5-26, mem0-ts/src/oss/src/llms/xai.ts:14-27, mem0-ts/src/oss/src/llms/lmstudio.ts:5-18, mem0-ts/src/oss/src/llms/sarvam.ts:14-29, mem0-ts/src/oss/src/llms/openai.ts:5-16
Warning
DeepSeekLLM, XAILLM, and SarvamLLM throw an explicit synchronous Error during initialization if an API key cannot be resolved from configuration parameters or their respective environment variables (DEEPSEEK_API_KEY, XAI_API_KEY, SARVAM_API_KEY).
Sources: mem0-ts/src/oss/src/llms/deepseek.ts:7-10, mem0-ts/src/oss/src/llms/xai.ts:16-19, mem0-ts/src/oss/src/llms/sarvam.ts:16-19
Error Handling and Subclass Wrappers
Each subclass wraps its execution methods (generateResponse and generateChat) in try...catch blocks to intercept runtime exceptions from the underlying OpenAI client and rethrow them with provider-prefixed context messages mem0-ts/src/oss/src/llms/deepseek.ts:22-42, mem0-ts/src/oss/src/llms/vllm.ts:28-48, mem0-ts/src/oss/src/llms/xai.ts:29-49, mem0-ts/src/oss/src/llms/lmstudio.ts:20-40, mem0-ts/src/oss/src/llms/sarvam.ts:31-51. For example, LMStudioLLM catches any error during generation and formats it into an LM Studio LLM failed: ${message} exception mem0-ts/src/oss/src/llms/lmstudio.ts:27-30.
Sources: mem0-ts/src/oss/src/llms/deepseek.ts:22-42, mem0-ts/src/oss/src/llms/vllm.ts:28-48, mem0-ts/src/oss/src/llms/xai.ts:29-49, mem0-ts/src/oss/src/llms/lmstudio.ts:20-40, mem0-ts/src/oss/src/llms/sarvam.ts:31-51
Proprietary SDK Providers
Anthropic, Google, Mistral, and Groq Integration
The TypeScript engine implements direct SDK client wrappers for proprietary language model providers that do not rely on the OpenAI-compatible base class. Each provider manages its own lazy client initialization using loadPeer to dynamically import underlying SDK packages such as @anthropic-ai/sdk, @google/genai, @mistralai/mistralai, and groq-sdk upon first invocation mem0-ts/src/oss/src/llms/anthropic.ts:34-42, mem0-ts/src/oss/src/llms/google.ts:16-24, mem0-ts/src/oss/src/llms/mistral.ts:19-27, mem0-ts/src/oss/src/llms/groq.ts:20-28.
| Provider Class | Default Model | Configuration Keys | SDK Peer Package |
|---|---|---|---|
AnthropicLLM | claude-sonnet-4-6 | config.apiKey || ANTHROPIC_API_KEY, config.baseURL, config.maxTokens, config.temperature, config.topP | @anthropic-ai/sdk |
GoogleLLM | gemini-2.0-flash | config.apiKey, config.model | @google/genai |
MistralLLM | mistral-tiny-latest | config.apiKey, config.model | @mistralai/mistralai |
GroqLLM | llama3-70b-8192 | config.apiKey || GROQ_API_KEY, config.model | groq-sdk |
Sources: mem0-ts/src/oss/src/llms/anthropic.ts:14-32, mem0-ts/src/oss/src/llms/google.ts:11-14, mem0-ts/src/oss/src/llms/mistral.ts:11-17, mem0-ts/src/oss/src/llms/groq.ts:11-18
Warning
AnthropicLLM, MistralLLM, and GroqLLM throw an explicit synchronous Error during instantiation if the required API key is missing from configuration parameters and environment variables. GoogleLLM permits an undefined API key during construction to support ambient credentials.
Sources: mem0-ts/src/oss/src/llms/anthropic.ts:15-18, mem0-ts/src/oss/src/llms/mistral.ts:11-14, mem0-ts/src/oss/src/llms/groq.ts:11-15, mem0-ts/src/oss/src/llms/google.ts:11-14
Message Formatting and Response Parsing
Each adapter adapts internal generic Message structures into provider-specific schemas. AnthropicLLM extracts system messages into a dedicated system property, forwards remaining messages with mapped roles, and iterates through response content blocks to handle text and tool_use blocks mem0-ts/src/oss/src/llms/anthropic.ts:50-101. GoogleLLM formats message contents into part arrays and maps system roles to model roles while setting responseMimeType to application/json when responseFormat.type equals json_object mem0-ts/src/oss/src/llms/google.ts:26-38, mem0-ts/src/oss/src/llms/google.ts:67-69.
Tip
GoogleLLM automatically strips leading markdown JSON fences (^```json\n and \n```$) from text completions when structured JSON output is returned without native mime-type enforcement.
Sources: mem0-ts/src/oss/src/llms/google.ts:89-91
MistralLLM includes a contentToString helper that processes text chunks and content arrays into strings, and maps tool calls when present in completion choices mem0-ts/src/oss/src/llms/mistral.ts:30-47, mem0-ts/src/oss/src/llms/mistral.ts:78-90. GroqLLM maps chat messages to standard completion inputs and returns message content strings or chat response structures directly mem0-ts/src/oss/src/llms/groq.ts:30-68.
Sources: mem0-ts/src/oss/src/llms/mistral.ts:30-93, mem0-ts/src/oss/src/llms/groq.ts:30-68
AWS Bedrock Converse Integration
Message Formatting and Provider Extraction
The AWSBedrockLLM class implements the LLM interface using the AWS Bedrock Converse API (ConverseCommand). This provides a unified message and tool interface across multiple model families, including Anthropic, Amazon (Nova), Meta, Mistral, and Cohere. The optional @aws-sdk/client-bedrock-runtime package is loaded dynamically on first use via an import() statement to ensure the SDK remains optional. Credentials resolve via the standard AWS chain or explicit configuration properties (awsRegion, awsAccessKeyId, awsSecretAccessKey, awsSessionToken, or an injected client).
const PROVIDERS = [
"ai21",
"amazon",
"anthropic",
"cohere",
"meta",
"mistral",
"stability",
"writer",
"deepseek",
"gpt-oss",
"perplexity",
"snowflake",
"titan",
"command",
"j2",
"llama",
"minimax",
];Sources: mem0-ts/src/oss/src/llms/aws_bedrock.ts:8-26
Warning
Dynamic SDK loading must use a dynamic import(), never require(). Bundlers like tsup and esbuild rewrite require() into a __require shim that throws an error when evaluating published ESM bundles (dist/oss/index.mjs), causing the provider to fail even when the AWS SDK is installed.
Sources: mem0-ts/src/oss/src/llms/aws_bedrock.ts:119-125
Model family identifiers are validated and extracted against a recognized provider list. If providerOverride is specified, it must match one of the recognized provider strings; otherwise, the adapter searches the model string using regular expressions.
export function extractProvider(
model: string,
providerOverride?: string,
): string {
if (providerOverride) {
if (!PROVIDERS.includes(providerOverride)) {
throw new Error(
`Unknown providerOverride '${providerOverride}'. Valid providers: ${PROVIDERS.join(", ")}`,
);
}
return providerOverride;
}
for (const provider of PROVIDERS) {
const re = new RegExp(
`\\b${provider.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`,
);
if (re.test(model)) return provider;
}
throw new Error(`Unknown provider in model: ${model}`);
}Sources: mem0-ts/src/oss/src/llms/aws_bedrock.ts:32-51
Messages are split into a top-level system block and role-tagged content blocks for the Converse API. System roles are accumulated into system parts, while assistant and user roles are mapped to converseMessages. If no messages are provided, a default empty user message is added.
/**
* Split messages into a top-level `system` block (Converse passes system
* prompts separately) and role-tagged content blocks for everything else.
*/
private formatMessages(messages: Message[]): {
system?: { text: string }[];
converseMessages: { role: string; content: { text: string }[] }[];
} {
const systemParts: string[] = [];
const converseMessages: { role: string; content: { text: string }[] }[] =
[];
for (const msg of messages) {
const role = msg.role;
const content =
typeof msg.content === "string"
? msg.content
: JSON.stringify(msg.content);
if (role === "system") {
systemParts.push(content);
} else {
converseMessages.push({
role: role === "assistant" ? "assistant" : "user",
content: [{ text: content }],
});
}
}
if (converseMessages.length === 0) {
converseMessages.push({ role: "user", content: [{ text: "" }] });
}
return {
system: systemParts.length
? [{ text: systemParts.join("\n") }]
: undefined,
converseMessages,
};
}Sources: mem0-ts/src/oss/src/llms/aws_bedrock.ts:156-194
Local Host and Framework Connectors
Ollama Client Initialization and Model Validation
The OllamaLLM class connects to local Ollama servers to manage local model execution. Host URLs default to http://localhost:11434 if neither config.url nor config.baseURL is supplied, and model selection defaults to llama3.1:8b. The peer dependency for Ollama is dynamically loaded via loadPeer.
export class OllamaLLM implements LLM {
private ollama!: Ollama;
private model: string;
private readonly host: string;
// Using this variable to avoid calling the Ollama server multiple times
private initialized: boolean = false;
constructor(config: LLMConfig) {
this.host = config.url || config.baseURL || "http://localhost:11434";
this.model = config.model || "llama3.1:8b";
this.ensureModelExists().catch((err) => {
logger.error(`Error ensuring model exists: ${err}`);
});
}
private async ensureClient(): Promise<void> {
if (this.ollama) return;
const sdk = await loadPeer("ollama", "Ollama LLM", () => import("ollama"));
this.ollama = new sdk.Ollama({ host: this.host });
}Sources: mem0-ts/src/oss/src/llms/ollama.ts:7-26
Before executing generations or chats, ensureModelExists checks whether the target model is present in the local server list using this.ollama.list(). If the model is absent, this.ollama.pull downloads it automatically while setting an internal flag to prevent redundant API checks across subsequent calls.
private async ensureModelExists(): Promise<boolean> {
if (this.initialized) {
return true;
}
await this.ensureClient();
const local_models = await this.ollama.list();
if (!local_models.models.find((m: any) => m.name === this.model)) {
logger.info(`Pulling model ${this.model}...`);
await this.ollama.pull({ model: this.model });
}
this.initialized = true;
return true;
}Sources: mem0-ts/src/oss/src/llms/ollama.ts:100-112
Note
The initialized boolean flag on OllamaLLM ensures that ensureModelExists only queries and pulls models once during the instance lifecycle, avoiding redundant network roundtrips to the local Ollama daemon.
Sources: mem0-ts/src/oss/src/llms/ollama.ts:11-12, mem0-ts/src/oss/src/llms/ollama.ts:100-103
LangChain Message Bridging and Schema Selection
The LangchainLLM adapter wraps existing LangChain language model instances (BaseLanguageModel). The constructor verifies that config.model is an object containing an invoke method. Model names are resolved from modelId, model, or defaulted to langchain-model.
export class LangchainLLM implements LLM {
private llmInstance: BaseLanguageModel;
private modelName: string;
constructor(config: LLMConfig) {
if (!config.model || typeof config.model !== "object") {
throw new Error(
"Langchain provider requires an initialized Langchain instance passed via the 'model' field in the LLM config.",
);
}
if (typeof (config.model as any).invoke !== "function") {
throw new Error(
"Provided Langchain 'instance' in the 'model' field does not appear to be a valid Langchain language model (missing invoke method).",
);
}
this.llmInstance = config.model as BaseLanguageModel;
this.modelName =
(this.llmInstance as any).modelId ||
(this.llmInstance as any).model ||
"langchain-model";
}Sources: mem0-ts/src/oss/src/llms/langchain.ts:37-57
The helper function convertToLangchainMessages translates Mem0 message roles into LangChain message classes. Unrecognized roles log a warning and fall back to HumanMessage.
| Mem0 Role | LangChain Message Class |
|---|---|
system | SystemMessage |
user, human | HumanMessage |
assistant, ai | AIMessage |
| unknown | HumanMessage (with console warning) |
const convertToLangchainMessages = async (
messages: Message[],
): Promise<BaseMessage[]> => {
const { AIMessage, HumanMessage, SystemMessage } =
await import("@langchain/core/messages");
return messages.map((msg) => {
const content =
typeof msg.content === "string"
? msg.content
: JSON.stringify(msg.content);
switch (msg.role?.toLowerCase()) {
case "system":
return new SystemMessage(content);
case "user":
case "human":
return new HumanMessage(content);
case "assistant":
case "ai":
return new AIMessage(content);
default:
console.warn(
`Unsupported message role '${msg.role}' for Langchain. Treating as 'human'.`,
);
return new HumanMessage(content);
}
});
};Sources: mem0-ts/src/oss/src/llms/langchain.ts:9-35
During response generation, LangchainLLM inspects system and user prompts to select schemas for structured extraction:
- If the system prompt contains
"Personal Information Organizer"and"extract relevant pieces of information",FactRetrievalSchemais selected. - If the user prompt contains
"smart memory manager"and"Compare newly retrieved facts",MemoryUpdateSchemais selected.
If a schema is matched and withStructuredOutput is available on the underlying instance, the adapter wraps the runnable using the schema. Tool bindings are applied via bindTools when available.
// --- Internal Schema Selection Logic (runs regardless of response_format) ---
const systemPromptContent =
(messages.find((m) => m.role === "system")?.content as string) || "";
const userPromptContent =
(messages.find((m) => m.role === "user")?.content as string) || "";
// Check for memory prompts
if (
systemPromptContent.includes("Personal Information Organizer") &&
systemPromptContent.includes("extract relevant pieces of information")
) {
selectedSchema = FactRetrievalSchema;
} else if (
userPromptContent.includes("smart memory manager") &&
userPromptContent.includes("Compare newly retrieved facts")
) {
selectedSchema = MemoryUpdateSchema;
}
// --- Apply Structured Output if Schema Selected ---
if (
selectedSchema &&
typeof (this.llmInstance as any).withStructuredOutput === "function"
) {
try {
runnable = (this.llmInstance as any).withStructuredOutput(
selectedSchema,
{ name: tools?.[0]?.function.name },
);
isStructuredOutput = true;
} catch (e) {
isStructuredOutput = false; // Ensure flag is false on error
// No fallback to response_format here unless explicitly passed
if (response_format?.type === "json_object") {
invokeOptions.response_format = { type: "json_object" };
}
}
} else if (selectedSchema && response_format?.type === "json_object") {
// Schema selected, but no .withStructuredOutput. Try basic response_format only if explicitly requested.
if (
(this.llmInstance as any)._identifyingParams?.response_format ||
(this.llmInstance as any).response_format
) {
invokeOptions.response_format = { type: "json_object" };
}
} else if (!selectedSchema && response_format?.type === "json_object") {
// Explicit JSON request, but no schema inferred. Try basic response_format.
if (
(this.llmInstance as any)._identifyingParams?.response_format ||
(this.llmInstance as any).response_format
) {
invokeOptions.response_format = { type: "json_object" };
}
}
// --- Handle tool binding ---
if (tools && tools.length > 0) {
if (typeof (runnable as any).bindTools === "function") {
try {
runnable = (runnable as any).bindTools(tools);
} catch (e) {}
} else {
}
}Sources: mem0-ts/src/oss/src/llms/langchain.ts:70-132
Related
On This Page
OverviewLLM Abstraction and TypesCore Interface and Response StructuresOpenAI and Compatible SubclassesBase OpenAI Client and Provider ConfigurationsError Handling and Subclass WrappersProprietary SDK ProvidersAnthropic, Google, Mistral, and Groq IntegrationMessage Formatting and Response ParsingAWS Bedrock Converse IntegrationMessage Formatting and Provider ExtractionLocal Host and Framework ConnectorsOllama Client Initialization and Model ValidationLangChain Message Bridging and Schema SelectionRelated