diff --git a/src/local_coding_slm/ollama_client.py b/src/local_coding_slm/ollama_client.py index 58b3a54..2a448ed 100644 --- a/src/local_coding_slm/ollama_client.py +++ b/src/local_coding_slm/ollama_client.py @@ -159,6 +159,11 @@ def list_model_names(settings: OllamaSettings | None = None) -> list[str]: return names +def _model_present(tag: str, names: list[str]) -> bool: + """Exact tag, or the same tag with an Ollama suffix such as :latest.""" + return any(name == tag or name.startswith(f"{tag}:") for name in names) + + def status_report(settings: OllamaSettings | None = None) -> str: settings = settings or OllamaSettings.from_env() try: @@ -168,8 +173,8 @@ def status_report(settings: OllamaSettings | None = None) -> str: f"host={settings.host_label()} ok=false error={exc} " f"fast={settings.fast_model} strong={settings.strong_model}" ) - have_fast = any(settings.fast_model in n for n in names) - have_strong = any(settings.strong_model in n for n in names) + have_fast = _model_present(settings.fast_model, names) + have_strong = _model_present(settings.strong_model, names) return ( f"host={settings.host_label()} ok=true " f"fast={settings.fast_model} present={have_fast} " diff --git a/tests/test_ollama_client.py b/tests/test_ollama_client.py index 23e058e..2f6de50 100644 --- a/tests/test_ollama_client.py +++ b/tests/test_ollama_client.py @@ -164,6 +164,22 @@ def test_status_report_marks_present_models(self) -> None: self.assertIn("fast=qwen3.5:9b present=True", report) self.assertIn("strong=devstral-small-2 present=False", report) + def test_status_report_ignores_substring_model_names(self) -> None: + """A name that merely contains the tag is not that model. A :latest suffix is.""" + payload = { + "models": [ + {"name": "not-qwen3.5:9b-extra"}, + {"name": "devstral-small-2:latest"}, + ] + } + with patch( + "local_coding_slm.ollama_client._open", + return_value=_FakeResp(payload), + ): + report = status_report(self.settings) + self.assertIn("fast=qwen3.5:9b present=False", report) + self.assertIn("strong=devstral-small-2 present=True", report) + def test_chat_returns_message_content(self) -> None: payload = {"message": {"content": "def ping(): return True"}} with patch(