Files
ai-agent/internal/ai/runtime/reply_interrupt_helpers.go
T
mlogclub 34051a4631 feat: Enhance AI Agent and Channel Management
- Updated labels in the AI Agents dashboard for clarity, changing "流程状态" to "Playbook 状态" and "未发布流程" to "未发布 Playbook".
- Introduced AI Agent rollout percentage management in channel editing, allowing users to set and rollback rollout percentages.
- Added new API endpoints for rolling back AI Agent rollout and fetching agent run metrics.
- Implemented new UI components for displaying agent run details, including status, duration, and input/output tokens.
- Enhanced type definitions for AdminChannel and AIAgent to include rollout percentages and runtime modes.
- Updated navigation to include a section for agent runs.
- Added new translations for agent run features in both English and Chinese.
2026-07-25 12:04:06 +08:00

91 lines
2.6 KiB
Go

package runtime
import (
"encoding/json"
"strings"
"time"
applicationruntime "agent-desk/internal/ai/application/runtime"
"agent-desk/internal/models"
"agent-desk/internal/pkg/i18nx"
svc "agent-desk/internal/services"
)
type interruptMessagePreview struct {
Message string `json:"message"`
}
func buildConversationInterrupt(conversation models.Conversation, message models.Message, aiAgent models.AIAgent, summary *applicationruntime.Summary) *models.ConversationInterrupt {
if summary == nil {
return nil
}
now := time.Now()
item := svc.ConversationInterruptService.GetByCheckPointID(summary.CheckPointID)
if item == nil {
item = &models.ConversationInterrupt{
CheckPointID: summary.CheckPointID,
CreatedAt: now,
}
}
item.ConversationID = conversation.ID
item.AIAgentID = aiAgent.ID
item.AgentRunID = summary.AgentRunID
item.SourceMessageID = message.ID
item.InterruptID = firstInterruptID(summary)
item.InterruptType = firstInterruptType(summary)
item.WorkflowRunID = summary.WorkflowRunID
item.WorkflowNodeID = firstInterruptID(summary)
item.Status = "pending"
item.PromptText = resolveInterruptPrompt(summary)
item.RequestData = strings.TrimSpace(summary.CheckPointData)
item.UpdatedAt = now
return item
}
func resolveInterruptPrompt(summary *applicationruntime.Summary) string {
if summary == nil || len(summary.Interrupts) == 0 {
return i18nx.Get("conversation.interrupt.defaultPrompt")
}
if prompt := extractInterruptMessage(summary.Interrupts[0].InfoPreview); prompt != "" {
return prompt
}
if prompt := strings.TrimSpace(summary.Interrupts[0].InfoPreview); prompt != "" {
return prompt
}
return i18nx.Get("conversation.interrupt.defaultPrompt")
}
func extractInterruptMessage(infoPreview string) string {
infoPreview = strings.TrimSpace(infoPreview)
if infoPreview == "" {
return ""
}
var payload interruptMessagePreview
if err := json.Unmarshal([]byte(infoPreview), &payload); err != nil {
return ""
}
return strings.TrimSpace(payload.Message)
}
func firstInterruptID(summary *applicationruntime.Summary) string {
if summary == nil || len(summary.Interrupts) == 0 {
return ""
}
return strings.TrimSpace(summary.Interrupts[0].ID)
}
func firstInterruptType(summary *applicationruntime.Summary) string {
if summary == nil || len(summary.Interrupts) == 0 {
return ""
}
return strings.TrimSpace(summary.Interrupts[0].Type)
}
func isCheckpointMissingError(err error) bool {
if err == nil {
return false
}
message := strings.ToLower(strings.TrimSpace(err.Error()))
return strings.Contains(message, "failed to load from checkpoint") && strings.Contains(message, "not exist")
}