Spaces:
Paused
Paused
| package executor | |
| import ( | |
| "testing" | |
| "github.com/tidwall/gjson" | |
| ) | |
| func TestNormalizeKimiToolMessageLinks_UsesCallIDFallback(t *testing.T) { | |
| body := []byte(`{ | |
| "messages":[ | |
| {"role":"assistant","tool_calls":[{"id":"list_directory:1","type":"function","function":{"name":"list_directory","arguments":"{}"}}]}, | |
| {"role":"tool","call_id":"list_directory:1","content":"[]"} | |
| ] | |
| }`) | |
| out, err := normalizeKimiToolMessageLinks(body) | |
| if err != nil { | |
| t.Fatalf("normalizeKimiToolMessageLinks() error = %v", err) | |
| } | |
| got := gjson.GetBytes(out, "messages.1.tool_call_id").String() | |
| if got != "list_directory:1" { | |
| t.Fatalf("messages.1.tool_call_id = %q, want %q", got, "list_directory:1") | |
| } | |
| } | |
| func TestNormalizeKimiToolMessageLinks_InferSinglePendingID(t *testing.T) { | |
| body := []byte(`{ | |
| "messages":[ | |
| {"role":"assistant","tool_calls":[{"id":"call_123","type":"function","function":{"name":"read_file","arguments":"{}"}}]}, | |
| {"role":"tool","content":"file-content"} | |
| ] | |
| }`) | |
| out, err := normalizeKimiToolMessageLinks(body) | |
| if err != nil { | |
| t.Fatalf("normalizeKimiToolMessageLinks() error = %v", err) | |
| } | |
| got := gjson.GetBytes(out, "messages.1.tool_call_id").String() | |
| if got != "call_123" { | |
| t.Fatalf("messages.1.tool_call_id = %q, want %q", got, "call_123") | |
| } | |
| } | |
| func TestNormalizeKimiToolMessageLinks_AmbiguousMissingIDIsNotInferred(t *testing.T) { | |
| body := []byte(`{ | |
| "messages":[ | |
| {"role":"assistant","tool_calls":[ | |
| {"id":"call_1","type":"function","function":{"name":"list_directory","arguments":"{}"}}, | |
| {"id":"call_2","type":"function","function":{"name":"read_file","arguments":"{}"}} | |
| ]}, | |
| {"role":"tool","content":"result-without-id"} | |
| ] | |
| }`) | |
| out, err := normalizeKimiToolMessageLinks(body) | |
| if err != nil { | |
| t.Fatalf("normalizeKimiToolMessageLinks() error = %v", err) | |
| } | |
| if gjson.GetBytes(out, "messages.1.tool_call_id").Exists() { | |
| t.Fatalf("messages.1.tool_call_id should be absent for ambiguous case, got %q", gjson.GetBytes(out, "messages.1.tool_call_id").String()) | |
| } | |
| } | |
| func TestNormalizeKimiToolMessageLinks_PreservesExistingToolCallID(t *testing.T) { | |
| body := []byte(`{ | |
| "messages":[ | |
| {"role":"assistant","tool_calls":[{"id":"call_1","type":"function","function":{"name":"list_directory","arguments":"{}"}}]}, | |
| {"role":"tool","tool_call_id":"call_1","call_id":"different-id","content":"result"} | |
| ] | |
| }`) | |
| out, err := normalizeKimiToolMessageLinks(body) | |
| if err != nil { | |
| t.Fatalf("normalizeKimiToolMessageLinks() error = %v", err) | |
| } | |
| got := gjson.GetBytes(out, "messages.1.tool_call_id").String() | |
| if got != "call_1" { | |
| t.Fatalf("messages.1.tool_call_id = %q, want %q", got, "call_1") | |
| } | |
| } | |
| func TestNormalizeKimiToolMessageLinks_InheritsPreviousReasoningForAssistantToolCalls(t *testing.T) { | |
| body := []byte(`{ | |
| "messages":[ | |
| {"role":"assistant","content":"plan","reasoning_content":"previous reasoning"}, | |
| {"role":"assistant","tool_calls":[{"id":"call_1","type":"function","function":{"name":"list_directory","arguments":"{}"}}]} | |
| ] | |
| }`) | |
| out, err := normalizeKimiToolMessageLinks(body) | |
| if err != nil { | |
| t.Fatalf("normalizeKimiToolMessageLinks() error = %v", err) | |
| } | |
| got := gjson.GetBytes(out, "messages.1.reasoning_content").String() | |
| if got != "previous reasoning" { | |
| t.Fatalf("messages.1.reasoning_content = %q, want %q", got, "previous reasoning") | |
| } | |
| } | |
| func TestNormalizeKimiToolMessageLinks_InsertsFallbackReasoningWhenMissing(t *testing.T) { | |
| body := []byte(`{ | |
| "messages":[ | |
| {"role":"assistant","tool_calls":[{"id":"call_1","type":"function","function":{"name":"list_directory","arguments":"{}"}}]} | |
| ] | |
| }`) | |
| out, err := normalizeKimiToolMessageLinks(body) | |
| if err != nil { | |
| t.Fatalf("normalizeKimiToolMessageLinks() error = %v", err) | |
| } | |
| reasoning := gjson.GetBytes(out, "messages.0.reasoning_content") | |
| if !reasoning.Exists() { | |
| t.Fatalf("messages.0.reasoning_content should exist") | |
| } | |
| if reasoning.String() != "[reasoning unavailable]" { | |
| t.Fatalf("messages.0.reasoning_content = %q, want %q", reasoning.String(), "[reasoning unavailable]") | |
| } | |
| } | |
| func TestNormalizeKimiToolMessageLinks_UsesContentAsReasoningFallback(t *testing.T) { | |
| body := []byte(`{ | |
| "messages":[ | |
| {"role":"assistant","content":[{"type":"text","text":"first line"},{"type":"text","text":"second line"}],"tool_calls":[{"id":"call_1","type":"function","function":{"name":"list_directory","arguments":"{}"}}]} | |
| ] | |
| }`) | |
| out, err := normalizeKimiToolMessageLinks(body) | |
| if err != nil { | |
| t.Fatalf("normalizeKimiToolMessageLinks() error = %v", err) | |
| } | |
| got := gjson.GetBytes(out, "messages.0.reasoning_content").String() | |
| if got != "first line\nsecond line" { | |
| t.Fatalf("messages.0.reasoning_content = %q, want %q", got, "first line\nsecond line") | |
| } | |
| } | |
| func TestNormalizeKimiToolMessageLinks_ReplacesEmptyReasoningContent(t *testing.T) { | |
| body := []byte(`{ | |
| "messages":[ | |
| {"role":"assistant","content":"assistant summary","tool_calls":[{"id":"call_1","type":"function","function":{"name":"list_directory","arguments":"{}"}}],"reasoning_content":""} | |
| ] | |
| }`) | |
| out, err := normalizeKimiToolMessageLinks(body) | |
| if err != nil { | |
| t.Fatalf("normalizeKimiToolMessageLinks() error = %v", err) | |
| } | |
| got := gjson.GetBytes(out, "messages.0.reasoning_content").String() | |
| if got != "assistant summary" { | |
| t.Fatalf("messages.0.reasoning_content = %q, want %q", got, "assistant summary") | |
| } | |
| } | |
| func TestNormalizeKimiToolMessageLinks_PreservesExistingAssistantReasoning(t *testing.T) { | |
| body := []byte(`{ | |
| "messages":[ | |
| {"role":"assistant","tool_calls":[{"id":"call_1","type":"function","function":{"name":"list_directory","arguments":"{}"}}],"reasoning_content":"keep me"} | |
| ] | |
| }`) | |
| out, err := normalizeKimiToolMessageLinks(body) | |
| if err != nil { | |
| t.Fatalf("normalizeKimiToolMessageLinks() error = %v", err) | |
| } | |
| got := gjson.GetBytes(out, "messages.0.reasoning_content").String() | |
| if got != "keep me" { | |
| t.Fatalf("messages.0.reasoning_content = %q, want %q", got, "keep me") | |
| } | |
| } | |
| func TestNormalizeKimiToolMessageLinks_RepairsIDsAndReasoningTogether(t *testing.T) { | |
| body := []byte(`{ | |
| "messages":[ | |
| {"role":"assistant","tool_calls":[{"id":"call_1","type":"function","function":{"name":"list_directory","arguments":"{}"}}],"reasoning_content":"r1"}, | |
| {"role":"tool","call_id":"call_1","content":"[]"}, | |
| {"role":"assistant","tool_calls":[{"id":"call_2","type":"function","function":{"name":"read_file","arguments":"{}"}}]}, | |
| {"role":"tool","call_id":"call_2","content":"file"} | |
| ] | |
| }`) | |
| out, err := normalizeKimiToolMessageLinks(body) | |
| if err != nil { | |
| t.Fatalf("normalizeKimiToolMessageLinks() error = %v", err) | |
| } | |
| if got := gjson.GetBytes(out, "messages.1.tool_call_id").String(); got != "call_1" { | |
| t.Fatalf("messages.1.tool_call_id = %q, want %q", got, "call_1") | |
| } | |
| if got := gjson.GetBytes(out, "messages.3.tool_call_id").String(); got != "call_2" { | |
| t.Fatalf("messages.3.tool_call_id = %q, want %q", got, "call_2") | |
| } | |
| if got := gjson.GetBytes(out, "messages.2.reasoning_content").String(); got != "r1" { | |
| t.Fatalf("messages.2.reasoning_content = %q, want %q", got, "r1") | |
| } | |
| } | |