mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-30 19:09:28 +00:00
Systematic prune per AGENTS.md test policy, one pass over every major test tree (gateway, hermes_cli, tools, agent, run_agent, plugins, cli, cron, tui_gateway, honcho/openviking, root-level): - DELETE: source-reading tests (read_text/getsource on prod files), change-detector tests (exact catalog counts, model-name snapshots, config version literals), mock-echo tests (assert a mock returns what it was told), assertion-free/trivial tests, near-duplicate parametrizations (boundaries + one representative kept), async/sync twin duplicates, cosmetic within-file variations. - KEEP (mandatory): security/redaction/approval guards, message-role alternation invariants, prompt-caching/deterministic-call-id invariants, issue-number regression tests (deduped), E2E tests. - 6 test files deleted outright (script-style/no-assert or fully redundant); conftest.py, fakes/, fixtures/ untouched. - tests/acp/conftest.py added: autouse fixture stubs the live models.dev/GitHub/Copilot/Anthropic inventory fetches that ACP server tests performed on every session create — test_server.py 147s → 3.4s, and the tests are now genuinely hermetic. - Sleep-based slowness shrunk where safe (codex_ttfb_watchdog, compression_concurrent_fork, etc.); no wall-clock assertion tightened. Verification: full hermetic suite via scripts/run_tests.sh — 2439 files, 31,130 tests passed, 0 failed, 0 flaky retries, 315s wall (baseline: 583s wall, 13,564s subprocess CPU).
132 lines
5.1 KiB
Python
132 lines
5.1 KiB
Python
"""Tests for empty model fallback — when provider is configured but model is missing."""
|
|
|
|
from unittest.mock import patch
|
|
|
|
|
|
class TestGetDefaultModelForProvider:
|
|
"""Unit tests for hermes_cli.models.get_default_model_for_provider."""
|
|
|
|
def test_known_provider_returns_first_model(self):
|
|
from hermes_cli.models import get_default_model_for_provider
|
|
result = get_default_model_for_provider("openai-codex")
|
|
# Should return first model from _PROVIDER_MODELS["openai-codex"]
|
|
assert result
|
|
assert isinstance(result, str)
|
|
|
|
|
|
|
|
|
|
|
|
def test_catalog_label_overrides_constant(self):
|
|
"""A ``"default": true`` label in the cached catalog manifest wins over
|
|
the in-repo constant, so maintainers can rotate the silent default
|
|
without shipping a release."""
|
|
from unittest.mock import patch
|
|
|
|
from hermes_cli import models as models_mod
|
|
|
|
with patch(
|
|
"hermes_cli.model_catalog.get_default_model_from_cache",
|
|
return_value="qwen/qwen3.7-max",
|
|
):
|
|
assert (
|
|
models_mod.get_preferred_silent_default_model("nous")
|
|
== "qwen/qwen3.7-max"
|
|
)
|
|
# nous catalog carries qwen3.7-max, so the full resolver follows.
|
|
assert (
|
|
models_mod.get_default_model_for_provider("nous")
|
|
== "qwen/qwen3.7-max"
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestGatewayEmptyModelFallback:
|
|
"""Test that _resolve_session_agent_runtime fills in empty model from provider catalog."""
|
|
|
|
def test_empty_model_filled_from_provider(self):
|
|
"""When config has no model but provider is openai-codex, use first codex model."""
|
|
from gateway.run import GatewayRunner
|
|
|
|
runner = object.__new__(GatewayRunner)
|
|
runner._session_model_overrides = {}
|
|
|
|
# Mock _resolve_gateway_model to return empty string
|
|
# Mock _resolve_runtime_agent_kwargs to return openai-codex provider
|
|
with patch("gateway.run._resolve_gateway_model", return_value=""), \
|
|
patch("gateway.run._resolve_runtime_agent_kwargs", return_value={
|
|
"provider": "openai-codex",
|
|
"api_key": "test-key",
|
|
"base_url": "https://chatgpt.com/backend-api/codex",
|
|
"api_mode": "codex_responses",
|
|
}):
|
|
model, kwargs = runner._resolve_session_agent_runtime()
|
|
|
|
# Model should have been filled in from provider catalog
|
|
assert model, "Model should not be empty when provider is known"
|
|
assert isinstance(model, str)
|
|
assert kwargs["provider"] == "openai-codex"
|
|
|
|
def test_nonempty_model_not_overridden(self):
|
|
"""When config has a model set, don't override it."""
|
|
from gateway.run import GatewayRunner
|
|
|
|
runner = object.__new__(GatewayRunner)
|
|
runner._session_model_overrides = {}
|
|
|
|
with patch("gateway.run._resolve_gateway_model", return_value="gpt-5.4"), \
|
|
patch("gateway.run._resolve_runtime_agent_kwargs", return_value={
|
|
"provider": "openai-codex",
|
|
"api_key": "test-key",
|
|
"base_url": "https://chatgpt.com/backend-api/codex",
|
|
"api_mode": "codex_responses",
|
|
}):
|
|
model, kwargs = runner._resolve_session_agent_runtime()
|
|
|
|
assert model == "gpt-5.4", "Explicit model should not be overridden"
|
|
|
|
def test_empty_model_no_provider_stays_empty(self):
|
|
"""When both model and provider are empty, model stays empty."""
|
|
from gateway.run import GatewayRunner
|
|
|
|
runner = object.__new__(GatewayRunner)
|
|
runner._session_model_overrides = {}
|
|
|
|
with patch("gateway.run._resolve_gateway_model", return_value=""), \
|
|
patch("gateway.run._resolve_runtime_agent_kwargs", return_value={
|
|
"provider": "",
|
|
"api_key": "test-key",
|
|
"base_url": "https://example.com",
|
|
"api_mode": "chat_completions",
|
|
}):
|
|
model, kwargs = runner._resolve_session_agent_runtime()
|
|
|
|
# Can't fill in a default without knowing the provider
|
|
assert model == ""
|
|
|
|
|
|
class TestResolveGatewayModel:
|
|
"""Test _resolve_gateway_model reads model from config correctly."""
|
|
|
|
def test_returns_default_key(self):
|
|
from gateway.run import _resolve_gateway_model
|
|
assert _resolve_gateway_model({"model": {"default": "gpt-5.4"}}) == "gpt-5.4"
|
|
|
|
def test_returns_model_key_fallback(self):
|
|
from gateway.run import _resolve_gateway_model
|
|
assert _resolve_gateway_model({"model": {"model": "gpt-5.4"}}) == "gpt-5.4"
|
|
|
|
def test_returns_empty_when_missing(self):
|
|
from gateway.run import _resolve_gateway_model
|
|
assert _resolve_gateway_model({"model": {}}) == ""
|
|
|
|
def test_returns_empty_when_no_model_section(self):
|
|
from gateway.run import _resolve_gateway_model
|
|
assert _resolve_gateway_model({}) == ""
|
|
|
|
def test_string_model_config(self):
|
|
from gateway.run import _resolve_gateway_model
|
|
assert _resolve_gateway_model({"model": "my-model"}) == "my-model"
|