From eca8b429f55e6e346a69463b844b466cf79d4a54 Mon Sep 17 00:00:00 2001 From: Prasanna Jain Date: Tue, 27 Oct 2026 16:20:57 -0400 Subject: [PATCH 1/2] fix(databricks): accept tool-only assistant messages without content --- .../llms/databricks/chat/transformation.py | 2 +- .../test_databricks_chat_transformation.py | 40 ++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/litellm/llms/databricks/chat/transformation.py b/litellm/llms/databricks/chat/transformation.py index 48118c23ed7..8d702c8270b 100644 --- a/litellm/llms/databricks/chat/transformation.py +++ b/litellm/llms/databricks/chat/transformation.py @@ -659,7 +659,7 @@ class DatabricksConfig(DatabricksBase, OpenAILikeChatConfig, AnthropicConfig): def resolve_reasoning_and_content( message: DatabricksMessage, block_reasoning_content: str | None ) -> tuple[str | None, str | None]: - content_str: Final = DatabricksConfig.extract_content_str(message["content"]) + content_str: Final = DatabricksConfig.extract_content_str(message.get("content")) if block_reasoning_content is not None: return block_reasoning_content, content_str return extract_reasoning_content({**message, "content": content_str}) diff --git a/tests/unit/llms/databricks/chat/test_databricks_chat_transformation.py b/tests/unit/llms/databricks/chat/test_databricks_chat_transformation.py index b3a224209e9..2e2dc50fae0 100644 --- a/tests/unit/llms/databricks/chat/test_databricks_chat_transformation.py +++ b/tests/unit/llms/databricks/chat/test_databricks_chat_transformation.py @@ -8,7 +8,7 @@ import httpx import pytest import respx from openai.lib.streaming.chat import ChatCompletionStreamState -from openai.types.chat import ChatCompletionChunk +from openai.types.chat import ChatCompletion, ChatCompletionChunk from pydantic import TypeAdapter from fastapi.testclient import TestClient from pydantic import BaseModel, ConfigDict @@ -2429,6 +2429,44 @@ def test_transform_response_carries_served_service_tier(served_tier: str | None) assert result.to_dict().get("service_tier") == served_tier +def test_transform_response_keeps_a_tool_only_message_without_content() -> None: + tool_call: Final = { + "id": "call_weather", + "type": "function", + "function": {"name": "get_weather", "arguments": '{"city": "Paris"}'}, + } + raw_response: Final = httpx.Response( + 200, + json={ + "id": "chatcmpl-1", + "object": "chat.completion", + "created": 0, + "model": "dbrx", + "choices": [ + {"index": 0, "message": {"role": "assistant", "tool_calls": [tool_call]}, "finish_reason": "tool_calls"} + ], + "usage": {"prompt_tokens": 5, "completion_tokens": 3, "total_tokens": 8}, + }, + ) + + result: Final = DatabricksConfig().transform_response( + model="databricks/dbrx", + raw_response=raw_response, + model_response=litellm.ModelResponse(), + logging_obj=MagicMock(), + request_data={}, + messages=[{"role": "user", "content": "weather in Paris?"}], + optional_params={}, + litellm_params={}, + encoding=None, + ) + + completion: Final = ChatCompletion.model_validate(result.model_dump()) + assert completion.choices[0].finish_reason == "tool_calls" + assert completion.choices[0].message.model_dump(exclude_none=True) == {"role": "assistant", "tool_calls": [tool_call]} + assert completion.usage is not None and completion.usage.total_tokens == 8 + + _DATABRICKS_TOOLS_WITH_OPENAI_TOOL_SEARCH: Final = [ {"type": "tool_search", "execution": "server"}, { From c7fa3584ce8e1f370190443369be494ef7aabe13 Mon Sep 17 00:00:00 2001 From: Prasanna Jain Date: Wed, 28 Oct 2026 10:27:01 -0400 Subject: [PATCH 2/2] test(databricks): assert the full usage payload on tool-only responses --- .../databricks/chat/test_databricks_chat_transformation.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unit/llms/databricks/chat/test_databricks_chat_transformation.py b/tests/unit/llms/databricks/chat/test_databricks_chat_transformation.py index 2e2dc50fae0..fc86a7fd40d 100644 --- a/tests/unit/llms/databricks/chat/test_databricks_chat_transformation.py +++ b/tests/unit/llms/databricks/chat/test_databricks_chat_transformation.py @@ -2464,7 +2464,8 @@ def test_transform_response_keeps_a_tool_only_message_without_content() -> None: completion: Final = ChatCompletion.model_validate(result.model_dump()) assert completion.choices[0].finish_reason == "tool_calls" assert completion.choices[0].message.model_dump(exclude_none=True) == {"role": "assistant", "tool_calls": [tool_call]} - assert completion.usage is not None and completion.usage.total_tokens == 8 + assert completion.usage is not None + assert (completion.usage.prompt_tokens, completion.usage.completion_tokens, completion.usage.total_tokens) == (5, 3, 8) _DATABRICKS_TOOLS_WITH_OPENAI_TOOL_SEARCH: Final = [