mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-11 22:51:28 +00:00
fix(github_copilot): forward Claude thinking and reasoning_effort in map_openai_params
get_supported_openai_params advertised thinking and reasoning_effort for extended-thinking Claude models, but map_openai_params was never overridden. OpenAIConfig routes non-o-series/non-gpt-5 models to OpenAIGPTConfig, whose supported-param whitelist contains neither key, so both were dropped during mapping and never reached the Copilot API. Fixes #25666
This commit is contained in:
parent
09889e1986
commit
1c1c96441f
2 changed files with 90 additions and 0 deletions
|
|
@ -17,6 +17,8 @@ from ..common_utils import (
|
|||
get_copilot_default_headers,
|
||||
)
|
||||
|
||||
_CLAUDE_REASONING_PARAMS: Final = frozenset({"thinking", "reasoning_effort"})
|
||||
|
||||
|
||||
class GithubCopilotConfig(OpenAIConfig):
|
||||
def __init__(
|
||||
|
|
@ -134,6 +136,26 @@ class GithubCopilotConfig(OpenAIConfig):
|
|||
|
||||
return base_params
|
||||
|
||||
def map_openai_params(
|
||||
self,
|
||||
non_default_params: dict,
|
||||
optional_params: dict,
|
||||
model: str,
|
||||
drop_params: bool,
|
||||
) -> dict:
|
||||
# OpenAIConfig routes non-o-series/non-gpt-5 models to OpenAIGPTConfig, whose
|
||||
# whitelist has neither key, so advertising them alone dropped them (#25666)
|
||||
supported: Final = frozenset(self.get_supported_openai_params(model)) & _CLAUDE_REASONING_PARAMS
|
||||
claude_params: Final = {k: v for k, v in non_default_params.items() if k in supported}
|
||||
remaining: Final = {k: v for k, v in non_default_params.items() if k not in supported}
|
||||
|
||||
return super().map_openai_params(
|
||||
non_default_params=remaining,
|
||||
optional_params={**optional_params, **claude_params},
|
||||
model=model,
|
||||
drop_params=drop_params,
|
||||
)
|
||||
|
||||
def _determine_initiator(self, messages: list[AllMessageValues]) -> str:
|
||||
"""
|
||||
Determine if request is user or agent initiated based on message roles.
|
||||
|
|
|
|||
|
|
@ -982,3 +982,71 @@ def test_openai_handler_repairs_github_copilot_empty_choices(
|
|||
assert result.choices[0].message.content == "Hi there"
|
||||
assert result.choices[0].finish_reason == "stop"
|
||||
mock_request.assert_called_once()
|
||||
|
||||
|
||||
def test_map_openai_params_forwards_reasoning_effort_for_claude():
|
||||
"""Claude reasoning params must survive map_openai_params, not just be advertised.
|
||||
|
||||
Regression test for the gap behind #25666: GithubCopilotConfig overrode
|
||||
get_supported_openai_params() to advertise ``thinking``/``reasoning_effort``
|
||||
for extended-thinking Claude models, but never overrode map_openai_params().
|
||||
Mapping therefore fell through to OpenAIConfig -> OpenAIGPTConfig, whose
|
||||
supported-param whitelist has neither key, so both were silently discarded
|
||||
and never reached the Copilot API. The advertise-only assertions in
|
||||
test_get_supported_openai_params_claude_model passed the whole time, because
|
||||
they never inspect the mapped output.
|
||||
"""
|
||||
config = GithubCopilotConfig()
|
||||
model = "claude-sonnet-4-20250514"
|
||||
|
||||
# Guard the premise: the param is advertised as supported for this model.
|
||||
assert "reasoning_effort" in config.get_supported_openai_params(model)
|
||||
|
||||
mapped = config.map_openai_params(
|
||||
non_default_params={"reasoning_effort": "high"},
|
||||
optional_params={},
|
||||
model=model,
|
||||
drop_params=False,
|
||||
)
|
||||
assert mapped.get("reasoning_effort") == "high"
|
||||
|
||||
mapped_thinking = config.map_openai_params(
|
||||
non_default_params={"thinking": {"type": "enabled", "budget_tokens": 4096}},
|
||||
optional_params={},
|
||||
model=model,
|
||||
drop_params=False,
|
||||
)
|
||||
assert mapped_thinking.get("thinking") == {
|
||||
"type": "enabled",
|
||||
"budget_tokens": 4096,
|
||||
}
|
||||
|
||||
|
||||
def test_map_openai_params_does_not_forward_reasoning_for_unsupported_claude():
|
||||
"""A Claude model without extended thinking must not gain reasoning params."""
|
||||
config = GithubCopilotConfig()
|
||||
model = "claude-3.5-sonnet"
|
||||
|
||||
assert "reasoning_effort" not in config.get_supported_openai_params(model)
|
||||
|
||||
mapped = config.map_openai_params(
|
||||
non_default_params={"reasoning_effort": "high"},
|
||||
optional_params={},
|
||||
model=model,
|
||||
drop_params=True,
|
||||
)
|
||||
assert "reasoning_effort" not in mapped
|
||||
|
||||
|
||||
def test_map_openai_params_preserves_standard_openai_params_for_claude():
|
||||
"""The Claude passthrough must not regress ordinary OpenAI param mapping."""
|
||||
config = GithubCopilotConfig()
|
||||
|
||||
mapped = config.map_openai_params(
|
||||
non_default_params={"temperature": 0.5, "max_tokens": 128},
|
||||
optional_params={},
|
||||
model="claude-sonnet-4-20250514",
|
||||
drop_params=False,
|
||||
)
|
||||
assert mapped.get("temperature") == 0.5
|
||||
assert mapped.get("max_tokens") == 128
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue