Files
moteva/server/internal/application/agent_memory_test.go
T
root 44406b72db Initial commit: img-infinite-canvas AI design workbench MVP
Moteva-style AI design workbench replica. Home prompt creates a project;
the project page provides an infinite canvas with node drag, zoom/pan,
a design chat panel, history replay, image asset upload, and project
save/regenerate.

- Backend: go-zero, DDD layering, sqlc/pgx, optional PostgreSQL; memory
  or Redis cache; asynq job queue; MinIO/S3/R2/OSS object storage;
  sky-valley/pi agent runtime adapter.
- Frontend: Next.js App Router + Vite artifact build, TypeScript, i18n,
  shadcn/ui components, auth (OTP/Turnstile/Google/WeChat).
- Deploy: Docker Compose and k3s manifests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 23:15:37 +08:00

83 lines
2.9 KiB
Go

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))
}
}