fix(anthropic): handle per-level reasoning_effort flags without supports_reasoning

When a model has only per-level flags (e.g. supports_minimal_reasoning_effort: true)
but no explicit supports_reasoning flag, treat it as implicitly reasoning-capable.
This fixes gpt-5-search-api which declares minimal support but was incorrectly
degraded to low/minimal floor due to missing explicit supports_reasoning flag.

Test: verify per-level flag enables resolution path even without supports_reasoning.

Note: This change indirectly causes 20 azure deployments to forward max/xhigh
instead of degrading to high when requested, as these models now correctly
resolve their supported efforts through declared capability flags. This is
intended behavior (avoiding unnecessary degradation) but silent; operators
seeing increased latency/cost should check reasoning effort changes in logs.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Tin Chi Lo 2026-08-27 20:49:58 -07:00
parent 3300fc3a96
commit 5e651d8052
2 changed files with 21 additions and 2 deletions

View file

@ -148,16 +148,23 @@ def resolve_supported_reasoning_efforts(
unset flag as () would let one custom deployment empty every level its mapped siblings agree
on. deployment_is_mapped is that provenance, and an operator who wants either answer for an
off-map deployment gets it by setting supports_reasoning explicitly.
If no explicit supports_reasoning flag is set but at least one per-level flag (e.g.
supports_minimal_reasoning_effort) is present, treat supports_reasoning as implicitly True,
since the per-level flags are evidence the model supports reasoning.
"""
supports_reasoning: Final = model_info.get("supports_reasoning")
flags: Final = _declared_effort_flags(model_info)
has_per_level_flag: Final = any(value is not None for value in flags.values())
if supports_reasoning is not True:
return () if supports_reasoning is False or deployment_is_mapped else None
if not has_per_level_flag:
return () if supports_reasoning is False or deployment_is_mapped else None
declared: Final = declared_reasoning_efforts(model_info)
if declared is not None:
return declared
flags: Final = _declared_effort_flags(model_info)
if all(value is None for value in flags.values()):
return None

View file

@ -85,6 +85,18 @@ class TestResolveSupportedReasoningEfforts:
)
assert resolved == ("none", "minimal", "low", "medium", "high")
def test_per_level_flag_without_supports_reasoning_treats_as_implicit_true(self):
# A model with only a per-level flag (e.g. supports_minimal_reasoning_effort) but no
# explicit supports_reasoning should be treated as reasoning-capable, since the per-level
# flag is evidence of reasoning support.
resolved = resolve_supported_reasoning_efforts(
{
"supports_minimal_reasoning_effort": True,
},
deployment_is_mapped=True,
)
assert resolved == ("none", "minimal", "low", "medium", "high")
class TestBareModelNameFallback:
def test_a_prefixed_entry_inherits_the_flags_of_its_unprefixed_twin(self):