-
-
Notifications
You must be signed in to change notification settings - Fork 390
Fix GitHub Copilot gpt-5.4 endpoint routing #453
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
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -577,9 +577,32 @@ func useGitHubCopilotResponsesEndpoint(sourceFormat sdktranslator.Format, model | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| baseModel := strings.ToLower(thinking.ParseSuffix(model).ModelName) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if info := registry.GetGlobalRegistry().GetModelInfo(baseModel, ""); info != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if len(info.SupportedEndpoints) > 0 && !containsEndpoint(info.SupportedEndpoints, githubCopilotChatPath) && containsEndpoint(info.SupportedEndpoints, githubCopilotResponsesPath) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if info := registry.GetGlobalRegistry().GetModelInfo(baseModel, ""); info != nil { | |
| if len(info.SupportedEndpoints) > 0 && !containsEndpoint(info.SupportedEndpoints, githubCopilotChatPath) && containsEndpoint(info.SupportedEndpoints, githubCopilotResponsesPath) { | |
| return true | |
| } | |
| } |
Outdated
Copilot
AI
Mar 22, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useGitHubCopilotResponsesEndpoint calls registry.GetGitHubCopilotModels() (which constructs the full static model list) on every request and then linearly scans it. This adds avoidable allocations/CPU in a hot path; consider caching a map/set of responses-only Copilot models (or consulting the dynamic registry first and only falling back to static definitions on miss).
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current logic for determining which endpoint to use has a potential flaw in how it prioritizes model definitions. It first checks the dynamic registry, and if the model is found but isn't a /responses-only model, it falls through to check the static list of GitHub Copilot models. This can lead to incorrect behavior if a model has different definitions in the dynamic and static registries, as the dynamic definition should be considered authoritative.
For instance, if a model is dynamically registered with SupportedEndpoints: ["/chat/completions", "/responses"], the first check fails. If a stale static definition for the same model exists with SupportedEndpoints: ["/responses"], the function will incorrectly return true.
The logic should be revised to ensure that if a model is found in the dynamic registry, that definition is used exclusively for the decision, and the static list is only consulted as a fallback.
| if info := registry.GetGlobalRegistry().GetModelInfo(baseModel, ""); info != nil { | |
| if len(info.SupportedEndpoints) > 0 && !containsEndpoint(info.SupportedEndpoints, githubCopilotChatPath) && containsEndpoint(info.SupportedEndpoints, githubCopilotResponsesPath) { | |
| return true | |
| } | |
| } | |
| for _, info := range registry.GetGitHubCopilotModels() { | |
| if info == nil || !strings.EqualFold(info.ID, baseModel) { | |
| continue | |
| } | |
| if len(info.SupportedEndpoints) > 0 && !containsEndpoint(info.SupportedEndpoints, githubCopilotChatPath) && containsEndpoint(info.SupportedEndpoints, githubCopilotResponsesPath) { | |
| return true | |
| } | |
| break | |
| } | |
| if info := registry.GetGlobalRegistry().GetModelInfo(baseModel, ""); info != nil { | |
| // If model is in dynamic registry, its definition is authoritative. | |
| if len(info.SupportedEndpoints) > 0 { | |
| return !containsEndpoint(info.SupportedEndpoints, githubCopilotChatPath) && containsEndpoint(info.SupportedEndpoints, githubCopilotResponsesPath) | |
| } | |
| // No endpoint info, so fall through to the codex check. | |
| } else { | |
| // If not in dynamic registry, check static definitions. | |
| for _, info := range registry.GetGitHubCopilotModels() { | |
| if info != nil && strings.EqualFold(info.ID, baseModel) { | |
| if len(info.SupportedEndpoints) > 0 { | |
| return !containsEndpoint(info.SupportedEndpoints, githubCopilotChatPath) && containsEndpoint(info.SupportedEndpoints, githubCopilotResponsesPath) | |
| } | |
| // Found model, but no endpoint info, so fall through to codex check. | |
| break | |
| } | |
| } | |
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -70,6 +70,13 @@ func TestUseGitHubCopilotResponsesEndpoint_CodexModel(t *testing.T) { | |||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| func TestUseGitHubCopilotResponsesEndpoint_RegistryResponsesOnlyModel(t *testing.T) { | ||||||||||||||||||
| t.Parallel() | ||||||||||||||||||
| if !useGitHubCopilotResponsesEndpoint(sdktranslator.FromString("openai"), "gpt-5.4") { | ||||||||||||||||||
| t.Fatal("expected responses-only registry model to use /responses") | ||||||||||||||||||
|
Comment on lines
+74
to
+77
|
||||||||||||||||||
| func TestUseGitHubCopilotResponsesEndpoint_RegistryResponsesOnlyModel(t *testing.T) { | |
| t.Parallel() | |
| if !useGitHubCopilotResponsesEndpoint(sdktranslator.FromString("openai"), "gpt-5.4") { | |
| t.Fatal("expected responses-only registry model to use /responses") | |
| func TestUseGitHubCopilotResponsesEndpoint_StaticResponsesOnlyModel(t *testing.T) { | |
| t.Parallel() | |
| if !useGitHubCopilotResponsesEndpoint(sdktranslator.FromString("openai"), "gpt-5.4") { | |
| t.Fatal("expected responses-only model to use /responses") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For consistency with other
/responses-only models likegpt-5.3-codex, consider adding"none"to theThinking.Levelsforgpt-5.4. This would allow users to explicitly disable the thinking feature for this model, which is a common option for similar models.