127 lines
3.8 KiB
Go
127 lines
3.8 KiB
Go
package chat
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"chat-agent-system/internal/coordinator"
|
|
"chat-agent-system/internal/docgov"
|
|
"chat-agent-system/internal/intent"
|
|
)
|
|
|
|
const stageAdvanceGuidance = "该文档所属阶段尚未激活。请先完成当前阶段并推进后再编制。"
|
|
|
|
const researchFirstHint = "当前还没有完成调研报告。调研是可行性评估的前置输入。是否先进行调研?"
|
|
|
|
func stageAccessDenied(reply string) bool {
|
|
return strings.Contains(reply, "workflow stage access denied") || strings.Contains(reply, "stage access denied")
|
|
}
|
|
|
|
// workflowPrerequisiteHint 在用户要写可行性评估、而调研仍是模板或尚未建账时,建议先调研。
|
|
// docs 为 nil 表示台账未知,不猜测。
|
|
func workflowPrerequisiteHint(userInput string, docs []docgov.WorkflowDocumentSummary, known bool) (string, string) {
|
|
if !known || !strings.Contains(userInput, "可行性") {
|
|
return "", ""
|
|
}
|
|
ready, key := researchMaterialReady(docs)
|
|
if ready {
|
|
return "", ""
|
|
}
|
|
if key == "" {
|
|
key = "bd_research"
|
|
}
|
|
return researchFirstHint, key
|
|
}
|
|
|
|
func isResearchTaskKey(key string) bool {
|
|
switch strings.TrimSpace(key) {
|
|
case "research", "bd_research":
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func researchMaterialReady(docs []docgov.WorkflowDocumentSummary) (ready bool, taskKey string) {
|
|
for _, doc := range docs {
|
|
if !isResearchTaskKey(doc.TaskKey) {
|
|
continue
|
|
}
|
|
taskKey = doc.TaskKey
|
|
if !doc.IsTemplateOnly {
|
|
return true, taskKey
|
|
}
|
|
}
|
|
return false, taskKey
|
|
}
|
|
|
|
func researchFirstExpectation(taskKey string) *intent.PendingExpectation {
|
|
if taskKey == "" {
|
|
taskKey = "bd_research"
|
|
}
|
|
opt := intent.ExpectationOption{
|
|
OptionID: "1",
|
|
Title: "先进行调研",
|
|
Description: "先生成调研报告,再编写可行性评估",
|
|
Intent: intent.IntentTriggerTask,
|
|
Slots: map[string]string{intent.SlotTargetTask: taskKey},
|
|
}
|
|
talk := intent.ExpectationOption{
|
|
OptionID: "2",
|
|
Title: "先补充信息,暂不调研",
|
|
Intent: intent.IntentCasualChat,
|
|
}
|
|
return &intent.PendingExpectation{
|
|
ExpectationID: fmt.Sprintf("research-first-%d", time.Now().UnixNano()),
|
|
ExpectedIntent: intent.IntentTriggerTask,
|
|
TargetAction: "confirm_trigger_task",
|
|
Prompt: researchFirstHint,
|
|
AffirmativeWord: "好",
|
|
DeclineWord: "先不",
|
|
ExpiresAt: time.Now().Add(30 * time.Minute),
|
|
ContextSnippet: "可行性评估的前置调研尚未完成",
|
|
DefaultOption: &opt,
|
|
Options: []intent.ExpectationOption{opt, talk},
|
|
AllowAffirmative: true,
|
|
CreatedAt: time.Now(),
|
|
}
|
|
}
|
|
|
|
func (s *Session) listWorkflowDocs(ctx context.Context) ([]docgov.WorkflowDocumentSummary, bool) {
|
|
if s == nil || s.Actions == nil || s.Actions.DocGov == nil || s.Project() <= 0 {
|
|
return nil, false
|
|
}
|
|
docs, err := s.Actions.DocGov.ListWorkflowDocumentsByProject(ctx, s.Project())
|
|
if err != nil {
|
|
return nil, false
|
|
}
|
|
return docs, true
|
|
}
|
|
|
|
func (s *Session) augmentWorkflowGuidance(ctx context.Context, userInput string, res *coordinator.CoordinationResult) {
|
|
if s == nil || res == nil {
|
|
return
|
|
}
|
|
if stageAccessDenied(res.NaturalReply) && !strings.Contains(res.NaturalReply, stageAdvanceGuidance) {
|
|
res.NaturalReply = strings.TrimSpace(res.NaturalReply) + "\n\n" + stageAdvanceGuidance
|
|
}
|
|
docs, known := s.listWorkflowDocs(ctx)
|
|
hint, taskKey := workflowPrerequisiteHint(userInput, docs, known)
|
|
if hint == "" {
|
|
return
|
|
}
|
|
if !strings.Contains(res.NaturalReply, "是否先进行调研") {
|
|
res.NaturalReply = strings.TrimSpace(res.NaturalReply) + "\n\n" + hint
|
|
}
|
|
if res.ClearExpectation || res.NextExpectation != nil {
|
|
return
|
|
}
|
|
exp := researchFirstExpectation(taskKey)
|
|
res.NextExpectation = exp
|
|
if res.UpdatedContext != nil && res.UpdatedContext.PendingExpectation == nil {
|
|
res.UpdatedContext.PendingExpectation = exp
|
|
}
|
|
}
|