Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 31 additions & 12 deletions unstract/sdk1/src/unstract/sdk1/adapters/base1.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,17 @@
# AI Foundry / Vertex proxies). Opus 4.6 / Sonnet 4.6 and older still accept
# them, so detection is a narrow allowlist rather than a broad `claude-*` match.
#
# Each stem is compiled into a pattern that is regex-searched against the model
# id after lowercasing and normalizing `.` / `_` to `-`. The match is anchored
# at the trailing edge so unrelated future ids (`claude-sonnet-50`,
# `claude-opus-4-70`, `claude-sonnet-5verbose`) do not match. One stem covers
# every encoding of the id we have observed, e.g. for `claude-sonnet-5`:
# Detection is a mix of literal stems and Opus family ranges. The Opus ranges
# cover every Opus release from 4.7 onwards — 4.7, 4.8, 4.9 and every Opus 5+
# release — so a new Opus id does not need a code change; the other families
# (Sonnet 5, Fable 5, Mythos 5) are listed as literal stems.
#
# Each entry is compiled into a pattern that is regex-searched against the
# model id after lowercasing and normalizing `.` / `_` to `-`. The match is
# anchored at the trailing edge so unrelated future ids (`claude-sonnet-50`,
# `claude-opus-4-70`, `claude-opus-50`, `claude-sonnet-5verbose`) do not
# match. One entry covers every encoding of the id we have observed, e.g. for
# `claude-sonnet-5`:
# - Native Anthropic `claude-sonnet-5`, `anthropic/claude-sonnet-5`
# - Bedrock foundation model `anthropic.claude-sonnet-5-<date>-v1:0`
# - Bedrock cross-region profile `us.anthropic.claude-sonnet-5-...`,
Expand All @@ -42,23 +48,34 @@
# Leading text (route prefixes like `converse/`, `invoke/`, `bedrock/`) passes
# through because the regex is anchored only at the trailing edge.
# Keep this list current — add a stem here when Anthropic deprecates sampling on
# a new model.
# a new (non-Opus) model.
# Trailing anchor allows: end-of-string, or one of `-`/`:`/`@`/`/` (the
# delimiters used in date suffixes, ARN paths, Vertex `@<date>`, and the
# `v1:0` tag), or `v` followed by a digit (the version-tag start). A bare
# `v` is intentionally rejected so alpha continuations like `sonnet-5verbose`
# do not silently match.
# See https://docs.claude.com/en/about-claude/models/overview
# See https://docs.claude.com/en/about-claude/models/overview and
# https://docs.claude.com/en/about-claude/models/whats-new-claude-4-7
_SAMPLING_TRAILING_EDGE: str = r"(?=$|[-:@/]|v\d)"
_SAMPLING_DEPRECATED_MODEL_STEMS: tuple[str, ...] = (
"claude-opus-4-7",
"claude-opus-4-8",
"claude-sonnet-5",
"claude-fable-5",
"claude-mythos-5",
)
# Regex fragments (not escaped) for model families where a whole version range
# is deprecated. `claude-opus-4-[789]` covers 4.7–4.9 but not a hypothetical
# `claude-opus-4-10`; Anthropic's cadence makes an Opus 5 jump far more likely,
# and Opus 5+ is covered by the second entry.
_SAMPLING_DEPRECATED_MODEL_FAMILIES: tuple[str, ...] = (
r"claude-opus-4-[789]", # Opus 4.7, 4.8, 4.9
r"claude-opus-[5-9]", # Opus 5 and later
)
_SAMPLING_DEPRECATED_MODEL_PATTERNS: tuple[re.Pattern[str], ...] = tuple(
re.compile(rf"{re.escape(stem)}(?=$|[-:@/]|v\d)")
for stem in _SAMPLING_DEPRECATED_MODEL_STEMS
re.compile(rf"{fragment}{_SAMPLING_TRAILING_EDGE}")
for fragment in (
*(re.escape(stem) for stem in _SAMPLING_DEPRECATED_MODEL_STEMS),
*_SAMPLING_DEPRECATED_MODEL_FAMILIES,
)
)
_DEPRECATED_SAMPLING_PARAMS: tuple[str, ...] = ("temperature", "top_p", "top_k")
# Fields whose value can carry a model id. `model` is universal; `model_id` is
Expand Down Expand Up @@ -90,7 +107,9 @@ def _has_deprecated_sampling_params(model: str | None) -> bool:
Claude Opus 4.7, and every model released since (Opus 4.8, Sonnet 5,
Fable 5, Mythos 5) rejects them too; sending any of them yields a 400 from
Anthropic and from the providers that proxy it (Bedrock, Azure AI Foundry,
Vertex AI). See `_SAMPLING_DEPRECATED_MODEL_STEMS` for the covered set.
Vertex AI). Every Opus release from 4.7 onwards (4.7, 4.8, 4.9, Opus 5+)
is covered by version-range patterns; see `_SAMPLING_DEPRECATED_MODEL_STEMS`
and `_SAMPLING_DEPRECATED_MODEL_FAMILIES` for the covered set.

