From 2fc87985d2b43b5482d4be021d08e9911ce4c737 Mon Sep 17 00:00:00 2001 From: I Putu Eddy Irawan Date: Tue, 3 Mar 2026 09:18:26 +0700 Subject: [PATCH] fix: add kimi-code migration alias and User-Agent test - Add "kimi-code" to the moonshot provider's providerNames in ConvertProvidersToModelList so configs using agents.defaults.provider: "kimi-code" migrate correctly. - Add TestProviderChat_KimiCodeUserAgent verifying that User-Agent: KimiCLI/0.77 is set when apiBase hostname is api.kimi.com and not set for other hosts. Co-Authored-By: Claude Opus 4.6 --- pkg/config/migration.go | 2 +- pkg/providers/openai_compat/provider_test.go | 78 ++++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/pkg/config/migration.go b/pkg/config/migration.go index 105e35fce..2475f5aa9 100644 --- a/pkg/config/migration.go +++ b/pkg/config/migration.go @@ -208,7 +208,7 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { }, }, { - providerNames: []string{"moonshot", "kimi"}, + providerNames: []string{"moonshot", "kimi", "kimi-code"}, protocol: "moonshot", buildConfig: func(p ProvidersConfig) (ModelConfig, bool) { if p.Moonshot.APIKey == "" && p.Moonshot.APIBase == "" { diff --git a/pkg/providers/openai_compat/provider_test.go b/pkg/providers/openai_compat/provider_test.go index d9e6ba871..014451144 100644 --- a/pkg/providers/openai_compat/provider_test.go +++ b/pkg/providers/openai_compat/provider_test.go @@ -2,9 +2,11 @@ package openai_compat import ( "encoding/json" + "io" "net/http" "net/http/httptest" "net/url" + "strings" "testing" "time" ) @@ -411,3 +413,79 @@ func TestProvider_FunctionalOptionRequestTimeoutNonPositive(t *testing.T) { t.Fatalf("http timeout = %v, want %v", p.httpClient.Timeout, defaultRequestTimeout) } } + +// roundTripFunc adapts a function to http.RoundTripper for test injection. +type roundTripFunc func(*http.Request) (*http.Response, error) + +func (f roundTripFunc) RoundTrip(r *http.Request) (*http.Response, error) { + return f(r) +} + +func TestProviderChat_KimiCodeUserAgent(t *testing.T) { + okBody := `{"choices":[{"message":{"content":"ok"},"finish_reason":"stop"}]}` + + tests := []struct { + name string + apiBase string + wantAgent string + }{ + { + name: "sets KimiCLI User-Agent for api.kimi.com", + apiBase: "https://api.kimi.com/coding/v1", + wantAgent: "KimiCLI/0.77", + }, + { + name: "does not set KimiCLI User-Agent for other hosts", + apiBase: "https://api.example.com/v1", + wantAgent: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var gotUserAgent string + + p := NewProvider("key", tt.apiBase, "") + p.httpClient.Transport = roundTripFunc( + func(r *http.Request) (*http.Response, error) { + gotUserAgent = r.Header.Get("User-Agent") + return &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser( + strings.NewReader(okBody), + ), + Header: http.Header{ + "Content-Type": {"application/json"}, + }, + }, nil + }, + ) + + _, err := p.Chat( + t.Context(), + []Message{{Role: "user", Content: "hi"}}, + nil, + "kimi-k2.5", + nil, + ) + if err != nil { + t.Fatalf("Chat() error = %v", err) + } + + if tt.wantAgent != "" { + if gotUserAgent != tt.wantAgent { + t.Fatalf( + "User-Agent = %q, want %q", + gotUserAgent, tt.wantAgent, + ) + } + } else { + if gotUserAgent == "KimiCLI/0.77" { + t.Fatalf( + "User-Agent should not be KimiCLI/0.77 for non-kimi host", + ) + } + } + }) + } +}