chore(github_copilot): sync model catalog with Copilot's served models (#45386)

* chore(github_copilot): sync model catalog with Copilot's served models

* test(github_copilot): assert catalog invariants instead of pinning vendor facts

* fix(github_copilot): keep thinking capabilities on served Claude catalog rows

* fix(github_copilot): keep supports_reasoning on catalog rows that shadow the family fallback

* fix(model-catalog): preserve merged Copilot Haiku metadata

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Yassin Kortam 2026-10-09 15:19:08 -07:00 • committed by GitHub
parent d36b66e19e
commit d1945f69da
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 828 additions and 319 deletions

View file

@ -31293,6 +31293,42 @@
"video"
]
},
"github_copilot/claude-fable-5": {
"litellm_provider": "github_copilot",
"max_input_tokens": 200000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/messages"
],
"supports_adaptive_thinking": true,
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true,
"thinking_always_on": true
},
"github_copilot/claude-fable-5.1": {
"litellm_provider": "github_copilot",
"max_input_tokens": 200000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/messages"
],
"supports_adaptive_thinking": true,
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true,
"thinking_always_on": true
},
"github_copilot/claude-haiku-4.5": {
"cache_creation_input_token_cost": 1.25e-06,
"cache_read_input_token_cost": 1e-07,
@ -31308,76 +31344,166 @@
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_vision": true
},
"github_copilot/claude-opus-4.5": {
"github_copilot/claude-haiku-5.5": {
"cache_creation_input_token_cost": 1.25e-07,
"cache_creation_input_token_cost_above_100k_tokens": 6.25e-07,
"cache_read_input_token_cost": 1e-08,
"cache_read_input_token_cost_above_100k_tokens": 5e-08,
"input_cost_per_token": 1e-07,
"input_cost_per_token_above_100k_tokens": 5e-07,
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 16000,
"max_tokens": 16000,
"mode": "chat",
"output_cost_per_token": 5e-07,
"output_cost_per_token_above_100k_tokens": 2.5e-06,
"source": "https://raw.githubusercontent.com/github/docs/main/data/tables/copilot/models-and-pricing.yml",
"supported_endpoints": [
"/v1/chat/completions"
"/v1/chat/completions",
"/v1/messages"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_vision": true,
"supports_output_config": true
},
"github_copilot/claude-opus-4.6-fast": {
"supports_adaptive_thinking": true,
"supports_legacy_thinking": true,
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true,
"thinking_always_on": false
},
"github_copilot/claude-opus-4.8": {
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 16000,
"max_tokens": 16000,
"max_input_tokens": 200000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/messages"
],
"supports_adaptive_thinking": true,
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/claude-opus-4.8-fast": {
"litellm_provider": "github_copilot",
"max_input_tokens": 200000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/messages"
],
"supports_adaptive_thinking": true,
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/claude-opus-5": {
"litellm_provider": "github_copilot",
"max_input_tokens": 200000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/messages"
],
"supports_adaptive_thinking": true,
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/claude-opus-5.5": {
"litellm_provider": "github_copilot",
"max_input_tokens": 200000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/messages"
],
"supports_adaptive_thinking": true,
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true,
"thinking_always_on": true
},
"github_copilot/claude-sonnet-5": {
"litellm_provider": "github_copilot",
"max_input_tokens": 200000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/messages"
],
"supports_adaptive_thinking": true,
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/claude-sonnet-5.5": {
"litellm_provider": "github_copilot",
"max_input_tokens": 200000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/messages"
],
"supports_adaptive_thinking": true,
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true,
"thinking_always_on": true
},
"github_copilot/gemini-3.7-flash": {
"litellm_provider": "github_copilot",
"max_input_tokens": 200000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_vision": true
},
"github_copilot/claude-opus-41": {
"github_copilot/gemini-3.8-flash": {
"litellm_provider": "github_copilot",
"max_input_tokens": 80000,
"max_output_tokens": 16000,
"max_tokens": 16000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions"
],
"supports_vision": true
},
"github_copilot/claude-sonnet-4": {
"cache_creation_input_token_cost": 3.75e-06,
"cache_read_input_token_cost": 3e-07,
"input_cost_per_token": 3e-06,
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 16000,
"max_tokens": 16000,
"mode": "chat",
"output_cost_per_token": 1.5e-05,
"supported_endpoints": [
"/v1/chat/completions"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_vision": true
},
"github_copilot/claude-sonnet-4.5": {
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 16000,
"max_tokens": 16000,
"max_input_tokens": 200000,
"max_output_tokens": 65536,
"max_tokens": 65536,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_vision": true
},
"github_copilot/gpt-3.5-turbo": {
@ -31504,21 +31630,6 @@
"supports_function_calling": true,
"supports_parallel_function_calling": true
},
"github_copilot/gpt-5": {
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-5-mini": {
"cache_read_input_token_cost": 2.5e-08,
"input_cost_per_token": 2.5e-07,
@ -31533,50 +31644,6 @@
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-5.1": {
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-5.1-codex-max": {
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-5.2": {
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-5.3-codex": {
"cache_read_input_token_cost": 1.75e-07,
"input_cost_per_token": 1.75e-06,
@ -31591,40 +31658,188 @@
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/mai-code-1-flash": {
"cache_read_input_token_cost": 7.5e-08,
"input_cost_per_token": 7.5e-07,
"github_copilot/gpt-5.4": {
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"max_input_tokens": 272000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "chat",
"output_cost_per_token": 4.5e-06,
"supported_endpoints": [
"/v1/chat/completions"
"/v1/chat/completions",
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_response_schema": true
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/mai-code-1-flash-internal": {
"cache_read_input_token_cost": 7.5e-08,
"input_cost_per_token": 7.5e-07,
"github_copilot/gpt-5.4-mini": {
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"max_input_tokens": 272000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-5.5": {
"litellm_provider": "github_copilot",
"max_input_tokens": 272000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-5.6-luna": {
"litellm_provider": "github_copilot",
"max_input_tokens": 200000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-5.6-sol": {
"litellm_provider": "github_copilot",
"max_input_tokens": 272000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-5.6-terra": {
"litellm_provider": "github_copilot",
"max_input_tokens": 272000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-6-astra": {
"litellm_provider": "github_copilot",
"max_input_tokens": 272000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-6-luna": {
"litellm_provider": "github_copilot",
"max_input_tokens": 272000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-6-sol": {
"litellm_provider": "github_copilot",
"max_input_tokens": 272000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-6.1-sol": {
"litellm_provider": "github_copilot",
"max_input_tokens": 272000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/kimi-k3": {
"litellm_provider": "github_copilot",
"max_input_tokens": 917504,
"max_output_tokens": 131072,
"max_tokens": 131072,
"mode": "chat",
"output_cost_per_token": 4.5e-06,
"supported_endpoints": [
"/v1/chat/completions"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_response_schema": true
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/mai-code-1.1-flash": {
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/text-embedding-3-small": {
"litellm_provider": "github_copilot",
@ -78959,27 +79174,5 @@
"supported_endpoints": [
"/v1/responses"
]
},
"github_copilot/claude-haiku-5.5": {
"cache_creation_input_token_cost": 1.25e-07,
"cache_creation_input_token_cost_above_100k_tokens": 6.25e-07,
"cache_read_input_token_cost": 1e-08,
"cache_read_input_token_cost_above_100k_tokens": 5e-08,
"input_cost_per_token": 1e-07,
"input_cost_per_token_above_100k_tokens": 5e-07,
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 16000,
"max_tokens": 16000,
"mode": "chat",
"output_cost_per_token": 5e-07,
"output_cost_per_token_above_100k_tokens": 2.5e-06,
"source": "https://raw.githubusercontent.com/github/docs/main/data/tables/copilot/models-and-pricing.yml",
"supported_endpoints": [
"/v1/chat/completions"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_vision": true
}
}

View file

@ -31293,6 +31293,42 @@
"video"
]
},
"github_copilot/claude-fable-5": {
"litellm_provider": "github_copilot",
"max_input_tokens": 200000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/messages"
],
"supports_adaptive_thinking": true,
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true,
"thinking_always_on": true
},
"github_copilot/claude-fable-5.1": {
"litellm_provider": "github_copilot",
"max_input_tokens": 200000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/messages"
],
"supports_adaptive_thinking": true,
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true,
"thinking_always_on": true
},
"github_copilot/claude-haiku-4.5": {
"cache_creation_input_token_cost": 1.25e-06,
"cache_read_input_token_cost": 1e-07,
@ -31308,76 +31344,166 @@
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_vision": true
},
"github_copilot/claude-opus-4.5": {
"github_copilot/claude-haiku-5.5": {
"cache_creation_input_token_cost": 1.25e-07,
"cache_creation_input_token_cost_above_100k_tokens": 6.25e-07,
"cache_read_input_token_cost": 1e-08,
"cache_read_input_token_cost_above_100k_tokens": 5e-08,
"input_cost_per_token": 1e-07,
"input_cost_per_token_above_100k_tokens": 5e-07,
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 16000,
"max_tokens": 16000,
"mode": "chat",
"output_cost_per_token": 5e-07,
"output_cost_per_token_above_100k_tokens": 2.5e-06,
"source": "https://raw.githubusercontent.com/github/docs/main/data/tables/copilot/models-and-pricing.yml",
"supported_endpoints": [
"/v1/chat/completions"
"/v1/chat/completions",
"/v1/messages"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_vision": true,
"supports_output_config": true
},
"github_copilot/claude-opus-4.6-fast": {
"supports_adaptive_thinking": true,
"supports_legacy_thinking": true,
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true,
"thinking_always_on": false
},
"github_copilot/claude-opus-4.8": {
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 16000,
"max_tokens": 16000,
"max_input_tokens": 200000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/messages"
],
"supports_adaptive_thinking": true,
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/claude-opus-4.8-fast": {
"litellm_provider": "github_copilot",
"max_input_tokens": 200000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/messages"
],
"supports_adaptive_thinking": true,
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/claude-opus-5": {
"litellm_provider": "github_copilot",
"max_input_tokens": 200000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/messages"
],
"supports_adaptive_thinking": true,
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/claude-opus-5.5": {
"litellm_provider": "github_copilot",
"max_input_tokens": 200000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/messages"
],
"supports_adaptive_thinking": true,
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true,
"thinking_always_on": true
},
"github_copilot/claude-sonnet-5": {
"litellm_provider": "github_copilot",
"max_input_tokens": 200000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/messages"
],
"supports_adaptive_thinking": true,
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/claude-sonnet-5.5": {
"litellm_provider": "github_copilot",
"max_input_tokens": 200000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/messages"
],
"supports_adaptive_thinking": true,
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true,
"thinking_always_on": true
},
"github_copilot/gemini-3.7-flash": {
"litellm_provider": "github_copilot",
"max_input_tokens": 200000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_vision": true
},
"github_copilot/claude-opus-41": {
"github_copilot/gemini-3.8-flash": {
"litellm_provider": "github_copilot",
"max_input_tokens": 80000,
"max_output_tokens": 16000,
"max_tokens": 16000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions"
],
"supports_vision": true
},
"github_copilot/claude-sonnet-4": {
"cache_creation_input_token_cost": 3.75e-06,
"cache_read_input_token_cost": 3e-07,
"input_cost_per_token": 3e-06,
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 16000,
"max_tokens": 16000,
"mode": "chat",
"output_cost_per_token": 1.5e-05,
"supported_endpoints": [
"/v1/chat/completions"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_vision": true
},
"github_copilot/claude-sonnet-4.5": {
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 16000,
"max_tokens": 16000,
"max_input_tokens": 200000,
"max_output_tokens": 65536,
"max_tokens": 65536,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_vision": true
},
"github_copilot/gpt-3.5-turbo": {
@ -31504,21 +31630,6 @@
"supports_function_calling": true,
"supports_parallel_function_calling": true
},
"github_copilot/gpt-5": {
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-5-mini": {
"cache_read_input_token_cost": 2.5e-08,
"input_cost_per_token": 2.5e-07,
@ -31533,50 +31644,6 @@
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-5.1": {
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-5.1-codex-max": {
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-5.2": {
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"mode": "chat",
"supported_endpoints": [
"/v1/chat/completions",
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-5.3-codex": {
"cache_read_input_token_cost": 1.75e-07,
"input_cost_per_token": 1.75e-06,
@ -31591,40 +31658,188 @@
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/mai-code-1-flash": {
"cache_read_input_token_cost": 7.5e-08,
"input_cost_per_token": 7.5e-07,
"github_copilot/gpt-5.4": {
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"max_input_tokens": 272000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "chat",
"output_cost_per_token": 4.5e-06,
"supported_endpoints": [
"/v1/chat/completions"
"/v1/chat/completions",
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_response_schema": true
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/mai-code-1-flash-internal": {
"cache_read_input_token_cost": 7.5e-08,
"input_cost_per_token": 7.5e-07,
"github_copilot/gpt-5.4-mini": {
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 64000,
"max_tokens": 64000,
"max_input_tokens": 272000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-5.5": {
"litellm_provider": "github_copilot",
"max_input_tokens": 272000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-5.6-luna": {
"litellm_provider": "github_copilot",
"max_input_tokens": 200000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-5.6-sol": {
"litellm_provider": "github_copilot",
"max_input_tokens": 272000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-5.6-terra": {
"litellm_provider": "github_copilot",
"max_input_tokens": 272000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-6-astra": {
"litellm_provider": "github_copilot",
"max_input_tokens": 272000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-6-luna": {
"litellm_provider": "github_copilot",
"max_input_tokens": 272000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-6-sol": {
"litellm_provider": "github_copilot",
"max_input_tokens": 272000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/gpt-6.1-sol": {
"litellm_provider": "github_copilot",
"max_input_tokens": 272000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/kimi-k3": {
"litellm_provider": "github_copilot",
"max_input_tokens": 917504,
"max_output_tokens": 131072,
"max_tokens": 131072,
"mode": "chat",
"output_cost_per_token": 4.5e-06,
"supported_endpoints": [
"/v1/chat/completions"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_response_schema": true
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/mai-code-1.1-flash": {
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "responses",
"supported_endpoints": [
"/v1/responses"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_response_schema": true,
"supports_vision": true
},
"github_copilot/text-embedding-3-small": {
"litellm_provider": "github_copilot",
@ -78959,27 +79174,5 @@
"supported_endpoints": [
"/v1/responses"
]
},
"github_copilot/claude-haiku-5.5": {
"cache_creation_input_token_cost": 1.25e-07,
"cache_creation_input_token_cost_above_100k_tokens": 6.25e-07,
"cache_read_input_token_cost": 1e-08,
"cache_read_input_token_cost_above_100k_tokens": 5e-08,
"input_cost_per_token": 1e-07,
"input_cost_per_token_above_100k_tokens": 5e-07,
"litellm_provider": "github_copilot",
"max_input_tokens": 128000,
"max_output_tokens": 16000,
"max_tokens": 16000,
"mode": "chat",
"output_cost_per_token": 5e-07,
"output_cost_per_token_above_100k_tokens": 2.5e-06,
"source": "https://raw.githubusercontent.com/github/docs/main/data/tables/copilot/models-and-pricing.yml",
"supported_endpoints": [
"/v1/chat/completions"
],
"supports_function_calling": true,
"supports_parallel_function_calling": true,
"supports_vision": true
}
}

View file

@ -31,10 +31,10 @@ pytestmark: Final = pytest.mark.timeout(900)
_STARTED_WORKER: Final = re.compile(r"Started server process \[(\d+)\]")
_DROPPED: Final = re.compile(r"original model: (\S+), ignoring and continuing")
_FIXED: Final[Mapping[str, str]] = MappingProxyType(
{"chatgpt-fixed": "chatgpt/gpt-5.6-terra", "copilot-fixed": "github_copilot/gpt-5.2"}
{"chatgpt-fixed": "chatgpt/gpt-5.6-terra", "copilot-fixed": "github_copilot/gpt-5.4"}
)
_WILDCARDS: Final[Mapping[str, str]] = MappingProxyType(
{"chatgpt/*": "chatgpt/gpt-5.6-terra", "github_copilot/*": "github_copilot/gpt-5.2"}
{"chatgpt/*": "chatgpt/gpt-5.6-terra", "github_copilot/*": "github_copilot/gpt-5.4"}
)
_LOGIN_PREFIXES: Final = ("chatgpt/", "github_copilot/")
_LOGIN_NAMES: Final = (*_FIXED, *_FIXED.values())
@ -424,7 +424,7 @@ async def test_worker_sigkill_mid_burst_leaves_the_sibling_refusing_logins_and_s
for item in served:
assert item.status == 200, item.text
refusals: Final = await _burst(
_base_url(owned), key, ("chatgpt/gpt-5.6-terra", "github_copilot/gpt-5.2") * 10
_base_url(owned), key, ("chatgpt/gpt-5.6-terra", "github_copilot/gpt-5.4") * 10
)
for index, answer in enumerate(refusals):
assert answer is not None and answer.status == 400, answer

View file

@ -41,9 +41,9 @@ _MODELS: Final[Mapping[tuple[Provider, Endpoint], str]] = MappingProxyType(
("chatgpt", "chat"): "chatgpt/gpt-5.6-terra",
("chatgpt", "responses"): "chatgpt/gpt-5.6-terra",
("chatgpt", "messages"): "chatgpt/gpt-5.6-terra",
("copilot", "chat"): "github_copilot/gpt-5.2",
("copilot", "responses"): "github_copilot/gpt-5.2",
("copilot", "messages"): "github_copilot/claude-sonnet-4.5",
("copilot", "chat"): "github_copilot/gpt-5.4",
("copilot", "responses"): "github_copilot/gpt-5.4",
("copilot", "messages"): "github_copilot/claude-sonnet-5.5",
}
)
_REFUSALS: Final[Mapping[Provider, str]] = MappingProxyType(
@ -469,9 +469,9 @@ _ROUTES: Final = (
"/v1/embeddings",
{"model": "github_copilot/text-embedding-3-small", "input": "login"},
),
_Route("copilot-completions", "copilot", "/v1/completions", {"model": "github_copilot/gpt-5.2", "prompt": "login"}),
_Route("copilot-completions", "copilot", "/v1/completions", {"model": "github_copilot/gpt-5.4", "prompt": "login"}),
_Route(
"copilot-images", "copilot", "/v1/images/generations", {"model": "github_copilot/gpt-5.2", "prompt": "login"}
"copilot-images", "copilot", "/v1/images/generations", {"model": "github_copilot/gpt-5.4", "prompt": "login"}
),
)

View file

@ -19,7 +19,7 @@ pytestmark: Final = pytest.mark.timeout(300)
Provider: TypeAlias = Literal["chatgpt", "copilot"]
_MODELS: Final[Mapping[Provider, str]] = MappingProxyType(
{"chatgpt": "chatgpt/gpt-5.6-terra", "copilot": "github_copilot/gpt-5.2"}
{"chatgpt": "chatgpt/gpt-5.6-terra", "copilot": "github_copilot/gpt-5.4"}
)
_REFUSALS: Final[Mapping[Provider, str]] = MappingProxyType(
{"chatgpt": dl.CHATGPT_REFUSAL, "copilot": dl.COPILOT_REFUSAL}

View file

@ -531,7 +531,7 @@ class TestShortCircuitEmitsNativeBlocks:
new=AsyncMock(return_value=("Title: x\nURL: y", _make_search_response())),
):
result = await logger.try_short_circuit_search(
model="github_copilot/claude-sonnet-4",
model="github_copilot/claude-sonnet-5.5",
messages=[{"role": "user", "content": "search query"}],
tools=[
{
@ -569,7 +569,7 @@ class TestShortCircuitEmitsNativeBlocks:
new=AsyncMock(return_value=("Title: x\nURL: y", _make_search_response())),
):
result = await logger.try_short_circuit_search(
model="github_copilot/claude-sonnet-4",
model="github_copilot/claude-sonnet-5.5",
messages=[{"role": "user", "content": "search query"}],
tools=[
{
@ -601,7 +601,7 @@ class TestShortCircuitEmitsNativeBlocks:
side_effect=RateLimitError("slow down", llm_provider="tavily", model="tavily"),
):
result = await logger.try_short_circuit_search(
model="github_copilot/claude-sonnet-4",
model="github_copilot/claude-sonnet-5.5",
messages=[{"role": "user", "content": "search query"}],
tools=[{"type": "web_search_20250305", "name": "web_search"}],
custom_llm_provider="github_copilot",

View file

@ -35,7 +35,7 @@ class TestTryShortCircuitSearch:
)
result = await logger.try_short_circuit_search(
model="github_copilot/claude-sonnet-4",
model="github_copilot/claude-sonnet-5.5",
messages=[
{"role": "user", "content": "Search for Claude Code releases"}
],
@ -66,7 +66,7 @@ class TestTryShortCircuitSearch:
logger = WebSearchInterceptionLogger(enabled_providers=["github_copilot"])
result = await logger.try_short_circuit_search(
model="github_copilot/claude-sonnet-4",
model="github_copilot/claude-sonnet-5.5",
messages=[{"role": "user", "content": "Do something"}],
tools=[
{"type": "web_search_20250305", "name": "web_search", "max_uses": 8},
@ -83,7 +83,7 @@ class TestTryShortCircuitSearch:
logger = WebSearchInterceptionLogger(enabled_providers=["github_copilot"])
result = await logger.try_short_circuit_search(
model="github_copilot/claude-sonnet-4",
model="github_copilot/claude-sonnet-5.5",
messages=[{"role": "user", "content": "Hello"}],
tools=None,
custom_llm_provider="github_copilot",
@ -97,7 +97,7 @@ class TestTryShortCircuitSearch:
logger = WebSearchInterceptionLogger(enabled_providers=["github_copilot"])
result = await logger.try_short_circuit_search(
model="github_copilot/claude-sonnet-4",
model="github_copilot/claude-sonnet-5.5",
messages=[{"role": "user", "content": "Hello"}],
tools=[],
custom_llm_provider="github_copilot",
@ -111,7 +111,7 @@ class TestTryShortCircuitSearch:
logger = WebSearchInterceptionLogger(enabled_providers=["bedrock"])
result = await logger.try_short_circuit_search(
model="github_copilot/claude-sonnet-4",
model="github_copilot/claude-sonnet-5.5",
messages=[{"role": "user", "content": "Search for something"}],
tools=[
{"type": "web_search_20250305", "name": "web_search", "max_uses": 8}
@ -150,7 +150,7 @@ class TestTryShortCircuitSearch:
logger = WebSearchInterceptionLogger(enabled_providers=["github_copilot"])
result = await logger.try_short_circuit_search(
model="github_copilot/claude-sonnet-4",
model="github_copilot/claude-sonnet-5.5",
messages=[],
tools=[
{"type": "web_search_20250305", "name": "web_search", "max_uses": 8}
@ -171,7 +171,7 @@ class TestTryShortCircuitSearch:
mock_search.side_effect = RuntimeError("Tavily API error")
result = await logger.try_short_circuit_search(
model="github_copilot/claude-sonnet-4",
model="github_copilot/claude-sonnet-5.5",
messages=[{"role": "user", "content": "Search for something"}],
tools=[
{"type": "web_search_20250305", "name": "web_search", "max_uses": 8}
@ -194,7 +194,7 @@ class TestTryShortCircuitSearch:
mock_search.return_value = ("search results here", None)
result = await logger.try_short_circuit_search(
model="github_copilot/claude-sonnet-4",
model="github_copilot/claude-sonnet-5.5",
messages=[{"role": "user", "content": "Search query"}],
tools=[{"type": "web_search_20250305", "name": "web_search"}],
custom_llm_provider="github_copilot",
@ -206,7 +206,7 @@ class TestTryShortCircuitSearch:
assert result["id"].startswith("msg_")
assert result["type"] == "message"
assert result["role"] == "assistant"
assert result["model"] == "github_copilot/claude-sonnet-4"
assert result["model"] == "github_copilot/claude-sonnet-5.5"
assert result["stop_reason"] == "end_turn"
assert result["stop_sequence"] is None
assert "usage" in result
@ -257,7 +257,7 @@ class TestShortCircuitEntryPoint:
mock_search.return_value = ("results", None)
with patch("litellm.callbacks", [logger]):
result = await _try_websearch_short_circuit(
model="github_copilot/claude-sonnet-4",
model="github_copilot/claude-sonnet-5.5",
messages=[{"role": "user", "content": "search query"}],
tools=[{"type": "web_search_20250305", "name": "web_search"}],
custom_llm_provider="github_copilot",
@ -285,7 +285,7 @@ class TestShortCircuitEntryPoint:
mock_search.return_value = ("streaming results", None)
with patch("litellm.callbacks", [logger]):
result = await _try_websearch_short_circuit(
model="github_copilot/claude-sonnet-4",
model="github_copilot/claude-sonnet-5.5",
messages=[{"role": "user", "content": "search query"}],
tools=[{"type": "web_search_20250305", "name": "web_search"}],
custom_llm_provider="github_copilot",
@ -353,7 +353,7 @@ class TestShortCircuitEntryPoint:
# is passed to the short-circuit, even though the hook would have
# already converted stream to False in request_kwargs.
result = await _try_websearch_short_circuit(
model="github_copilot/claude-sonnet-4",
model="github_copilot/claude-sonnet-5.5",
messages=[{"role": "user", "content": "search query"}],
tools=[{"type": "web_search_20250305", "name": "web_search"}],
custom_llm_provider="github_copilot",
@ -382,7 +382,7 @@ class TestShortCircuitEntryPoint:
# Simulate the caller having derived custom_llm_provider from
# the model string before calling _try_websearch_short_circuit
result = await _try_websearch_short_circuit(
model="github_copilot/claude-sonnet-4",
model="github_copilot/claude-sonnet-5.5",
messages=[{"role": "user", "content": "search query"}],
tools=[{"type": "web_search_20250305", "name": "web_search"}],
custom_llm_provider="github_copilot",

View file

@ -625,8 +625,8 @@ def test_shipped_version_boundaries(shipped_cost_map, model, provider, adaptive,
assert info.get("supports_mid_conversation_system") is mid_conversation, model
def test_shipped_claude_version_regex_excludes_undelimited_41(shipped_cost_map):
unmatched = match_capability_generalizations("github_copilot/claude-opus-41")
def test_shipped_claude_version_regex_excludes_two_digit_major(shipped_cost_map):
unmatched = match_capability_generalizations("github_copilot/claude-opus-42")
assert unmatched is None or "supports_adaptive_thinking" not in unmatched
assert unmatched is None or "supports_mid_conversation_system" not in unmatched

View file

@ -336,7 +336,7 @@ def test_validate_environment_uses_per_user_session_and_skips_authenticator():
session = GithubCopilotUserSession(token="user-copilot-token", api_base="https://tenant.githubcopilot.com/")
headers, api_base = config.validate_anthropic_messages_environment(
headers={},
model="github_copilot/claude-sonnet-4.5",
model="github_copilot/claude-sonnet-5.5",
messages=[],
optional_params={},
litellm_params={"github_copilot_user_session": session},
@ -371,14 +371,14 @@ def test_transform_response_carries_upstream_usage():
"id": "msg_1",
"type": "message",
"role": "assistant",
"model": "github_copilot/claude-sonnet-4.5",
"model": "github_copilot/claude-sonnet-5.5",
"content": [{"type": "text", "text": "hi"}],
"stop_reason": "end_turn",
"usage": {"input_tokens": 14, "output_tokens": 3},
},
)
result = config.transform_anthropic_messages_response(
model="github_copilot/claude-sonnet-4.5",
model="github_copilot/claude-sonnet-5.5",
raw_response=raw,
logging_obj=MagicMock(),
)

View file

@ -765,7 +765,7 @@ def test_validate_environment_uses_per_user_session_and_skips_authenticator():
session = GithubCopilotUserSession(token="user-copilot-token", api_base="https://api.githubcopilot.com")
headers = config.validate_environment(
headers={},
model="github_copilot/gpt-5.1",
model="github_copilot/gpt-5.4",
litellm_params={"github_copilot_user_session": session},
)
assert headers["Authorization"] == "Bearer user-copilot-token"
@ -811,7 +811,7 @@ def test_transform_response_carries_upstream_usage():
"object": "response",
"created_at": 1,
"status": "completed",
"model": "github_copilot/gpt-5.1",
"model": "github_copilot/gpt-5.4",
"output": [
{
"type": "message",
@ -825,7 +825,7 @@ def test_transform_response_carries_upstream_usage():
},
)
result = config.transform_response_api_response(
model="github_copilot/gpt-5.1",
model="github_copilot/gpt-5.4",
raw_response=raw,
logging_obj=MagicMock(),
)

View file

@ -500,7 +500,7 @@ class TestGithubCopilotTransformResponse:
"id": "chatcmpl-123",
"object": "chat.completion",
"created": 1700000000,
"model": "github_copilot/claude-opus-4.5",
"model": "github_copilot/claude-opus-4.8",
"choices": [
{
"index": 0,
@ -519,7 +519,7 @@ class TestGithubCopilotTransformResponse:
model_response = ModelResponse()
result = config.transform_response(
model="github_copilot/claude-opus-4.5",
model="github_copilot/claude-opus-4.8",
raw_response=raw_response,
model_response=model_response,
logging_obj=self._make_logging_obj(),

View file

@ -10,8 +10,10 @@ from typing import Final
import jsonschema
import pytest
from pydantic import BaseModel, ConfigDict, JsonValue, TypeAdapter
import litellm
from litellm.litellm_core_utils.fallback_generalizations import match_capability_generalizations
from litellm.llms.openai.chat.gpt_5_transformation import is_gpt_reasoning_series_name
from litellm.llms.openai_like.json_loader import JSONProviderRegistry
from litellm.router_utils.reasoning_effort_capability import resolve_supported_reasoning_efforts
@ -45,6 +47,127 @@ def prices() -> dict:
return json.loads(PRICES_PATH.read_text())
class _CopilotEndpointRow(BaseModel):
model_config = ConfigDict(frozen=True, extra="ignore")
mode: str
max_input_tokens: int
max_output_tokens: int
max_tokens: int
supported_endpoints: tuple[str, ...]
class _CopilotThinkingCapabilities(BaseModel):
model_config = ConfigDict(frozen=True, extra="ignore")
supports_reasoning: bool | None = None
supports_adaptive_thinking: bool | None = None
supports_legacy_thinking: bool | None = None
thinking_always_on: bool | None = None
def _copilot_endpoint_rows(path: Path) -> Mapping[str, _CopilotEndpointRow]:
prices: Final[dict[str, JsonValue]] = TypeAdapter(dict[str, JsonValue]).validate_json(path.read_bytes())
return MappingProxyType(
{
key: _CopilotEndpointRow.model_validate(value)
for key, value in prices.items()
if key.startswith("github_copilot/") and isinstance(value, dict) and "supported_endpoints" in value
}
)
def _thinking_capabilities(prices: Mapping[str, JsonValue], key: str) -> _CopilotThinkingCapabilities:
return _CopilotThinkingCapabilities.model_validate(prices[key])
def _github_copilot_catalog_rows(path: Path) -> Mapping[str, JsonValue]:
prices: Final[dict[str, JsonValue]] = TypeAdapter(dict[str, JsonValue]).validate_json(path.read_bytes())
return MappingProxyType({key: value for key, value in prices.items() if key.startswith("github_copilot/")})
_THINKING_KEYS: Final[tuple[str, ...]] = (
"supports_reasoning",
"supports_adaptive_thinking",
"supports_legacy_thinking",
"thinking_always_on",
)
def _anthropic_counterpart(key: str) -> str:
return key.removeprefix("github_copilot/").removesuffix("-fast").replace(".", "-")
@pytest.mark.parametrize(("path",), [(PRICES_PATH,), (BACKUP_PRICES_PATH,)], ids=("main", "backup"))
def test_github_copilot_rows_derive_mode_and_max_tokens_from_their_endpoints(path: Path) -> None:
rows: Final[Mapping[str, _CopilotEndpointRow]] = _copilot_endpoint_rows(path)
assert rows, f"No GitHub Copilot endpoint rows found in {path}"
assert {key: (row.mode, row.max_tokens) for key, row in rows.items()} == {
key: (
"chat" if "/v1/chat/completions" in row.supported_endpoints else "responses",
row.max_output_tokens,
)
for key, row in rows.items()
}
def test_github_copilot_backup_rows_match_the_main_catalog() -> None:
assert _github_copilot_catalog_rows(PRICES_PATH) == _github_copilot_catalog_rows(BACKUP_PRICES_PATH)
def test_github_copilot_rows_resolve_through_get_model_info() -> None:
rows: Final[Mapping[str, _CopilotEndpointRow]] = _copilot_endpoint_rows(PRICES_PATH)
assert {
key: (litellm.get_model_info(key)["mode"], litellm.get_model_info(key)["max_input_tokens"]) for key in rows
} == {key: (row.mode, row.max_input_tokens) for key, row in rows.items()}
def test_github_copilot_rows_keep_the_reasoning_flag_their_family_fallback_supplies() -> None:
reasoning_rows: Final = tuple(
key
for key in _copilot_endpoint_rows(PRICES_PATH)
if (match_capability_generalizations(key) or {}).get("supports_reasoning") is True
)
prices: Final[dict[str, JsonValue]] = TypeAdapter(dict[str, JsonValue]).validate_json(PRICES_PATH.read_bytes())
assert reasoning_rows
assert {key: _thinking_capabilities(prices, key).supports_reasoning for key in reasoning_rows} == dict.fromkeys(
reasoning_rows, True
)
assert {key: litellm.get_model_info(key).get("supports_reasoning") for key in reasoning_rows} == dict.fromkeys(
reasoning_rows, True
)
assert {
key: resolve_supported_reasoning_efforts(
litellm.get_model_info(key),
deployment_is_mapped=True,
)
!= ()
for key in reasoning_rows
} == dict.fromkeys(reasoning_rows, True)
def test_github_copilot_messages_claude_rows_keep_their_anthropic_thinking_capabilities() -> None:
prices: Final[dict[str, JsonValue]] = TypeAdapter(dict[str, JsonValue]).validate_json(PRICES_PATH.read_bytes())
claude_rows: Final = tuple(
key
for key, row in _copilot_endpoint_rows(PRICES_PATH).items()
if key.startswith("github_copilot/claude-") and "/v1/messages" in row.supported_endpoints
)
assert claude_rows
assert {key: _thinking_capabilities(prices, key) for key in claude_rows} == {
key: _thinking_capabilities(prices, _anthropic_counterpart(key)) for key in claude_rows
}
assert {
key: tuple(litellm.get_model_info(key).get(thinking_key) for thinking_key in _THINKING_KEYS)
for key in claude_rows
} == {
key: tuple(
litellm.get_model_info(_anthropic_counterpart(key)).get(thinking_key) for thinking_key in _THINKING_KEYS
)
for key in claude_rows
}
def test_committed_schema_matches_generator_output(prices: dict, committed_schema: dict):
generator = load_generator()
regenerated = json.loads(generator.render(generator.build_schema(prices)))