Files
Agent-Native/runtime/session/r2_regression_test.go
T
weichenandCursor 6fd1d441a9
ci / vet-and-test (pull_request) Successful in 45s
ci / docker-checkout-hostgateway (pull_request) Successful in 1s
Keep tool pairs and fold reminders into the last result
Why: Old tool results were filling the window, compaction could split a tool group or commit a stale summary, and reminders arrived as extra user messages.
Evidence: Compaction retries a conflict and opens the circuit after three failures; clearing keeps the last five tool results; a stale file write is rejected; RPC reports started, queued, or handled.
Impact: Requests over the context window replace older tool results with a placeholder. Rewriting an existing file now requires a read in the same run. Subagent text over 32000 characters is capped.
Refs: feature/context-engineering
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-03 16:19:36 +00:00

185 lines
4.4 KiB
Go

package session
import (
"fmt"
"path/filepath"
"strings"
"testing"
"agent-native/runtime/llm"
)
func TestR2CompactKeepsToolPair(t *testing.T) {
s, err := Open(filepath.Join(t.TempDir(), "s.jsonl"))
if err != nil {
t.Fatal(err)
}
msgs := []llm.Message{
{Role: llm.RoleUser, Content: "ask"},
{Role: llm.RoleAssistant, Content: "", ToolCalls: []llm.ToolCall{{ID: "c", Name: "read"}}},
{Role: llm.RoleTool, ToolCallID: "c", Content: "file-body"},
}
for _, m := range msgs {
if err := s.Append(m); err != nil {
t.Fatal(err)
}
}
ok, err := s.Compact(1, func(messages []llm.Message) (string, error) {
return "summary", nil
})
if err != nil || !ok {
t.Fatalf("compact: %v %v", ok, err)
}
loaded, err := s.Load()
if err != nil {
t.Fatal(err)
}
var sawTool bool
for _, m := range loaded {
if m.Role == llm.RoleTool && m.Content == "file-body" {
sawTool = true
}
}
if !sawTool {
t.Fatalf("tool result dropped: %+v", loaded)
}
}
func TestR2CompactRejectsAppendDuringSummary(t *testing.T) {
s, err := Open(filepath.Join(t.TempDir(), "s.jsonl"))
if err != nil {
t.Fatal(err)
}
for _, text := range []string{"a", "b", "c"} {
if err := s.Append(llm.Message{Role: llm.RoleUser, Content: text}); err != nil {
t.Fatal(err)
}
}
_, err = s.Compact(1, func(messages []llm.Message) (string, error) {
return "summary", s.Append(llm.Message{Role: llm.RoleUser, Content: "raced"})
})
if err == nil || !strings.Contains(err.Error(), "compaction conflict") {
t.Fatalf("want conflict, got %v", err)
}
}
func TestCompactRetriesThenCommits(t *testing.T) {
s, err := Open(filepath.Join(t.TempDir(), "s.jsonl"))
if err != nil {
t.Fatal(err)
}
for _, text := range []string{"a", "b", "c"} {
if err := s.Append(llm.Message{Role: llm.RoleUser, Content: text}); err != nil {
t.Fatal(err)
}
}
raced := false
ok, err := s.Compact(1, func(messages []llm.Message) (string, error) {
if !raced {
raced = true
if err := s.Append(llm.Message{Role: llm.RoleUser, Content: "raced"}); err != nil {
return "", err
}
return "", fmt.Errorf("compaction conflict: session changed during summary")
}
return "summary", nil
})
if err != nil || !ok {
t.Fatalf("retry compact: %v %v", ok, err)
}
loaded, err := s.Load()
if err != nil {
t.Fatal(err)
}
var saw bool
for _, m := range loaded {
if m.Content == "raced" || m.Content == "summary" {
saw = true
}
}
if !saw {
t.Fatalf("retried summary missing: %+v", loaded)
}
}
func TestCompactLeavesNoOrphanToolCall(t *testing.T) {
s, err := Open(filepath.Join(t.TempDir(), "s.jsonl"))
if err != nil {
t.Fatal(err)
}
msgs := []llm.Message{
{Role: llm.RoleUser, Content: "先看"},
{Role: llm.RoleAssistant, ToolCalls: []llm.ToolCall{{ID: "old", Name: "read_file"}}},
{Role: llm.RoleTool, ToolCallID: "old", Name: "read_file", Content: "旧"},
{Role: llm.RoleUser, Content: "再改"},
{Role: llm.RoleAssistant, ToolCalls: []llm.ToolCall{{ID: "a", Name: "read_file"}, {ID: "b", Name: "grep"}}},
{Role: llm.RoleTool, ToolCallID: "a", Name: "read_file", Content: "甲"},
{Role: llm.RoleTool, ToolCallID: "b", Name: "grep", Content: "乙"},
}
for _, m := range msgs {
if err := s.Append(m); err != nil {
t.Fatal(err)
}
}
ok, err := s.Compact(2, func(messages []llm.Message) (string, error) {
return "摘要", nil
})
if err != nil || !ok {
t.Fatalf("compact: %v %v", ok, err)
}
loaded, err := s.Load()
if err != nil {
t.Fatal(err)
}
assertToolPairs(t, loaded)
}
func assertToolPairs(t *testing.T, msgs []llm.Message) {
t.Helper()
calls := map[string]int{}
for _, m := range msgs {
if m.Role != llm.RoleAssistant {
continue
}
for _, c := range m.ToolCalls {
calls[c.ID]++
}
}
for _, m := range msgs {
if m.Role != llm.RoleTool {
continue
}
if calls[m.ToolCallID] == 0 {
t.Fatalf("orphan tool result %s in %+v", m.ToolCallID, msgs)
}
calls[m.ToolCallID]--
}
for id, n := range calls {
if n != 0 {
t.Fatalf("orphan tool call %s in %+v", id, msgs)
}
}
}
func TestR2AppendVisibleAfterReopen(t *testing.T) {
path := filepath.Join(t.TempDir(), "s.jsonl")
s, err := Open(path)
if err != nil {
t.Fatal(err)
}
if err := s.Append(llm.Message{Role: llm.RoleUser, Content: "durable"}); err != nil {
t.Fatal(err)
}
again, err := Open(path)
if err != nil {
t.Fatal(err)
}
msgs, err := again.Load()
if err != nil {
t.Fatal(err)
}
if len(msgs) != 1 || msgs[0].Content != "durable" {
t.Fatalf("reopen: %+v", msgs)
}
}