package session import ( "testing" "nub/internal/llm" ) func textMsg(role llm.Role, text string) llm.Message { return llm.Message{Role: role, Content: []llm.Block{{Kind: llm.KindText, Text: text}}} } func TestSession_PathToHead_OrdersRootToHead(t *testing.T) { s := New("s1") n1 := NewNode("", textMsg(llm.RoleUser, "one"), NodeMeta{}) must(t, s.Append(n1)) n2 := NewNode(n1.ID, textMsg(llm.RoleAssistant, "two"), NodeMeta{}) must(t, s.Append(n2)) n3 := NewNode(n2.ID, textMsg(llm.RoleUser, "three"), NodeMeta{}) must(t, s.Append(n3)) msgs := s.PathToHead() if len(msgs) != 3 { t.Fatalf("len = %d, want 3", len(msgs)) } want := []string{"one", "two", "three"} for i, w := range want { if msgs[i].Content[0].Text != w { t.Errorf("msgs[%d] = %q, want %q", i, msgs[i].Content[0].Text, w) } } } func TestSession_PathToHead_StopsAtSummary(t *testing.T) { s := New("s1") n1 := NewNode("", textMsg(llm.RoleUser, "old-1"), NodeMeta{}) must(t, s.Append(n1)) n2 := NewNode(n1.ID, textMsg(llm.RoleAssistant, "old-2"), NodeMeta{}) must(t, s.Append(n2)) summary := &Node{ ID: "summary-1", ParentID: n2.ID, Kind: NodeSummary, Message: textMsg(llm.RoleUser, "SUMMARY of old-1/old-2"), Replaces: []string{n1.ID, n2.ID}, } must(t, s.Append(summary)) n3 := NewNode(summary.ID, textMsg(llm.RoleUser, "new"), NodeMeta{}) must(t, s.Append(n3)) msgs := s.PathToHead() if len(msgs) != 2 { t.Fatalf("len = %d, want 2 (summary + new)", len(msgs)) } if msgs[0].Content[0].Text != "SUMMARY of old-1/old-2" { t.Errorf("msgs[0] = %q", msgs[0].Content[0].Text) } if msgs[1].Content[0].Text != "new" { t.Errorf("msgs[1] = %q", msgs[1].Content[0].Text) } } func TestSession_Branch_CreatesSecondPath(t *testing.T) { s := New("s1") n1 := NewNode("", textMsg(llm.RoleUser, "root"), NodeMeta{}) must(t, s.Append(n1)) n2a := NewNode(n1.ID, textMsg(llm.RoleAssistant, "branch-a"), NodeMeta{}) must(t, s.Append(n2a)) must(t, s.Branch(n1.ID)) n2b := NewNode(n1.ID, textMsg(llm.RoleAssistant, "branch-b"), NodeMeta{}) must(t, s.Append(n2b)) if s.Head != n2b.ID { t.Fatalf("head = %s, want %s", s.Head, n2b.ID) } must(t, s.Branch(n2a.ID)) msgsA := s.PathToHead() if msgsA[len(msgsA)-1].Content[0].Text != "branch-a" { t.Errorf("branch a tip = %q", msgsA[len(msgsA)-1].Content[0].Text) } must(t, s.Branch(n2b.ID)) msgsB := s.PathToHead() if msgsB[len(msgsB)-1].Content[0].Text != "branch-b" { t.Errorf("branch b tip = %q", msgsB[len(msgsB)-1].Content[0].Text) } } func TestSession_Append_RejectsUnknownParent(t *testing.T) { s := New("s1") n := NewNode("does-not-exist", textMsg(llm.RoleUser, "x"), NodeMeta{}) if err := s.Append(n); err == nil { t.Fatal("expected error for unknown parent") } } func must(t *testing.T, err error) { t.Helper() if err != nil { t.Fatal(err) } }