diff --git a/src/llm_core.py b/src/llm_core.py index 4dec32376..2a389f266 100644 --- a/src/llm_core.py +++ b/src/llm_core.py @@ -1231,10 +1231,18 @@ def _omit_temperature(provider: str, model: str) -> bool: # even 0.0 — returns HTTP 400. Earlier Claude models (Opus 4.6 and below, every # Sonnet/Haiku) still accept temperature in [0.0, 1.0], so the omission must be # version-gated rather than applied to all `claude-*` models. +# +# The bare "Claude 5" generation (claude-opus-5, claude-sonnet-5, claude-fable-5 +# — no minor version number) dropped the same sampling params across every +# model line, not just Opus. Confirmed via live probe 2026-07-30: Anthropic +# returns HTTP 400 "`temperature` is deprecated for this model." for all three +# when `temperature` is sent at all, so they need a second, family-wide check +# since they don't carry a major.minor pair for the Opus-only version gate below. def _anthropic_rejects_temperature(model: str) -> bool: - """Check if a native-Anthropic model rejects the temperature field (Opus 4.7+).""" + """Check if a native-Anthropic model rejects the temperature field (Opus 4.7+, or the bare Claude 5 generation).""" if not isinstance(model, str) or not model: return False + model_lower = model.lower() # `(? bool: # minor match, kept) instead of reading the date `20250514` as a giant minor # that would falsely test >= 4.7. Dated 4.7+ snapshots (`claude-opus-4-7- # 20260201`) keep their explicit minor and are still matched. - match = re.search(r"(?= (4, 7) + match = re.search(r"(?= (4, 7): + return True + # Bare "-5" check: matches claude-opus-5, claude-sonnet-5, claude-fable-5, + # and dated snapshots thereof (e.g. claude-sonnet-5-20260615), but not + # dotted-version ids like claude-opus-4-5 (Opus 4.5, pre-4.7, still accepts + # temperature) since "5" there isn't directly adjacent to the family name. + return bool(re.search(r"(?