package server import ( "strings" "testing" "chat-agent-system/internal/bizdev" "chat-agent-system/internal/chat" "chat-agent-system/internal/coordinator" "chat-agent-system/internal/taskrun" ) func TestProjectContextConflictCards_ArmsSessionExpectation(t *testing.T) { s := &Server{sessions: map[string]*chat.Session{}} sess := chat.NewSession("sess-cc", &coordinator.UserProjectContext{ Project: coordinator.ProjectInfo{Name: "便携式掌上超声项目"}, BlackboardFacts: map[string]string{}, }, nil, nil) s.sessions[sess.ID] = sess record := &taskrun.RunRecord{RunID: "run_1", SessionID: sess.ID, ProjectID: 42} result := &bizdev.TaskRunResult{ Success: true, PendingContextConflicts: []bizdev.ContextConflictCard{{ ExpectationID: "ctx_conflict_run_1_device_type", FactKey: "device_type", WinningValue: "一次性使用采血管", Prompt: "对话与现有事实对「device_type」说法不一致。", Snippet: "同级时间相近且无明确证据", }}, } s.projectContextConflictCards(t.Context(), record, result) if sess.UserCtx.PendingExpectation == nil { t.Fatal("expected session PendingExpectation armed") } exp := sess.UserCtx.PendingExpectation if exp.TargetAction != "confirm_context_fact" || exp.Payload["fact_key"] != "device_type" { t.Fatalf("unexpected armed expectation: %+v", exp) } msgs := sess.SnapshotMessages() if len(msgs) == 0 || !strings.Contains(msgs[len(msgs)-1].Content, "确认") { t.Fatalf("expected card message appended, got %+v", msgs) } } func TestProjectContextConflictCards_NoSession_SkipsSilently(t *testing.T) { s := &Server{sessions: map[string]*chat.Session{}} record := &taskrun.RunRecord{RunID: "run_2", SessionID: "sess-missing", ProjectID: 7} result := &bizdev.TaskRunResult{PendingContextConflicts: []bizdev.ContextConflictCard{{ ExpectationID: "e", FactKey: "budget", WinningValue: "15万", Prompt: "p", Snippet: "s", }}} s.projectContextConflictCards(t.Context(), record, result) // must not panic } func TestProjectContextConflictCards_EmptySkips(t *testing.T) { s := &Server{sessions: map[string]*chat.Session{}} s.projectContextConflictCards(t.Context(), &taskrun.RunRecord{SessionID: "x"}, &bizdev.TaskRunResult{}) } func TestRenderContextConflictCardMessage(t *testing.T) { msg := renderContextConflictCardMessage([]bizdev.ContextConflictCard{{ FactKey: "device_type", WinningValue: "一次性使用采血管", Prompt: "冲突提示", Snippet: "同级相近", }}) for _, want := range []string{"冲突", "device_type", "一次性使用采血管", "确认", "纠正"} { if !strings.Contains(msg, want) { t.Fatalf("card message missing %q: %s", want, msg) } } }