package openai import ( "encoding/json" "strings" "testing" ) func TestDisplayReasoningContent(t *testing.T) { raw := "hello" + claudeReasoningRoundTripSep + `[{"type":"thinking","thinking":"x","signature":"sig"}]` if d := DisplayReasoningContent(raw); d != "hello" { t.Fatalf("got %q", d) } if DisplayReasoningContent("plain") != "plain" { t.Fatal() } } func TestAppendParseClaudeReasoningRoundTrip(t *testing.T) { blocks := []claudeContentBlock{ {Type: "thinking", Thinking: "a", Signature: "s1"}, {Type: "thinking", Thinking: "b", Signature: "s2"}, } s := appendClaudeReasoningRoundTrip("sum", blocks) if !strings.Contains(s, claudeReasoningRoundTripSep) { t.Fatal("missing sep") } display, back := parseClaudeReasoningAssistantBlocks(s) if display != "sum" || len(back) != 2 { t.Fatalf("display=%q len=%d", display, len(back)) } if back[0].Signature != "s1" || back[1].Thinking != "b" { t.Fatalf("%+v", back) } } func TestConvertOpenAIToClaude_AssistantReasoningReplay(t *testing.T) { rc := appendClaudeReasoningRoundTrip("vis", []claudeContentBlock{ {Type: "thinking", Thinking: "t1", Signature: "sig1"}, }) payload := map[string]interface{}{ "model": "claude-3-5-sonnet-latest", "messages": []interface{}{ map[string]interface{}{ "role": "assistant", "content": "out", "reasoning_content": rc, }, }, } req, err := convertOpenAIToClaude(payload) if err != nil { t.Fatal(err) } if len(req.Messages) != 1 { t.Fatalf("messages=%d", len(req.Messages)) } blocks := req.Messages[0].Content.Blocks if len(blocks) < 2 { t.Fatalf("blocks=%d", len(blocks)) } if blocks[0].Type != "thinking" || blocks[0].Signature != "sig1" { t.Fatalf("first block %+v", blocks[0]) } foundText := false for _, b := range blocks { if b.Type == "text" && b.Text == "out" { foundText = true } } if !foundText { t.Fatalf("blocks=%+v", blocks) } } func TestClaudeToOpenAIResponseJSON_Thinking(t *testing.T) { claudeBody := []byte(`{ "id":"msg_1","type":"message","role":"assistant","model":"x","stop_reason":"end_turn", "content":[ {"type":"thinking","thinking":"step","signature":"sigx"}, {"type":"text","text":"hi"} ] }`) oai, err := claudeToOpenAIResponseJSON(claudeBody) if err != nil { t.Fatal(err) } var wrap map[string]interface{} if err := json.Unmarshal(oai, &wrap); err != nil { t.Fatal(err) } choices := wrap["choices"].([]interface{}) ch0 := choices[0].(map[string]interface{}) msg := ch0["message"].(map[string]interface{}) rc, _ := msg["reasoning_content"].(string) if !strings.Contains(rc, "step") || !strings.Contains(rc, claudeReasoningRoundTripSep) { t.Fatalf("reasoning_content=%q", rc) } if msg["content"] != "hi" { t.Fatal() } }