-
-
Notifications
You must be signed in to change notification settings - Fork 11.6k
feat(github_copilot): route /v1/messages to Copilot native Anthropic endpoint #31802
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
mateo-berri
merged 9 commits into
litellm_internal_staging
from
litellm_copilot_anthropic_messages_native
Jul 2, 2026
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
e98610e
feat(github_copilot): route /v1/messages to Copilot native Anthropic …
ririnto 538c801
fix(github_copilot): address PR review feedback
ririnto c1ffdca
style(github_copilot): apply black formatting
ririnto 88ef136
test(github_copilot): cover ProviderConfigManager dispatch for Anthro…
ririnto 518b0a1
fix(github_copilot): apply messages-proxy intent header to /v1/messages
ririnto 0e0eff9
fix(github_copilot): use modern generic annotations
ririnto ada5fcc
refactor(github_copilot): decouple web-search short-circuit and harde…
mateo-berri 210bc94
fix(github_copilot): forward anthropic-beta headers on /v1/messages
cursoragent 54bff77
test(github_copilot): remove dead branch in beta-header regression test
mateo-berri File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| from typing import Any, Optional | ||
|
|
||
| from litellm.exceptions import AuthenticationError | ||
| from litellm.llms.anthropic.experimental_pass_through.messages.transformation import ( | ||
| AnthropicMessagesConfig, | ||
| ) | ||
|
|
||
| from ..authenticator import Authenticator | ||
| from ..common_utils import ( | ||
| DEFAULT_GITHUB_COPILOT_API_BASE, | ||
| GetAPIKeyError, | ||
| get_copilot_default_headers, | ||
| ) | ||
|
|
||
| _MESSAGES_PROXY_API_VERSION = "2026-06-01" | ||
|
|
||
|
|
||
| class GithubCopilotAnthropicMessagesConfig(AnthropicMessagesConfig): | ||
| """ | ||
| GitHub Copilot implementation of Anthropic messages API. | ||
| Routes requests to Copilot's /v1/messages endpoint with appropriate authentication and headers. | ||
| """ | ||
|
|
||
| def __init__(self) -> None: | ||
| super().__init__() | ||
| self.authenticator = Authenticator() | ||
|
|
||
| def handles_web_search_natively(self) -> bool: | ||
| """ | ||
| Copilot's /v1/messages endpoint does not execute ``web_search`` tools, so | ||
| the interception handler must short-circuit web-search-only requests | ||
| instead of routing them here. | ||
| """ | ||
| return False | ||
|
|
||
| def should_filter_anthropic_beta_headers(self) -> bool: | ||
| """ | ||
| Copilot's /v1/messages is a native Anthropic Messages passthrough, so | ||
| ``anthropic-beta`` values injected by ``_update_headers_with_anthropic_beta`` | ||
| (context_management, structured outputs, ...) must reach the upstream | ||
| verbatim. The default provider-scoped filter would drop them because | ||
| github_copilot has no entry in ``anthropic_beta_headers_config.json``. | ||
| """ | ||
| return False | ||
|
|
||
| def validate_anthropic_messages_environment( | ||
| self, | ||
| headers: dict, | ||
| model: str, | ||
| messages: list[Any], | ||
| optional_params: dict, | ||
| litellm_params: dict, | ||
| api_key: Optional[str] = None, | ||
| api_base: Optional[str] = None, | ||
| ) -> tuple[dict, Optional[str]]: | ||
| """ | ||
| Validate environment for GitHub Copilot and add Copilot-specific headers. | ||
|
|
||
| The caller-supplied ``api_base`` is intentionally ignored. Routing this | ||
| request anywhere other than the authenticated Copilot endpoint would | ||
| leak the Copilot bearer token to a caller-controlled URL. | ||
| """ | ||
| # Always use the Copilot endpoint resolved from the authenticated | ||
| # session, never the caller-supplied api_base. rstrip so a | ||
| # tenant-specific base with a trailing slash does not yield a | ||
| # double-slash URL once "/v1/messages" is appended downstream. | ||
| dynamic_api_base = (self.authenticator.get_api_base() or DEFAULT_GITHUB_COPILOT_API_BASE).rstrip("/") | ||
| try: | ||
| dynamic_api_key = self.authenticator.get_api_key() | ||
| except GetAPIKeyError as e: | ||
| raise AuthenticationError( | ||
| model=model, | ||
| llm_provider="github_copilot", | ||
| message=str(e), | ||
| ) | ||
|
|
||
| # Merge Copilot headers with provided headers | ||
| copilot_headers = get_copilot_default_headers(dynamic_api_key) | ||
| for key, value in copilot_headers.items(): | ||
| if key not in headers: | ||
| headers[key] = value | ||
|
|
||
| headers["openai-intent"] = "messages-proxy" | ||
| headers["x-interaction-type"] = "messages-proxy" | ||
| headers["x-github-api-version"] = _MESSAGES_PROXY_API_VERSION | ||
|
|
||
| if "anthropic-version" not in headers: | ||
| headers["anthropic-version"] = "2023-06-01" | ||
|
|
||
| headers = self._update_headers_with_anthropic_beta( | ||
| headers, optional_params, custom_llm_provider="github_copilot" | ||
| ) | ||
|
|
||
| return headers, dynamic_api_base | ||
|
|
||
| def get_complete_url( | ||
| self, | ||
| api_base: Optional[str], | ||
| api_key: Optional[str], | ||
| model: str, | ||
| optional_params: dict, | ||
| litellm_params: dict, | ||
| stream: Optional[bool] = None, | ||
| ) -> str: | ||
| """ | ||
| Return the complete URL for GitHub Copilot /v1/messages endpoint. | ||
|
|
||
| ``api_base`` here is the value already resolved by | ||
| ``validate_anthropic_messages_environment`` (the authenticated Copilot | ||
| host), not the raw caller-supplied base — that one is discarded there to | ||
| avoid leaking the Copilot bearer token to a caller-controlled URL. We | ||
| reuse it to avoid a second authenticator read, falling back to a fresh | ||
| resolution only if it was not provided. | ||
| """ | ||
| resolved = (api_base or self.authenticator.get_api_base() or DEFAULT_GITHUB_COPILOT_API_BASE).rstrip("/") | ||
| if not resolved.endswith("/v1/messages"): | ||
| resolved = f"{resolved}/v1/messages" | ||
| return resolved | ||
|
greptile-apps[bot] marked this conversation as resolved.
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.