This commit is contained in:
Bharat Lakhiyani 2026-09-14 23:23:19 -07:00 • committed by GitHub
commit 54d7db92f0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 140 additions and 1 deletions

View file

@ -774,7 +774,7 @@ def is_bedrock_application_inference_profile_arn(model: str) -> bool:
def strip_bedrock_routing_prefix(model: str) -> str:
"""Strip LiteLLM routing prefixes from model name."""
for prefix in ["bedrock/", "converse/", "invoke/", "openai/", "nova-2/", "nova/"]:
for prefix in ["bedrock/", "converse/", "invoke/", "openai/", "mantle/", "nova-2/", "nova/"]:
if model.startswith(prefix):
model = model.split("/", 1)[1]
return model

View file

@ -820,6 +820,31 @@
"supports_tool_choice": true,
"prompt_cache_min_tokens": 2048
},
"anthropic.claude-haiku-4-5": {
"cache_creation_input_token_cost": 1.25e-06,
"cache_creation_input_token_cost_above_1hr": 2e-06,
"cache_read_input_token_cost": 1e-07,
"input_cost_per_token": 1e-06,
"litellm_provider": "bedrock",
"max_input_tokens": 200000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"output_cost_per_token": 5e-06,
"source": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-haiku-4-5.html",
"supports_assistant_prefill": true,
"supports_computer_use": true,
"supports_function_calling": true,
"supports_pdf_input": true,
"supports_prompt_caching": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_tool_choice": true,
"supports_vision": true,
"supports_native_structured_output": true,
"supports_parallel_tool_use_config": true,
"prompt_cache_min_tokens": 4096
},
"anthropic.claude-haiku-4-5-20251001-v1:0": {
"cache_creation_input_token_cost": 1.25e-06,
"cache_creation_input_token_cost_above_1hr": 2e-06,

View file

@ -820,6 +820,31 @@
"supports_tool_choice": true,
"prompt_cache_min_tokens": 2048
},
"anthropic.claude-haiku-4-5": {
"cache_creation_input_token_cost": 1.25e-06,
"cache_creation_input_token_cost_above_1hr": 2e-06,
"cache_read_input_token_cost": 1e-07,
"input_cost_per_token": 1e-06,
"litellm_provider": "bedrock",
"max_input_tokens": 200000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"output_cost_per_token": 5e-06,
"source": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-haiku-4-5.html",
"supports_assistant_prefill": true,
"supports_computer_use": true,
"supports_function_calling": true,
"supports_pdf_input": true,
"supports_prompt_caching": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_tool_choice": true,
"supports_vision": true,
"supports_native_structured_output": true,
"supports_parallel_tool_use_config": true,
"prompt_cache_min_tokens": 4096
},
"anthropic.claude-haiku-4-5-20251001-v1:0": {
"cache_creation_input_token_cost": 1.25e-06,
"cache_creation_input_token_cost_above_1hr": 2e-06,

View file

@ -735,3 +735,92 @@ async def test_mantle_anthropic_messages_streaming_sends_stream_and_passes_throu
assert "event: message_start" in text
assert '"text": "pong"' in text
assert "event: message_stop" in text
@pytest.fixture
def local_cost_map(monkeypatch):
import litellm
from litellm.utils import _invalidate_model_cost_lowercase_map
original_model_cost = litellm.model_cost
try:
monkeypatch.setenv("LITELLM_LOCAL_MODEL_COST_MAP", "true")
litellm.model_cost = litellm.get_model_cost_map(url="")
_invalidate_model_cost_lowercase_map()
yield
finally:
litellm.model_cost = original_model_cost
_invalidate_model_cost_lowercase_map()
@pytest.mark.parametrize(
"model_id,max_input,max_output,input_cost,output_cost",
[
("anthropic.claude-opus-5", 1_000_000, 128_000, 5e-06, 2.5e-05),
("anthropic.claude-sonnet-5", 1_000_000, 128_000, 2e-06, 1e-05),
("anthropic.claude-haiku-4-5", 200_000, 64_000, 1e-06, 5e-06),
],
)
def test_mantle_route_resolves_exact_model_info(
local_cost_map, model_id, max_input, max_output, input_cost, output_cost
):
"""The mantle/ routing prefix must resolve the exact bare-model cost-map
entry, not a generalization fallback. Before the fix,
strip_bedrock_routing_prefix left the mantle/ prefix in place, so
bedrock/mantle/anthropic.claude-opus-5 resolved generic 200k/64k limits
instead of the 1M/128k entry, and anthropic.claude-haiku-4-5 (the dateless
ID the Mantle endpoint uses) had no entry at all and cost $0."""
import litellm
info = litellm.get_model_info(f"bedrock/mantle/{model_id}")
assert info["max_input_tokens"] == max_input
assert info["max_output_tokens"] == max_output
assert info["input_cost_per_token"] == input_cost
assert info["output_cost_per_token"] == output_cost
@pytest.mark.parametrize(
"model_id",
[
"anthropic.claude-opus-5",
"anthropic.claude-sonnet-5",
"anthropic.claude-haiku-4-5",
],
)
def test_get_bedrock_route_mantle_claude_models(model_id):
assert BedrockModelInfo.get_bedrock_route(f"mantle/{model_id}") == "mantle"
assert BedrockModelInfo.get_bedrock_route(f"bedrock/mantle/{model_id}") == "mantle"
def test_strip_bedrock_routing_prefix_strips_mantle_but_not_provider_prefix():
from litellm.llms.bedrock.common_utils import strip_bedrock_routing_prefix
assert (
strip_bedrock_routing_prefix("bedrock/mantle/anthropic.claude-opus-5")
== "anthropic.claude-opus-5"
)
assert (
strip_bedrock_routing_prefix("mantle/anthropic.claude-sonnet-5")
== "anthropic.claude-sonnet-5"
)
assert (
strip_bedrock_routing_prefix("bedrock_mantle/openai.gpt-5.5")
== "bedrock_mantle/openai.gpt-5.5"
)
def test_mantle_haiku_4_5_cost_tracking(local_cost_map):
"""Regression: the Mantle endpoint serves Haiku 4.5 under the dateless ID
anthropic.claude-haiku-4-5 (bedrock-runtime uses the dated
anthropic.claude-haiku-4-5-20251001-v1:0). Without a dateless entry,
completion_cost silently returned 0.0."""
import litellm
from litellm.types.utils import Choices, Message, ModelResponse, Usage
response = ModelResponse(
model="anthropic.claude-haiku-4-5",
choices=[Choices(message=Message(content="ok"))],
usage=Usage(prompt_tokens=1000, completion_tokens=1000),
)
cost = litellm.completion_cost(completion_response=response, custom_llm_provider="bedrock")
assert cost == pytest.approx(1000 * 1e-06 + 1000 * 5e-06)