package server import ( "strings" "testing" ) func TestToolCallStreamParser_PlainTextPassThrough(t *testing.T) { p := NewToolCallStreamParser() emit, calls, err := p.Feed("hello world\n") if err != nil { t.Fatalf("unexpected error: %v", err) } if len(calls) != 0 { t.Fatalf("expected no calls, got %+v", calls) } if emit != "hello world\n" { t.Fatalf("emit = %q, want passthrough", emit) } rest, err := p.Flush() if err != nil { t.Fatalf("flush error: %v", err) } if rest != "" { t.Fatalf("flush leftover = %q, want empty", rest) } } func TestToolCallStreamParser_ExtractsCompleteCall(t *testing.T) { p := NewToolCallStreamParser() in := "before\n\n{\"name\":\"bash\",\"input\":{\"command\":\"ls\"}}\n\nafter" emit, calls, err := p.Feed(in) if err != nil { t.Fatalf("error: %v", err) } if len(calls) != 1 { t.Fatalf("expected 1 call, got %d", len(calls)) } if calls[0].Name != "bash" { t.Fatalf("name = %q", calls[0].Name) } if !strings.Contains(string(calls[0].Input), `"command":"ls"`) { t.Fatalf("input = %s", calls[0].Input) } if !strings.Contains(emit, "before") || !strings.Contains(emit, "after") { t.Fatalf("emit lost surrounding text: %q", emit) } } func TestToolCallStreamParser_HoldsPartialOpenSentinel(t *testing.T) { p := NewToolCallStreamParser() // Feed a chunk ending with a partial "{\"name\":\"x\"}") if err != nil { t.Fatalf("error 2: %v", err) } if emit2 != "" { t.Fatalf("emit2 = %q, want empty (only call extracted)", emit2) } if len(calls2) != 1 || calls2[0].Name != "x" { t.Fatalf("calls2 = %+v", calls2) } } func TestToolCallStreamParser_RejectsInvalidJSON(t *testing.T) { p := NewToolCallStreamParser() _, _, err := p.Feed("not json") if err == nil { t.Fatal("expected parse error for invalid JSON inside sentinels") } } func TestExtractAllToolCalls_MultipleAndCleanText(t *testing.T) { in := "preamble\n{\"name\":\"a\",\"input\":{}}\nmiddle\n{\"tool\":\"b\",\"arguments\":{\"x\":1}}\nend" clean, calls := ExtractAllToolCalls(in) if len(calls) != 2 { t.Fatalf("calls = %d", len(calls)) } if calls[0].Name != "a" || calls[1].Name != "b" { t.Fatalf("names = %q, %q", calls[0].Name, calls[1].Name) } if !strings.Contains(clean, "preamble") || !strings.Contains(clean, "middle") || !strings.Contains(clean, "end") { t.Fatalf("clean text wrong: %q", clean) } if strings.Contains(clean, "") { t.Fatalf("clean text still contains sentinels: %q", clean) } }