fix(databricks): accept Reasoning(effort=..., summary=...) dict in reasoning_effort

The Responses->Chat parser keeps reasoning_effort as a dict whenever
summary is set (#28196), so DatabricksConfig.map_openai_params hands a
dict to AnthropicConfig._map_reasoning_effort and no thinking payload is
produced. Coerce the dict to its effort value first, matching what the
direct Anthropic and Bedrock Converse adapters already do.

Signed-off-by: Chenglun Hu <chenglunhu@gmail.com>
This commit is contained in:
Chenglun Hu 2026-09-25 09:32:20 +08:00
parent 25fb7810c2
commit 6793eb54d6
2 changed files with 26 additions and 2 deletions

View file

@ -387,7 +387,15 @@ class DatabricksConfig(DatabricksBase, OpenAILikeChatConfig, AnthropicConfig):
) # unsupported for claude models - if json_schema -> convert to tool call
if "reasoning_effort" in non_default_params and self._uses_anthropic_thinking_param(model):
reasoning_effort_value: Final = non_default_params.get("reasoning_effort")
reasoning_effort_value = non_default_params.get("reasoning_effort")
# Accept both the string form ("low") and the dict form
# ({"effort": "low", "summary": "concise"}). The Responses->Chat
# parser keeps the full dict whenever `summary` is set (#28196),
# so a dict is the standard shape Responses-bridge callers send.
# Same coercion the direct Anthropic and Bedrock Converse
# adapters already do.
if isinstance(reasoning_effort_value, dict):
reasoning_effort_value = reasoning_effort_value.get("effort")
mapped_thinking: Final = AnthropicConfig._map_reasoning_effort(
reasoning_effort=reasoning_effort_value,
model=model,

View file

@ -544,7 +544,7 @@ def test_map_openai_params_upgrades_legacy_thinking_on_adaptive_only_claude(
assert mapped.get("output_config") == expected_output_config
def _map_reasoning_effort(model: str, reasoning_effort: str):
def _map_reasoning_effort(model: str, reasoning_effort: str | dict):
return DatabricksConfig().map_openai_params(
non_default_params={"reasoning_effort": reasoning_effort},
optional_params={},
@ -578,6 +578,22 @@ def test_unmapped_claude_endpoint_still_translates(_use_local_model_cost_map):
assert "reasoning_effort" not in params
@pytest.mark.parametrize(
"model",
["databricks-claude-3-7-sonnet", "my-claude-serving-endpoint"],
)
def test_reasoning_effort_dict_is_coerced(_use_local_model_cost_map, model):
"""The Responses->Chat parser keeps `reasoning_effort` as a dict whenever
`summary` is set (#28196). Without coercion the dict reaches
`_map_reasoning_effort` and no thinking payload is produced."""
params = _map_reasoning_effort(model, {"effort": "low", "summary": "concise"})
assert params.get("thinking") == {
"type": "enabled",
"budget_tokens": DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET,
}
assert "reasoning_effort" not in params
def test_gemini_2_5_low_translates_to_thinking_budget(_use_local_model_cost_map):
params = _map_reasoning_effort("databricks-gemini-2-5-flash", "low")
assert params.get("thinking") == {