Files
nousresearch--hermes-agent/tests/run_agent/test_nous_fallback_unavailable.py
T
wehub-resource-sync b4fbd6fe9f
Deploy Site / deploy-vercel (push) Has been skipped
Deploy Site / deploy-docs (push) Has been skipped
Build Skills Index / build-index (push) Has been skipped
CI / Deny unrelated histories (push) Has been skipped
CI / Detect affected areas (push) Successful in 27m35s
CI / OSV scan (push) Failing after 4s
CI / Build&Test Docker image (push) Successful in 9s
CI / Supply-chain scan (push) Has been skipped
CI / Lint Docker scripts (push) Failing after 5m13s
CI / Check contributors (push) Failing after 12m8s
CI / Docs Site (push) Failing after 12m8s
CI / TypeScript (push) Failing after 12m8s
CI / Python lints (push) Failing after 12m9s
CI / Python tests (push) Failing after 12m9s
CI / Check uv.lock (push) Failing after 23m22s
CI / CI timing report (push) Has been cancelled
Build Skills Index / trigger-deploy (push) Has been cancelled
CI / All required checks pass (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 11:56:03 +08:00

102 lines
3.5 KiB
Python

"""Tests for Nous fallback local-availability suppression.
Blocker if Nous token material is missing locally: the fallback chain
should not repeatedly attempt Nous resolution; it must skip and continue
to the next provider.
"""
from __future__ import annotations
from unittest.mock import patch
from run_agent import AIAgent
def _make_agent(fallback_model=None):
with (
patch("run_agent.get_tool_definitions", return_value=[]),
patch("run_agent.check_toolset_requirements", return_value={}),
patch("run_agent.OpenAI"),
):
agent = AIAgent(
api_key="test-key",
provider="openai-codex",
base_url="https://chatgpt.com/backend-api/codex",
quiet_mode=True,
skip_context_files=True,
skip_memory=True,
fallback_model=fallback_model,
)
agent.client = None
return agent
def _mock_client(base_url="https://chatgpt.com/backend-api/codex", api_key="fb-key"):
mock = type("Client", (), {})()
mock.base_url = base_url
mock.api_key = api_key
mock.chat = type("Chat", (), {})()
mock.chat.completions = type("Completions", (), {})()
mock.chat.completions.create = lambda *args, **kwargs: None
return mock
class TestNousFallbackLocalAvailability:
def test_missing_nous_token_is_skipped_once(self):
"""Nous fallback is skipped when no access/refresh token is stored."""
agent = _make_agent(
fallback_model=[
{"provider": "nous", "model": "anthropic/claude-sonnet-4.6"},
{"provider": "openai-codex", "model": "gpt-5.5"},
]
)
with patch(
"hermes_cli.auth.get_provider_auth_state",
return_value={},
), patch(
"agent.auxiliary_client.resolve_provider_client",
return_value=(_mock_client(api_key="fb"), "gpt-5.5"),
):
activated = agent._try_activate_fallback(None)
assert activated is True
assert agent.model == "gpt-5.5"
def test_nous_unavailable_not_retried_in_same_session(self):
"""After Nous is skipped once, subsequent activations continue further."""
agent = _make_agent(
fallback_model=[
{"provider": "nous", "model": "anthropic/claude-sonnet-4.6"},
{"provider": "openai-codex", "model": "gpt-5.5"},
]
)
with patch(
"hermes_cli.auth.get_provider_auth_state",
return_value={},
):
agent._try_activate_fallback(None)
key = (
"nous",
"anthropic/claude-sonnet-4.6",
"",
)
assert key in getattr(agent, "_unavailable_fallback_keys", set())
def test_present_nous_token_allows_activation(self):
"""Nous is considered when token material exists."""
agent = _make_agent(
fallback_model=[
{"provider": "nous", "model": "anthropic/claude-sonnet-4.6"},
{"provider": "openai-codex", "model": "gpt-5.5"},
]
)
with patch(
"hermes_cli.auth.get_provider_auth_state",
return_value={"access_token": "abc", "refresh_token": "xyz"},
), patch(
"agent.auxiliary_client.resolve_provider_client",
return_value=(_mock_client(api_key="fb"), "anthropic/claude-sonnet-4.6"),
):
activated = agent._try_activate_fallback(None)
assert activated is True
assert agent.provider == "nous"