test(chat): 添加基于真实Agent工作区的多轮人机交互E2E测试用例

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
WeiCHEN
2026-09-13 02:50:19 +00:00
committed by weichen
co-authored by Cursor
parent e2ca8ad55a
commit aa968d277b
+131
View File
@@ -0,0 +1,131 @@
package chat_test
import (
"context"
"os"
"path/filepath"
"strings"
"testing"
"chat-agent-system/internal/bizdev"
"chat-agent-system/internal/chat"
"chat-agent-system/internal/coordinator"
"chat-agent-system/internal/intent"
)
// TestRealE2EWorkspaceChatSimulation 基于真实 Agent 生成的业务工作区开展端到端参谋对话与三分支消解实机验证
func TestRealE2EWorkspaceChatSimulation(t *testing.T) {
wsDir := "data/dev/workspaces/bizdev/intake_1788792827436879000"
if _, err := os.Stat(wsDir); os.IsNotExist(err) {
wsDir = filepath.Join("..", "..", wsDir)
}
u := coordinator.UserInfo{
ID: "u_test_user",
Name: "张工",
Role: "研发负责人",
ProjectRole: "composer",
}
assembler := coordinator.NewContextAssembler()
userCtx, err := assembler.AssembleFromWorkspace(wsDir, u)
if err != nil {
t.Fatalf("failed to assemble context from real workspace: %v", err)
}
if userCtx.Project.Name != "研发流程辅助智能体系统" {
t.Errorf("expected project name '研发流程辅助智能体系统', got %s", userCtx.Project.Name)
}
if userCtx.Project.CustomerName != "北京水木东方科技有限公司" {
t.Errorf("expected customer name '北京水木东方科技有限公司', got %s", userCtx.Project.CustomerName)
}
rec := intent.NewRecognizer()
engine := coordinator.NewCoordinatorEngine(nil) // 参谋交互层验证协调决策与上下文更新
session := chat.NewSession("real_e2e_session", userCtx, rec, engine)
// Turn 1: 真实工作区状态与背景查询 (分支 2: 新意图抢占 QUERY_PROGRESS)
t.Log("=== Turn 1: 询问真实工作区当前状态与风险 ===")
resp1, err := session.SendMessage(context.Background(), "帮我看看当前项目的整体进展如何,材料到底够不够?")
if err != nil {
t.Fatalf("Turn 1 failed: %v", err)
}
if resp1.Branch != intent.BranchNewIntentPreempt {
t.Errorf("Turn 1 expected NEW_INTENT_PREEMPT, got %s", resp1.Branch)
}
if resp1.IntentResult.TopIntent.Intent != intent.IntentQueryProgress {
t.Errorf("Turn 1 expected QUERY_PROGRESS, got %s", resp1.IntentResult.TopIntent.Intent)
}
if !strings.Contains(resp1.ReplyText, "研发流程辅助智能体系统") {
t.Errorf("Turn 1 reply should mention project name, got: %s", resp1.ReplyText)
}
t.Logf("Turn 1 响应:\n%s\n", resp1.ReplyText)
// Turn 2: 补充事实黑板 (分支 2: 补充信息 SUPPLEMENT_INFO)
t.Log("=== Turn 2: 补充事实设定至真实项目黑板 ===")
resp2, err := session.SendMessage(context.Background(), "客户确定目标市场不仅是国内,还要扩展到欧洲CE")
if err != nil {
t.Fatalf("Turn 2 failed: %v", err)
}
if resp2.Branch != intent.BranchNewIntentPreempt {
t.Errorf("Turn 2 expected NEW_INTENT_PREEMPT, got %s", resp2.Branch)
}
if resp2.IntentResult.TopIntent.Intent != intent.IntentSupplementInfo {
t.Errorf("Turn 2 expected SUPPLEMENT_INFO, got %s", resp2.IntentResult.TopIntent.Intent)
}
if !strings.Contains(session.UserCtx.BlackboardFacts["target_market"], "欧洲CE") {
t.Errorf("target_market not properly updated in blackboard: %v", session.UserCtx.BlackboardFacts)
}
t.Logf("Turn 2 响应:\n%s\n", resp2.ReplyText)
// Turn 3: 模糊分忧/咨询 (分支 3: 模糊降级 AMBIGUOUS_FALLBACK)
t.Log("=== Turn 3: 用户犹豫不决,参谋给出客观建议与选项 ===")
resp3, err := session.SendMessage(context.Background(), "这个先放放,你觉得呢")
if err != nil {
t.Fatalf("Turn 3 failed: %v", err)
}
if resp3.Branch != intent.BranchAmbiguousFallback {
t.Errorf("Turn 3 expected AMBIGUOUS_FALLBACK, got %s", resp3.Branch)
}
if !strings.Contains(resp3.ReplyText, "审慎考量") && !strings.Contains(resp3.ReplyText, "参谋建议") {
t.Errorf("Turn 3 expected advisor consultation style, got: %s", resp3.ReplyText)
}
t.Logf("Turn 3 响应:\n%s\n", resp3.ReplyText)
// Turn 4: 极速肯定兑现推进 (分支 1: 挂起预期命中 EXPECTATION_HIT)
t.Log("=== Turn 4: 用户极速回复“好”,直接兑现挂起预期推进至 V0.5 ===")
resp4, err := session.SendMessage(context.Background(), "好")
if err != nil {
t.Fatalf("Turn 4 failed: %v", err)
}
if resp4.Branch != intent.BranchExpectationHit {
t.Errorf("Turn 4 expected EXPECTATION_HIT, got %s", resp4.Branch)
}
if resp4.IntentResult.TopIntent.Intent != intent.IntentAdvanceStage {
t.Errorf("Turn 4 expected ADVANCE_STAGE, got %s", resp4.IntentResult.TopIntent.Intent)
}
if session.UserCtx.Project.CurrentStage != bizdev.StageV05_Feasibility {
t.Errorf("expected project advanced to V0.5, got %s", session.UserCtx.Project.CurrentStage)
}
t.Logf("Turn 4 响应:\n%s\n", resp4.ReplyText)
// Turn 5: 否定/暂缓挂起预期 (分支 1: 显式拒绝 DECLINE_EXPECTATION)
t.Log("=== Turn 5: 用户对新阶段的下一步建议表示暂缓 ===")
resp5, err := session.SendMessage(context.Background(), "先别推,等等")
if err != nil {
t.Fatalf("Turn 5 failed: %v", err)
}
if resp5.Branch != intent.BranchExpectationHit {
t.Errorf("Turn 5 expected EXPECTATION_HIT, got %s", resp5.Branch)
}
if resp5.IntentResult.TopIntent.Intent != intent.IntentDeclineExpectation {
t.Errorf("Turn 5 expected DECLINE_EXPECTATION, got %s", resp5.IntentResult.TopIntent.Intent)
}
if !strings.Contains(resp5.ReplyText, "听您的") {
t.Errorf("Turn 5 expected polite reply, got: %s", resp5.ReplyText)
}
if session.UserCtx.PendingExpectation != nil {
t.Errorf("expected PendingExpectation to be cleared after decline")
}
t.Logf("Turn 5 响应:\n%s\n", resp5.ReplyText)
}