package coordinator_test import ( "context" "testing" "chat-agent-system/internal/bizdev" "chat-agent-system/internal/coordinator" "chat-agent-system/internal/intent" "chat-agent-system/internal/squad" ) func TestCoordinatorEngine_QueryProgress(t *testing.T) { engine := coordinator.NewCoordinatorEngine(nil) userCtx := &coordinator.UserProjectContext{ Project: coordinator.ProjectInfo{ Name: "便携式掌上超声项目", }, LatestAdvisorBrief: &squad.AdvisorBriefing{ MaturityScore: 70, MaturityLevel: "V0.1", MaturityHeadline: "已具备基本产品定义,亟待补充探头频率与目标市场", PreemptiveRisks: []string{"欧盟CE MDR认证周期较长"}, NextBestActions: []string{"推进进入V0.5可行性论证"}, CommunicationKit: "【给客户的建议沟通要点】...", }, } recRes := &intent.IntentRecognitionResult{ TopIntent: &intent.CandidateIntent{ Intent: intent.IntentQueryProgress, FilledSlots: map[string]string{ intent.SlotQueryTopic: "risk", }, }, } res, err := engine.ProcessIntent(context.Background(), recRes, userCtx) if err != nil { t.Fatalf("process intent failed: %v", err) } if res.Status != coordinator.StatusAccepted { t.Errorf("expected status ACCEPTED, got %s", res.Status) } if res.AdvisorBrief == nil { t.Errorf("expected advisor brief in result") } } func TestCoordinatorEngine_SupplementInfo(t *testing.T) { engine := coordinator.NewCoordinatorEngine(nil) userCtx := &coordinator.UserProjectContext{ Project: coordinator.ProjectInfo{ Name: "便携式掌上超声项目", }, BlackboardFacts: make(map[string]string), } recRes := &intent.IntentRecognitionResult{ TopIntent: &intent.CandidateIntent{ Intent: intent.IntentSupplementInfo, FilledSlots: map[string]string{ intent.SlotFactKey: "target_market", intent.SlotFactValue: "国内及欧盟CE", }, }, } res, err := engine.ProcessIntent(context.Background(), recRes, userCtx) if err != nil { t.Fatalf("process intent failed: %v", err) } if res.Status != coordinator.StatusAccepted { t.Errorf("expected status ACCEPTED, got %s", res.Status) } if userCtx.BlackboardFacts["target_market"] != "国内及欧盟CE" { t.Errorf("expected blackboard target_market updated, got %s", userCtx.BlackboardFacts["target_market"]) } } func TestCoordinatorEngine_AdvanceStage(t *testing.T) { engine := coordinator.NewCoordinatorEngine(nil) userCtx := &coordinator.UserProjectContext{ Project: coordinator.ProjectInfo{ Name: "超声测试项目", CurrentStage: bizdev.StageV01_Triage, }, User: coordinator.UserInfo{ ProjectRole: "composer", }, } recRes := &intent.IntentRecognitionResult{ TopIntent: &intent.CandidateIntent{ Intent: intent.IntentAdvanceStage, FilledSlots: map[string]string{ intent.SlotTargetStage: string(bizdev.StageV05_Feasibility), }, }, } res, err := engine.ProcessIntent(context.Background(), recRes, userCtx) if err != nil { t.Fatalf("process intent failed: %v", err) } if res.Status != coordinator.StatusAccepted { t.Errorf("expected status ACCEPTED, got %s", res.Status) } if userCtx.Project.CurrentStage != bizdev.StageV05_Feasibility { t.Errorf("expected stage V0.5_feasibility, got %s", userCtx.Project.CurrentStage) } } func TestCoordinatorEngine_DeclineExpectation(t *testing.T) { engine := coordinator.NewCoordinatorEngine(nil) userCtx := &coordinator.UserProjectContext{ Project: coordinator.ProjectInfo{ Name: "超声测试项目", CurrentStage: bizdev.StageV01_Triage, }, PendingExpectation: coordinator.BuildNextExpectation(bizdev.StageV01_Triage, "超声测试项目"), } recRes := &intent.IntentRecognitionResult{ Branch: intent.BranchExpectationHit, TopIntent: &intent.CandidateIntent{ Intent: intent.IntentDeclineExpectation, Branch: intent.BranchExpectationHit, IsDecline: true, }, } res, err := engine.ProcessIntent(context.Background(), recRes, userCtx) if err != nil { t.Fatalf("process intent failed: %v", err) } if res.Status != coordinator.StatusAccepted { t.Errorf("expected status ACCEPTED, got %s", res.Status) } if !res.ClearExpectation { t.Errorf("expected ClearExpectation to be true") } if userCtx.PendingExpectation != nil { t.Errorf("expected PendingExpectation to be cleared in userCtx") } } func TestCoordinatorEngine_AmbiguousConsult(t *testing.T) { engine := coordinator.NewCoordinatorEngine(nil) userCtx := &coordinator.UserProjectContext{ Project: coordinator.ProjectInfo{ Name: "超声测试项目", CurrentStage: bizdev.StageV01_Triage, }, } recRes := &intent.IntentRecognitionResult{ Branch: intent.BranchAmbiguousFallback, TopIntent: &intent.CandidateIntent{ Intent: intent.IntentCasualChat, Branch: intent.BranchAmbiguousFallback, }, } res, err := engine.ProcessIntent(context.Background(), recRes, userCtx) if err != nil { t.Fatalf("process intent failed: %v", err) } if res.Branch != intent.BranchAmbiguousFallback { t.Errorf("expected branch AMBIGUOUS_FALLBACK, got %s", res.Branch) } if res.NextExpectation == nil { t.Errorf("expected NextExpectation to be populated") } } func TestCoordinatorEngine_AdvanceStageWithPatch(t *testing.T) { engine := coordinator.NewCoordinatorEngine(nil) userCtx := &coordinator.UserProjectContext{ Project: coordinator.ProjectInfo{ Name: "超声测试项目", CurrentStage: bizdev.StageV01_Triage, }, BlackboardFacts: make(map[string]string), } recRes := &intent.IntentRecognitionResult{ Branch: intent.BranchExpectationHit, TopIntent: &intent.CandidateIntent{ Intent: intent.IntentAdvanceStage, Branch: intent.BranchExpectationHit, FilledSlots: map[string]string{ intent.SlotTargetStage: string(bizdev.StageV05_Feasibility), "target_market": "欧洲CE", }, PatchSlots: map[string]string{ "target_market": "欧洲CE", }, }, } res, err := engine.ProcessIntent(context.Background(), recRes, userCtx) if err != nil { t.Fatalf("process intent failed: %v", err) } if res.Status != coordinator.StatusAccepted { t.Errorf("expected status ACCEPTED, got %s", res.Status) } if userCtx.BlackboardFacts["target_market"] != "欧洲CE" { t.Errorf("expected target_market '欧洲CE' in blackboard facts, got '%s'", userCtx.BlackboardFacts["target_market"]) } if userCtx.Project.TargetMarket != "欧洲CE" { t.Errorf("expected project TargetMarket '欧洲CE', got '%s'", userCtx.Project.TargetMarket) } }