From 813ce5c9f7db2910eb12d8c84d3d99f464c430ed Mon Sep 17 00:00:00 2001 From: Robert Hyman <13157542+brt-h@users.noreply.github.com> Date: Sat, 29 Nov 2025 18:00:31 -0500 Subject: [PATCH 1/2] feat: Add Claude Opus 4.5 model via OpenRouter - Add anthropic/claude-opus-4.5 with aliases: opus, opus4.5, claude-opus - Set intelligence_score to 18 (matching Gemini 3 Pro) - Update Opus 4.1 to use opus4.1 alias only - Update tests to reflect new alias mappings Note: supports_function_calling and supports_json_mode set to false following existing project pattern for Claude models, despite OpenRouter API support for these features. --- conf/openrouter_models.json | 22 +++++++++++++++++++--- tests/test_openrouter_provider.py | 17 ++++++++++++----- tests/test_openrouter_registry.py | 11 +++++++---- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/conf/openrouter_models.json b/conf/openrouter_models.json index 1c733f6..06864ae 100644 --- a/conf/openrouter_models.json +++ b/conf/openrouter_models.json @@ -24,6 +24,23 @@ } }, "models": [ + { + "model_name": "anthropic/claude-opus-4.5", + "aliases": [ + "opus", + "opus4.5", + "claude-opus" + ], + "context_window": 200000, + "max_output_tokens": 64000, + "supports_extended_thinking": false, + "supports_json_mode": false, + "supports_function_calling": false, + "supports_images": true, + "max_image_size_mb": 5.0, + "description": "Claude Opus 4.5 - Anthropic's frontier reasoning model for complex software engineering and agentic workflows", + "intelligence_score": 18 + }, { "model_name": "anthropic/claude-sonnet-4.5", "aliases": [ @@ -43,8 +60,7 @@ { "model_name": "anthropic/claude-opus-4.1", "aliases": [ - "opus", - "claude-opus" + "opus4.1" ], "context_window": 200000, "max_output_tokens": 64000, @@ -53,7 +69,7 @@ "supports_function_calling": false, "supports_images": true, "max_image_size_mb": 5.0, - "description": "Claude Opus 4.1 - Our most capable and intelligent model yet", + "description": "Claude Opus 4.1 - Last generation flagship model with strong coding and reasoning", "intelligence_score": 14 }, { diff --git a/tests/test_openrouter_provider.py b/tests/test_openrouter_provider.py index 231d13e..bc67d75 100644 --- a/tests/test_openrouter_provider.py +++ b/tests/test_openrouter_provider.py @@ -79,7 +79,9 @@ class TestOpenRouterProvider: provider = OpenRouterProvider(api_key="test-key") # Test alias resolution - assert provider._resolve_model_name("opus") == "anthropic/claude-opus-4.1" + assert provider._resolve_model_name("opus") == "anthropic/claude-opus-4.5" + assert provider._resolve_model_name("opus4.5") == "anthropic/claude-opus-4.5" + assert provider._resolve_model_name("opus4.1") == "anthropic/claude-opus-4.1" assert provider._resolve_model_name("sonnet") == "anthropic/claude-sonnet-4.5" assert provider._resolve_model_name("sonnet4.1") == "anthropic/claude-sonnet-4.1" assert provider._resolve_model_name("o3") == "openai/o3" @@ -96,7 +98,7 @@ class TestOpenRouterProvider: assert provider._resolve_model_name("r1") == "deepseek/deepseek-r1-0528" # Test case-insensitive - assert provider._resolve_model_name("OPUS") == "anthropic/claude-opus-4.1" + assert provider._resolve_model_name("OPUS") == "anthropic/claude-opus-4.5" assert provider._resolve_model_name("SONNET") == "anthropic/claude-sonnet-4.5" assert provider._resolve_model_name("O3") == "openai/o3" assert provider._resolve_model_name("Mistral") == "mistralai/mistral-large-2411" @@ -305,17 +307,22 @@ class TestOpenRouterRegistry: registry = OpenRouterModelRegistry() - # Test known model + # Test known model (opus alias now points to 4.5) caps = registry.get_capabilities("opus") assert caps is not None - assert caps.model_name == "anthropic/claude-opus-4.1" + assert caps.model_name == "anthropic/claude-opus-4.5" assert caps.context_window == 200000 # Claude's context window - # Test using full model name + # Test using full model name for 4.1 caps = registry.get_capabilities("anthropic/claude-opus-4.1") assert caps is not None assert caps.model_name == "anthropic/claude-opus-4.1" + # Test opus4.1 alias still works + caps = registry.get_capabilities("opus4.1") + assert caps is not None + assert caps.model_name == "anthropic/claude-opus-4.1" + # Test unknown model caps = registry.get_capabilities("non-existent-model") assert caps is None diff --git a/tests/test_openrouter_registry.py b/tests/test_openrouter_registry.py index e1738e5..936d60f 100644 --- a/tests/test_openrouter_registry.py +++ b/tests/test_openrouter_registry.py @@ -88,8 +88,10 @@ class TestOpenRouterModelRegistry: # Test various aliases test_cases = [ - ("opus", "anthropic/claude-opus-4.1"), - ("OPUS", "anthropic/claude-opus-4.1"), # Case insensitive + ("opus", "anthropic/claude-opus-4.5"), # opus now points to 4.5 + ("OPUS", "anthropic/claude-opus-4.5"), # Case insensitive + ("opus4.5", "anthropic/claude-opus-4.5"), + ("opus4.1", "anthropic/claude-opus-4.1"), # 4.1 still accessible ("sonnet", "anthropic/claude-sonnet-4.5"), ("o3", "openai/o3"), ("deepseek", "deepseek/deepseek-r1-0528"), @@ -131,9 +133,10 @@ class TestOpenRouterModelRegistry: assert config is not None # Registry now returns ModelCapabilities objects directly + # opus alias now points to 4.5 assert config.provider == ProviderType.OPENROUTER - assert config.model_name == "anthropic/claude-opus-4.1" - assert config.friendly_name == "OpenRouter (anthropic/claude-opus-4.1)" + assert config.model_name == "anthropic/claude-opus-4.5" + assert config.friendly_name == "OpenRouter (anthropic/claude-opus-4.5)" assert config.context_window == 200000 assert not config.supports_extended_thinking From cf63fd25440d599f2ec006bb8cfda5b8a6f61524 Mon Sep 17 00:00:00 2001 From: Robert Hyman <13157542+brt-h@users.noreply.github.com> Date: Sat, 29 Nov 2025 18:23:44 -0500 Subject: [PATCH 2/2] test: Add comprehensive test coverage for Opus 4.5 aliases Address review feedback: - Add test for claude-opus alias in test_alias_resolution - Add tests for anthropic/claude-opus-4.5 full name and opus4.5 alias in test_registry_capabilities --- tests/test_openrouter_provider.py | 10 ++++++++++ tests/test_openrouter_registry.py | 1 + 2 files changed, 11 insertions(+) diff --git a/tests/test_openrouter_provider.py b/tests/test_openrouter_provider.py index bc67d75..b7cff4c 100644 --- a/tests/test_openrouter_provider.py +++ b/tests/test_openrouter_provider.py @@ -313,6 +313,16 @@ class TestOpenRouterRegistry: assert caps.model_name == "anthropic/claude-opus-4.5" assert caps.context_window == 200000 # Claude's context window + # Test using full model name for 4.5 + caps = registry.get_capabilities("anthropic/claude-opus-4.5") + assert caps is not None + assert caps.model_name == "anthropic/claude-opus-4.5" + + # Test opus4.5 alias + caps = registry.get_capabilities("opus4.5") + assert caps is not None + assert caps.model_name == "anthropic/claude-opus-4.5" + # Test using full model name for 4.1 caps = registry.get_capabilities("anthropic/claude-opus-4.1") assert caps is not None diff --git a/tests/test_openrouter_registry.py b/tests/test_openrouter_registry.py index 936d60f..1194106 100644 --- a/tests/test_openrouter_registry.py +++ b/tests/test_openrouter_registry.py @@ -90,6 +90,7 @@ class TestOpenRouterModelRegistry: test_cases = [ ("opus", "anthropic/claude-opus-4.5"), # opus now points to 4.5 ("OPUS", "anthropic/claude-opus-4.5"), # Case insensitive + ("claude-opus", "anthropic/claude-opus-4.5"), ("opus4.5", "anthropic/claude-opus-4.5"), ("opus4.1", "anthropic/claude-opus-4.1"), # 4.1 still accessible ("sonnet", "anthropic/claude-sonnet-4.5"),