(#39) Status answers read the nest #47

Merged
jacisjake merged 2 commits from task/39-quill-reads-nest into main 2026-10-28 14:57:16 +00:00
Showing only changes of commit a70c12a52d - Show all commits
+117
View File
@@ -2,6 +2,7 @@ package main
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"strings"
@@ -95,3 +96,119 @@ func TestQuillNotInNestCrows(t *testing.T) {
t.Fatal("Quill must not need or earn a worker trust record")
}
}
func TestQuillPromptContainsNestHistory(t *testing.T) {
ts, _, qb := newQuillServer(t, "Hugin finished the build already.")
id := newNest(t, ts, "Lab", `"Hugin","Munin"`)
// 1. owner says something that sets up context
code, out := post(t, ts.URL+"/api/nests/"+id+"/messages",
`{"author":"owner","to":"Hugin","kind":"say","text":"build the widget factory"}`)
if code != http.StatusCreated {
t.Fatalf("post say: %d", code)
}
sayMsgID := out["msg_id"].(string)
// 2. Hugin delivers an answer
code, _ = post(t, ts.URL+"/api/nests/"+id+"/messages",
`{"author":"Hugin","kind":"deliver","text":"the widget factory is live","refers_to":"`+sayMsgID+`"}`)
if code != http.StatusCreated {
t.Fatalf("post deliver: %d", code)
}
// 3. owner asks Quill for status
code, _ = post(t, ts.URL+"/api/nests/"+id+"/messages",
`{"author":"owner","to":"Quill","kind":"request","text":"where did that get to"}`)
if code != http.StatusCreated {
t.Fatalf("post request to Quill: %d", code)
}
// Wait for Quill's reply (3 prior + 1 Quill reply = 4)
msgs := awaitMessages(t, ts, id, 4)
var quillReply map[string]any
for _, m := range msgs {
if m["author"] == "Quill" {
quillReply = m
}
}
if quillReply == nil {
t.Fatalf("Quill never answered: %v", msgs)
}
qb.mu.Lock()
defer qb.mu.Unlock()
if len(qb.pairs) != 1 {
t.Fatalf("want exactly one model call, got %d", len(qb.pairs))
}
prompt := qb.pairs[0][1]
if !strings.Contains(prompt, "build the widget factory") {
t.Fatalf("prompt must contain the owner's earlier message: %q", prompt)
}
if !strings.Contains(prompt, "the widget factory is live") {
t.Fatalf("prompt must contain Hugin's deliver: %q", prompt)
}
}
func TestQuillEmptyNestSaysQuiet(t *testing.T) {
ts, _, qb := newQuillServer(t, "All quiet here.")
id := newNest(t, ts, "Quiet", `"Hugin"`)
// Only message is the request to Quill — history excluding it is empty
code, _ := post(t, ts.URL+"/api/nests/"+id+"/messages",
`{"author":"owner","to":"Quill","kind":"request","text":"any updates?"}`)
if code != http.StatusCreated {
t.Fatalf("post: %d", code)
}
awaitMessages(t, ts, id, 2)
qb.mu.Lock()
defer qb.mu.Unlock()
if len(qb.pairs) != 1 {
t.Fatalf("want exactly one model call, got %d", len(qb.pairs))
}
prompt := qb.pairs[0][1]
if !strings.Contains(prompt, "no earlier messages") {
t.Fatalf("prompt must state the nest is empty: %q", prompt)
}
}
func TestQuillHistoryCap(t *testing.T) {
ts, _, qb := newQuillServer(t, "got it")
id := newNest(t, ts, "Busy", `"Hugin"`)
// Post 25 filler messages from owner
for i := 0; i < 25; i++ {
code, _ := post(t, ts.URL+"/api/nests/"+id+"/messages",
fmt.Sprintf(`{"author":"owner","kind":"say","text":"filler line %d"}`, i))
if code != http.StatusCreated {
t.Fatalf("post filler %d: %d", i, code)
}
}
// Ask Quill
code, _ := post(t, ts.URL+"/api/nests/"+id+"/messages",
`{"author":"owner","to":"Quill","kind":"request","text":"status"}`)
if code != http.StatusCreated {
t.Fatalf("post to Quill: %d", code)
}
awaitMessages(t, ts, id, 27)
qb.mu.Lock()
defer qb.mu.Unlock()
if len(qb.pairs) != 1 {
t.Fatalf("want exactly one model call, got %d", len(qb.pairs))
}
prompt := qb.pairs[0][1]
historyLines := 0
for _, line := range strings.Split(prompt, "\n") {
if strings.HasPrefix(line, "[") {
historyLines++
}
}
if historyLines > 20 {
t.Fatalf("history lines must be capped at 20, got %d\nprompt:\n%s", historyLines, prompt)
}
if historyLines == 0 {
t.Fatalf("expected some history lines, got none")
}
}