package agent import ( "context" "testing" "git.gopher.ink/mirrors2/AutoZero/llm" "git.gopher.ink/mirrors2/AutoZero/session" ) type turnRecorder struct{ turns []int } func (r *turnRecorder) BeginTurn(n int) { r.turns = append(r.turns, n) } // TestRunSyntheticSkipsPromptAccounting:后台通知落盘时带 synthetic 标记, // 不计入提问数、不推进 rewind 回合号;随后的真实提问仍从 1 开始。 func TestRunSyntheticSkipsPromptAccounting(t *testing.T) { prov := &scriptedProvider{fn: func(int, string, []llm.Message, []llm.ToolDef) (llm.Message, error) { return llm.Message{Role: llm.RoleAssistant, Content: "ok"}, nil }} a, sess := newTestAgent(t) a.Provider = prov rec := &turnRecorder{} a.TurnMarker = rec if err := a.RunSynthetic(context.Background(), "[background job finished] bg-1"); err != nil { t.Fatal(err) } last := sess.Messages[len(sess.Messages)-1] if last.Role != llm.RoleAssistant { t.Fatalf("last message = %s", last.Role) } var notice *llm.Message for i := range sess.Messages { if sess.Messages[i].Role == llm.RoleUser { notice = &sess.Messages[i] } } if notice == nil || !notice.Synthetic { t.Fatalf("notification not marked synthetic: %+v", notice) } if got := session.CountPrompts(sess.Messages); got != 0 { t.Fatalf("CountPrompts = %d, want 0", got) } // 没有真实提问时的边界仍是 1;通知本身不推进号。 if len(rec.turns) != 1 || rec.turns[0] != 1 { t.Fatalf("turn markers after synthetic = %v, want [1]", rec.turns) } if err := a.Run(context.Background(), "real task"); err != nil { t.Fatal(err) } if got := session.CountPrompts(sess.Messages); got != 1 { t.Fatalf("CountPrompts after real prompt = %d, want 1", got) } // 第一个真实提问仍拿到 1——后台通知没有把 rewind 的号顶走。 if len(rec.turns) != 2 || rec.turns[1] != 1 { t.Fatalf("turn markers = %v, want [1 1]", rec.turns) } }