Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions hermes_cli/model_switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,10 @@ def list_authenticated_providers(
# "nous" shares OpenRouter's curated list if not separately defined
if "nous" not in curated:
curated["nous"] = curated["openrouter"]
# Ollama Cloud uses dynamic discovery (no static curated list)
if "ollama-cloud" not in curated:
from hermes_cli.models import fetch_ollama_cloud_models
curated["ollama-cloud"] = fetch_ollama_cloud_models()

# --- 1. Check Hermes-mapped providers ---
for hermes_id, mdev_id in PROVIDER_TO_MODELS_DEV.items():
Expand Down
4 changes: 4 additions & 0 deletions hermes_cli/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1286,6 +1286,10 @@ def provider_model_ids(provider: Optional[str], *, force_refresh: bool = False)
live = _fetch_ai_gateway_models()
if live:
return live
if normalized == "ollama-cloud":
live = fetch_ollama_cloud_models(force_refresh=force_refresh)
if live:
return live
if normalized == "custom":
base_url = _get_custom_base_url()
if base_url:
Expand Down
59 changes: 59 additions & 0 deletions tests/hermes_cli/test_ollama_cloud_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,65 @@ def test_provider_label(self):
assert "ollama-cloud" in _PROVIDER_LABELS
assert _PROVIDER_LABELS["ollama-cloud"] == "Ollama Cloud"

def test_provider_model_ids_returns_dynamic_models(self, tmp_path, monkeypatch):
"""provider_model_ids('ollama-cloud') should call fetch_ollama_cloud_models()."""
from hermes_cli.models import provider_model_ids

monkeypatch.setenv("HERMES_HOME", str(tmp_path))
monkeypatch.setenv("OLLAMA_API_KEY", "test-key")

mock_mdev = {
"ollama-cloud": {
"models": {
"qwen3.5:397b": {"tool_call": True},
"glm-5": {"tool_call": True},
}
}
}
with patch("hermes_cli.models.fetch_api_models", return_value=["qwen3.5:397b"]), \
patch("agent.models_dev.fetch_models_dev", return_value=mock_mdev):
result = provider_model_ids("ollama-cloud", force_refresh=True)

assert len(result) > 0
assert "qwen3.5:397b" in result


# ── Model Picker (list_authenticated_providers) ──

class TestOllamaCloudModelPicker:
def test_ollama_cloud_shows_model_count(self, tmp_path, monkeypatch):
"""Ollama Cloud should show non-zero model count in provider picker."""
from hermes_cli.model_switch import list_authenticated_providers

monkeypatch.setenv("HERMES_HOME", str(tmp_path))
monkeypatch.setenv("OLLAMA_API_KEY", "test-key")

mock_mdev = {
"ollama-cloud": {
"models": {
"qwen3.5:397b": {"tool_call": True},
"glm-5": {"tool_call": True},
}
}
}
with patch("hermes_cli.models.fetch_api_models", return_value=["qwen3.5:397b"]), \
patch("agent.models_dev.fetch_models_dev", return_value=mock_mdev):
providers = list_authenticated_providers(current_provider="ollama-cloud")

ollama = next((p for p in providers if p["slug"] == "ollama-cloud"), None)
assert ollama is not None, "ollama-cloud should appear when OLLAMA_API_KEY is set"
assert ollama["total_models"] > 0, "ollama-cloud should show non-zero model count"

def test_ollama_cloud_not_shown_without_creds(self, monkeypatch):
"""Ollama Cloud should not appear without credentials."""
from hermes_cli.model_switch import list_authenticated_providers

monkeypatch.delenv("OLLAMA_API_KEY", raising=False)

providers = list_authenticated_providers(current_provider="openrouter")
ollama = next((p for p in providers if p["slug"] == "ollama-cloud"), None)
assert ollama is None, "ollama-cloud should not appear without OLLAMA_API_KEY"


# ── Merged Model Discovery ──

Expand Down
Loading