From aa968d277bde1fa2b6911a34d124a5946053f9f3 Mon Sep 17 00:00:00 2001 From: WeiCHEN Date: Mon, 7 Sep 2026 23:16:37 +0800 Subject: [PATCH] =?UTF-8?q?test(chat):=20=E6=B7=BB=E5=8A=A0=E5=9F=BA?= =?UTF-8?q?=E4=BA=8E=E7=9C=9F=E5=AE=9EAgent=E5=B7=A5=E4=BD=9C=E5=8C=BA?= =?UTF-8?q?=E7=9A=84=E5=A4=9A=E8=BD=AE=E4=BA=BA=E6=9C=BA=E4=BA=A4=E4=BA=92?= =?UTF-8?q?E2E=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- internal/chat/multi_turn_e2e_test.go | 131 +++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 internal/chat/multi_turn_e2e_test.go diff --git a/internal/chat/multi_turn_e2e_test.go b/internal/chat/multi_turn_e2e_test.go new file mode 100644 index 00000000..0a295180 --- /dev/null +++ b/internal/chat/multi_turn_e2e_test.go @@ -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) +}