e4e34b092c
A fourth leaf role: Review(finished, history) returns a two-line Reflection (recap + carry_forward) over the same CLI backend as the coach. Primitive-only, with a JSON prompt and a tolerant parser that rejects a blank recap but allows an empty carry_forward. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
78 lines
2.5 KiB
Go
78 lines
2.5 KiB
Go
package ai
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestReviewPromptIncludesSessionAndHistory(t *testing.T) {
|
|
fb := &fakeBackend{out: `{"recap":"r","carry_forward":"c"}`}
|
|
if _, err := NewService(fb).Review(context.Background(), "FINISHED-BLOCK", "HISTORY-BLOCK"); err != nil {
|
|
t.Fatalf("review: %v", err)
|
|
}
|
|
if !strings.Contains(fb.gotPrompt, "FINISHED-BLOCK") {
|
|
t.Fatalf("prompt missing finished session: %s", fb.gotPrompt)
|
|
}
|
|
if !strings.Contains(fb.gotPrompt, "HISTORY-BLOCK") || !strings.Contains(fb.gotPrompt, "Recent sessions") {
|
|
t.Fatalf("prompt missing history block: %s", fb.gotPrompt)
|
|
}
|
|
}
|
|
|
|
func TestReviewPromptOmitsEmptyHistory(t *testing.T) {
|
|
fb := &fakeBackend{out: `{"recap":"r","carry_forward":"c"}`}
|
|
if _, err := NewService(fb).Review(context.Background(), "FINISHED-BLOCK", ""); err != nil {
|
|
t.Fatalf("review: %v", err)
|
|
}
|
|
if strings.Contains(fb.gotPrompt, "Recent sessions") {
|
|
t.Fatalf("empty history must not add a history header: %s", fb.gotPrompt)
|
|
}
|
|
}
|
|
|
|
func TestReviewServiceParsesReflection(t *testing.T) {
|
|
fb := &fakeBackend{out: `sure: {"recap":"held focus on the port","carry_forward":"start in the editor next time"}`}
|
|
refl, err := NewService(fb).Review(context.Background(), "f", "h")
|
|
if err != nil {
|
|
t.Fatalf("review: %v", err)
|
|
}
|
|
if refl.Recap != "held focus on the port" || refl.CarryForward != "start in the editor next time" {
|
|
t.Fatalf("bad reflection: %+v", refl)
|
|
}
|
|
}
|
|
|
|
func TestReviewServiceBackendError(t *testing.T) {
|
|
fb := &fakeBackend{err: errors.New("boom")}
|
|
if _, err := NewService(fb).Review(context.Background(), "f", "h"); err == nil {
|
|
t.Fatal("want backend error")
|
|
}
|
|
}
|
|
|
|
func TestParseReflectionEmpty(t *testing.T) {
|
|
if _, err := parseReflection(""); !errors.Is(err, ErrEmptyResponse) {
|
|
t.Fatalf("want ErrEmptyResponse, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestParseReflectionNoJSON(t *testing.T) {
|
|
if _, err := parseReflection("I cannot help."); !errors.Is(err, ErrNoJSON) {
|
|
t.Fatalf("want ErrNoJSON, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestParseReflectionRequiresRecap(t *testing.T) {
|
|
if _, err := parseReflection(`{"recap":" ","carry_forward":"x"}`); !errors.Is(err, ErrInvalidReflection) {
|
|
t.Fatalf("blank recap should be invalid, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestParseReflectionAllowsEmptyCarryForward(t *testing.T) {
|
|
refl, err := parseReflection(`{"recap":"did the thing","carry_forward":""}`)
|
|
if err != nil {
|
|
t.Fatalf("carry_forward may be empty: %v", err)
|
|
}
|
|
if refl.Recap != "did the thing" || refl.CarryForward != "" {
|
|
t.Fatalf("bad reflection: %+v", refl)
|
|
}
|
|
}
|