Merge pull request #13955 from ckoehler/push-oymwkvxmkqxv

feat: add image headers for Copilot
This commit is contained in:
Krish Dholakia 2025-08-25 23:04:24 -07:00 • committed by GitHub
commit b1bc8e3aa2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 124 additions and 0 deletions

View file

@ -75,6 +75,10 @@ class GithubCopilotConfig(OpenAIConfig):
initiator = self._determine_initiator(messages)
validated_headers["X-Initiator"] = initiator
# Add Copilot-Vision-Request header if request contains images
if self._has_vision_content(messages):
validated_headers["Copilot-Vision-Request"] = "true"
return validated_headers
def _determine_initiator(self, messages: List[AllMessageValues]) -> str:
@ -87,3 +91,27 @@ class GithubCopilotConfig(OpenAIConfig):
if role in ["tool", "assistant"]:
return "agent"
return "user"
def _has_vision_content(self, messages: List[AllMessageValues]) -> bool:
"""
Check if any message contains vision content (images).
Returns True if any message has content with vision-related types, otherwise False.
Checks for:
- image_url content type (OpenAI format)
- Content items with type 'image_url'
"""
for message in messages:
content = message.get("content")
if isinstance(content, list):
# Check if any content item indicates vision content
for content_item in content:
if isinstance(content_item, dict):
# Check for image_url field (direct image URL)
if "image_url" in content_item:
return True
# Check for type field indicating image content
content_type = content_item.get("type")
if content_type == "image_url":
return True
return False

View file

@ -362,3 +362,99 @@ def test_x_initiator_header_system_only_messages():
)
assert headers["X-Initiator"] == "user"
def test_copilot_vision_request_header_with_image():
"""Test that Copilot-Vision-Request header is added when messages contain images"""
config = GithubCopilotConfig()
# Mock the authenticator
config.authenticator = MagicMock()
config.authenticator.get_api_key.return_value = "gh.test-key-123"
config.authenticator.get_api_base.return_value = None
messages = [
{
"role": "user",
"content": [
{"type": "text", "text": "What's in this image?"},
{
"type": "image_url",
"image_url": {"url": "data:image/jpeg;base64,abc123"}
}
]
}
]
headers = config.validate_environment(
headers={},
model="github_copilot/gpt-4-vision-preview",
messages=messages,
optional_params={},
litellm_params={},
api_key=None,
api_base=None,
)
assert headers["Copilot-Vision-Request"] == "true"
assert headers["X-Initiator"] == "user"
def test_copilot_vision_request_header_text_only():
"""Test that Copilot-Vision-Request header is not added for text-only messages"""
config = GithubCopilotConfig()
# Mock the authenticator
config.authenticator = MagicMock()
config.authenticator.get_api_key.return_value = "gh.test-key-123"
config.authenticator.get_api_base.return_value = None
messages = [
{"role": "user", "content": "Just a text message"},
]
headers = config.validate_environment(
headers={},
model="github_copilot/gpt-4",
messages=messages,
optional_params={},
litellm_params={},
api_key=None,
api_base=None,
)
assert "Copilot-Vision-Request" not in headers
assert headers["X-Initiator"] == "user"
def test_copilot_vision_request_header_with_type_image_url():
"""Test that Copilot-Vision-Request header is added for content with type: image_url"""
config = GithubCopilotConfig()
# Mock the authenticator
config.authenticator = MagicMock()
config.authenticator.get_api_key.return_value = "gh.test-key-123"
config.authenticator.get_api_base.return_value = None
messages = [
{
"role": "user",
"content": [
{"type": "text", "text": "Analyze this image"},
{"type": "image_url", "image_url": {"url": "https://example.com/image.jpg"}}
]
}
]
headers = config.validate_environment(
headers={},
model="github_copilot/gpt-4-vision-preview",
messages=messages,
optional_params={},
litellm_params={},
api_key=None,
api_base=None,
)
assert headers["Copilot-Vision-Request"] == "true"
assert headers["X-Initiator"] == "user"