fix(mem0): make prompt label + platform setup honor host routing precedence

Follow-up on the salvaged #55614. The PR added host-based routing to
_create_backend (precedence: oss > host > platform) but two sibling surfaces
didn't mirror it:

- system_prompt_block() checked host before oss, so an oss+host config ran
  OSS but told the model it was self-hosted HTTP. Reordered to match routing.
- Platform setup (hermes memory setup mem0 --mode platform) left a stale host
  in mem0.json; since host beats platform, the user kept routing to the
  self-hosted server. save_config merges (no delete), so clear host to ""
  rather than pop() so the merge actually overwrites it.

Adds regression tests for both (mutation-checked).
This commit is contained in:
kshitijk4poor 2026-07-02 14:42:16 +05:30 committed by kshitij
parent 2a14205ff4
commit 53edf6f983
4 changed files with 42 additions and 5 deletions

View file

@ -373,12 +373,16 @@ class Mem0MemoryProvider(MemoryProvider):
return {"channel": self._channel} if self._channel else {}
def system_prompt_block(self) -> str:
if self._host:
mode_label = "self-hosted (HTTP API)"
elif self._mode == "platform":
mode_label = "platform (cloud API)"
else:
# Mirror the precedence in _create_backend (oss > host > platform) so
# the label always names the backend that actually runs. Checking
# ``host`` first here would mislabel an ``oss``+``host`` config as
# self-hosted HTTP even though OSS wins the routing.
if self._mode == "oss":
mode_label = "OSS (self-hosted)"
elif self._host:
mode_label = "self-hosted (HTTP API)"
else:
mode_label = "platform (cloud API)"
# Rerank is a Mem0 Platform feature only.
rerank_note = " Rerank is available on search." if (self._mode == "platform" and not self._host) else ""
return (

View file

@ -293,6 +293,13 @@ def _setup_platform(hermes_home: str, config: dict, flags: dict[str, str]) -> No
return
provider_config["mode"] = "platform"
# Clear any stale self-hosted host: routing checks ``host`` before platform
# (see _create_backend), so leaving it would silently keep routing to the
# self-hosted server even though the user just chose platform mode. Set it
# to "" rather than pop() — save_config merges into the existing mem0.json
# (existing.update), so a popped key would survive; an empty value overwrites
# it and reads as falsy at routing time.
provider_config["host"] = ""
from hermes_cli.config import save_config
config["memory"]["provider"] = "mem0"

View file

@ -179,6 +179,22 @@ class TestPostSetup:
mem0_json = json.loads((tmp_path / "mem0.json").read_text())
assert mem0_json["mode"] == "platform"
def test_platform_setup_clears_stale_host(self, tmp_path, monkeypatch):
# A user who previously ran self-hosted has host in mem0.json. Switching
# to platform must drop host — otherwise routing (host > platform) keeps
# sending them to the self-hosted server despite --mode platform.
(tmp_path / "mem0.json").write_text(
json.dumps({"mode": "platform", "host": "http://old-selfhosted:8888"})
)
monkeypatch.setattr("sys.argv", ["hermes", "--mode", "platform", "--api-key", "sk-test"])
monkeypatch.setattr("plugins.memory.mem0._setup.get_hermes_home", lambda: tmp_path)
_inject_fake_hermes_cli(monkeypatch)
config = {"memory": {}}
post_setup(str(tmp_path), config)
mem0_json = json.loads((tmp_path / "mem0.json").read_text())
assert mem0_json["mode"] == "platform"
assert not mem0_json.get("host") # cleared to falsy so routing → platform
def test_oss_flag_mode(self, tmp_path, monkeypatch):
monkeypatch.setattr("sys.argv", [
"hermes", "--mode", "oss", "--oss-llm-key", "sk-oai",

View file

@ -581,6 +581,16 @@ class TestCreateBackendRouting:
provider = self._provider(monkeypatch, mode="oss", host="http://sh:8888")
assert isinstance(provider._create_backend(), OB)
def test_prompt_label_matches_routing_when_oss_and_host_both_set(self, monkeypatch):
# system_prompt_block must mirror _create_backend precedence: with both
# mode=oss and host set, OSS wins the routing, so the prompt must label
# OSS — not "self-hosted (HTTP API)". Guards the prompt-vs-routing lie.
provider = self._provider(monkeypatch, mode="oss", host="http://sh:8888")
provider._user_id = "test"
block = provider.system_prompt_block()
assert "OSS" in block
assert "HTTP API" not in block
class TestSelfHostedConfig:
"""Config plumbing for self-hosted (MEM0_HOST env + is_available)."""