mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
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 <noreply@anthropic.com>
This commit is contained in:
parent
785f53f2ec
commit
3f79f15764
2 changed files with 40 additions and 37 deletions
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue