package proxy import ( "strings" "testing" ) func TestNothingIsCapturedUnlessAThreadAsked(t *testing.T) { // This is the hottest path in the system. A gateway that accumulated every // reply in memory would be one long answer away from trouble, so a request // that stores nothing must pay nothing. var r replyBuilder // cap zero, which is every ordinary request r.add("a long assistant reply that nobody asked to keep") if got, truncated := r.result(); got != "" || truncated { t.Errorf("a request with no thread accumulated %q", got) } } func TestALongReplyCostsNoMoreThanTheCap(t *testing.T) { // Stopping at the cap rather than growing and truncating afterwards is // what makes the cap a memory bound instead of a formatting rule. r := replyBuilder{cap: 10} for range 1000 { r.add(strings.Repeat("x", 100)) } got, truncated := r.result() if len(got) > 10 { t.Errorf("accumulated %d bytes against a cap of 10", len(got)) } if !truncated { t.Error("truncation was not reported") } } func TestATruncatedReplyIsStillValidUTF8(t *testing.T) { // It goes back into a JSON body on the next turn. A split multi-byte // character would make that body unserialisable, and the thread would // break for good rather than for one turn. r := replyBuilder{cap: 4} r.add("üçüncü") // two-byte runes either side of the cut got, _ := r.result() for i, ch := range got { if ch == '�' { t.Fatalf("invalid UTF-8 at byte %d of %q", i, got) } } } func TestTheAssistantTextIsFoundInBothResponseShapes(t *testing.T) { chat := `{"choices":[{"message":{"role":"assistant","content":"hello"}}]}` if got := replyFromJSON([]byte(chat)); got != "hello" { t.Errorf("chat completion reply = %q", got) } // The completions endpoint, which has no message wrapper. legacy := `{"choices":[{"text":"hello"}]}` if got := replyFromJSON([]byte(legacy)); got != "hello" { t.Errorf("completion reply = %q", got) } } func TestOnlyTheFirstChoiceIsKept(t *testing.T) { // A request asking for several is not one continuing a conversation, and // storing one of them as "what the assistant said" would invent a // conversation that never happened. body := `{"choices":[{"message":{"content":"one"}},{"message":{"content":"two"}}]}` if got := replyFromJSON([]byte(body)); got != "one" { t.Errorf("reply = %q", got) } } func TestStreamedDeltasAssembleIntoTheReply(t *testing.T) { r := replyBuilder{cap: 1024} for _, ev := range []string{ `{"choices":[{"delta":{"role":"assistant"}}]}`, `{"choices":[{"delta":{"content":"Hel"}}]}`, `{"choices":[{"delta":{"content":"lo"}}]}`, `[DONE]`, } { r.add(replyDelta(ev)) } if got, _ := r.result(); got != "Hello" { t.Errorf("assembled %q", got) } } func TestAMalformedEventContributesNothing(t *testing.T) { // An engine sending something unexpected must not corrupt a stored // conversation; the worst case is a turn that is shorter than it was. if got := replyDelta(`not json at all`); got != "" { t.Errorf("garbage produced %q", got) } if got := replyDelta(``); got != "" { t.Errorf("an empty event produced %q", got) } }