mirror of
https://github.com/router-for-me/CLIProxyAPIPlus.git
synced 2026-03-09 15:25:17 +00:00
Merge pull request #214 from anilcancakir/fix/github-copilot-model-alias-suffix
fix(auth): strip model suffix in GitHub Copilot executor before upstream call
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/google/uuid"
|
||||
copilotauth "github.com/router-for-me/CLIProxyAPI/v6/internal/auth/copilot"
|
||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/thinking"
|
||||
cliproxyauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
|
||||
cliproxyexecutor "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/executor"
|
||||
sdktranslator "github.com/router-for-me/CLIProxyAPI/v6/sdk/translator"
|
||||
@@ -471,9 +472,14 @@ func detectVisionContent(body []byte) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// normalizeModel is a no-op as GitHub Copilot accepts model names directly.
|
||||
// Model mapping should be done at the registry level if needed.
|
||||
func (e *GitHubCopilotExecutor) normalizeModel(_ string, body []byte) []byte {
|
||||
// normalizeModel strips the suffix (e.g. "(medium)") from the model name
|
||||
// before sending to GitHub Copilot, as the upstream API does not accept
|
||||
// suffixed model identifiers.
|
||||
func (e *GitHubCopilotExecutor) normalizeModel(model string, body []byte) []byte {
|
||||
baseModel := thinking.ParseSuffix(model).ModelName
|
||||
if baseModel != model {
|
||||
body, _ = sjson.SetBytes(body, "model", baseModel)
|
||||
}
|
||||
return body
|
||||
}
|
||||
|
||||
|
||||
54
internal/runtime/executor/github_copilot_executor_test.go
Normal file
54
internal/runtime/executor/github_copilot_executor_test.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package executor
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
func TestGitHubCopilotNormalizeModel_StripsSuffix(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
model string
|
||||
wantModel string
|
||||
}{
|
||||
{
|
||||
name: "suffix stripped",
|
||||
model: "claude-opus-4.6(medium)",
|
||||
wantModel: "claude-opus-4.6",
|
||||
},
|
||||
{
|
||||
name: "no suffix unchanged",
|
||||
model: "claude-opus-4.6",
|
||||
wantModel: "claude-opus-4.6",
|
||||
},
|
||||
{
|
||||
name: "different suffix stripped",
|
||||
model: "gpt-4o(high)",
|
||||
wantModel: "gpt-4o",
|
||||
},
|
||||
{
|
||||
name: "numeric suffix stripped",
|
||||
model: "gemini-2.5-pro(8192)",
|
||||
wantModel: "gemini-2.5-pro",
|
||||
},
|
||||
}
|
||||
|
||||
e := &GitHubCopilotExecutor{}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
body := []byte(`{"model":"` + tt.model + `","messages":[]}`)
|
||||
got := e.normalizeModel(tt.model, body)
|
||||
|
||||
gotModel := gjson.GetBytes(got, "model").String()
|
||||
if gotModel != tt.wantModel {
|
||||
t.Fatalf("normalizeModel() model = %q, want %q", gotModel, tt.wantModel)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -79,6 +79,24 @@ func TestResolveOAuthUpstreamModel_SuffixPreservation(t *testing.T) {
|
||||
input: "gemini-2.5-pro(none)",
|
||||
want: "gemini-2.5-pro-exp-03-25(none)",
|
||||
},
|
||||
{
|
||||
name: "github-copilot suffix preserved",
|
||||
aliases: map[string][]internalconfig.OAuthModelAlias{
|
||||
"github-copilot": {{Name: "claude-opus-4.6", Alias: "opus"}},
|
||||
},
|
||||
channel: "github-copilot",
|
||||
input: "opus(medium)",
|
||||
want: "claude-opus-4.6(medium)",
|
||||
},
|
||||
{
|
||||
name: "github-copilot no suffix",
|
||||
aliases: map[string][]internalconfig.OAuthModelAlias{
|
||||
"github-copilot": {{Name: "claude-opus-4.6", Alias: "opus"}},
|
||||
},
|
||||
channel: "github-copilot",
|
||||
input: "opus",
|
||||
want: "claude-opus-4.6",
|
||||
},
|
||||
{
|
||||
name: "kimi suffix preserved",
|
||||
aliases: map[string][]internalconfig.OAuthModelAlias{
|
||||
@@ -174,6 +192,8 @@ func createAuthForChannel(channel string) *Auth {
|
||||
return &Auth{Provider: "kimi"}
|
||||
case "kiro":
|
||||
return &Auth{Provider: "kiro"}
|
||||
case "github-copilot":
|
||||
return &Auth{Provider: "github-copilot"}
|
||||
default:
|
||||
return &Auth{Provider: channel}
|
||||
}
|
||||
@@ -187,6 +207,22 @@ func TestOAuthModelAliasChannel_Kimi(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestOAuthModelAliasChannel_GitHubCopilot(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if got := OAuthModelAliasChannel("github-copilot", ""); got != "github-copilot" {
|
||||
t.Fatalf("OAuthModelAliasChannel() = %q, want %q", got, "github-copilot")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOAuthModelAliasChannel_Kiro(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if got := OAuthModelAliasChannel("kiro", ""); got != "kiro" {
|
||||
t.Fatalf("OAuthModelAliasChannel() = %q, want %q", got, "kiro")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyOAuthModelAlias_SuffixPreservation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user