feat(cli): add three-branch interaction feedback and comprehensive verification test cases

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 97c8a7629c
commit eedda67aad
2 changed files with 109 additions and 6 deletions
+8 -6
View File
@@ -411,7 +411,7 @@ func handleChatMode(
os.Exit(1)
}
top := resp.IntentResult.TopIntent
fmt.Printf("[意图识别: %s (置信度: %.0f%%)] - %s\n", top.Intent, top.Confidence*100, top.Reasoning)
fmt.Printf("[意图识别: %s (置信度: %.0f%%) | 消解分支: %s] - %s\n", top.Intent, top.Confidence*100, resp.Branch, top.Reasoning)
fmt.Printf("\n%s\n", resp.ReplyText)
if resp.AdvisorBrief != nil && (top.Intent == intent.IntentAdvanceStage || top.Intent == intent.IntentQueryProgress) {
printAdvisorBrief(resp.AdvisorBrief)
@@ -427,10 +427,12 @@ func handleChatMode(
fmt.Printf("当前阶段: %s | 用户身份: %s (%s)\n", userCtx.Project.CurrentStage, userCtx.User.Name, userCtx.User.Role)
fmt.Printf("可用动作: %v\n", userCtx.AvailableActions)
fmt.Println("------------------------------------------------------------------")
fmt.Println("💡 提示:您可以直接输入自然语言,例如:")
fmt.Println(" • \"现在这个便携超声立项评估到哪一步了?有啥风险没?\"")
fmt.Println(" • \"客户补充说目标市场除了国内还想考虑欧洲 CE 认证\"")
fmt.Println(" • \"我看摸底结果可以,进入方案论证阶段吧\"")
fmt.Println("💡 参谋互动小贴士(三分支柔性消解):")
fmt.Println(" • 极速兑现(分支 1):当参谋给出下一步建议时,回复“好”、“行”或“1”直接推进")
fmt.Println(" • 复合补丁(分支 1):可以肯定并同时附带微调,如:“好,但目标市场改成欧洲CE”")
fmt.Println(" • 暂缓撤销(分支 1):如果不想推进,直接说:“先别推,等等”")
fmt.Println(" • 突发抢占(分支 2):随时发起新问题,如:“查一下探头功耗要怎么设计”")
fmt.Println(" • 模糊分忧(分支 3):拿不定主意时,可以说:“这个先放放,你觉得呢”")
fmt.Println(" • 输入 'exit' 或 'quit' 退出")
fmt.Println("==================================================================")
@@ -456,7 +458,7 @@ func handleChatMode(
}
top := resp.IntentResult.TopIntent
fmt.Printf("\n[智能参谋] (识别意图: %s | 置信度: %.0f%%)\n", top.Intent, top.Confidence*100)
fmt.Printf("\n[智能参谋] (消解分支: %s | 核心意图: %s | 置信度: %.0f%%)\n", resp.Branch, top.Intent, top.Confidence*100)
fmt.Println(resp.ReplyText)
if resp.AdvisorBrief != nil && (top.Intent == intent.IntentAdvanceStage || top.Intent == intent.IntentQueryProgress) {
+101
View File
@@ -235,3 +235,104 @@ func TestBizdevCLIChatQueries(t *testing.T) {
t.Errorf("expected stage advance success, got: %s", string(out4))
}
}
func TestBizdevCLIThreeBranchQueries(t *testing.T) {
tmpDir := t.TempDir()
envContent := "ENV=dev\nDATA_DIR=" + tmpDir + "\nAGENT_BACKEND=stub\n"
envPath := filepath.Join(tmpDir, ".env")
_ = os.WriteFile(envPath, []byte(envContent), 0o644)
// 用例 1: 极速兑现 (好)
cmd1 := exec.Command("go", "run", "./cmd/bizdev-cli",
"-env", envPath,
"-backend", "stub",
"-chat",
"-query", "好",
"-project", "掌上便携超声",
)
cmd1.Dir = moduleRoot(t)
out1, err := cmd1.CombinedOutput()
if err != nil {
t.Fatalf("query 1 failed: %v, out: %s", err, string(out1))
}
if !strings.Contains(string(out1), "消解分支: EXPECTATION_HIT") {
t.Errorf("expected EXPECTATION_HIT, got: %s", string(out1))
}
// 用例 2: 复合打补丁 (好,但目标市场改成欧洲CE)
cmd2 := exec.Command("go", "run", "./cmd/bizdev-cli",
"-env", envPath,
"-backend", "stub",
"-chat",
"-query", "好,但目标市场改成欧洲CE",
"-project", "掌上便携超声",
)
cmd2.Dir = moduleRoot(t)
out2, err := cmd2.CombinedOutput()
if err != nil {
t.Fatalf("query 2 failed: %v, out: %s", err, string(out2))
}
if !strings.Contains(string(out2), "消解分支: EXPECTATION_HIT") || !strings.Contains(string(out2), "target_market") {
t.Errorf("expected EXPECTATION_HIT with target_market patch, got: %s", string(out2))
}
// 用例 3: 否定暂缓 (先别推,等等)
cmd3 := exec.Command("go", "run", "./cmd/bizdev-cli",
"-env", envPath,
"-backend", "stub",
"-chat",
"-query", "先别推,等等",
"-project", "掌上便携超声",
)
cmd3.Dir = moduleRoot(t)
out3, err := cmd3.CombinedOutput()
if err != nil {
t.Fatalf("query 3 failed: %v, out: %s", err, string(out3))
}
if !strings.Contains(string(out3), "消解分支: EXPECTATION_HIT") || !strings.Contains(string(out3), "DECLINE_EXPECTATION") {
t.Errorf("expected DECLINE_EXPECTATION, got: %s", string(out3))
}
if !strings.Contains(string(out3), "听您的") {
t.Errorf("expected polite advisor reply: %s", string(out3))
}
// 用例 4: 话题突发抢占 (查一下探头功耗要怎么设计)
cmd4 := exec.Command("go", "run", "./cmd/bizdev-cli",
"-env", envPath,
"-backend", "stub",
"-chat",
"-query", "查一下探头功耗要怎么设计",
"-project", "掌上便携超声",
)
cmd4.Dir = moduleRoot(t)
out4, err := cmd4.CombinedOutput()
if err != nil {
t.Fatalf("query 4 failed: %v, out: %s", err, string(out4))
}
if !strings.Contains(string(out4), "消解分支: NEW_INTENT_PREEMPT") {
t.Errorf("expected NEW_INTENT_PREEMPT, got: %s", string(out4))
}
if !strings.Contains(string(out4), "功耗") {
t.Errorf("expected technical answer in reply: %s", string(out4))
}
// 用例 5: 模糊分忧 (这个先放放,你觉得呢)
cmd5 := exec.Command("go", "run", "./cmd/bizdev-cli",
"-env", envPath,
"-backend", "stub",
"-chat",
"-query", "这个先放放,你觉得呢",
"-project", "掌上便携超声",
)
cmd5.Dir = moduleRoot(t)
out5, err := cmd5.CombinedOutput()
if err != nil {
t.Fatalf("query 5 failed: %v, out: %s", err, string(out5))
}
if !strings.Contains(string(out5), "消解分支: AMBIGUOUS_FALLBACK") {
t.Errorf("expected AMBIGUOUS_FALLBACK, got: %s", string(out5))
}
if !strings.Contains(string(out5), "审慎考量") && !strings.Contains(string(out5), "参谋建议") {
t.Errorf("expected consultative advisor answer in reply: %s", string(out5))
}
}