Files
clawgo/pkg/providers/kimi_provider_test.go

159 lines
5.1 KiB
Go

package providers
import (
"net/http"
"testing"
"time"
)
func TestBuildKimiChatRequestStripsPrefixAndAppliesThinking(t *testing.T) {
base := NewHTTPProvider("kimi", "token", kimiCompatBaseURL, "kimi-k2.5", false, "oauth", 5*time.Second, nil)
body := buildKimiChatRequest(base, []Message{{Role: "user", Content: "hi"}}, nil, "kimi-k2.5(high)", nil, false)
if got := body["model"]; got != "k2.5" {
t.Fatalf("model = %#v, want k2.5", got)
}
if got := body["reasoning_effort"]; got != "high" {
t.Fatalf("reasoning_effort = %#v, want high", got)
}
}
func TestBuildKimiChatRequestDisablesThinking(t *testing.T) {
base := NewHTTPProvider("kimi", "token", kimiCompatBaseURL, "kimi-k2.5", false, "oauth", 5*time.Second, nil)
body := buildKimiChatRequest(base, []Message{{Role: "user", Content: "hi"}}, nil, "kimi-k2.5(none)", nil, false)
thinking, _ := body["thinking"].(map[string]interface{})
if got := thinking["type"]; got != "disabled" {
t.Fatalf("thinking.type = %#v, want disabled", got)
}
}
func TestNormalizeKimiToolMessagesBackfillsToolCallID(t *testing.T) {
body := map[string]interface{}{
"messages": []map[string]interface{}{
{
"role": "assistant",
"tool_calls": []map[string]interface{}{
{"id": "call_1"},
},
"content": "thinking content",
},
{
"role": "tool",
"content": "tool result",
},
},
}
normalizeKimiToolMessages(body)
msgs := body["messages"].([]map[string]interface{})
if got := msgs[1]["tool_call_id"]; got != "call_1" {
t.Fatalf("tool_call_id = %#v, want call_1", got)
}
if got := msgs[0]["reasoning_content"]; got != "thinking content" {
t.Fatalf("reasoning_content = %#v, want fallback content", got)
}
}
func TestNormalizeKimiToolMessagesPromotesCallID(t *testing.T) {
body := map[string]interface{}{
"messages": []map[string]interface{}{
{
"role": "tool",
"call_id": "call_2",
},
},
}
normalizeKimiToolMessages(body)
msgs := body["messages"].([]map[string]interface{})
if got := msgs[0]["tool_call_id"]; got != "call_2" {
t.Fatalf("tool_call_id = %#v, want call_2", got)
}
}
func TestApplyAttemptProviderHeadersKimiUsesResolvedDeviceFields(t *testing.T) {
req, err := http.NewRequest(http.MethodPost, kimiCompatBaseURL+"/chat/completions", nil)
if err != nil {
t.Fatalf("new request: %v", err)
}
provider := &HTTPProvider{
oauth: &oauthManager{cfg: oauthConfig{Provider: defaultKimiOAuthProvider}},
}
attempt := authAttempt{
kind: "oauth",
token: "kimi-token",
session: &oauthSession{
DeviceID: "device-123",
},
}
applyAttemptProviderHeaders(req, attempt, provider, true)
if got := req.Header.Get("X-Msh-Device-Id"); got != "device-123" {
t.Fatalf("X-Msh-Device-Id = %q, want device-123", got)
}
if got := req.Header.Get("X-Msh-Device-Model"); got != kimiDeviceModel() {
t.Fatalf("X-Msh-Device-Model = %q, want %q", got, kimiDeviceModel())
}
if got := req.Header.Get("X-Msh-Device-Name"); got == "" {
t.Fatal("expected X-Msh-Device-Name to be set")
}
}
func TestKimiHookUsesSessionResourceURL(t *testing.T) {
hooks := kimiProviderHooks{}
base := NewHTTPProvider("kimi", "token", kimiCompatBaseURL, "kimi-k2.5", false, "oauth", 5*time.Second, nil)
got := hooks.endpoint(base, authAttempt{
kind: "oauth",
session: &oauthSession{
ResourceURL: "https://api.kimi.com/coding/v1",
},
}, "/chat/completions")
if got != "https://api.kimi.com/coding/v1/chat/completions" {
t.Fatalf("endpoint = %q", got)
}
}
func TestNormalizeKimiResourceURL(t *testing.T) {
tests := []struct {
in string
want string
}{
{in: "https://api.kimi.com/coding", want: "https://api.kimi.com/coding/v1"},
{in: "api.kimi.com/coding", want: "https://api.kimi.com/coding/v1"},
{in: "https://api.kimi.com/coding/v1", want: "https://api.kimi.com/coding/v1"},
}
for _, tt := range tests {
if got := normalizeKimiResourceURL(tt.in); got != tt.want {
t.Fatalf("normalizeKimiResourceURL(%q) = %q, want %q", tt.in, got, tt.want)
}
}
}
func TestKimiProviderCountTokens(t *testing.T) {
provider := NewKimiProvider("kimi", "token", kimiCompatBaseURL, "kimi-k2.5", false, "api_key", 5*time.Second, nil)
usage, err := provider.CountTokens(t.Context(), []Message{{Role: "user", Content: "hello kimi"}}, nil, "kimi-k2.5", nil)
if err != nil {
t.Fatalf("CountTokens error: %v", err)
}
if usage == nil || usage.PromptTokens <= 0 || usage.TotalTokens != usage.PromptTokens {
t.Fatalf("usage = %#v, want positive prompt-only count", usage)
}
}
func TestBuildKimiChatRequestSupportsNumericAutoAndDisable(t *testing.T) {
base := NewHTTPProvider("kimi", "token", kimiCompatBaseURL, "kimi-k2.5", false, "oauth", 5*time.Second, nil)
autoBody := buildKimiChatRequest(base, []Message{{Role: "user", Content: "hi"}}, nil, "kimi-k2.5(-1)", nil, false)
if got := autoBody["reasoning_effort"]; got != "auto" {
t.Fatalf("reasoning_effort = %#v, want auto", got)
}
disableBody := buildKimiChatRequest(base, []Message{{Role: "user", Content: "hi"}}, nil, "kimi-k2.5(0)", nil, false)
thinking, _ := disableBody["thinking"].(map[string]interface{})
if got := thinking["type"]; got != "disabled" {
t.Fatalf("thinking.type = %#v, want disabled", got)
}
}