package native import ( "context" "os" "path/filepath" "strings" "testing" "agent-native/exec" "agent-native/runtime/llm" ) func TestBackendCompactBeforeRun(t *testing.T) { dir := t.TempDir() // 预置一份超阈值的长转录(系统消息 + 12 条历史)。 transcript := filepath.Join(dir, ".agentx", "transcript.jsonl") if err := os.MkdirAll(filepath.Dir(transcript), 0o755); err != nil { t.Fatal(err) } var b strings.Builder b.WriteString(`{"role":"system","content":"sys"}` + "\n") for i := 0; i < 12; i++ { b.WriteString(`{"role":"user","content":"` + strings.Repeat("x", 400) + `"}` + "\n") } if err := os.WriteFile(transcript, []byte(b.String()), 0o644); err != nil { t.Fatal(err) } var sawSummary bool // 注入式捕获:验证 Run 收到的消息里有摘要标记。 bk2 := New(Options{ ModelOptions: ModelOptions{ Model: "fake", Stream: captureFirstStream(&sawSummary), }, SessionOptions: SessionOptions{ Compact: &CompactConfig{ThresholdChars: 1000, KeepLastN: 3, Summarizer: func(ctx context.Context, messages []llm.Message) (string, error) { return "预置历史摘要", nil }}, }, }) res, err := bk2.Execute(context.Background(), exec.Request{ WorkDir: dir, Prompt: "继续", Targets: []string{"output.md"}, ToolProfile: exec.ToolProfileReasoning, }) if err != nil { t.Fatal(err) } if res.Success && !sawSummary { t.Fatal("compaction should have run before the loop") } data, _ := os.ReadFile(transcript) if !strings.Contains(string(data), "预置历史摘要") || !strings.Contains(string(data), `"type":"compaction"`) { t.Fatalf("transcript should keep history and append a compaction entry, got:\n%.400s", data) } if !strings.Contains(string(data), `"role":"system"`) { t.Fatal("compaction must not rewrite the original transcript") } } func captureFirstStream(saw *bool) llm.StreamFunc { return func(ctx context.Context, model string, messages []llm.Message, decls []llm.ToolDecl, opts llm.StreamOptions) <-chan llm.Event { for _, m := range messages { if strings.Contains(m.Content, "[conversation summary]") { *saw = true } } ch := make(chan llm.Event, 4) go func() { defer close(ch) ch <- llm.Event{Kind: llm.KindMessageEnd, Message: llm.Message{Role: llm.RoleAssistant, Content: "压缩后续写完成", StopReason: llm.StopEnd}} }() return ch } }