fix(mem0): migrate legacy OSS base URL aliases
Normalize stale api_base keys to each mem0 provider's accepted URL field before Memory.from_config, without mutating the saved config.
This commit is contained in:
parent
4c0546c9cc
commit
07f07c7b51
5 changed files with 86 additions and 6 deletions
|
|
@ -160,6 +160,23 @@ class OSSBackend(Mem0Backend):
|
|||
import os
|
||||
from mem0 import Memory
|
||||
|
||||
def _provider_block(name: str) -> dict:
|
||||
block = dict(oss_config[name])
|
||||
provider = str(block.get("provider") or "").strip().lower()
|
||||
provider_config = dict(block.get("config", {}))
|
||||
legacy_base = provider_config.pop("api_base", None)
|
||||
if legacy_base:
|
||||
from ._oss_providers import EMBEDDER_PROVIDERS, LLM_PROVIDERS
|
||||
|
||||
provider_def = (
|
||||
LLM_PROVIDERS if name == "llm" else EMBEDDER_PROVIDERS
|
||||
).get(provider, {})
|
||||
canonical_key = provider_def.get("base_url_key")
|
||||
if canonical_key:
|
||||
provider_config.setdefault(canonical_key, legacy_base)
|
||||
block["config"] = provider_config
|
||||
return block
|
||||
|
||||
vector_store = dict(oss_config["vector_store"])
|
||||
vs_config = dict(vector_store.get("config", {}))
|
||||
|
||||
|
|
@ -182,8 +199,8 @@ class OSSBackend(Mem0Backend):
|
|||
|
||||
config = {
|
||||
"vector_store": vector_store,
|
||||
"llm": oss_config["llm"],
|
||||
"embedder": oss_config["embedder"],
|
||||
"llm": _provider_block("llm"),
|
||||
"embedder": _provider_block("embedder"),
|
||||
"version": "v1.1",
|
||||
}
|
||||
self._memory = Memory.from_config(config)
|
||||
|
|
|
|||
|
|
@ -11,12 +11,14 @@ LLM_PROVIDERS: dict[str, dict[str, Any]] = {
|
|||
"needs_key": True,
|
||||
"env_var": "OPENAI_API_KEY",
|
||||
"default_model": "gpt-5-mini",
|
||||
"base_url_key": "openai_base_url",
|
||||
},
|
||||
"ollama": {
|
||||
"label": "Ollama (local)",
|
||||
"needs_key": False,
|
||||
"default_model": "llama3.1:8b",
|
||||
"default_url": "http://localhost:11434",
|
||||
"base_url_key": "ollama_base_url",
|
||||
"pip_dep": "ollama",
|
||||
},
|
||||
}
|
||||
|
|
@ -27,6 +29,7 @@ EMBEDDER_PROVIDERS: dict[str, dict[str, Any]] = {
|
|||
"needs_key": True,
|
||||
"env_var": "OPENAI_API_KEY",
|
||||
"default_model": "text-embedding-3-small",
|
||||
"base_url_key": "openai_base_url",
|
||||
"dims": 1536,
|
||||
},
|
||||
"ollama": {
|
||||
|
|
@ -34,6 +37,7 @@ EMBEDDER_PROVIDERS: dict[str, dict[str, Any]] = {
|
|||
"needs_key": False,
|
||||
"default_model": "nomic-embed-text",
|
||||
"default_url": "http://localhost:11434",
|
||||
"base_url_key": "ollama_base_url",
|
||||
"dims": 768,
|
||||
"pip_dep": "ollama",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -135,15 +135,17 @@ def build_oss_config(flags: dict[str, str]) -> tuple[dict, dict[str, str]]:
|
|||
llm_def = LLM_PROVIDERS[llm_id]
|
||||
llm_model = flags.get("oss_llm_model") or llm_def["default_model"]
|
||||
llm_config: dict[str, Any] = {"model": llm_model}
|
||||
if "default_url" in llm_def:
|
||||
llm_config["ollama_base_url"] = flags.get("oss_llm_url") or llm_def["default_url"]
|
||||
llm_url = flags.get("oss_llm_url") or llm_def.get("default_url")
|
||||
if llm_url and llm_def.get("base_url_key"):
|
||||
llm_config[llm_def["base_url_key"]] = llm_url
|
||||
|
||||
embedder_id = flags.get("oss_embedder", "openai")
|
||||
embedder_def = EMBEDDER_PROVIDERS[embedder_id]
|
||||
embedder_model = flags.get("oss_embedder_model") or embedder_def["default_model"]
|
||||
embedder_config: dict[str, Any] = {"model": embedder_model}
|
||||
if "default_url" in embedder_def:
|
||||
embedder_config["ollama_base_url"] = flags.get("oss_embedder_url") or embedder_def["default_url"]
|
||||
embedder_url = flags.get("oss_embedder_url") or embedder_def.get("default_url")
|
||||
if embedder_url and embedder_def.get("base_url_key"):
|
||||
embedder_config[embedder_def["base_url_key"]] = embedder_url
|
||||
dims = KNOWN_DIMS.get(embedder_model)
|
||||
if dims:
|
||||
embedder_config["embedding_dims"] = dims
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
"""Tests for Mem0Backend abstraction — PlatformBackend, OSSBackend, SelfHostedBackend."""
|
||||
|
||||
import copy
|
||||
import pytest
|
||||
|
||||
from plugins.memory.mem0._backend import (
|
||||
|
|
@ -191,6 +192,45 @@ class TestOSSBackend:
|
|||
result = backend.delete("m1")
|
||||
assert result == {"result": "Memory deleted.", "memory_id": "m1"}
|
||||
|
||||
def test_legacy_api_base_aliases_are_normalized_before_mem0_init(self, monkeypatch):
|
||||
import sys
|
||||
import types
|
||||
|
||||
captured = {}
|
||||
|
||||
class Memory:
|
||||
@staticmethod
|
||||
def from_config(config):
|
||||
captured.update(config)
|
||||
return FakeOSSMemory()
|
||||
|
||||
# OSSBackend.__init__ does `from mem0 import Memory`. mem0 is a lazy
|
||||
# optional dep absent from CI's env, so inject a stub module rather
|
||||
# than importing the real package (which would ModuleNotFoundError).
|
||||
stub_mem0 = types.ModuleType("mem0")
|
||||
stub_mem0.Memory = Memory # type: ignore[attr-defined]
|
||||
monkeypatch.setitem(sys.modules, "mem0", stub_mem0)
|
||||
raw = {
|
||||
"llm": {
|
||||
"provider": "openai",
|
||||
"config": {"model": "gpt-5-mini", "api_base": "https://llm.example/v1"},
|
||||
},
|
||||
"embedder": {
|
||||
"provider": "ollama",
|
||||
"config": {"model": "nomic-embed-text", "api_base": "http://ollama:11434"},
|
||||
},
|
||||
"vector_store": {"provider": "qdrant", "config": {}},
|
||||
}
|
||||
before = copy.deepcopy(raw)
|
||||
|
||||
OSSBackend(raw)
|
||||
|
||||
assert captured["llm"]["config"]["openai_base_url"] == "https://llm.example/v1"
|
||||
assert captured["embedder"]["config"]["ollama_base_url"] == "http://ollama:11434"
|
||||
assert "api_base" not in captured["llm"]["config"]
|
||||
assert "api_base" not in captured["embedder"]["config"]
|
||||
assert raw == before
|
||||
|
||||
|
||||
httpx = pytest.importorskip("httpx")
|
||||
|
||||
|
|
|
|||
|
|
@ -96,11 +96,28 @@ class TestBuildOSSConfig:
|
|||
assert oss["vector_store"]["provider"] == "qdrant"
|
||||
assert env_writes["OPENAI_API_KEY"] == "sk-oai"
|
||||
|
||||
def test_openai_custom_urls_use_mem0_provider_specific_keys(self):
|
||||
flags = parse_flags([
|
||||
"--mode", "oss",
|
||||
"--oss-llm-key", "sk-oai",
|
||||
"--oss-llm-url", "https://llm.example/v1",
|
||||
"--oss-embedder-url", "https://embed.example/v1",
|
||||
])
|
||||
|
||||
oss, _ = build_oss_config(flags)
|
||||
|
||||
assert oss["llm"]["config"]["openai_base_url"] == "https://llm.example/v1"
|
||||
assert oss["embedder"]["config"]["openai_base_url"] == "https://embed.example/v1"
|
||||
assert "api_base" not in oss["llm"]["config"]
|
||||
assert "api_base" not in oss["embedder"]["config"]
|
||||
|
||||
def test_ollama_no_key_needed(self):
|
||||
flags = parse_flags(["--mode", "oss", "--oss-llm", "ollama", "--oss-embedder", "ollama"])
|
||||
oss, env_writes = build_oss_config(flags)
|
||||
assert oss["llm"]["provider"] == "ollama"
|
||||
assert "model" in oss["llm"]["config"]
|
||||
assert oss["llm"]["config"]["ollama_base_url"] == "http://localhost:11434"
|
||||
assert oss["embedder"]["config"]["ollama_base_url"] == "http://localhost:11434"
|
||||
assert env_writes == {}
|
||||
|
||||
def test_embedder_reuses_llm_key(self):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue