fix(databricks): handle tool-only replies without content

This commit is contained in:
Daniel 2026-09-24 15:19:37 +08:00
parent 6dbd65b230
commit ffef39710a
3 changed files with 66 additions and 4 deletions

View file

@ -558,7 +558,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})

View file

@ -56,7 +56,7 @@ class DatabricksTool(TypedDict):
class DatabricksMessage(TypedDict, total=False):
role: Required[str]
content: Required[AllDatabricksContentValues]
content: ReadOnly[AllDatabricksContentValues | None]
tool_calls: list[DatabricksTool] | None
reasoning_content: ReadOnly[str | None]
reasoning: ReadOnly[str | None]

View file

@ -7,6 +7,64 @@ import respx
import litellm
def test_completion_accepts_tool_call_without_content(respx_mock: respx.MockRouter):
upstream: Final = respx_mock.post("https://example.databricks.test/serving-endpoints/chat/completions").mock(
return_value=httpx.Response(
status_code=200,
json={
"id": "chatcmpl-tool-call",
"object": "chat.completion",
"created": 1677652288,
"model": "my-custom-model",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"tool_calls": [
{
"id": "call_weather",
"type": "function",
"function": {"name": "get_weather", "arguments": '{"city":"Paris"}'},
}
],
},
"finish_reason": "tool_calls",
}
],
"usage": {"prompt_tokens": 9, "completion_tokens": 5, "total_tokens": 14},
},
)
)
response: Final = litellm.completion(
model="databricks/my-custom-model",
messages=[{"role": "user", "content": "What is the weather in Paris?"}],
tools=[
{
"type": "function",
"function": {
"name": "get_weather",
"parameters": {"type": "object", "properties": {"city": {"type": "string"}}},
},
}
],
api_base="https://example.databricks.test/serving-endpoints",
api_key="fake-databricks-api-key",
num_retries=0,
)
assert upstream.call_count == 1
assert response.choices[0].finish_reason == "tool_calls"
message: Final = response.choices[0].message
assert message.content is None
assert message.tool_calls is not None
assert len(message.tool_calls) == 1
assert message.tool_calls[0].id == "call_weather"
assert message.tool_calls[0].function.name == "get_weather"
assert message.tool_calls[0].function.arguments == '{"city":"Paris"}'
def test_completion_merges_leading_system_and_developer_messages_for_chat_template_models(
respx_mock: respx.MockRouter,
):
@ -18,7 +76,9 @@ def test_completion_merges_leading_system_and_developer_messages_for_chat_templa
"object": "chat.completion",
"created": 1677652288,
"model": "my-custom-model",
"choices": [{"index": 0, "message": {"role": "assistant", "content": "Answer"}, "finish_reason": "stop"}],
"choices": [
{"index": 0, "message": {"role": "assistant", "content": "Answer"}, "finish_reason": "stop"}
],
"usage": {"prompt_tokens": 9, "completion_tokens": 1, "total_tokens": 10},
},
)
@ -54,7 +114,9 @@ def test_completion_merges_system_messages_when_one_has_empty_content(respx_mock
"object": "chat.completion",
"created": 1677652288,
"model": "my-custom-model",
"choices": [{"index": 0, "message": {"role": "assistant", "content": "Answer"}, "finish_reason": "stop"}],
"choices": [
{"index": 0, "message": {"role": "assistant", "content": "Answer"}, "finish_reason": "stop"}
],
"usage": {"prompt_tokens": 9, "completion_tokens": 1, "total_tokens": 10},
},
)