2026-11-14 01:14:08 +00:00
|
|
|
package domain
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"reflect"
|
|
|
|
|
"testing"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func TestExchangeHistoryOwnershipAndBranches(t *testing.T) {
|
|
|
|
|
control := &CacheControl{Type: CacheControlEphemeral, TTL: "1h"}
|
|
|
|
|
source := []RenderedMessage{{Role: RoleSystem, Content: "", CacheControl: control}, {Role: RoleUser, Content: "question"}}
|
|
|
|
|
initial := CaptureExchange(nil, "first", source, " answer ")
|
|
|
|
|
first := CaptureExchange(initial, "second", []RenderedMessage{{Role: RoleUser, Content: "follow-up"}}, "reply")
|
|
|
|
|
second := CaptureExchange(initial, "third", []RenderedMessage{{Role: RoleDeveloper, Content: "other"}}, "")
|
|
|
|
|
source[0].Content = "changed"
|
|
|
|
|
control.TTL = "changed"
|
|
|
|
|
got := initial.Messages()
|
|
|
|
|
want := []RenderedMessage{{Role: RoleSystem, Content: "", CacheControl: &CacheControl{Type: CacheControlEphemeral, TTL: "1h"}}, {Role: RoleUser, Content: "question"}, {Role: RoleAssistant, Content: " answer "}}
|
|
|
|
|
if !reflect.DeepEqual(got, want) {
|
|
|
|
|
t.Fatalf("initial messages = %#v, want %#v", got, want)
|
|
|
|
|
}
|
|
|
|
|
got[0].CacheControl.TTL = "mutated"
|
|
|
|
|
got[1].Content = "mutated"
|
|
|
|
|
if !reflect.DeepEqual(initial.Messages(), want) {
|
|
|
|
|
t.Fatal("returned messages changed retained history")
|
|
|
|
|
}
|
|
|
|
|
if first.RunID() != "second" || first.ParentRunID() != "first" || first.MessageCount() != 5 {
|
|
|
|
|
t.Fatal("incorrect branch metadata")
|
|
|
|
|
}
|
|
|
|
|
if second.ParentRunID() != "first" || second.Messages()[3].Content != "other" || second.Messages()[4].Content != "" {
|
|
|
|
|
t.Fatal("incorrect sibling history")
|
|
|
|
|
}
|
|
|
|
|
if first.Messages()[3].Content != "follow-up" || !reflect.DeepEqual(initial.Messages(), want) {
|
|
|
|
|
t.Fatal("branches changed each other or their parent")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestExchangeManyTurns(t *testing.T) {
|
|
|
|
|
var exchange *Exchange
|
|
|
|
|
const turns = 2000
|
|
|
|
|
for i := 0; i < turns; i++ {
|
|
|
|
|
exchange = CaptureExchange(exchange, fmt.Sprint(i), []RenderedMessage{{Role: RoleUser, Content: fmt.Sprint(i)}}, fmt.Sprint(i))
|
|
|
|
|
}
|
|
|
|
|
messages := exchange.Messages()
|
|
|
|
|
if len(messages) != turns*2 || exchange.MessageCount() != len(messages) {
|
|
|
|
|
t.Fatalf("unexpected history length: %d", len(messages))
|
|
|
|
|
}
|
|
|
|
|
for i := 0; i < turns; i++ {
|
|
|
|
|
if messages[2*i].Content != fmt.Sprint(i) || messages[2*i+1].Role != RoleAssistant || messages[2*i+1].Content != fmt.Sprint(i) {
|
|
|
|
|
t.Fatalf("unexpected turn %d: %#v", i, messages[2*i:2*i+2])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-11-14 14:28:08 +00:00
|
|
|
|
|
|
|
|
func TestExchangeMessagesWithSuffix(t *testing.T) {
|
|
|
|
|
for _, history := range []*Exchange{nil, CaptureExchange(nil, "source", nil, "answer")} {
|
|
|
|
|
control := &CacheControl{Type: CacheControlEphemeral, TTL: "1h"}
|
|
|
|
|
first := []RenderedMessage{{Role: RoleUser, Content: "new", CacheControl: control}}
|
|
|
|
|
last := []RenderedMessage{{Role: RoleDeveloper, Content: "suffix"}}
|
|
|
|
|
got := history.MessagesWithSuffix(first, nil, last)
|
|
|
|
|
want := append(history.Messages(), first...)
|
|
|
|
|
want = append(want, last...)
|
|
|
|
|
if !reflect.DeepEqual(got, want) {
|
|
|
|
|
t.Fatalf("messages = %#v, want %#v", got, want)
|
|
|
|
|
}
|
|
|
|
|
got[history.MessageCount()].CacheControl.TTL = "changed"
|
|
|
|
|
got[history.MessageCount()].Content = "changed"
|
|
|
|
|
if first[0].Content != "new" || control.TTL != "1h" {
|
|
|
|
|
t.Fatal("assembled messages alias the caller suffix")
|
|
|
|
|
}
|
|
|
|
|
if history != nil && history.Messages()[0].Content != "answer" {
|
|
|
|
|
t.Fatal("assembly changed retained history")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|