232 lines
9.4 KiB
Python
232 lines
9.4 KiB
Python
"""Anthropic-specific fast mode tests moved from tests/cli/test_fast_command.py."""
|
|
|
|
import unittest
|
|
from types import SimpleNamespace
|
|
|
|
|
|
def _import_cli():
|
|
import hermes_cli.config as config_mod
|
|
|
|
if not hasattr(config_mod, "save_env_value_secure"):
|
|
config_mod.save_env_value_secure = lambda key, value: {
|
|
"success": True,
|
|
"stored_as": key,
|
|
"validated": False,
|
|
}
|
|
|
|
import cli as cli_mod
|
|
|
|
return cli_mod
|
|
|
|
|
|
class TestAnthropicFastMode(unittest.TestCase):
|
|
"""Verify Anthropic Fast Mode model support and override resolution."""
|
|
|
|
def test_anthropic_opus_supported(self):
|
|
from hermes_cli.models import model_supports_fast_mode
|
|
|
|
# Native Anthropic format (hyphens)
|
|
assert model_supports_fast_mode("claude-opus-4-6") is True
|
|
# OpenRouter format (dots)
|
|
assert model_supports_fast_mode("claude-opus-4.6") is True
|
|
# With vendor prefix
|
|
assert model_supports_fast_mode("anthropic/claude-opus-4-6") is True
|
|
assert model_supports_fast_mode("anthropic/claude-opus-4.6") is True
|
|
|
|
def test_anthropic_non_opus46_models_excluded(self):
|
|
"""Anthropic restricts fast mode to Opus 4.6 — others must be excluded.
|
|
|
|
Per https://platform.claude.com/docs/en/build-with-claude/fast-mode,
|
|
sending speed=fast to Opus 4.7, Sonnet, or Haiku returns HTTP 400.
|
|
"""
|
|
from hermes_cli.models import model_supports_fast_mode
|
|
|
|
assert model_supports_fast_mode("claude-sonnet-4-6") is False
|
|
assert model_supports_fast_mode("claude-sonnet-4.6") is False
|
|
assert model_supports_fast_mode("claude-haiku-4-5") is False
|
|
assert model_supports_fast_mode("claude-opus-4-7") is False
|
|
assert model_supports_fast_mode("anthropic/claude-sonnet-4.6") is False
|
|
assert model_supports_fast_mode("anthropic/claude-opus-4-7") is False
|
|
|
|
def test_non_claude_models_not_anthropic_fast(self):
|
|
"""Non-Claude models should not be treated as Anthropic fast-mode."""
|
|
from hermes_cli.models import _is_anthropic_fast_model
|
|
|
|
assert _is_anthropic_fast_model("gpt-5.4") is False
|
|
assert _is_anthropic_fast_model("gemini-3-pro") is False
|
|
assert _is_anthropic_fast_model("kimi-k2-thinking") is False
|
|
|
|
def test_anthropic_variant_tags_stripped(self):
|
|
from hermes_cli.models import model_supports_fast_mode
|
|
|
|
# OpenRouter variant tags after colon should be stripped
|
|
assert model_supports_fast_mode("claude-opus-4.6:fast") is True
|
|
assert model_supports_fast_mode("claude-opus-4.6:beta") is True
|
|
|
|
def test_resolve_overrides_returns_speed_for_anthropic(self):
|
|
from hermes_cli.models import resolve_fast_mode_overrides
|
|
|
|
result = resolve_fast_mode_overrides("claude-opus-4-6")
|
|
assert result == {"speed": "fast"}
|
|
|
|
result = resolve_fast_mode_overrides("anthropic/claude-opus-4.6")
|
|
assert result == {"speed": "fast"}
|
|
|
|
def test_resolve_overrides_returns_none_for_unsupported_claude(self):
|
|
"""Opus 4.7 and other Claude models don't support fast mode (API 400s).
|
|
|
|
Per Anthropic docs, fast mode is currently Opus 4.6 only.
|
|
"""
|
|
from hermes_cli.models import resolve_fast_mode_overrides
|
|
|
|
assert resolve_fast_mode_overrides("claude-opus-4-7") is None
|
|
assert resolve_fast_mode_overrides("claude-sonnet-4-6") is None
|
|
assert resolve_fast_mode_overrides("claude-haiku-4-5") is None
|
|
|
|
def test_resolve_overrides_returns_service_tier_for_openai(self):
|
|
"""OpenAI models should still get service_tier, not speed."""
|
|
from hermes_cli.models import resolve_fast_mode_overrides
|
|
|
|
result = resolve_fast_mode_overrides("gpt-5.4")
|
|
assert result == {"service_tier": "priority"}
|
|
|
|
def test_is_anthropic_fast_model(self):
|
|
"""Fast mode is currently Opus 4.6 only — other Claude variants must be excluded."""
|
|
from hermes_cli.models import _is_anthropic_fast_model
|
|
|
|
# Supported: Opus 4.6 in any form
|
|
assert _is_anthropic_fast_model("claude-opus-4-6") is True
|
|
assert _is_anthropic_fast_model("claude-opus-4.6") is True
|
|
assert _is_anthropic_fast_model("anthropic/claude-opus-4-6") is True
|
|
assert _is_anthropic_fast_model("claude-opus-4.6:fast") is True
|
|
|
|
# Unsupported per Anthropic API contract — would 400 if we sent speed=fast
|
|
assert _is_anthropic_fast_model("claude-opus-4-7") is False
|
|
assert _is_anthropic_fast_model("claude-sonnet-4-6") is False
|
|
assert _is_anthropic_fast_model("claude-haiku-4-5") is False
|
|
|
|
# Non-Claude
|
|
assert _is_anthropic_fast_model("gpt-5.4") is False
|
|
assert _is_anthropic_fast_model("") is False
|
|
|
|
def test_fast_command_exposed_for_anthropic_model(self):
|
|
cli_mod = _import_cli()
|
|
stub = SimpleNamespace(
|
|
provider="anthropic", requested_provider="anthropic",
|
|
model="claude-opus-4-6", agent=None,
|
|
)
|
|
assert cli_mod.HermesCLI._fast_command_available(stub) is True
|
|
|
|
def test_fast_command_hidden_for_anthropic_sonnet(self):
|
|
"""Sonnet doesn't support fast mode (Opus 4.6 only) — /fast must be hidden."""
|
|
cli_mod = _import_cli()
|
|
stub = SimpleNamespace(
|
|
provider="anthropic", requested_provider="anthropic",
|
|
model="claude-sonnet-4-6", agent=None,
|
|
)
|
|
assert cli_mod.HermesCLI._fast_command_available(stub) is False
|
|
|
|
def test_fast_command_hidden_for_anthropic_opus_47(self):
|
|
"""Opus 4.7 doesn't support fast mode — /fast must be hidden."""
|
|
cli_mod = _import_cli()
|
|
stub = SimpleNamespace(
|
|
provider="anthropic", requested_provider="anthropic",
|
|
model="claude-opus-4-7", agent=None,
|
|
)
|
|
assert cli_mod.HermesCLI._fast_command_available(stub) is False
|
|
|
|
def test_fast_command_hidden_for_non_claude_non_openai(self):
|
|
"""Non-Claude, non-OpenAI models should not expose /fast."""
|
|
cli_mod = _import_cli()
|
|
stub = SimpleNamespace(
|
|
provider="gemini", requested_provider="gemini",
|
|
model="gemini-3-pro-preview", agent=None,
|
|
)
|
|
assert cli_mod.HermesCLI._fast_command_available(stub) is False
|
|
|
|
def test_turn_route_injects_speed_for_anthropic(self):
|
|
"""Anthropic models should get speed:'fast' override, not service_tier."""
|
|
cli_mod = _import_cli()
|
|
stub = SimpleNamespace(
|
|
model="claude-opus-4-6",
|
|
api_key="sk-ant-test",
|
|
base_url="https://api.anthropic.com",
|
|
provider="anthropic",
|
|
api_mode="anthropic_messages",
|
|
acp_command=None,
|
|
acp_args=[],
|
|
_credential_pool=None,
|
|
service_tier="priority",
|
|
)
|
|
|
|
route = cli_mod.HermesCLI._resolve_turn_agent_config(stub, "hi")
|
|
|
|
assert route["runtime"]["provider"] == "anthropic"
|
|
assert route["request_overrides"] == {"speed": "fast"}
|
|
|
|
|
|
class TestAnthropicFastModeAdapter(unittest.TestCase):
|
|
"""Verify build_anthropic_kwargs handles fast_mode parameter."""
|
|
|
|
def test_fast_mode_adds_speed_and_beta(self):
|
|
from hermes_agent_anthropic import build_anthropic_kwargs, _FAST_MODE_BETA
|
|
|
|
kwargs = build_anthropic_kwargs(
|
|
model="claude-opus-4-6",
|
|
messages=[{"role": "user", "content": [{"type": "text", "text": "hi"}]}],
|
|
tools=None,
|
|
max_tokens=None,
|
|
reasoning_config=None,
|
|
fast_mode=True,
|
|
)
|
|
assert kwargs.get("extra_body", {}).get("speed") == "fast"
|
|
assert "speed" not in kwargs
|
|
assert "extra_headers" in kwargs
|
|
assert _FAST_MODE_BETA in kwargs["extra_headers"].get("anthropic-beta", "")
|
|
|
|
def test_fast_mode_off_no_speed(self):
|
|
from hermes_agent_anthropic import build_anthropic_kwargs
|
|
|
|
kwargs = build_anthropic_kwargs(
|
|
model="claude-opus-4-6",
|
|
messages=[{"role": "user", "content": [{"type": "text", "text": "hi"}]}],
|
|
tools=None,
|
|
max_tokens=None,
|
|
reasoning_config=None,
|
|
fast_mode=False,
|
|
)
|
|
assert kwargs.get("extra_body", {}).get("speed") is None
|
|
assert "speed" not in kwargs
|
|
assert "extra_headers" not in kwargs
|
|
|
|
def test_fast_mode_skipped_for_third_party_endpoint(self):
|
|
from hermes_agent_anthropic import build_anthropic_kwargs
|
|
|
|
kwargs = build_anthropic_kwargs(
|
|
model="claude-opus-4-6",
|
|
messages=[{"role": "user", "content": [{"type": "text", "text": "hi"}]}],
|
|
tools=None,
|
|
max_tokens=None,
|
|
reasoning_config=None,
|
|
fast_mode=True,
|
|
base_url="https://api.minimax.io/anthropic/v1",
|
|
)
|
|
# Third-party endpoints should NOT get speed or fast-mode beta
|
|
assert kwargs.get("extra_body", {}).get("speed") is None
|
|
assert "speed" not in kwargs
|
|
assert "extra_headers" not in kwargs
|
|
|
|
def test_fast_mode_kwargs_are_safe_for_sdk_unpacking(self):
|
|
from hermes_agent_anthropic import build_anthropic_kwargs
|
|
|
|
kwargs = build_anthropic_kwargs(
|
|
model="claude-opus-4-6",
|
|
messages=[{"role": "user", "content": [{"type": "text", "text": "hi"}]}],
|
|
tools=None,
|
|
max_tokens=None,
|
|
reasoning_config=None,
|
|
fast_mode=True,
|
|
)
|
|
assert "speed" not in kwargs
|
|
assert kwargs.get("extra_body", {}).get("speed") == "fast"
|