package application import ( "fmt" "strings" "testing" "time" "unicode/utf8" "img_infinite_canvas/internal/domain/design" ) func TestAgentShortMemoryUsesSlidingWindow(t *testing.T) { now := time.Now() project := design.Project{Title: "Memory project"} for index := 0; index < 24; index++ { project.Messages = append(project.Messages, design.Message{ ID: fmt.Sprintf("m-%d", index), Role: "user", Type: "user", Content: fmt.Sprintf("历史消息 %02d 需要保留高级品牌风格", index), CreatedAt: now.Add(time.Duration(index) * time.Second), }) } memory := buildAgentMemory(project, "继续优化当前画面", "design", nil) if !strings.Contains(memory.ShortTerm, "历史消息 23") { t.Fatalf("expected latest message in short memory, got %s", memory.ShortTerm) } if strings.Contains(memory.ShortTerm, "历史消息 00") { t.Fatalf("expected oldest message to be outside sliding window, got %s", memory.ShortTerm) } if utf8.RuneCountInString(memory.ShortTerm) > shortMemoryMaxRunes+80 { t.Fatalf("short memory exceeds budget: %d", utf8.RuneCountInString(memory.ShortTerm)) } } func TestAgentMemoryDoesNotLeakRawAssetURLs(t *testing.T) { project := design.Project{ Title: "Asset memory", Nodes: []design.Node{ {ID: "image-1", Type: design.NodeTypeImage, Title: "参考图", Content: "http://localhost:19000/canvas-assets/raw.png", Status: "success"}, }, } memory := buildAgentMemory(project, "参考这张图继续", "image", []design.AgentChatMessage{ { Contents: []design.AgentContent{ {Type: "image", ImageURL: "https://example.com/private/upload.png", ImageWidth: 1024, ImageHeight: 1024}, }, }, }) joined := memory.ShortTerm + "\n" + memory.LongTerm if strings.Contains(joined, "localhost:19000") || strings.Contains(joined, "example.com/private") { t.Fatalf("expected raw asset urls to be omitted from memory, got %s", joined) } if !strings.Contains(joined, "reference image") || !strings.Contains(joined, "asset reference") { t.Fatalf("expected compact asset references, got %s", joined) } } func TestAgentLongMemoryKeepsRecentDurableDecisions(t *testing.T) { project := design.Project{Title: "Long memory"} for index := 0; index < 20; index++ { project.Messages = append(project.Messages, design.Message{ ID: fmt.Sprintf("d-%d", index), Role: "user", Type: "user", Content: fmt.Sprintf("必须保留品牌风格决定 %02d", index), }) } memory := buildAgentMemory(project, "继续", "design", nil) if !strings.Contains(memory.LongTerm, "品牌风格决定 19") { t.Fatalf("expected recent durable decision in long memory, got %s", memory.LongTerm) } if strings.Contains(memory.LongTerm, "品牌风格决定 00") { t.Fatalf("expected oldest durable decision to be omitted, got %s", memory.LongTerm) } if utf8.RuneCountInString(memory.LongTerm) > longMemoryMaxRunes+80 { t.Fatalf("long memory exceeds budget: %d", utf8.RuneCountInString(memory.LongTerm)) } }