fix(databricks): bridge GPT-5.4+ function tools to the Responses API

Databricks forwards its OpenAI GPT endpoints (databricks-gpt-5-4, -5-6-sol,
...) to OpenAI, whose Chat Completions rejects function tools while
reasoning is on. The version check never matched the hyphenated Databricks
names, so these requests were sent to /chat/completions and failed.
This commit is contained in:
72004 2026-10-11 19:26:21 +05:00
parent e0e3523246
commit 250a694864

View file

@ -1,3 +1,4 @@
import re
from collections.abc import Mapping, Sequence
from typing import Final, cast # noqa: TID251 # moved unchanged from litellm/main.py
from urllib.parse import urlsplit
@ -15,6 +16,15 @@ from litellm.utils import get_model_info_helper
_OPENAI_DEFAULT_API_BASE: Final = "https://api.openai.com/v1"
_OPENAI_API_HOST: Final = "api.openai.com"
# Databricks serves OpenAI GPT models as e.g. ``databricks-gpt-5-6-sol``: the minor version is
# hyphenated, so the OpenAI version parser does not recognise it.
_DATABRICKS_GPT_NAME: Final = re.compile(r"^databricks-gpt-(\d+)-(\d+)(?=-|$)")
def _openai_name_for_databricks_model(model: str) -> str:
"""``databricks-gpt-5-6-sol`` -> ``gpt-5.6-sol``; other names are returned unchanged."""
model_name: Final = model.split("/")[-1]
return _DATABRICKS_GPT_NAME.sub(r"gpt-\1.\2", model_name)
def _is_openai_backed_api_base(api_base: str) -> bool:
@ -122,8 +132,15 @@ def responses_api_bridge_check(
on_foundry_openai_endpoint: Final = custom_llm_provider == "azure_ai" and azure_ai_supports_native_responses(
model, api_base
)
# Databricks proxies OpenAI GPT models to the real OpenAI backend, which enforces the
# reasoning+tools constraint, and serves them on its own /responses route as well.
on_databricks_gpt_endpoint: Final = custom_llm_provider == "databricks" and OpenAIGPT5Config.is_model_gpt_5_model(
model
)
on_constraint_enforcing_endpoint: Final = (
custom_llm_provider == "azure" or resolved_api_base == "" or _is_openai_backed_api_base(resolved_api_base)
custom_llm_provider in ("azure", "databricks")
or resolved_api_base == ""
or _is_openai_backed_api_base(resolved_api_base)
)
chat_rejects_function_tools: Final = (
has_function_tool
@ -132,7 +149,9 @@ def responses_api_bridge_check(
foundry_chat_rejects_function_tools_while_reasoning(model, reasoning_effort)
if on_foundry_openai_endpoint
else (
OpenAIGPT5Config.is_model_gpt_5_4_plus_model(model)
OpenAIGPT5Config.is_model_gpt_5_4_plus_model(
_openai_name_for_databricks_model(model) if on_databricks_gpt_endpoint else model
)
and (reasoning_effort is not None or on_constraint_enforcing_endpoint)
)
)
@ -143,7 +162,7 @@ def responses_api_bridge_check(
and OpenAIGPT5Config.is_model_gpt_5_model(model)
and not OpenAIGPT5Config.is_model_gpt_5_search_model(model)
and ((reasoning_effort is not None and reasoning_summary is not None) or chat_rejects_function_tools)
):
) or (on_databricks_gpt_endpoint and model_info.get("mode") != "responses" and chat_rejects_function_tools):
model_info["mode"] = "responses"
model = model.replace("responses/", "")