From 117ea7f90761071043ee484d44293cf32c5ae215 Mon Sep 17 00:00:00 2001 From: Andrew Mattie Date: Mon, 24 Aug 2026 19:13:48 -0500 Subject: [PATCH 1/2] fix(bedrock): preserve usage details in fake streams --- litellm/llms/bedrock/chat/invoke_handler.py | 10 ++++ .../llms/bedrock/chat/test_invoke_handler.py | 52 +++++++++++++++++-- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/litellm/llms/bedrock/chat/invoke_handler.py b/litellm/llms/bedrock/chat/invoke_handler.py index 35e82f1961a..ddc5f6e064f 100644 --- a/litellm/llms/bedrock/chat/invoke_handler.py +++ b/litellm/llms/bedrock/chat/invoke_handler.py @@ -824,6 +824,16 @@ class MockResponseIterator: # for returning ai21 streaming responses prompt_tokens=chunk_usage.prompt_tokens, completion_tokens=chunk_usage.completion_tokens, total_tokens=chunk_usage.total_tokens, + prompt_tokens_details=( + chunk_usage.prompt_tokens_details.model_dump(exclude_none=True) + if chunk_usage.prompt_tokens_details is not None + else None + ), + completion_tokens_details=( + chunk_usage.completion_tokens_details.model_dump(exclude_none=True) + if chunk_usage.completion_tokens_details is not None + else None + ), ), index=0, ) diff --git a/tests/test_litellm/llms/bedrock/chat/test_invoke_handler.py b/tests/test_litellm/llms/bedrock/chat/test_invoke_handler.py index cd305d8ed26..594159cbe74 100644 --- a/tests/test_litellm/llms/bedrock/chat/test_invoke_handler.py +++ b/tests/test_litellm/llms/bedrock/chat/test_invoke_handler.py @@ -9,10 +9,57 @@ from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLogging from litellm.litellm_core_utils.streaming_handler import CustomStreamWrapper from litellm.llms.bedrock.chat.invoke_handler import ( AWSEventStreamDecoder, + MockResponseIterator, make_call, make_sync_call, ) from litellm.llms.custom_httpx.http_handler import AsyncHTTPHandler, HTTPHandler +from litellm.types.utils import ( + Choices, + CompletionTokensDetailsWrapper, + Message, + ModelResponse, + PromptTokensDetailsWrapper, + Usage, +) + + +def test_mock_response_iterator_preserves_usage_details(): + response = ModelResponse( + choices=[ + Choices( + finish_reason="stop", + index=0, + message=Message(content="done", role="assistant"), + ) + ], + usage=Usage( + prompt_tokens=500, + completion_tokens=25, + total_tokens=525, + prompt_tokens_details=PromptTokensDetailsWrapper( + cached_tokens=321, + cache_write_tokens=123, + ), + completion_tokens_details=CompletionTokensDetailsWrapper( + reasoning_tokens=11, + ), + ), + ) + + chunk = MockResponseIterator(model_response=response)._chunk_parser(response) + + assert chunk["usage"] == { + "prompt_tokens": 500, + "completion_tokens": 25, + "total_tokens": 525, + "prompt_tokens_details": { + "cached_tokens": 321, + "cache_write_tokens": 123, + "cache_creation_tokens": 123, + }, + "completion_tokens_details": {"reasoning_tokens": 11}, + } def test_transform_thinking_blocks_with_redacted_content(): @@ -203,9 +250,7 @@ def test_bedrock_converse_streaming_consistent_id(): expected_id = f"chatcmpl-{native_conversation_id}" for response in parsed_responses: - assert ( - response.id == expected_id - ), "All chunk IDs must match the one captured from the messageStart event" + assert response.id == expected_id, "All chunk IDs must match the one captured from the messageStart event" @pytest.mark.asyncio @@ -472,4 +517,3 @@ async def test_async_invoke_streaming_forwards_bedrock_response_headers(): ) assert stream._hidden_params["additional_headers"]["llm_provider-x-amzn-requestid"] == "req-987" - From 6d43ff63d6406135d74e34171ab8674b6e41d1f2 Mon Sep 17 00:00:00 2001 From: Andrew Mattie Date: Mon, 24 Aug 2026 19:21:37 -0500 Subject: [PATCH 2/2] test(bedrock): restore existing assertion formatting --- tests/test_litellm/llms/bedrock/chat/test_invoke_handler.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_litellm/llms/bedrock/chat/test_invoke_handler.py b/tests/test_litellm/llms/bedrock/chat/test_invoke_handler.py index 594159cbe74..d86989a8d5c 100644 --- a/tests/test_litellm/llms/bedrock/chat/test_invoke_handler.py +++ b/tests/test_litellm/llms/bedrock/chat/test_invoke_handler.py @@ -250,7 +250,9 @@ def test_bedrock_converse_streaming_consistent_id(): expected_id = f"chatcmpl-{native_conversation_id}" for response in parsed_responses: - assert response.id == expected_id, "All chunk IDs must match the one captured from the messageStart event" + assert ( + response.id == expected_id + ), "All chunk IDs must match the one captured from the messageStart event" @pytest.mark.asyncio