diff --git a/plugins/memory/mem0/__init__.py b/plugins/memory/mem0/__init__.py index 7763b385977..751efd0effb 100644 --- a/plugins/memory/mem0/__init__.py +++ b/plugins/memory/mem0/__init__.py @@ -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 ( diff --git a/plugins/memory/mem0/_setup.py b/plugins/memory/mem0/_setup.py index 52e5e42ff7e..021705aea9d 100644 --- a/plugins/memory/mem0/_setup.py +++ b/plugins/memory/mem0/_setup.py @@ -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" diff --git a/tests/plugins/memory/test_mem0_setup.py b/tests/plugins/memory/test_mem0_setup.py index e67293e8a23..b365970c56e 100644 --- a/tests/plugins/memory/test_mem0_setup.py +++ b/tests/plugins/memory/test_mem0_setup.py @@ -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", diff --git a/tests/plugins/memory/test_mem0_v3.py b/tests/plugins/memory/test_mem0_v3.py index f959f955012..fffb2f7eb3f 100644 --- a/tests/plugins/memory/test_mem0_v3.py +++ b/tests/plugins/memory/test_mem0_v3.py @@ -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)."""