From f96768ec6fee193320960eafe8613379137de346 Mon Sep 17 00:00:00 2001 From: teddiesloco Date: Thu, 27 Aug 2026 12:07:07 +0700 Subject: [PATCH] fix(token_counter): support input_audio content blocks in _count_content_list (#38459) --- litellm/litellm_core_utils/token_counter.py | 11 +++++++ .../test_input_audio_token_counter_38459.py | 32 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 tests/test_litellm/test_input_audio_token_counter_38459.py diff --git a/litellm/litellm_core_utils/token_counter.py b/litellm/litellm_core_utils/token_counter.py index 858b078d626..fb4d6c06baa 100644 --- a/litellm/litellm_core_utils/token_counter.py +++ b/litellm/litellm_core_utils/token_counter.py @@ -738,6 +738,17 @@ def _count_content_list( tool_name = str(c.get("tool_name") or "") if tool_name: num_tokens += count_function(tool_name) + elif c["type"] == "input_audio": + # OpenAI input_audio content block: {"type": "input_audio", "input_audio": {"data": "", "format": "wav"}} + # Estimate tokens based on payload size (or default floor) + input_audio = c.get("input_audio") + b64_data = input_audio.get("data") if isinstance(input_audio, dict) else None + if b64_data and isinstance(b64_data, str): + decoded_bytes = len(b64_data) * 3 // 4 + # 1 token ~ 32 bytes of 24kHz/16-bit mono audio (approx standard across audio models) + num_tokens += max(decoded_bytes // 32, 50) + else: + num_tokens += 50 else: content_type = c.get("type", type(c).__name__) if isinstance(c, dict) else type(c).__name__ raise ValueError( diff --git a/tests/test_litellm/test_input_audio_token_counter_38459.py b/tests/test_litellm/test_input_audio_token_counter_38459.py new file mode 100644 index 00000000000..e0e88083904 --- /dev/null +++ b/tests/test_litellm/test_input_audio_token_counter_38459.py @@ -0,0 +1,32 @@ +import unittest +from litellm.litellm_core_utils.token_counter import _count_content_list + +class TestInputAudioTokenCounter(unittest.TestCase): + def test_input_audio_block_does_not_raise(self): + """ + Regression test for #38459: + _count_content_list should handle input_audio blocks without raising ValueError. + """ + content_list = [ + {"type": "text", "text": "Hello audio"}, + { + "type": "input_audio", + "input_audio": { + "data": "UklGRiQAAABXQVZFZm10IBAAAAABAAEAQB8AAIA+AAACABAAZGF0YQAAAAA=", + "format": "wav" + } + } + ] + + # Simple character counter for testing + def mock_count_func(s): + return len(s) + + total_tokens = _count_content_list( + count_function=mock_count_func, + content_list=content_list, + use_default_image_token_count=True, + default_token_count=None + ) + + self.assertGreater(total_tokens, len("Hello audio"))