ccpoad / internal /protocol /builtin /request_reasoning_test.go
anyalerob's picture
Upload folder using huggingface_hub
2986042 verified
Raw
History Blame Contribute Delete
3.92 kB
package builtin
import (
"encoding/json"
"reflect"
"strings"
"testing"
)
func TestRequestReasoning(t *testing.T) {
t.Run("anthropic assistant thinking becomes reasoning part", func(t *testing.T) {
req := anthropicMessagesRequest{
Model: "claude-3-5-sonnet",
Messages: []anthropicMessageContent{{
Role: "assistant",
Content: []any{
map[string]any{"type": "thinking", "thinking": "step by step"},
map[string]any{"type": "redacted_thinking", "data": "enc_1"},
map[string]any{"type": "text", "text": "hello"},
},
}},
}
conv, err := normalizeAnthropicConversation(req)
if err != nil {
t.Fatalf("normalizeAnthropicConversation failed: %v", err)
}
if len(conv.Turns) != 1 || len(conv.Turns[0].Parts) != 3 {
t.Fatalf("unexpected turns: %+v", conv.Turns)
}
if got := conv.Turns[0].Parts[0].Kind; got != "reasoning" {
t.Fatalf("expected first part to be reasoning, got %q", got)
}
reasoning := reflect.ValueOf(conv.Turns[0].Parts[0]).FieldByName("Reasoning")
if !reasoning.IsValid() || reasoning.IsNil() {
t.Fatalf("expected reasoning payload on first part, got %+v", conv.Turns[0].Parts[0])
}
if got := reasoning.Elem().FieldByName("Subtype"); !got.IsValid() || got.String() != "thinking" {
t.Fatalf("expected thinking subtype, got %+v", reasoning.Interface())
}
redacted := reflect.ValueOf(conv.Turns[0].Parts[1]).FieldByName("Reasoning")
if !redacted.IsValid() || redacted.IsNil() {
t.Fatalf("expected reasoning payload on second part, got %+v", conv.Turns[0].Parts[1])
}
if got := redacted.Elem().FieldByName("Subtype"); !got.IsValid() || got.String() != "redacted_thinking" {
t.Fatalf("expected redacted_thinking subtype, got %+v", redacted.Interface())
}
})
t.Run("openai request flattens thinking into reasoning_content string only", func(t *testing.T) {
conv := conversation{
Turns: []conversationTurn{{
Role: "assistant",
Parts: []conversationPart{
newReasoningPart("thinking", "first thought", "", ""),
newReasoningPart("redacted_thinking", "", "", "enc_blob"),
newReasoningPart("thinking", "second thought", "sig_xyz", ""),
{Kind: partKindText, Text: "final answer"},
},
}},
}
raw, err := encodeOpenAIRequest("gpt-x", conv, false)
if err != nil {
t.Fatalf("encodeOpenAIRequest failed: %v", err)
}
body := string(raw)
if strings.Contains(body, `"reasoning":[`) {
t.Fatalf("openai request must not emit reasoning array, got: %s", body)
}
if strings.Contains(body, "redacted_thinking") || strings.Contains(body, "enc_blob") || strings.Contains(body, "sig_xyz") {
t.Fatalf("openai request must drop redacted_thinking and signatures, got: %s", body)
}
if !strings.Contains(body, `"reasoning_content":"first thought\n\nsecond thought"`) {
t.Fatalf("expected reasoning_content to join thinking texts with blank line, got: %s", body)
}
if !strings.Contains(body, `"final answer"`) {
t.Fatalf("expected sibling text preserved, got: %s", body)
}
})
t.Run("gemini request drops reasoning but keeps sibling text and tool content", func(t *testing.T) {
conv := conversation{
Turns: []conversationTurn{{
Role: "assistant",
Parts: []conversationPart{
{Kind: "reasoning"},
{Kind: partKindText, Text: "public"},
{Kind: partKindToolCall, ToolCall: &conversationToolCall{
ID: "call_1",
Name: "lookup",
Arguments: json.RawMessage(`{"q":"go"}`),
}},
},
}},
}
raw, err := encodeGeminiRequest(conv)
if err != nil {
t.Fatalf("encodeGeminiRequest failed: %v", err)
}
body := string(raw)
if !strings.Contains(body, `"public"`) || !strings.Contains(body, `"lookup"`) {
t.Fatalf("unexpected gemini request body: %s", body)
}
if strings.Contains(body, `"reasoning"`) {
t.Fatalf("expected gemini request to drop reasoning content, got %s", body)
}
})
}