#7349·mem0

bug(oss): ConfigManager injects OpenAI's baseURL and model into every other LLM provider, so documented non-OpenAI configs are sent to api.openai.com

Author: warun7Created Sep 16, 2026Updated Sep 16, 2026
Labelssdk-typescript

Component

TypeScript SDK

Description

Summary

DEFAULT_MEMORY_CONFIG.llm.config holds OpenAI's own values (baseURL: "https://api.openai.com/v1" at mem0-ts/src/oss/src/config/defaults.ts:23, model: "gpt-5-mini" at :25), and ConfigManager.mergeConfig treats them as universal defaults (mem0-ts/src/oss/src/config/manager.ts:126-136):

const llmBaseURL =
  userConf?.baseURL ??
  ...
  userConf?.url ??
  (provider.toLowerCase() === "vllm" ? undefined : defaultConf.baseURL);

So any config that omits baseURL gets OpenAI's, for every provider except vLLM. The providers then prefer it over their own default and over their documented env fallback:

  • llms/deepseek.ts:12-16: config.baseURL || process.env.DEEPSEEK_API_BASE || "https://api.deepseek.com"
  • llms/xai.ts:23-24: same shape, so XAI_API_BASE is dead code
  • llms/ollama.ts:15: config.url || config.baseURL || "http://localhost:11434"
  • llms/anthropic.ts:22-25: if (config.baseURL) clientArgs.baseURL = config.baseURL

model has the same shape: manager.ts:116 defaults it to gpt-5-mini for every provider, which makes each provider's own fallback unreachable (deepseek-chat, grok-4.3, llama3.1:8b, gemini-2.0-flash, claude-sonnet-4-6, ...).

The documented snippets are what break. docs/components/llms/models/deepseek.mdx:44-55 shows:

llm: {
  provider: 'deepseek',
  config: {
    apiKey: process.env.DEEPSEEK_API_KEY || '',
    model: 'deepseek-chat',
    temperature: 0.2,
    maxTokens: 2000,
    top_p: 1.0,
  },
}

There is no baseURL, so copying the docs sends a DeepSeek key to api.openai.com.

The repo already knows about this class of bug and has patched it twice, one provider at a time: manager.ts carves out vllm for baseURL (the ternary above), and the embedder block carves out fastembed for model (manager.ts:18-21, with a comment saying the OpenAI model "only makes sense for API-based providers"). Both carve-outs are correct; every other provider needs the same treatment.

Note this is only about baseURL and model. apiKey is the same shape (manager.ts:152-155 falls back to process.env.OPENAI_API_KEY || "") and the embedder model default is the same shape too. I left both alone here to keep the diff reviewable and because narrowing apiKey has a compatibility wrinkle (llms/azure.ts has no env fallback of its own and currently relies on that injection). Happy to extend the fix to either if you want it in scope.

Steps to Reproduce

import { ConfigManager } from "../src/config/manager";
import { LLMFactory } from "../src/utils/factory";

const cfg = ConfigManager.mergeConfig({
  llm: { provider: "deepseek", config: { apiKey: "k" } },
} as any);

console.log(cfg.llm.config.baseURL); // https://api.openai.com/v1
console.log(cfg.llm.config.model);   // gpt-5-mini

const llm = LLMFactory.create("deepseek", cfg.llm.config);
console.log((llm as any).openai.baseURL); // https://api.openai.com/v1

Or run the two tests that currently assert the old behaviour: pnpm exec jest --config jest.config.js --testPathPattern config-manager.

Expected Behavior

For a non-OpenAI provider, mergeConfig should leave baseURL and model unset unless the user supplied them, so the provider applies its own default and its *_API_BASE env fallback.

Actual Behavior

baseURL is https://api.openai.com/v1 and model is gpt-5-mini for every non-vLLM provider, including deepseek, xai, ollama, lmstudio, anthropic, google, groq, mistral, together, minimax, sarvam, and aws_bedrock.

Environment

  • mem0 version: mem0-ts @ main (0df3e4b8)
  • Node version: 24.18.0 (CI targets 20 / 22)
  • OS: macOS 15 (darwin), arm64

