History

fix(translator): correct gemini-cli log prefix

hkfires committed 9 months ago

Commit b7e4f001 parent f7d00195 files · +1 −266Browse files

Unified · Split

5 files
  1. internal/translator/gemini-cli/openai/chat-completions/gemini-cli_openai_response.go +1 −1
  2. sdk/cliproxy/auth/conductor_availability_test.go +0 −1
  3. sdk/cliproxy/service_oauth_excluded_models_test.go +0 −45
  4. sdk/cliproxy/service_oauth_model_alias_test.go +0 −24
  5. test/config_migration_test.go +0 −195
internal/translator/gemini-cli/openai/chat-completions/gemini-cli_openai_response.go+1−1
@@ -109,7 +109,7 @@ func ConvertCliResponseToOpenAI(_ context.Context, _ string, originalRequestRawJ · 108 unmodified lines
109 var err error109 var err error
110 template, err = sjson.Set(template, "usage.prompt_tokens_details.cached_tokens", cachedTokenCount)110 template, err = sjson.Set(template, "usage.prompt_tokens_details.cached_tokens", cachedTokenCount)
111 if err != nil {111 if err != nil {
112 log.Warnf("antigravity openai response: failed to set cached_tokens: %v", err)112 log.Warnf("gemini-cli openai response: failed to set cached_tokens: %v", err)
113 }113 }
114 }114 }
115 }115 }
sdk/cliproxy/auth/conductor_availability_test.go+0−1
@@ -59,4 +59,3 @@ func TestUpdateAggregatedAvailability_FutureNextRetryBlocksAuth(t *testing.T) { · 58 unmodified lines
59 t.Fatalf("auth.NextRetryAfter = %v, want %v", auth.NextRetryAfter, next)59 t.Fatalf("auth.NextRetryAfter = %v, want %v", auth.NextRetryAfter, next)
60 }60 }
61}61}
62
sdk/cliproxy/service_oauth_excluded_models_test.go+0−45
@@ -1,45 +0,0 @@
1package cliproxy
2
3import (
4 "testing"
5
6 "github.com/router-for-me/CLIProxyAPI/v6/sdk/config"
7)
8
9func TestOAuthExcludedModels_KimiOAuth(t *testing.T) {
10 t.Parallel()
11
12 svc := &Service{
13 cfg: &config.Config{
14 OAuthExcludedModels: map[string][]string{
15 "kimi": {"kimi-k2-thinking", "kimi-k2.5"},
16 },
17 },
18 }
19
20 got := svc.oauthExcludedModels("kimi", "oauth")
21 if len(got) != 2 {
22 t.Fatalf("expected 2 excluded models, got %d", len(got))
23 }
24 if got[0] != "kimi-k2-thinking" || got[1] != "kimi-k2.5" {
25 t.Fatalf("unexpected excluded models: %#v", got)
26 }
27}
28
29func TestOAuthExcludedModels_KimiAPIKeyReturnsNil(t *testing.T) {
30 t.Parallel()
31
32 svc := &Service{
33 cfg: &config.Config{
34 OAuthExcludedModels: map[string][]string{
35 "kimi": {"kimi-k2-thinking"},
36 },
37 },
38 }
39
40 got := svc.oauthExcludedModels("kimi", "apikey")
41 if got != nil {
42 t.Fatalf("expected nil for apikey auth kind, got %#v", got)
43 }
44}
45
sdk/cliproxy/service_oauth_model_alias_test.go+0−24
@@ -90,27 +90,3 @@ func TestApplyOAuthModelAlias_ForkAddsMultipleAliases(t *testing.T) { · 89 unmodified lines
90 t.Fatalf("expected forked model name %q, got %q", "models/g5-2", out[2].Name)90 t.Fatalf("expected forked model name %q, got %q", "models/g5-2", out[2].Name)
91 }91 }
92}92}
93
94func TestApplyOAuthModelAlias_KimiRename(t *testing.T) {
95 cfg := &config.Config{
96 OAuthModelAlias: map[string][]config.OAuthModelAlias{
97 "kimi": {
98 {Name: "kimi-k2.5", Alias: "k2.5"},
99 },
100 },
101 }
102 models := []*ModelInfo{
103 {ID: "kimi-k2.5", Name: "models/kimi-k2.5"},
104 }
105
106 out := applyOAuthModelAlias(cfg, "kimi", "oauth", models)
107 if len(out) != 1 {
108 t.Fatalf("expected 1 model, got %d", len(out))
109 }
110 if out[0].ID != "k2.5" {
111 t.Fatalf("expected model id %q, got %q", "k2.5", out[0].ID)
112 }
113 if out[0].Name != "models/k2.5" {
114 t.Fatalf("expected model name %q, got %q", "models/k2.5", out[0].Name)
115 }
116}
test/config_migration_test.go+0−195
@@ -1,195 +0,0 @@
1package test
2
3import (
4 "os"
5 "path/filepath"
6 "strings"
7 "testing"
8
9 "github.com/router-for-me/CLIProxyAPI/v6/internal/config"
10)
11
12func TestLegacyConfigMigration(t *testing.T) {
13 t.Run("onlyLegacyFields", func(t *testing.T) {
14 path := writeConfig(t, `
15port: 8080
16generative-language-api-key:
17 - "legacy-gemini-1"
18openai-compatibility:
19 - name: "legacy-provider"
20 base-url: "https://example.com"
21 api-keys:
22 - "legacy-openai-1"
23amp-upstream-url: "https://amp.example.com"
24amp-upstream-api-key: "amp-legacy-key"
25amp-restrict-management-to-localhost: false
26amp-model-mappings:
27 - from: "old-model"
28 to: "new-model"
29`)
30 cfg, err := config.LoadConfig(path)
31 if err != nil {
32 t.Fatalf("load legacy config: %v", err)
33 }
34 if got := len(cfg.GeminiKey); got != 1 || cfg.GeminiKey[0].APIKey != "legacy-gemini-1" {
35 t.Fatalf("gemini migration mismatch: %+v", cfg.GeminiKey)
36 }
37 if got := len(cfg.OpenAICompatibility); got != 1 {
38 t.Fatalf("expected 1 openai-compat provider, got %d", got)
39 }
40 if entries := cfg.OpenAICompatibility[0].APIKeyEntries; len(entries) != 1 || entries[0].APIKey != "legacy-openai-1" {
41 t.Fatalf("openai-compat migration mismatch: %+v", entries)
42 }
43 if cfg.AmpCode.UpstreamURL != "https://amp.example.com" || cfg.AmpCode.UpstreamAPIKey != "amp-legacy-key" {
44 t.Fatalf("amp migration failed: %+v", cfg.AmpCode)
45 }
46 if cfg.AmpCode.RestrictManagementToLocalhost {
47 t.Fatalf("expected amp restriction to be false after migration")
48 }
49 if got := len(cfg.AmpCode.ModelMappings); got != 1 || cfg.AmpCode.ModelMappings[0].From != "old-model" {
50 t.Fatalf("amp mappings migration mismatch: %+v", cfg.AmpCode.ModelMappings)
51 }
52 updated := readFile(t, path)
53 if strings.Contains(updated, "generative-language-api-key") {
54 t.Fatalf("legacy gemini key still present:\n%s", updated)
55 }
56 if strings.Contains(updated, "amp-upstream-url") || strings.Contains(updated, "amp-restrict-management-to-localhost") {
57 t.Fatalf("legacy amp keys still present:\n%s", updated)
58 }
59 if strings.Contains(updated, "\n api-keys:") {
60 t.Fatalf("legacy openai compat keys still present:\n%s", updated)
61 }
62 })
63
64 t.Run("mixedLegacyAndNewFields", func(t *testing.T) {
65 path := writeConfig(t, `
66gemini-api-key:
67 - api-key: "new-gemini"
68generative-language-api-key:
69 - "new-gemini"
70 - "legacy-gemini-only"
71openai-compatibility:
72 - name: "mixed-provider"
73 base-url: "https://mixed.example.com"
74 api-key-entries:
75 - api-key: "new-entry"
76 api-keys:
77 - "legacy-entry"
78 - "new-entry"
79`)
80 cfg, err := config.LoadConfig(path)
81 if err != nil {
82 t.Fatalf("load mixed config: %v", err)
83 }
84 if got := len(cfg.GeminiKey); got != 2 {
85 t.Fatalf("expected 2 gemini entries, got %d: %+v", got, cfg.GeminiKey)
86 }
87 seen := make(map[string]struct{}, len(cfg.GeminiKey))
88 for _, entry := range cfg.GeminiKey {
89 if _, exists := seen[entry.APIKey]; exists {
90 t.Fatalf("duplicate gemini key %q after migration", entry.APIKey)
91 }
92 seen[entry.APIKey] = struct{}{}
93 }
94 provider := cfg.OpenAICompatibility[0]
95 if got := len(provider.APIKeyEntries); got != 2 {
96 t.Fatalf("expected 2 openai entries, got %d: %+v", got, provider.APIKeyEntries)
97 }
98 entrySeen := make(map[string]struct{}, len(provider.APIKeyEntries))
99 for _, entry := range provider.APIKeyEntries {
100 if _, ok := entrySeen[entry.APIKey]; ok {
101 t.Fatalf("duplicate openai key %q after migration", entry.APIKey)
102 }
103 entrySeen[entry.APIKey] = struct{}{}
104 }
105 })
106
107 t.Run("onlyNewFields", func(t *testing.T) {
108 path := writeConfig(t, `
109gemini-api-key:
110 - api-key: "new-only"
111openai-compatibility:
112 - name: "new-only-provider"
113 base-url: "https://new-only.example.com"
114 api-key-entries:
115 - api-key: "new-only-entry"
116ampcode:
117 upstream-url: "https://amp.new"
118 upstream-api-key: "new-amp-key"
119 restrict-management-to-localhost: true
120 model-mappings:
121 - from: "a"
122 to: "b"
123`)
124 cfg, err := config.LoadConfig(path)
125 if err != nil {
126 t.Fatalf("load new config: %v", err)
127 }
128 if len(cfg.GeminiKey) != 1 || cfg.GeminiKey[0].APIKey != "new-only" {
129 t.Fatalf("unexpected gemini entries: %+v", cfg.GeminiKey)
130 }
131 if len(cfg.OpenAICompatibility) != 1 || len(cfg.OpenAICompatibility[0].APIKeyEntries) != 1 {
132 t.Fatalf("unexpected openai compat entries: %+v", cfg.OpenAICompatibility)
133 }
134 if cfg.AmpCode.UpstreamURL != "https://amp.new" || cfg.AmpCode.UpstreamAPIKey != "new-amp-key" {
135 t.Fatalf("unexpected amp config: %+v", cfg.AmpCode)
136 }
137 })
138
139 t.Run("duplicateNamesDifferentBase", func(t *testing.T) {
140 path := writeConfig(t, `
141openai-compatibility:
142 - name: "dup-provider"
143 base-url: "https://provider-a"
144 api-keys:
145 - "key-a"
146 - name: "dup-provider"
147 base-url: "https://provider-b"
148 api-keys:
149 - "key-b"
150`)
151 cfg, err := config.LoadConfig(path)
152 if err != nil {
153 t.Fatalf("load duplicate config: %v", err)
154 }
155 if len(cfg.OpenAICompatibility) != 2 {
156 t.Fatalf("expected 2 providers, got %d", len(cfg.OpenAICompatibility))
157 }
158 for _, entry := range cfg.OpenAICompatibility {
159 if len(entry.APIKeyEntries) != 1 {
160 t.Fatalf("expected 1 key entry per provider: %+v", entry)
161 }
162 switch entry.BaseURL {
163 case "https://provider-a":
164 if entry.APIKeyEntries[0].APIKey != "key-a" {
165 t.Fatalf("provider-a key mismatch: %+v", entry.APIKeyEntries)
166 }
167 case "https://provider-b":
168 if entry.APIKeyEntries[0].APIKey != "key-b" {
169 t.Fatalf("provider-b key mismatch: %+v", entry.APIKeyEntries)
170 }
171 default:
172 t.Fatalf("unexpected provider base url: %s", entry.BaseURL)
173 }
174 }
175 })
176}
177
178func writeConfig(t *testing.T, content string) string {
179 t.Helper()
180 dir := t.TempDir()
181 path := filepath.Join(dir, "config.yaml")
182 if err := os.WriteFile(path, []byte(strings.TrimSpace(content)+"\n"), 0o644); err != nil {
183 t.Fatalf("write temp config: %v", err)
184 }
185 return path
186}
187
188func readFile(t *testing.T, path string) string {
189 t.Helper()
190 data, err := os.ReadFile(path)
191 if err != nil {
192 t.Fatalf("read temp config: %v", err)
193 }
194 return string(data)
195}