{"repo":"NousResearch/hermes-agent","public_id":"10977","display_label":"Ollama Cloud provider integration and model picker fixes","summary":"These issues and pull requests concern adding Ollama Cloud as a built-in provider and fixing bugs where the model picker showed zero models or displayed local models instead of cloud models.","subsystem":null,"counts":{"members":3,"open_issues":0,"open_issues_distinct":0,"open_prs":0,"closed_issues":1,"merged_prs":1,"attempt_prs":1},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":11066,"merged_at":"2026-04-16T14:17:45+00:00"},"resolution":{"state":"resolved","by":"pr-11066"},"freshness":{"state":"stale","last_verified_at":"2026-04-16T14:17:45+00:00","is_stale":true},"grouping":{"backbone":"STRUCTURAL_SPANNING","link_density":0.6666666666666666},"fix_edges":[{"issue_number":10977,"pr_number":11066,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true,"pr_merged_at":"2026-04-16T14:17:45+00:00"}],"members":[{"kind":"issue","number":10977,"title":"[Bug]: Ollama Cloud shows 0 models in /model TUI picker","url":null,"state":"closed"},{"kind":"pr","number":10964,"title":"fix: Ollama Cloud shows 0 models in /model TUI picker","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"5b4773fc20e844e784d1b710adaa0cfcc5e14d87","number":0},{"kind":"pr","value":"#11066","number":11066},{"kind":"pr","value":"#10977","number":10977}],"category":"implemented_elsewhere","implication":"superseded"},"merged":false},{"kind":"pr","number":11066,"title":"fix: wire Ollama Cloud into /model TUI picker (0 models regression)","url":null,"state":"merged","close_reason":{"category":"merged"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["hermes_cli/model_switch.py","hermes_cli/models.py","tests/hermes_cli/test_ollama_cloud_provider.py"],"fix_hunks":[{"file":"hermes_cli/model_switch.py","hunks":["@@ -807,6 +807,10 @@ def list_authenticated_providers(\n     # \"nous\" shares OpenRouter's curated list if not separately defined\n     if \"nous\" not in curated:\n         curated[\"nous\"] = curated[\"openrouter\"]\n+    # Ollama Cloud uses dynamic discovery (no static curated list)\n+    if \"ollama-cloud\" not in curated:\n+        from hermes_cli.models import fetch_ollama_cloud_models\n+        curated[\"ollama-cloud\"] = fetch_ollama_cloud_models()\n \n     # --- 1. Check Hermes-mapped providers ---\n     for hermes_id, mdev_id in PROVIDER_TO_MODELS_DEV.items():"]},{"file":"hermes_cli/models.py","hunks":["@@ -1286,6 +1286,10 @@ def provider_model_ids(provider: Optional[str], *, force_refresh: bool = False)\n         live = _fetch_ai_gateway_models()\n         if live:\n             return live\n+    if normalized == \"ollama-cloud\":\n+        live = fetch_ollama_cloud_models(force_refresh=force_refresh)\n+        if live:\n+            return live\n     if normalized == \"custom\":\n         base_url = _get_custom_base_url()\n         if base_url:"]},{"file":"tests/hermes_cli/test_ollama_cloud_provider.py","hunks":["@@ -114,6 +114,65 @@ def test_provider_label(self):\n         assert \"ollama-cloud\" in _PROVIDER_LABELS\n         assert _PROVIDER_LABELS[\"ollama-cloud\"] == \"Ollama Cloud\"\n \n+    def test_provider_model_ids_returns_dynamic_models(self, tmp_path, monkeypatch):\n+        \"\"\"provider_model_ids('ollama-cloud') should call fetch_ollama_cloud_models().\"\"\"\n+        from hermes_cli.models import provider_model_ids\n+\n+        monkeypatch.setenv(\"HERMES_HOME\", str(tmp_path))\n+        monkeypatch.setenv(\"OLLAMA_API_KEY\", \"test-key\")\n+\n+        mock_mdev = {\n+            \"ollama-cloud\": {\n+                \"models\": {\n+                    \"qwen3.5:397b\": {\"tool_call\": True},\n+                    \"glm-5\": {\"tool_call\": True},\n+                }\n+            }\n+        }\n+        with patch(\"hermes_cli.models.fetch_api_models\", return_value=[\"qwen3.5:397b\"]), \\\n+             patch(\"agent.models_dev.fetch_models_dev\", return_value=mock_mdev):\n+            result = provider_model_ids(\"ollama-cloud\", force_refresh=True)\n+\n+        assert len(result) > 0\n+        assert \"qwen3.5:397b\" in result\n+\n+\n+# ── Model Picker (list_authenticated_providers) ──\n+\n+class TestOllamaCloudModelPicker:\n+    def test_ollama_cloud_shows_model_count(self, tmp_path, monkeypatch):\n+        \"\"\"Ollama Cloud should show non-zero model count in provider picker.\"\"\"\n+        from hermes_cli.model_switch import list_authenticated_providers\n+\n+        monkeypatch.setenv(\"HERMES_HOME\", str(tmp_path))\n+        monkeypatch.setenv(\"OLLAMA_API_KEY\", \"test-key\")\n+\n+        mock_mdev = {\n+            \"ollama-cloud\": {\n+                \"models\": {\n+                    \"qwen3.5:397b\": {\"tool_call\": True},\n+                    \"glm-5\": {\"tool_call\": True},\n+                }\n+            }\n+        }\n+        with patch(\"hermes_cli.models.fetch_api_models\", return_value=[\"qwen3.5:397b\"]), \\\n+             patch(\"agent.models_dev.fetch_models_dev\", return_value=mock_mdev):\n+            providers = list_authenticated_providers(current_provider=\"ollama-cloud\")\n+\n+        ollama = next((p for p in providers if p[\"slug\"] == \"ollama-cloud\"), None)\n+        assert ollama is not None, \"ollama-cloud should appear when OLLAMA_API_KEY is set\"\n+        assert ollama[\"total_models\"] > 0, \"ollama-cloud should show non-zero model count\"\n+\n+    def test_ollama_cloud_not_shown_without_creds(self, monkeypatch):\n+        \"\"\"Ollama Cloud should not appear without credentials.\"\"\"\n+        from hermes_cli.model_switch import list_authenticated_providers\n+\n+        monkeypatch.delenv(\"OLLAMA_API_KEY\", raising=False)\n+\n+        providers = list_authenticated_providers(current_provider=\"openrouter\")\n+        ollama = next((p for p in providers if p[\"slug\"] == \"ollama-cloud\"), None)\n+        assert ollama is None, \"ollama-cloud should not appear without OLLAMA_API_KEY\"\n+\n \n # ── Merged Model Discovery ──\n \n"]}]}],"trust":{"default_tier":"verified","includes_suggested":false}}