et un
en HTML.") {
t.Fatal("HTML ordinaire pris pour un appel d'outil")
}
}
// Le faux appel est repéré PENDANT le flux : la génération est coupée (la suite
// n'arrive jamais à l'écran) et la relance cite l'extrait fautif.
func TestAppelTextuelCoupeLeFlux(t *testing.T) {
testHome(t)
var n int32
var second string
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/event-stream")
w.WriteHeader(200)
if atomic.AddInt32(&n, 1) == 1 {
_, _ = w.Write([]byte(sseChunk("Je lance
")))
w.(http.Flusher).Flush()
time.Sleep(300 * time.Millisecond)
_, _ = w.Write([]byte(sseChunk("FIN-INUTILE")))
_, _ = w.Write([]byte(`data: {"choices":[{"delta":{},"finish_reason":"stop"}]}` + "\n\n"))
return
}
var body struct {
Messages []Message `json:"messages"`
}
_ = json.NewDecoder(r.Body).Decode(&body)
second = msgText(body.Messages[len(body.Messages)-1])
_, _ = w.Write([]byte(sseChunk("ok")))
_, _ = w.Write([]byte(`data: {"choices":[{"delta":{},"finish_reason":"stop"}]}` + "\n\ndata: [DONE]\n\n"))
}))
t.Cleanup(srv.Close)
u, _ := url.Parse(srv.URL)
if err := SetConfigKey("PORT", u.Port()); err != nil {
t.Fatal(err)
}
var content strings.Builder
if _, err := runChat(context.Background(), []Message{{Role: "user", Content: "liste"}}, 0.7, Caps{Agent: true}, func(ev StreamEvent) bool {
content.WriteString(ev.Content)
return true
}); err != nil {
t.Fatal(err)
}
if strings.Contains(content.String(), "FIN-INUTILE") {
t.Fatal("le flux n'a pas été coupé sur l'appel écrit en texte")
}
if !strings.Contains(second, "") || !strings.Contains(second, "WRITTEN AS TEXT") {
t.Fatalf("relance sans l'extrait fautif : %q", second)
}
}