From 025b598ea1f552eb283f93e1caa67fb73eda0608 Mon Sep 17 00:00:00 2001 From: Askhat Soltanov Date: Sat, 23 May 2026 18:53:51 -0500 Subject: [PATCH] Fix provider_for for full Claude model IDs ModelRegistry.provider_for previously matched only the short Claude aliases (opus / sonnet / haiku). Clients that pass canonical Claude model IDs such as claude-opus-4-7, claude-sonnet-4-6 or claude-haiku-4-5-20251001 fell through to the codex branch, breaking Claude routing. Match the claude- prefix in addition to the short aliases, and add a unit test covering both old aliases and the new full IDs. --- ductor_bot/config.py | 12 +++++-- tests/test_provider_for_claude_full_ids.py | 37 ++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 tests/test_provider_for_claude_full_ids.py diff --git a/ductor_bot/config.py b/ductor_bot/config.py index 4dfd4a1f..56b1a7ff 100644 --- a/ductor_bot/config.py +++ b/ductor_bot/config.py @@ -578,8 +578,16 @@ class ModelRegistry: @staticmethod def provider_for(model_id: str) -> str: - """Return the provider for a model ID.""" - if model_id in CLAUDE_MODELS: + """Return the provider for a model ID. + + Claude Code accepts both short aliases (opus/sonnet/haiku) and full + Claude model IDs such as ``claude-opus-4-7`` / + ``claude-sonnet-4-6`` / ``claude-haiku-4-5-20251001``. The registry + previously matched only the short aliases, so a full Claude model + ID fell through to the codex branch and broke Claude routing for + clients passing the canonical model name. + """ + if model_id in CLAUDE_MODELS or model_id.startswith("claude-"): return "claude" if ( model_id in _GEMINI_ALIASES diff --git a/tests/test_provider_for_claude_full_ids.py b/tests/test_provider_for_claude_full_ids.py new file mode 100644 index 00000000..b8b46ac6 --- /dev/null +++ b/tests/test_provider_for_claude_full_ids.py @@ -0,0 +1,37 @@ +"""Regression tests for ModelRegistry.provider_for full Claude model IDs. + +Claude Code accepts both short aliases (opus/sonnet/haiku) and full Claude +model IDs (claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5-20251001). +The registry historically matched only the short aliases, so a full ID fell +through to the codex branch and broke Claude routing for clients that pass +the canonical model name. +""" + +from __future__ import annotations + +import pytest + +from ductor_bot.config import ModelRegistry + + +@pytest.mark.parametrize( + "model_id", + [ + "claude-opus-4-7", + "claude-sonnet-4-6", + "claude-haiku-4-5-20251001", + ], +) +def test_provider_for_full_claude_model_ids(model_id: str) -> None: + assert ModelRegistry.provider_for(model_id) == "claude" + + +def test_provider_for_short_aliases_still_claude() -> None: + assert ModelRegistry.provider_for("opus") == "claude" + assert ModelRegistry.provider_for("sonnet") == "claude" + assert ModelRegistry.provider_for("haiku") == "claude" + + +def test_provider_for_non_claude_unchanged() -> None: + assert ModelRegistry.provider_for("gpt-5.2-codex") == "codex" + assert ModelRegistry.provider_for("gemini-2.5-pro") == "gemini"