fix(databricks): validate reasoning_effort and set output_config on adaptive Claude

The Databricks path called `AnthropicConfig._map_reasoning_effort` for
Claude models but never validated the effort string nor set
`output_config.effort` for adaptive models (Claude 4.6/4.7). Since
`_map_reasoning_effort` returns `type=adaptive` for ANY non-None /
non-"none" string on adaptive models (including "disabled",
"invalid", ""), Databricks silently accepted garbage and emitted a
request without an `output_config.effort`, collapsing every adaptive
tier to identical behavior.

Match the Anthropic native, Bedrock Converse, Bedrock Invoke, and
/v1/messages paths: when the resolved `thinking` is non-None on a
4.6/4.7 model, look up the value in
`REASONING_EFFORT_TO_OUTPUT_CONFIG_EFFORT` and either raise a clean
`BadRequestError` or set `optional_params["output_config"]`.
This commit is contained in:
Cursor Agent
2026-05-03 17:30:26 +00:00
parent 108b87fb24
commit 1a10746e95
+36 -3
View File
@@ -21,6 +21,7 @@ from typing import (
import httpx
from pydantic import BaseModel
import litellm
from litellm.constants import RESPONSE_FORMAT_TOOL_NAME
from litellm.litellm_core_utils.llm_response_utils.convert_dict_to_response import (
_handle_invalid_parallel_tool_calls,
@@ -56,7 +57,10 @@ from litellm.types.utils import (
Usage,
)
from ...anthropic.chat.transformation import AnthropicConfig
from ...anthropic.chat.transformation import (
REASONING_EFFORT_TO_OUTPUT_CONFIG_EFFORT,
AnthropicConfig,
)
from ...openai_like.chat.transformation import OpenAILikeChatConfig
from ..common_utils import DatabricksBase, DatabricksException
@@ -335,11 +339,40 @@ class DatabricksConfig(DatabricksBase, OpenAILikeChatConfig, AnthropicConfig):
# so the surfaced error carries the correct provider name (the
# default is ``"anthropic"``, which would mislead users routing
# via Databricks Foundation Model APIs).
optional_params["thinking"] = AnthropicConfig._map_reasoning_effort(
reasoning_effort=non_default_params.get("reasoning_effort"),
reasoning_effort_value = non_default_params.get("reasoning_effort")
mapped_thinking = AnthropicConfig._map_reasoning_effort(
reasoning_effort=reasoning_effort_value,
model=model,
llm_provider="databricks",
)
if mapped_thinking is None:
optional_params.pop("thinking", None)
optional_params.pop("output_config", None)
else:
optional_params["thinking"] = mapped_thinking
# For Claude 4.6/4.7 adaptive models, ``_map_reasoning_effort``
# returns ``type=adaptive`` for ANY non-None / non-"none"
# string without validating the value, so reject unmapped
# efforts here and set ``output_config.effort`` (matching the
# Anthropic native / Bedrock Converse / Bedrock Invoke /
# /v1/messages paths).
if AnthropicConfig._is_claude_4_6_model(
model
) or AnthropicConfig._is_claude_4_7_model(model):
mapped_effort = REASONING_EFFORT_TO_OUTPUT_CONFIG_EFFORT.get(
reasoning_effort_value
)
if mapped_effort is None:
raise litellm.exceptions.BadRequestError(
message=(
f"Invalid reasoning_effort: {reasoning_effort_value!r}. "
f"Must be one of: 'minimal', 'low', "
f"'medium', 'high', 'xhigh', 'max', 'none'"
),
model=model,
llm_provider="databricks",
)
optional_params["output_config"] = {"effort": mapped_effort}
optional_params.pop("reasoning_effort", None)
## handle thinking tokens
self.update_optional_params_with_thinking_tokens(