package openai import "testing" func runSplitter(deltas []string) (reasoning, text string) { var t thinkSplitter for _, d := range deltas { r, txt := t.push(d) reasoning += r text += txt } r, txt := t.flush() return reasoning + r, text + txt } func TestThinkSplitter(t *testing.T) { cases := []struct { name string deltas []string reasoning string text string }{ { name: "whole block in one delta", deltas: []string{"reasoning herethe answer"}, reasoning: "reasoning here", text: "the answer", }, { name: "open tag split across deltas", deltas: []string{"chain", " of thoughtanswer"}, reasoning: "chain of thought", text: "answer", }, { name: "close tag split across deltas", deltas: []string{"thinkingdone"}, reasoning: "thinking", text: "done", }, { name: "leading whitespace before think is dropped", deltas: []string{"\n\n r\n\nanswer"}, reasoning: "r", text: "answer", }, { name: "no think tag passes through as text", deltas: []string{"just a normal ", "answer"}, reasoning: "", text: "just a normal answer", }, { name: "think mentioned mid-answer is not hijacked", deltas: []string{"the model emits tags around its reasoning"}, reasoning: "", text: "the model emits tags around its reasoning", }, { name: "unterminated think block flushes as reasoning", deltas: []string{"still thinking when the stream ended"}, reasoning: "still thinking when the stream ended", text: "", }, { name: "per-character streaming", deltas: []string{"<", "t", "h", "i", "n", "k", ">", "a", "", "b"}, reasoning: "a", text: "b", }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { r, txt := runSplitter(tc.deltas) if r != tc.reasoning { t.Errorf("reasoning = %q, want %q", r, tc.reasoning) } if txt != tc.text { t.Errorf("text = %q, want %q", txt, tc.text) } }) } }