refactor: parse Kimi API hostname once in constructor instead of per-call

Avoid re-parsing apiBase URL on every Chat() invocation by computing
isKimiAPI once in NewProvider(). Also document why the KimiCLI/0.77
User-Agent string is required.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
I Putu Eddy Irawan 2026-03-03 21:34:31 +07:00
parent 2fc87985d2
commit e54b1d39a5

View file

@ -33,6 +33,7 @@ type Provider struct {
apiBase string apiBase string
maxTokensField string // Field name for max tokens (e.g., "max_completion_tokens" for o1/glm models) maxTokensField string // Field name for max tokens (e.g., "max_completion_tokens" for o1/glm models)
httpClient *http.Client httpClient *http.Client
isKimiAPI bool // true when apiBase points to api.kimi.com
} }
type Option func(*Provider) type Option func(*Provider)
@ -69,10 +70,17 @@ func NewProvider(apiKey, apiBase, proxy string, opts ...Option) *Provider {
} }
} }
trimmedBase := strings.TrimRight(apiBase, "/")
var isKimi bool
if parsed, err := url.Parse(trimmedBase); err == nil {
isKimi = parsed.Hostname() == "api.kimi.com"
}
p := &Provider{ p := &Provider{
apiKey: apiKey, apiKey: apiKey,
apiBase: strings.TrimRight(apiBase, "/"), apiBase: trimmedBase,
httpClient: client, httpClient: client,
isKimiAPI: isKimi,
} }
for _, opt := range opts { for _, opt := range opts {
@ -176,8 +184,10 @@ func (p *Provider) Chat(
if p.apiKey != "" { if p.apiKey != "" {
req.Header.Set("Authorization", "Bearer "+p.apiKey) req.Header.Set("Authorization", "Bearer "+p.apiKey)
} }
// Kimi Code API requires a coding agent User-Agent // Kimi Code API rejects requests without a recognized coding-agent
if parsedURL, parseErr := url.Parse(p.apiBase); parseErr == nil && parsedURL.Hostname() == "api.kimi.com" { // User-Agent. "KimiCLI/0.77" is the minimum version string accepted
// by the api.kimi.com/coding/v1 endpoint (per Kimi's API docs).
if p.isKimiAPI {
req.Header.Set("User-Agent", "KimiCLI/0.77") req.Header.Set("User-Agent", "KimiCLI/0.77")
} }