From 3f79f15764005ddb5b72c88ad624f6a9f0af4fca Mon Sep 17 00:00:00 2001 From: jtstothard Date: Tue, 21 Apr 2026 16:30:12 +0100 Subject: [PATCH] fix: resolve Greptile P0 issues for GitHub Copilot premium billing This commit addresses both P0 issues flagged in Greptile review to achieve 5/5 score (currently 4/5). **P0 Issue #1: Responses API X-Initiator never set** Root cause: The X-Initiator header was being set in validate_environment(), which doesn't have access to the `input` parameter. The _get_input_from_params() helper checked for `litellm_params.input`, but this attribute doesn't exist in GenericLiteLLMParams - the `input` parameter is passed separately to transform_responses_api_request(). Fix: Moved X-Initiator and vision header logic from validate_environment() to transform_responses_api_request() where the `input` parameter is available. This ensures the header is correctly set for Responses API requests. Changes: - Added transform_responses_api_request() override in GithubCopilotResponsesAPIConfig that: 1. Calculates X-Initiator based on input analysis 2. Adds copilot-vision-request header if images detected 3. Calls parent to validate input and handle reasoning items - Removed broken _get_input_from_params() helper - Simplified validate_environment() docstring and removed duplicate logic **P0 Issue #2: Integration test in wrong location** Root cause: tests/llm_translation/test_github_copilot_billing.py makes real network calls via litellm.completion(), violating the repository rule that tests/llm_translation/ is for mock-only tests. Fix: Moved test file to tests/llm_responses_api_testing/ which is the designated directory for integration tests that make real API calls. Impact: - Responses API requests now correctly set X-Initiator header - Multi-turn agentic workflows (Plan mode, tool calls, agent flows) will only consume 1 premium request per session instead of 1 per turn - Integration tests now in proper location per repository conventions Co-Authored-By: Claude Sonnet 4.6 --- .../responses/transformation.py | 77 ++++++++++--------- .../test_github_copilot_billing.py | 0 2 files changed, 40 insertions(+), 37 deletions(-) rename tests/{llm_translation => llm_responses_api_testing}/test_github_copilot_billing.py (100%) diff --git a/litellm/llms/github_copilot/responses/transformation.py b/litellm/llms/github_copilot/responses/transformation.py index 58778b148d4..948e2b9e118 100644 --- a/litellm/llms/github_copilot/responses/transformation.py +++ b/litellm/llms/github_copilot/responses/transformation.py @@ -88,6 +88,44 @@ class GithubCopilotResponsesAPIConfig(OpenAIResponsesAPIConfig): """ return dict(response_api_optional_params) + def transform_responses_api_request( + self, + model: str, + input: Union[str, ResponseInputParam], + response_api_optional_request_params: Dict, + litellm_params: GenericLiteLLMParams, + headers: dict, + ) -> Dict: + """ + Transform the Responses API request and set X-Initiator header. + + GitHub Copilot requires X-Initiator header based on input analysis. + This is set here (not in validate_environment) because only this method + has access to the input parameter. + """ + # Add X-Initiator header based on input analysis + initiator = self._get_initiator(input) + headers["X-Initiator"] = initiator + verbose_logger.debug( + f"GitHub Copilot Responses API: Set X-Initiator={initiator}" + ) + + # Add vision header if input contains images + if self._has_vision_input(input): + headers["copilot-vision-request"] = "true" + verbose_logger.debug( + "GitHub Copilot Responses API: Enabled vision request" + ) + + # Call parent to get request body (validates input, handles reasoning items) + return super().transform_responses_api_request( + model=model, + input=input, + response_api_optional_request_params=response_api_optional_request_params, + litellm_params=litellm_params, + headers=headers, + ) + def validate_environment( self, headers: dict, @@ -139,23 +177,8 @@ class GithubCopilotResponsesAPIConfig(OpenAIResponsesAPIConfig): # Merge with existing headers (user's extra_headers take priority) merged_headers = {**default_headers, **headers} - # Analyze input to determine additional headers - input_param = self._get_input_from_params(litellm_params) - - # Add X-Initiator header based on input analysis - if input_param is not None: - initiator = self._get_initiator(input_param) - merged_headers["X-Initiator"] = initiator - verbose_logger.debug( - f"GitHub Copilot Responses API: Set X-Initiator={initiator}" - ) - - # Add vision header if input contains images - if self._has_vision_input(input_param): - merged_headers["copilot-vision-request"] = "true" - verbose_logger.debug( - "GitHub Copilot Responses API: Enabled vision request" - ) + # X-Initiator and vision headers are set in transform_responses_api_request + # where we have access to the input parameter verbose_logger.debug( f"GitHub Copilot Responses API: Successfully configured headers for model {model}" @@ -232,26 +255,6 @@ class GithubCopilotResponsesAPIConfig(OpenAIResponsesAPIConfig): # ==================== Helper Methods ==================== - def _get_input_from_params( - self, litellm_params: Optional[GenericLiteLLMParams] - ) -> Optional[Union[str, ResponseInputParam]]: - """ - Extract input parameter from litellm_params. - - The input parameter contains the conversation history and is needed - for vision detection and initiator determination. - """ - if litellm_params is None: - return None - - # Try to get input from litellm_params - # This might be in different locations depending on how LiteLLM structures it - if hasattr(litellm_params, "input"): - return litellm_params.input - - # If not found, return None and let the API handle it - return None - def _get_initiator(self, input_param: Union[str, ResponseInputParam]) -> str: """ Determine X-Initiator header value based on input analysis. diff --git a/tests/llm_translation/test_github_copilot_billing.py b/tests/llm_responses_api_testing/test_github_copilot_billing.py similarity index 100% rename from tests/llm_translation/test_github_copilot_billing.py rename to tests/llm_responses_api_testing/test_github_copilot_billing.py