fix(bedrock): add Claude Opus 5 to the 1M context table

DEFAULT_CONTEXT_LENGTHS declares claude-opus-5 as 1M, but the Bedrock
static table never got the entry, so the offline path resolved the 128K
default and the agent compressed context ~8x early. Add the key and pin
the table pairing with a test so the next 1M generation cannot drift.

Co-authored-by: JiaDe-Wu <JiaDe-Wu@users.noreply.github.com>
(cherry picked from commit c1be16ecbdd267b14124dd35c0b92ccfcd201818)
This commit is contained in:
ryrenz
2026-09-05 16:40:01 -04:00
committed by kshitij
parent 32cab8475e
commit 6d42b876f2
2 changed files with 50 additions and 3 deletions

View File

@@ -1170,10 +1170,12 @@ BEDROCK_CONTEXT_LENGTHS: Dict[str, int] = {
# https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-xai-grok-4-6.html
"xai.grok-4.6": 500_000,
# Anthropic Claude: 1M GA vs 200K. The 1M entries must match agent/model_metadata.py
# DEFAULT_CONTEXT_LENGTHS or context compresses early.
# DEFAULT_CONTEXT_LENGTHS or context compresses early — Opus 5 reached that table and not this
# one, so the offline path resolved 128K for a 1M model (#74263); the pairing is now tested.
**dict.fromkeys((
"anthropic.claude-fable-5", "anthropic.claude-fable", "anthropic.claude-sonnet-5", "anthropic.claude-opus-4-8",
"anthropic.claude-opus-4-7", "anthropic.claude-opus-4-6", "anthropic.claude-sonnet-4-6",
"anthropic.claude-fable-5", "anthropic.claude-fable", "anthropic.claude-sonnet-5", "anthropic.claude-opus-5",
"anthropic.claude-opus-4-8", "anthropic.claude-opus-4-7",
"anthropic.claude-opus-4-6", "anthropic.claude-sonnet-4-6",
), 1_000_000),
**dict.fromkeys((
"anthropic.claude-sonnet-4-5", "anthropic.claude-haiku-4-5", "anthropic.claude-opus-4", "anthropic.claude-sonnet-4",

View File

@@ -1082,6 +1082,51 @@ class TestBedrockContextLength:
assert get_bedrock_context_length("anthropic.claude-opus-4-6") == 1_000_000
mock_probe.assert_not_called()
@pytest.mark.parametrize(
"model_id",
(
"anthropic.claude-opus-5",
"us.anthropic.claude-opus-5",
"eu.anthropic.claude-opus-5",
"global.anthropic.claude-opus-5",
# Longest-substring lookup: the bare key must keep winning once a dated revision ships.
"anthropic.claude-opus-5-v1:0",
"eu.anthropic.claude-opus-5-20260724-v1:0",
),
)
def test_claude_opus_5_uses_offline_context_table(self, model_id):
"""Claude Opus 5 keeps its documented 1M window without a probe."""
from agent.bedrock_adapter import get_bedrock_context_length
with patch("agent.bedrock_adapter.probe_bedrock_context_length") as mock_probe:
assert get_bedrock_context_length(model_id, probe=False) == 1_000_000
mock_probe.assert_not_called()
def test_million_token_claude_entries_match_model_metadata(self):
"""BEDROCK_CONTEXT_LENGTHS must not drift from DEFAULT_CONTEXT_LENGTHS.
The table's own comment requires the pairing, but nothing enforced it, so
``claude-opus-5`` reached one table and not the other and silently fell through to
BEDROCK_DEFAULT_CONTEXT_LENGTH (#74263). Assert the relationship, not a snapshot of
today's catalog. DEFAULT_CONTEXT_LENGTHS spells revisions with dots
(``claude-opus-4.8``) while Bedrock IDs use hyphens — normalize rather than skip, so a
future 1M model that only ever gets a dotted alias cannot escape the check.
"""
from agent.bedrock_adapter import get_bedrock_context_length
from agent.model_metadata import DEFAULT_CONTEXT_LENGTHS
mismatched = []
with patch("agent.bedrock_adapter.probe_bedrock_context_length") as mock_probe:
for name, expected in DEFAULT_CONTEXT_LENGTHS.items():
if not name.startswith("claude-") or expected < 1_000_000:
continue
actual = get_bedrock_context_length(f"anthropic.{name.replace('.', '-')}", probe=False)
if actual != expected:
mismatched.append((name, expected, actual))
mock_probe.assert_not_called()
assert not mismatched, f"1M Claude entries missing from BEDROCK_CONTEXT_LENGTHS: {mismatched}"
class TestInferenceProfileContextLength:
"""Application-inference-profile ARNs name no model, so the window must come from the model the