The check normalizes case and `.`/`_` separators to `-`, then regex-
searches against the patterns with a trailing-edge boundary, so
Expand Down
43 changes: 33 additions & 10 deletions unstract/sdk1/tests/test_sampling_strip.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""Tests for the Claude sampling-parameter strip.

Covers Claude Opus 4.7 and every model released since (Opus 4.8, Sonnet 5,
Fable 5, Mythos 5), all of which reject `temperature`/`top_p`/`top_k`. Sonnet 5
is the model behind the reported Azure AI Foundry `temperature is deprecated`
failure.
Covers Claude Opus 4.7 and every model released since — every Opus release from
4.7 onwards (4.7, 4.8, 4.9, Opus 5+) plus Sonnet 5, Fable 5 and Mythos 5 — all
of which reject `temperature`/`top_p`/`top_k`. Sonnet 5 is the model behind the
reported Azure AI Foundry `temperature is deprecated` failure.

Pins the detection regex and the four-adapter wiring against the failure
modes that surfaced in PR #1934 review:
Expand Down Expand Up @@ -65,6 +65,25 @@
# Version tag accepted only as `v\d` after the trailing edge
"claude-opus-4-7v1",
"claude-opus-4-7v9",
# Opus 4.8 / 4.9 — same deprecation, representative encodings
"claude-opus-4-8",
"anthropic/claude-opus-4-8",
"anthropic.claude-opus-4-8-20260101-v1:0",
"us.anthropic.claude-opus-4-8-20260101-v1:0",
"arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-opus-4-8-20260101-v1:0",
"vertex_ai/claude-opus-4-8@20260101",
"azure_ai/claude-opus-4-8",
"azure_ai/my-claude-opus-4-8-deployment",
"claude.opus.4.8",
"claude-opus-4-9",
# Opus 5 and later
"claude-opus-5",
"claude-opus-5-0",
"anthropic/claude-opus-5-0",
"anthropic.claude-opus-5-0-20270101-v1:0",
"us.anthropic.claude-opus-5-0-20270101-v1:0",
"vertex_ai/claude-opus-5-0@20270101",
"claude-opus-6-0",
]


Expand All @@ -73,8 +92,9 @@ def test_has_deprecated_sampling_params_positive(model: str) -> None:
assert _has_deprecated_sampling_params(model)


# Every Claude model released after Opus 4.7 also rejects sampling params
# (Opus 4.8, Sonnet 5, Fable 5, Mythos 5). Sonnet 5 is the model behind the
# Every Claude model released after Opus 4.7 also rejects sampling params.
# Opus 4.8+ is covered above; the non-Opus families (Sonnet 5, Fable 5,
# Mythos 5) are listed as literal stems. Sonnet 5 is the model behind the
# reported Azure AI Foundry `temperature is deprecated` failure.
POST_47_POSITIVES: list[str] = [
# Sonnet 5 — native, Azure AI Foundry (prefixed by validate_model), case,
Expand All @@ -90,10 +110,6 @@ def test_has_deprecated_sampling_params_positive(model: str) -> None:
"claude-sonnet-5v1", # version tag
"anthropic.claude-sonnet-5-20260101-v1:0", # Bedrock foundation model id
"vertex_ai/claude-sonnet-5@20260101", # Vertex AI
# Opus 4.8
"claude-opus-4-8",
"anthropic.claude-opus-4-8-20260101-v1:0",
"azure_ai/claude-opus-4-8",
# Fable 5 / Mythos 5
"claude-fable-5",
"vertex_ai/claude-fable-5@20260101",
Expand Down Expand Up @@ -142,6 +158,13 @@ def test_has_deprecated_sampling_params_positive_post_opus_47(model: str) -> Non
"claude-opus-4-7verbose",
"claude-opus-4-7vnext",
"claude-opus-4-7variant",
# Opus 5+ boundary: the major must end at a delimiter, not run into more
# digits or letters.
"claude-opus-50",
"claude-opus-5verbose",
# Opus 4.1–4.6 still accept sampling params; only 4.7+ is deprecated.
"claude-opus-4-1",
"anthropic.claude-opus-4-1-20250805-v1:0",
# Opaque Bedrock Application Inference Profile ARN — model id is not
# recoverable from the string. Strip-detection is expected to skip;
# callers must keep the standard id in `model` or `model_id`.
Expand Down
Loading