From 1e81a1bd7c13116d2dfc8429192f7cf38ece823f Mon Sep 17 00:00:00 2001 From: Tim Elfrink Date: Sun, 17 Aug 2025 17:13:29 +0200 Subject: [PATCH 1/6] feat: Add thinking and reasoning_effort parameter support for GitHub Copilot provider - Add github_copilot case to get_supported_openai_params function - Implement get_supported_openai_params method in GithubCopilotConfig - Dynamically add thinking and reasoning_effort params for Anthropic models - Add comprehensive tests for parameter support validation - Ensure case-insensitive model detection for parameter inclusion Fixes UnsupportedParamsError when using advanced reasoning parameters with Anthropic models through GitHub Copilot proxy. --- .../get_supported_openai_params.py | 2 + .../github_copilot/chat/transformation.py | 16 ++++++++ .../test_github_copilot_transformation.py | 40 +++++++++++++++++++ 3 files changed, 58 insertions(+) diff --git a/litellm/litellm_core_utils/get_supported_openai_params.py b/litellm/litellm_core_utils/get_supported_openai_params.py index 5fcd2ddb70..e17a0a88a0 100644 --- a/litellm/litellm_core_utils/get_supported_openai_params.py +++ b/litellm/litellm_core_utils/get_supported_openai_params.py @@ -271,6 +271,8 @@ def get_supported_openai_params( # noqa: PLR0915 model=model ) ) + elif custom_llm_provider == "github_copilot": + return litellm.GithubCopilotConfig().get_supported_openai_params(model=model) elif custom_llm_provider in litellm._custom_providers: if request_type == "chat_completion": provider_config = litellm.ProviderConfigManager.get_provider_chat_config( diff --git a/litellm/llms/github_copilot/chat/transformation.py b/litellm/llms/github_copilot/chat/transformation.py index 4526e6247b..de363654fe 100644 --- a/litellm/llms/github_copilot/chat/transformation.py +++ b/litellm/llms/github_copilot/chat/transformation.py @@ -77,6 +77,22 @@ class GithubCopilotConfig(OpenAIConfig): return validated_headers + def get_supported_openai_params(self, model: str) -> list: + """ + Get supported OpenAI parameters for GitHub Copilot. + + For Anthropic models (like claude-sonnet-4), includes thinking and reasoning parameters. + For other models, returns standard OpenAI parameters. + """ + # Get base OpenAI parameters + base_params = super().get_supported_openai_params(model) + + # Add thinking and reasoning parameters for Anthropic Claude models + if "claude" in model.lower(): + base_params.extend(["thinking", "reasoning_effort"]) + + return base_params + def _determine_initiator(self, messages: List[AllMessageValues]) -> str: """ Determine if request is user or agent initiated based on message roles. diff --git a/tests/test_litellm/llms/github_copilot/test_github_copilot_transformation.py b/tests/test_litellm/llms/github_copilot/test_github_copilot_transformation.py index f21c123579..ac7046f8ce 100644 --- a/tests/test_litellm/llms/github_copilot/test_github_copilot_transformation.py +++ b/tests/test_litellm/llms/github_copilot/test_github_copilot_transformation.py @@ -362,3 +362,43 @@ def test_x_initiator_header_system_only_messages(): ) assert headers["X-Initiator"] == "user" + + +def test_get_supported_openai_params_claude_model(): + """Test that Claude models support thinking and reasoning parameters.""" + config = GithubCopilotConfig() + + # Test Claude model supports thinking and reasoning_effort parameters + supported_params = config.get_supported_openai_params("claude-sonnet-4") + assert "thinking" in supported_params + assert "reasoning_effort" in supported_params + + # Test Claude model with different naming + supported_params_claude = config.get_supported_openai_params("claude-3.5-sonnet") + assert "thinking" in supported_params_claude + assert "reasoning_effort" in supported_params_claude + + # Test non-Claude model doesn't include thinking/reasoning parameters + supported_params_gpt = config.get_supported_openai_params("gpt-4o") + assert "thinking" not in supported_params_gpt + assert "reasoning_effort" not in supported_params_gpt + + # Test with other non-Claude models + supported_params_o3 = config.get_supported_openai_params("o3-mini") + assert "thinking" not in supported_params_o3 + assert "reasoning_effort" not in supported_params_o3 + + +def test_get_supported_openai_params_case_insensitive(): + """Test that Claude model detection is case-insensitive.""" + config = GithubCopilotConfig() + + # Test uppercase + supported_params_upper = config.get_supported_openai_params("CLAUDE-SONNET-4") + assert "thinking" in supported_params_upper + assert "reasoning_effort" in supported_params_upper + + # Test mixed case + supported_params_mixed = config.get_supported_openai_params("Claude-3.5-Sonnet") + assert "thinking" in supported_params_mixed + assert "reasoning_effort" in supported_params_mixed From d92092f04003dfeaee0cff5de7eb8ed4969fd570 Mon Sep 17 00:00:00 2001 From: Tim Elfrink Date: Sun, 17 Aug 2025 17:26:59 +0200 Subject: [PATCH 2/6] formatting --- litellm/litellm_core_utils/get_supported_openai_params.py | 7 +++---- litellm/llms/github_copilot/chat/transformation.py | 6 +++--- litellm/llms/github_copilot/common_utils.py | 1 - 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/litellm/litellm_core_utils/get_supported_openai_params.py b/litellm/litellm_core_utils/get_supported_openai_params.py index e17a0a88a0..b71b609cc5 100644 --- a/litellm/litellm_core_utils/get_supported_openai_params.py +++ b/litellm/litellm_core_utils/get_supported_openai_params.py @@ -266,10 +266,9 @@ def get_supported_openai_params( # noqa: PLR0915 from litellm.llms.elevenlabs.audio_transcription.transformation import ( ElevenLabsAudioTranscriptionConfig, ) - return ( - ElevenLabsAudioTranscriptionConfig().get_supported_openai_params( - model=model - ) + + return ElevenLabsAudioTranscriptionConfig().get_supported_openai_params( + model=model ) elif custom_llm_provider == "github_copilot": return litellm.GithubCopilotConfig().get_supported_openai_params(model=model) diff --git a/litellm/llms/github_copilot/chat/transformation.py b/litellm/llms/github_copilot/chat/transformation.py index de363654fe..8ef2a54c62 100644 --- a/litellm/llms/github_copilot/chat/transformation.py +++ b/litellm/llms/github_copilot/chat/transformation.py @@ -80,17 +80,17 @@ class GithubCopilotConfig(OpenAIConfig): def get_supported_openai_params(self, model: str) -> list: """ Get supported OpenAI parameters for GitHub Copilot. - + For Anthropic models (like claude-sonnet-4), includes thinking and reasoning parameters. For other models, returns standard OpenAI parameters. """ # Get base OpenAI parameters base_params = super().get_supported_openai_params(model) - + # Add thinking and reasoning parameters for Anthropic Claude models if "claude" in model.lower(): base_params.extend(["thinking", "reasoning_effort"]) - + return base_params def _determine_initiator(self, messages: List[AllMessageValues]) -> str: diff --git a/litellm/llms/github_copilot/common_utils.py b/litellm/llms/github_copilot/common_utils.py index 4c9a4b6dad..86fbb706e5 100644 --- a/litellm/llms/github_copilot/common_utils.py +++ b/litellm/llms/github_copilot/common_utils.py @@ -28,7 +28,6 @@ class GithubCopilotError(BaseLLMException): ) - class GetDeviceCodeError(GithubCopilotError): pass From 0febdf8c1ce8e4360fcd3032110a9590f1b3fcd2 Mon Sep 17 00:00:00 2001 From: Tim Elfrink Date: Sun, 17 Aug 2025 17:51:58 +0200 Subject: [PATCH 3/6] feat: add thinking and reasoning parameter support for GitHub Copilot provider - Add dynamic parameter support for anthropic models through GitHub Copilot - Include thinking parameter for anthropic model compatibility - Support reasoning_effort parameter for both anthropic and reasoning models - Update test coverage for parameter validation logic - Ensure proper parameter filtering based on model type --- litellm/llms/github_copilot/chat/transformation.py | 10 +++++++--- .../test_github_copilot_transformation.py | 8 +++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/litellm/llms/github_copilot/chat/transformation.py b/litellm/llms/github_copilot/chat/transformation.py index 8ef2a54c62..e71e9b610b 100644 --- a/litellm/llms/github_copilot/chat/transformation.py +++ b/litellm/llms/github_copilot/chat/transformation.py @@ -82,14 +82,18 @@ class GithubCopilotConfig(OpenAIConfig): Get supported OpenAI parameters for GitHub Copilot. For Anthropic models (like claude-sonnet-4), includes thinking and reasoning parameters. - For other models, returns standard OpenAI parameters. + For other models, returns standard OpenAI parameters (which may include reasoning_effort for o-series models). """ # Get base OpenAI parameters base_params = super().get_supported_openai_params(model) - # Add thinking and reasoning parameters for Anthropic Claude models + # Add Claude-specific parameters for Anthropic models if "claude" in model.lower(): - base_params.extend(["thinking", "reasoning_effort"]) + if "thinking" not in base_params: + base_params.append("thinking") + # reasoning_effort is not included by parent for Claude models, so add it + if "reasoning_effort" not in base_params: + base_params.append("reasoning_effort") return base_params diff --git a/tests/test_litellm/llms/github_copilot/test_github_copilot_transformation.py b/tests/test_litellm/llms/github_copilot/test_github_copilot_transformation.py index ac7046f8ce..d389c44552 100644 --- a/tests/test_litellm/llms/github_copilot/test_github_copilot_transformation.py +++ b/tests/test_litellm/llms/github_copilot/test_github_copilot_transformation.py @@ -378,15 +378,17 @@ def test_get_supported_openai_params_claude_model(): assert "thinking" in supported_params_claude assert "reasoning_effort" in supported_params_claude - # Test non-Claude model doesn't include thinking/reasoning parameters + # Test non-Claude model doesn't include thinking parameters but may include reasoning_effort supported_params_gpt = config.get_supported_openai_params("gpt-4o") assert "thinking" not in supported_params_gpt + # gpt-4o should NOT have reasoning_effort (not a reasoning model) assert "reasoning_effort" not in supported_params_gpt - # Test with other non-Claude models + # Test O-series reasoning models include reasoning_effort but not thinking supported_params_o3 = config.get_supported_openai_params("o3-mini") assert "thinking" not in supported_params_o3 - assert "reasoning_effort" not in supported_params_o3 + # o3-mini should have reasoning_effort (it's an O-series reasoning model) + assert "reasoning_effort" in supported_params_o3 def test_get_supported_openai_params_case_insensitive(): From 8b66b50c31809eae4f5efe80d3dddaab94951841 Mon Sep 17 00:00:00 2001 From: Tim Elfrink Date: Tue, 19 Aug 2025 08:15:50 +0200 Subject: [PATCH 4/6] fix: restrict thinking/reasoning_effort parameters to models with extended thinking support Only models in the 4 family and 3-7 family support extended thinking features. Previously all models would incorrectly receive these parameters. Now uses supports_reasoning() to check model registry for actual capability. --- litellm/llms/github_copilot/chat/transformation.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/litellm/llms/github_copilot/chat/transformation.py b/litellm/llms/github_copilot/chat/transformation.py index e71e9b610b..2aab0207ca 100644 --- a/litellm/llms/github_copilot/chat/transformation.py +++ b/litellm/llms/github_copilot/chat/transformation.py @@ -81,14 +81,19 @@ class GithubCopilotConfig(OpenAIConfig): """ Get supported OpenAI parameters for GitHub Copilot. - For Anthropic models (like claude-sonnet-4), includes thinking and reasoning parameters. + For Claude models that support extended thinking (Claude 4 family and Claude 3-7), includes thinking and reasoning_effort parameters. For other models, returns standard OpenAI parameters (which may include reasoning_effort for o-series models). """ + from litellm.utils import supports_reasoning + # Get base OpenAI parameters base_params = super().get_supported_openai_params(model) - # Add Claude-specific parameters for Anthropic models - if "claude" in model.lower(): + # Add Claude-specific parameters for models that support extended thinking + if "claude" in model.lower() and supports_reasoning( + model=model, + custom_llm_provider="github_copilot", + ): if "thinking" not in base_params: base_params.append("thinking") # reasoning_effort is not included by parent for Claude models, so add it From 9f82b89051bb2ef5d9938493e8a93b45b1346c23 Mon Sep 17 00:00:00 2001 From: Tim Elfrink Date: Tue, 19 Aug 2025 08:21:18 +0200 Subject: [PATCH 5/6] fix: remove redundant github_copilot check in get_supported_openai_params The provider_config_manager already handles github_copilot provider through LlmProviders.GITHUB_COPILOT mapping, making the explicit check unnecessary. --- litellm/litellm_core_utils/get_supported_openai_params.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/litellm/litellm_core_utils/get_supported_openai_params.py b/litellm/litellm_core_utils/get_supported_openai_params.py index b71b609cc5..35a3af0939 100644 --- a/litellm/litellm_core_utils/get_supported_openai_params.py +++ b/litellm/litellm_core_utils/get_supported_openai_params.py @@ -270,8 +270,6 @@ def get_supported_openai_params( # noqa: PLR0915 return ElevenLabsAudioTranscriptionConfig().get_supported_openai_params( model=model ) - elif custom_llm_provider == "github_copilot": - return litellm.GithubCopilotConfig().get_supported_openai_params(model=model) elif custom_llm_provider in litellm._custom_providers: if request_type == "chat_completion": provider_config = litellm.ProviderConfigManager.get_provider_chat_config( From 9b0fda7b14c3c6237b78e201d5537bce93efb25b Mon Sep 17 00:00:00 2001 From: Tim Elfrink Date: Tue, 19 Aug 2025 08:40:10 +0200 Subject: [PATCH 6/6] fix: resolve case sensitivity and test failures for extended thinking support - Fix supports_reasoning() call to use lowercase model names for proper lookup - Remove custom_llm_provider parameter as model registry entries are provider-agnostic - Update tests to use full model names with date stamps (required for supports_reasoning) - Add test coverage for models without extended thinking support --- .../github_copilot/chat/transformation.py | 3 +- .../test_github_copilot_transformation.py | 34 ++++++++++++------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/litellm/llms/github_copilot/chat/transformation.py b/litellm/llms/github_copilot/chat/transformation.py index 2aab0207ca..65f83c178a 100644 --- a/litellm/llms/github_copilot/chat/transformation.py +++ b/litellm/llms/github_copilot/chat/transformation.py @@ -91,8 +91,7 @@ class GithubCopilotConfig(OpenAIConfig): # Add Claude-specific parameters for models that support extended thinking if "claude" in model.lower() and supports_reasoning( - model=model, - custom_llm_provider="github_copilot", + model=model.lower(), ): if "thinking" not in base_params: base_params.append("thinking") diff --git a/tests/test_litellm/llms/github_copilot/test_github_copilot_transformation.py b/tests/test_litellm/llms/github_copilot/test_github_copilot_transformation.py index d389c44552..96da5fb942 100644 --- a/tests/test_litellm/llms/github_copilot/test_github_copilot_transformation.py +++ b/tests/test_litellm/llms/github_copilot/test_github_copilot_transformation.py @@ -365,18 +365,23 @@ def test_x_initiator_header_system_only_messages(): def test_get_supported_openai_params_claude_model(): - """Test that Claude models support thinking and reasoning parameters.""" + """Test that Claude models with extended thinking support have thinking and reasoning parameters.""" config = GithubCopilotConfig() - # Test Claude model supports thinking and reasoning_effort parameters - supported_params = config.get_supported_openai_params("claude-sonnet-4") + # Test Claude 4 model supports thinking and reasoning_effort parameters + supported_params = config.get_supported_openai_params("claude-sonnet-4-20250514") assert "thinking" in supported_params assert "reasoning_effort" in supported_params - # Test Claude model with different naming - supported_params_claude = config.get_supported_openai_params("claude-3.5-sonnet") - assert "thinking" in supported_params_claude - assert "reasoning_effort" in supported_params_claude + # Test Claude 3-7 model supports thinking and reasoning_effort parameters + supported_params_claude37 = config.get_supported_openai_params("claude-3-7-sonnet-20250219") + assert "thinking" in supported_params_claude37 + assert "reasoning_effort" in supported_params_claude37 + + # Test Claude 3.5 model does NOT support thinking parameters (no extended thinking) + supported_params_claude35 = config.get_supported_openai_params("claude-3.5-sonnet") + assert "thinking" not in supported_params_claude35 + assert "reasoning_effort" not in supported_params_claude35 # Test non-Claude model doesn't include thinking parameters but may include reasoning_effort supported_params_gpt = config.get_supported_openai_params("gpt-4o") @@ -392,15 +397,20 @@ def test_get_supported_openai_params_claude_model(): def test_get_supported_openai_params_case_insensitive(): - """Test that Claude model detection is case-insensitive.""" + """Test that Claude model detection is case-insensitive for models with extended thinking.""" config = GithubCopilotConfig() - # Test uppercase - supported_params_upper = config.get_supported_openai_params("CLAUDE-SONNET-4") + # Test uppercase Claude 4 model with full model name + supported_params_upper = config.get_supported_openai_params("CLAUDE-SONNET-4-20250514") assert "thinking" in supported_params_upper assert "reasoning_effort" in supported_params_upper - # Test mixed case - supported_params_mixed = config.get_supported_openai_params("Claude-3.5-Sonnet") + # Test mixed case Claude 3-7 model (has extended thinking) with full model name + supported_params_mixed = config.get_supported_openai_params("Claude-3-7-Sonnet-20250219") assert "thinking" in supported_params_mixed assert "reasoning_effort" in supported_params_mixed + + # Test that Claude 3.5 models don't have thinking support (case insensitive) + supported_params_35 = config.get_supported_openai_params("CLAUDE-3.5-SONNET") + assert "thinking" not in supported_params_35 + assert "reasoning_effort" not in supported_params_35