How You Verified This

What I Ran

Two tests in mem0-ts/src/oss/tests/config-manager.test.ts already asserted the OpenAI default being injected for a non-OpenAI provider, so they fail as soon as the behaviour is corrected:

  • config-manager.test.ts:145 (provider ollama) expects https://api.openai.com/v1
  • config-manager.test.ts:370 (provider lmstudio) expects https://api.openai.com/v1

I ran pnpm exec jest --config jest.config.js --testPathPattern config-manager before touching manager.ts and both failed against the corrected expectation, which is the reproduction.

I also read every provider's baseURL/model resolution to confirm the injected values are what win: llms/deepseek.ts:12-16, llms/xai.ts:23-24, llms/ollama.ts:15, llms/lmstudio.ts:15-16, llms/anthropic.ts:22-25, llms/litellm.ts:9-13, plus the embedder block at manager.ts:18-21.

What I Saw

ConfigManager.mergeConfig({ llm: { provider: "deepseek", config: { apiKey: "k" } } })
// cfg.llm.config.baseURL === "https://api.openai.com/v1"
// cfg.llm.config.model   === "gpt-5-mini"

and via the real provider:

LLMFactory.create("deepseek", cfg.llm.config) // client baseURL === "https://api.openai.com/v1"

Why This Is a Bug

  • llms/deepseek.ts:12-16 and llms/xai.ts:23-24 both list their own default and their env fallback after config.baseURL, so the injected value makes DEEPSEEK_API_BASE / XAI_API_BASE unreachable. Those fallbacks are documented and tested.
  • Every LLM provider has its own model default (deepseek-chat, grok-4.3, llama3.1:8b, gemini-2.0-flash, claude-sonnet-4-6, mistral-tiny-latest, MiniMax-M2.7, anthropic.claude-3-5-sonnet-20240620-v1:0, ...), and the injected gpt-5-mini makes all of them dead code.
  • The repo carves out vllm for exactly this reason and fastembed for the embedder equivalent, so the intended rule is "provider-specific defaults stay with their provider". The other providers were simply missed.
  • docs/components/llms/models/deepseek.mdx:44-55 ships a TypeScript config with no baseURL, so the documented path is affected.

What I Ruled Out

  • Not the provider's own default. DeepSeekLLM defaults to https://api.deepseek.com, but config.baseURL is checked first, so it never runs.
  • Not the factory. LLMFactory.create (utils/factory.ts:108-150) passes the config straight to the provider with no injection. mergeConfig is the only place the OpenAI defaults are applied. (RerankerFactory.buildLLMRerankerLLM at utils/factory.ts:252-253 does something similar for the LLM reranker, but that is a separate path and not part of this report.)
  • Not openai_structured. It shares the OpenAI defaults legitimately, so it is included in the provider test alongside openai.
  • Not the embedder's baseURL. The embedder block does not fall back to an OpenAI baseURL at all (manager.ts:30-35), so only the LLM endpoint is affected. The embedder model default is a real sibling issue, noted above and left out of this change.
  • No provider loses its model. I checked all 18 LLM providers and each one supplies its own fallback when model is undefined, including aws_bedrock (anthropic.claude-3-5-sonnet-20240620-v1:0) and langchain, which requires the model field to be a LangChain instance and throws the same error either way.

Suggested fix

Give the OpenAI defaults only to the OpenAI providers, which also subsumes the vLLM carve-out:

const usesOpenAIDefaults =
  provider.toLowerCase() === "openai" ||
  provider.toLowerCase() === "openai_structured";
let finalModel: string | any = usesOpenAIDefaults ? defaultConf.model : undefined;
// ...
userConf?.url ?? (usesOpenAIDefaults ? defaultConf.baseURL : undefined);

The two tests that assert the old behaviour change with it. I have this written, with regression tests covering deepseek, xai, lmstudio, ollama, openai and openai_structured, and the full TypeScript suite passes (68 suites, 1024 tests).

AI Assistance

AI found and wrote this, and I have not reproduced it myself