package logic import ( "strings" "time" "img_infinite_canvas/internal/domain/design" "img_infinite_canvas/internal/types" ) func latestLovartThreadID(project design.Project) string { if threadID := strings.TrimSpace(project.LastThreadID); threadID != "" { return threadID } for index := len(project.Messages) - 1; index >= 0; index-- { message := project.Messages[index] if isHiddenAgentMessage(message) { continue } if threadID := strings.TrimSpace(message.ThreadID); threadID != "" { return threadID } } return "" } func toCandaChatHistoryItem(message design.Message, projectID string, threadID string) types.CandaChatHistoryItem { messageType := strings.TrimSpace(message.Type) if messageType == "" { messageType = strings.TrimSpace(message.Role) } if messageType == "tool" { messageType = "tool_use" } item := types.CandaChatHistoryItem{ Id: message.ID, Timestamp: formatCandaTimestamp(message.CreatedAt), Type: messageType, ActionId: nonEmpty(message.ActionID, threadID), StepId: nonEmpty(message.StepID, message.ID), Status: message.Status, ToolCallId: message.ToolCallID, Name: message.Name, ThreadMeta: types.CandaThreadMeta{ ActionId: nonEmpty(message.ActionID, threadID), SessionId: threadID + "_main", StepId: nonEmpty(message.StepID, message.ID), Depth: 0, AgentName: "next_agent", ProjectId: projectID, }, } if message.Role == "user" { item.Text = message.Content } else { item.Content = message.Content if item.Name == "" { item.Name = message.Title } } return item } func nonEmpty(values ...string) string { for _, value := range values { if strings.TrimSpace(value) != "" { return value } } return "" } func formatCandaTimestamp(value time.Time) string { if value.IsZero() { value = time.Now() } return value.UTC().Format(time.RFC3339Nano) }