diff --git a/agent/anthropic_adapter.py b/agent/anthropic_adapter.py index e4d1d5ac125e..89c232e9f90a 100644 --- a/agent/anthropic_adapter.py +++ b/agent/anthropic_adapter.py @@ -126,6 +126,8 @@ def _is_claude_model(model: str | None) -> bool: _ANTHROPIC_OUTPUT_LIMITS = { # Mythos-class named models (claude-fable-5, …) — 1M context, reasoning "claude-fable": 128_000, + # Claude Sonnet 5 + "claude-sonnet-5": 128_000, # Claude 4.8 "claude-opus-4-8": 128_000, # Claude 4.7 diff --git a/agent/bedrock_adapter.py b/agent/bedrock_adapter.py index d5dab7bafff2..606b2925ce9e 100644 --- a/agent/bedrock_adapter.py +++ b/agent/bedrock_adapter.py @@ -1297,6 +1297,7 @@ def classify_bedrock_error(error_message: str) -> str: BEDROCK_CONTEXT_LENGTHS: Dict[str, int] = { # Anthropic Claude models on Bedrock + "anthropic.claude-sonnet-5": 1_000_000, "anthropic.claude-opus-4-6": 200_000, "anthropic.claude-sonnet-4-6": 200_000, "anthropic.claude-sonnet-4-5": 200_000, diff --git a/agent/model_metadata.py b/agent/model_metadata.py index 734febd3bf43..d2b36323bb0a 100644 --- a/agent/model_metadata.py +++ b/agent/model_metadata.py @@ -195,6 +195,7 @@ def _save_model_metadata_disk_cache(data: Dict[str, Dict[str, Any]]) -> None: # OpenRouter-prefixed models resolve via OpenRouter live API or models.dev. "claude-fable-5": 1000000, "claude-fable": 1000000, + "claude-sonnet-5": 1000000, "claude-opus-4-8": 1000000, "claude-opus-4.8": 1000000, "claude-opus-4-7": 1000000, diff --git a/agent/reasoning_timeouts.py b/agent/reasoning_timeouts.py index 9e0b5cab9b91..48b1bb7883de 100644 --- a/agent/reasoning_timeouts.py +++ b/agent/reasoning_timeouts.py @@ -98,6 +98,7 @@ # ``claude-opus-4`` so non-thinking Claude 3.x or future # non-reasoning Claude variants don't match. ("claude-opus-4", 240), + ("claude-sonnet-5", 180), ("claude-sonnet-4.5", 180), ("claude-sonnet-4.6", 180), # xAI Grok reasoning variants. Explicit reasoning-only keys diff --git a/agent/usage_pricing.py b/agent/usage_pricing.py index 7c4416e5fb25..b6b6b7bb0f52 100644 --- a/agent/usage_pricing.py +++ b/agent/usage_pricing.py @@ -165,6 +165,18 @@ class CostResult: source_url="https://platform.claude.com/docs/en/about-claude/pricing", pricing_version="anthropic-pricing-2026-05", ), + ( + "anthropic", + "claude-sonnet-5", + ): PricingEntry( + input_cost_per_million=Decimal("3.00"), + output_cost_per_million=Decimal("15.00"), + cache_read_cost_per_million=Decimal("0.30"), + cache_write_cost_per_million=Decimal("3.75"), + source="official_docs_snapshot", + source_url="https://platform.claude.com/docs/en/about-claude/pricing", + pricing_version="anthropic-pricing-2026-06", + ), ( "anthropic", "claude-sonnet-4-6", @@ -457,6 +469,18 @@ class CostResult: source_url="https://aws.amazon.com/bedrock/pricing/", pricing_version="bedrock-pricing-2026-04", ), + ( + "bedrock", + "anthropic.claude-sonnet-5", + ): PricingEntry( + input_cost_per_million=Decimal("3.00"), + output_cost_per_million=Decimal("15.00"), + cache_read_cost_per_million=Decimal("0.30"), + cache_write_cost_per_million=Decimal("3.75"), + source="official_docs_snapshot", + source_url="https://aws.amazon.com/bedrock/pricing/", + pricing_version="bedrock-pricing-2026-06", + ), ( "bedrock", "anthropic.claude-sonnet-4-6", diff --git a/hermes_cli/models.py b/hermes_cli/models.py index cf3eb40edaaf..da5dd2ae7d9b 100644 --- a/hermes_cli/models.py +++ b/hermes_cli/models.py @@ -36,6 +36,7 @@ # Anthropic ("anthropic/claude-opus-4.8", ""), ("anthropic/claude-opus-4.8-fast", "2x price, higher output speed"), + ("anthropic/claude-sonnet-5", ""), ("anthropic/claude-sonnet-4.6", ""), ("anthropic/claude-haiku-4.5", ""), # OpenAI @@ -177,6 +178,7 @@ def _xai_curated_models() -> list[str]: "nous": [ # Anthropic "anthropic/claude-opus-4.8", + "anthropic/claude-sonnet-5", "anthropic/claude-sonnet-4.6", "anthropic/claude-haiku-4.5", # OpenAI @@ -340,6 +342,7 @@ def _xai_curated_models() -> list[str]: ], "anthropic": [ "claude-fable-5", + "claude-sonnet-5", "claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-6", @@ -376,6 +379,7 @@ def _xai_curated_models() -> list[str]: "deepseek-ai/DeepSeek-V3.2", "moonshotai/Kimi-K2.5", "google/gemini-3.1-flash-lite-preview", + "anthropic/claude-sonnet-5", "anthropic/claude-sonnet-4.6", "openai/gpt-5.4", ], @@ -400,6 +404,7 @@ def _xai_curated_models() -> list[str]: "gpt-5-codex", "gpt-5-nano", "claude-fable-5", + "claude-sonnet-5", "claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-6", @@ -498,6 +503,7 @@ def _xai_curated_models() -> list[str]: # prefers live discovery via ListFoundationModels + ListInferenceProfiles. # Use inference profile IDs (us.*) since most models require them. "bedrock": [ + "us.anthropic.claude-sonnet-5", "us.anthropic.claude-sonnet-4-6", "us.anthropic.claude-opus-4-6-v1", "us.anthropic.claude-haiku-4-5-20251001-v1:0", @@ -3153,6 +3159,7 @@ def _fetch_github_models(api_key: Optional[str] = None, timeout: float = 5.0) -> "openai/o3-mini": "gpt-5-mini", "openai/o4-mini": "gpt-5-mini", "anthropic/claude-opus-4.6": "claude-opus-4.6", + "anthropic/claude-sonnet-5": "claude-sonnet-5", "anthropic/claude-sonnet-4.6": "claude-sonnet-4.6", "anthropic/claude-sonnet-4": "claude-sonnet-4", "anthropic/claude-sonnet-4.5": "claude-sonnet-4.5", @@ -3162,12 +3169,14 @@ def _fetch_github_models(api_key: Optional[str] = None, timeout: float = 5.0) -> # dot-notation. Accept both so users who configure copilot + a # default hyphenated Claude model don't hit HTTP 400 # "model_not_supported". See issue #6879. + "claude-sonnet-5": "claude-sonnet-5", "claude-opus-4-6": "claude-opus-4.6", "claude-sonnet-4-6": "claude-sonnet-4.6", "claude-sonnet-4-0": "claude-sonnet-4", "claude-sonnet-4-5": "claude-sonnet-4.5", "claude-haiku-4-5": "claude-haiku-4.5", "anthropic/claude-opus-4-6": "claude-opus-4.6", + "anthropic/claude-sonnet-5": "claude-sonnet-5", "anthropic/claude-sonnet-4-6": "claude-sonnet-4.6", "anthropic/claude-sonnet-4-0": "claude-sonnet-4", "anthropic/claude-sonnet-4-5": "claude-sonnet-4.5", diff --git a/hermes_cli/setup.py b/hermes_cli/setup.py index a178c0b5ca9e..aade677027be 100644 --- a/hermes_cli/setup.py +++ b/hermes_cli/setup.py @@ -84,6 +84,7 @@ def _supports_same_provider_pool_setup(provider: str) -> bool: "gpt-4o", "gpt-4o-mini", "claude-opus-4.6", + "claude-sonnet-5", "claude-sonnet-4.6", "claude-sonnet-4.5", "claude-haiku-4.5", @@ -100,8 +101,8 @@ def _supports_same_provider_pool_setup(provider: str) -> bool: "arcee": ["trinity-large-thinking", "trinity-large-preview", "trinity-mini"], "minimax": ["MiniMax-M2.7", "MiniMax-M2.5", "MiniMax-M2.1", "MiniMax-M2"], "minimax-cn": ["MiniMax-M2.7", "MiniMax-M2.5", "MiniMax-M2.1", "MiniMax-M2"], - "kilocode": ["anthropic/claude-opus-4.6", "anthropic/claude-sonnet-4.6", "openai/gpt-5.4", "google/gemini-3-pro-preview", "google/gemini-3-flash-preview"], - "opencode-zen": ["gpt-5.4", "gpt-5.3-codex", "claude-sonnet-4-6", "gemini-3-flash", "glm-5", "kimi-k2.5", "minimax-m2.7"], + "kilocode": ["anthropic/claude-sonnet-5", "anthropic/claude-opus-4.6", "anthropic/claude-sonnet-4.6", "openai/gpt-5.4", "google/gemini-3-pro-preview", "google/gemini-3-flash-preview"], + "opencode-zen": ["gpt-5.4", "gpt-5.3-codex", "claude-sonnet-5", "claude-sonnet-4-6", "gemini-3-flash", "glm-5", "kimi-k2.5", "minimax-m2.7"], "opencode-go": ["kimi-k2.6", "kimi-k2.5", "glm-5.1", "glm-5", "mimo-v2.5-pro", "mimo-v2.5", "mimo-v2-pro", "mimo-v2-omni", "minimax-m2.7", "minimax-m2.5", "qwen3.7-max", "qwen3.6-plus", "qwen3.5-plus"], "huggingface": [ "Qwen/Qwen3.5-397B-A17B", "Qwen/Qwen3-235B-A22B-Thinking-2507", diff --git a/tests/agent/test_minimax_provider.py b/tests/agent/test_minimax_provider.py index 2dd1510786e7..1152514c1e52 100644 --- a/tests/agent/test_minimax_provider.py +++ b/tests/agent/test_minimax_provider.py @@ -330,6 +330,7 @@ def test_claude_output_unaffected(self): from agent.anthropic_adapter import _get_anthropic_max_output # Sanity: Claude limits are not broken by the MiniMax entry assert _get_anthropic_max_output("claude-sonnet-4-6") == 64_000 + assert _get_anthropic_max_output("claude-sonnet-5") == 128_000 class TestMinimaxPreserveDots: diff --git a/tests/hermes_cli/test_anthropic_picker_curated.py b/tests/hermes_cli/test_anthropic_picker_curated.py index 407bb362b1f2..6465a87396a0 100644 --- a/tests/hermes_cli/test_anthropic_picker_curated.py +++ b/tests/hermes_cli/test_anthropic_picker_curated.py @@ -20,6 +20,7 @@ def test_anthropic_curated_alias_survives_when_live_omits_it(): """A curated alias missing from /v1/models still surfaces (first).""" curated = M._PROVIDER_MODELS["anthropic"] assert "claude-fable-5" in curated # sanity: the alias is curated + assert "claude-sonnet-5" in curated # newest Sonnet alias is curated # Live catalog the API would actually return — no fable-5. live = ["claude-opus-4-8", "claude-sonnet-4-6", "claude-haiku-4-5-20251001"] @@ -27,6 +28,7 @@ def test_anthropic_curated_alias_survives_when_live_omits_it(): result = M.provider_model_ids("anthropic") assert "claude-fable-5" in result + assert "claude-sonnet-5" in result # Curated order is preserved at the front. assert result[:len(curated)] == list(curated)