From 528cc06045367b956b7124f99591f6cd1c83b27a Mon Sep 17 00:00:00 2001 From: truongsontung Date: Wed, 9 Sep 2026 12:50:26 +0700 Subject: [PATCH 1/3] fix: correct cache pricing for Claude 3 Haiku CRIS variants on Bedrock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four cross-region Bedrock keys for Claude 3 Haiku carry cache prices derived from the generic 1.25x write / 0.1x read ratios, but Anthropic's published prices are non-round values (/usr/bin/zsh.30 write / /usr/bin/zsh.03 read per Mtok). Keys fixed: - anthropic.claude-3-haiku-20240307-v1:0 - apac.anthropic.claude-3-haiku-20240307-v1:0 - eu.anthropic.claude-3-haiku-20240307-v1:0 - us.anthropic.claude-3-haiku-20240307-v1:0 Changes: - cache_read_input_token_cost: 2.5e-08 → 3e-08 (/usr/bin/zsh.025 → /usr/bin/zsh.03) - cache_creation_input_token_cost: 3.125e-07 → 3e-07 (/usr/bin/zsh.3125 → /usr/bin/zsh.30) Impact: corrects cache-read costs understated by 16.7% and cache-write costs overstated by 4.2% for these four keys. Fixes #40360 --- model_prices_and_context_window.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index 54ebdc85be9..2b06d9e9035 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -953,8 +953,8 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "cache_read_input_token_cost": 2.5e-08, - "cache_creation_input_token_cost": 3.125e-07 + "cache_read_input_token_cost": 3e-08, + "cache_creation_input_token_cost": 3e-07 }, "anthropic.claude-3-opus-20240229-v1:0": { "input_cost_per_token": 1.5e-05, @@ -2955,8 +2955,8 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "cache_read_input_token_cost": 2.5e-08, - "cache_creation_input_token_cost": 3.125e-07 + "cache_read_input_token_cost": 3e-08, + "cache_creation_input_token_cost": 3e-07 }, "apac.anthropic.claude-haiku-4-5-20251001-v1:0": { "cache_creation_input_token_cost": 1.375e-06, @@ -21104,8 +21104,8 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "cache_read_input_token_cost": 2.5e-08, - "cache_creation_input_token_cost": 3.125e-07 + "cache_read_input_token_cost": 3e-08, + "cache_creation_input_token_cost": 3e-07 }, "eu.anthropic.claude-3-opus-20240229-v1:0": { "input_cost_per_token": 1.5e-05, @@ -43829,8 +43829,8 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "cache_read_input_token_cost": 2.5e-08, - "cache_creation_input_token_cost": 3.125e-07 + "cache_read_input_token_cost": 3e-08, + "cache_creation_input_token_cost": 3e-07 }, "us.anthropic.claude-3-opus-20240229-v1:0": { "input_cost_per_token": 1.5e-05, From 1ac7195a3597f842a0d844e1b59fabf73f9861e7 Mon Sep 17 00:00:00 2001 From: truongsontung Date: Wed, 9 Sep 2026 12:54:21 +0700 Subject: [PATCH 2/3] chore: sync backup cost map with corrected Claude 3 Haiku cache prices --- .../model_prices_and_context_window_backup.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index 54ebdc85be9..2b06d9e9035 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -953,8 +953,8 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "cache_read_input_token_cost": 2.5e-08, - "cache_creation_input_token_cost": 3.125e-07 + "cache_read_input_token_cost": 3e-08, + "cache_creation_input_token_cost": 3e-07 }, "anthropic.claude-3-opus-20240229-v1:0": { "input_cost_per_token": 1.5e-05, @@ -2955,8 +2955,8 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "cache_read_input_token_cost": 2.5e-08, - "cache_creation_input_token_cost": 3.125e-07 + "cache_read_input_token_cost": 3e-08, + "cache_creation_input_token_cost": 3e-07 }, "apac.anthropic.claude-haiku-4-5-20251001-v1:0": { "cache_creation_input_token_cost": 1.375e-06, @@ -21104,8 +21104,8 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "cache_read_input_token_cost": 2.5e-08, - "cache_creation_input_token_cost": 3.125e-07 + "cache_read_input_token_cost": 3e-08, + "cache_creation_input_token_cost": 3e-07 }, "eu.anthropic.claude-3-opus-20240229-v1:0": { "input_cost_per_token": 1.5e-05, @@ -43829,8 +43829,8 @@ "supports_response_schema": true, "supports_tool_choice": true, "supports_vision": true, - "cache_read_input_token_cost": 2.5e-08, - "cache_creation_input_token_cost": 3.125e-07 + "cache_read_input_token_cost": 3e-08, + "cache_creation_input_token_cost": 3e-07 }, "us.anthropic.claude-3-opus-20240229-v1:0": { "input_cost_per_token": 1.5e-05, From 63d74a25440d07fc345f74194641014fdb0fddde Mon Sep 17 00:00:00 2001 From: truongsontung Date: Wed, 9 Sep 2026 12:55:32 +0700 Subject: [PATCH 3/3] test: add regression tests for Claude 3 Haiku CRIS cache pricing Verifies all 4 Bedrock cross-region entries have correct Anthropic-published cache prices (write $0.30/M, read $0.03/M) matching the direct entry. --- ...laude3_haiku_bedrock_cris_cache_pricing.py | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 tests/test_litellm/test_claude3_haiku_bedrock_cris_cache_pricing.py diff --git a/tests/test_litellm/test_claude3_haiku_bedrock_cris_cache_pricing.py b/tests/test_litellm/test_claude3_haiku_bedrock_cris_cache_pricing.py new file mode 100644 index 00000000000..1a46debcc24 --- /dev/null +++ b/tests/test_litellm/test_claude3_haiku_bedrock_cris_cache_pricing.py @@ -0,0 +1,100 @@ +""" +Validate that the four Bedrock cross-region Claude 3 Haiku CRIS entries +carry the correct Anthropic-published cache pricing ($0.30 write / $0.03 read +per Mtok), matching the direct `claude-3-haiku-20240307` entry. + +Previous values were incorrectly derived from the generic 1.25x write / 0.1x +read ratios (write $0.3125, read $0.025), which understated cache-read costs +by 16.7% and overstated cache-write costs by 4.2%. + +This test guards against regression of the fix in PR #40368. +""" + +import json +import os + +import pytest + +JSON_PATH = os.path.join( + os.path.dirname(__file__), "../../model_prices_and_context_window.json" +) + +BACKUP_PATH = os.path.join( + os.path.dirname(__file__), "../../litellm/model_prices_and_context_window_backup.json" +) + +# The four CRIS (cross-region inference) Bedrock variants that were fixed +CRIS_KEYS = [ + "anthropic.claude-3-haiku-20240307-v1:0", + "apac.anthropic.claude-3-haiku-20240307-v1:0", + "eu.anthropic.claude-3-haiku-20240307-v1:0", + "us.anthropic.claude-3-haiku-20240307-v1:0", +] + +# The direct (non-CRIS) entry that has the correct values — used for comparison +DIRECT_KEY = "claude-3-haiku-20240307" + +EXPECTED_CACHE_CREATION = 3e-07 # $0.30 per M tokens +EXPECTED_CACHE_READ = 3e-08 # $0.03 per M tokens + + +@pytest.fixture(scope="module") +def model_data(): + with open(JSON_PATH) as f: + return json.load(f) + + +@pytest.fixture(scope="module") +def backup_data(): + with open(BACKUP_PATH) as f: + return json.load(f) + + +@pytest.mark.parametrize("key", CRIS_KEYS) +def test_cris_cache_creation_price(model_data, key): + """Each CRIS variant should have the correct cache creation price.""" + assert key in model_data, f"Missing model entry: {key}" + entry = model_data[key] + actual = entry.get("cache_creation_input_token_cost") + assert actual == EXPECTED_CACHE_CREATION, ( + f"{key}: expected cache_creation_input_token_cost={EXPECTED_CACHE_CREATION} " + f"($0.30/M), got {actual}" + ) + + +@pytest.mark.parametrize("key", CRIS_KEYS) +def test_cris_cache_read_price(model_data, key): + """Each CRIS variant should have the correct cache read price.""" + assert key in model_data, f"Missing model entry: {key}" + entry = model_data[key] + actual = entry.get("cache_read_input_token_cost") + assert actual == EXPECTED_CACHE_READ, ( + f"{key}: expected cache_read_input_token_cost={EXPECTED_CACHE_READ} " + f"($0.03/M), got {actual}" + ) + + +@pytest.mark.parametrize("key", CRIS_KEYS) +def test_cris_prices_match_direct_entry(model_data, key): + """CRIS variants should match the direct Claude 3 Haiku entry.""" + assert key in model_data, f"Missing CRIS entry: {key}" + assert DIRECT_KEY in model_data, f"Missing direct entry: {DIRECT_KEY}" + cris = model_data[key] + direct = model_data[DIRECT_KEY] + assert cris.get("cache_creation_input_token_cost") == direct.get("cache_creation_input_token_cost"), ( + f"{key} cache_creation mismatch with {DIRECT_KEY}" + ) + assert cris.get("cache_read_input_token_cost") == direct.get("cache_read_input_token_cost"), ( + f"{key} cache_read mismatch with {DIRECT_KEY}" + ) + + +@pytest.mark.parametrize("key", CRIS_KEYS) +def test_backup_matches_main(backup_data, model_data, key): + """Backup cost map should match the main cost map for all CRIS entries.""" + assert key in backup_data, f"Missing CRIS entry in backup: {key}" + assert backup_data[key].get("cache_creation_input_token_cost") == EXPECTED_CACHE_CREATION + assert backup_data[key].get("cache_read_input_token_cost") == EXPECTED_CACHE_READ + assert backup_data[key] == model_data[key], ( + f"Backup and main differ for {key}" + )