fix: prevent repeated off-hours handoff notices
This commit is contained in:
@@ -52,6 +52,9 @@ func (g *HandoffGraph) Run(ctx context.Context, argumentsInJSON string) (string,
|
|||||||
}
|
}
|
||||||
handled, err := services.ConversationService.TryOffHoursHandoffByAI(g.conversation.ID, g.aiAgent, reason)
|
handled, err := services.ConversationService.TryOffHoursHandoffByAI(g.conversation.ID, g.aiAgent, reason)
|
||||||
if err != nil || handled {
|
if err != nil || handled {
|
||||||
|
if handled && err == nil {
|
||||||
|
return services.HandoffOffHoursMessage, nil
|
||||||
|
}
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
info := HandoffGraphInterruptInfo{
|
info := HandoffGraphInterruptInfo{
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ func TestHandoffGraphOffHoursSendsNoticeWithoutConfirmation(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Run() error = %v", err)
|
t.Fatalf("Run() error = %v", err)
|
||||||
}
|
}
|
||||||
if reply != "" {
|
if reply != services.HandoffOffHoursMessage {
|
||||||
t.Fatalf("expected no graph reply, got %q", reply)
|
t.Fatalf("expected off-hours graph reply, got %q", reply)
|
||||||
}
|
}
|
||||||
|
|
||||||
message := services.MessageService.FindOne(sqls.NewCnd().Eq("conversation_id", conversation.ID).Desc("id"))
|
message := services.MessageService.FindOne(sqls.NewCnd().Eq("conversation_id", conversation.ID).Desc("id"))
|
||||||
|
|||||||
@@ -58,6 +58,9 @@ func (s *conversationHumanDispatchService) TryOffHoursHandoffByAI(conversationID
|
|||||||
if err := s.createEvent(conversationID, enums.IMEventTypeTransfer, enums.IMSenderTypeAI, aiAgent.ID, "转人工失败:非服务时间", strings.TrimSpace(reason)); err != nil {
|
if err := s.createEvent(conversationID, enums.IMEventTypeTransfer, enums.IMSenderTypeAI, aiAgent.ID, "转人工失败:非服务时间", strings.TrimSpace(reason)); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
if s.hasLatestAIText(conversationID, HandoffOffHoursMessage) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
if err := s.sendAIText(conversationID, aiAgent.ID, HandoffOffHoursMessage); err != nil {
|
if err := s.sendAIText(conversationID, aiAgent.ID, HandoffOffHoursMessage); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
@@ -288,6 +291,14 @@ func (s *conversationHumanDispatchService) sendAIText(conversationID, aiAgentID
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *conversationHumanDispatchService) hasLatestAIText(conversationID int64, content string) bool {
|
||||||
|
latest, err := MessageService.GetConversationReadTarget(conversationID, 0)
|
||||||
|
if err != nil || latest == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return latest.SenderType == enums.IMSenderTypeAI && strings.TrimSpace(latest.Content) == strings.TrimSpace(content)
|
||||||
|
}
|
||||||
|
|
||||||
func orderedPositiveIDs(value string) []int64 {
|
func orderedPositiveIDs(value string) []int64 {
|
||||||
return uniquePositiveInt64sFromStrings(strings.Split(value, ","))
|
return uniquePositiveInt64sFromStrings(strings.Split(value, ","))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,32 @@ func TestConversationHumanDispatchAIHandoffOffHoursKeepsAIServingAndSendsNotice(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConversationHumanDispatchAIHandoffOffHoursDoesNotDuplicateNotice(t *testing.T) {
|
||||||
|
db := setupConversationHumanDispatchTestDB(t)
|
||||||
|
aiAgent := createHumanDispatchAIAgent(t, db, enums.IMConversationServiceModeAIFirst, "1")
|
||||||
|
conversation := createHumanDispatchConversation(t, db, aiAgent.ID, enums.IMConversationStatusAIServing)
|
||||||
|
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
result, err := services.ConversationHumanDispatchService.HandoffByAI(conversation.ID, aiAgent, "用户要求转人工")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("HandoffByAI() round %d error = %v", i+1, err)
|
||||||
|
}
|
||||||
|
if result == nil || result.Decision != services.HandoffDecisionOffHours {
|
||||||
|
t.Fatalf("expected off_hours decision on round %d, got %+v", i+1, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var count int64
|
||||||
|
if err := db.Model(&models.Message{}).
|
||||||
|
Where("conversation_id = ? AND sender_type = ? AND content = ?", conversation.ID, enums.IMSenderTypeAI, services.HandoffOffHoursMessage).
|
||||||
|
Count(&count).Error; err != nil {
|
||||||
|
t.Fatalf("count off-hours messages error = %v", err)
|
||||||
|
}
|
||||||
|
if count != 1 {
|
||||||
|
t.Fatalf("expected one off-hours notice, got %d", count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestConversationHumanDispatchAIHandoffAssignsAvailableAgent(t *testing.T) {
|
func TestConversationHumanDispatchAIHandoffAssignsAvailableAgent(t *testing.T) {
|
||||||
db := setupConversationHumanDispatchTestDB(t)
|
db := setupConversationHumanDispatchTestDB(t)
|
||||||
aiAgent := createHumanDispatchAIAgent(t, db, enums.IMConversationServiceModeAIFirst, "1")
|
aiAgent := createHumanDispatchAIAgent(t, db, enums.IMConversationServiceModeAIFirst, "1")
|
||||||
|
|||||||
Reference in New Issue
Block a user