Files
moteva/server/internal/logic/lovart_agent_mapper.go
T
root 263748af4a feat(api): add Lovart-style project and agent thread endpoints
Add canva/canda-compatible routes for lightweight project open/save and
agent thread history:
- POST /canva/project/queryProject, saveProject
- POST /canva/agent/queryAgentLastThread, agentThreadList
- GET /canda/chat-history, /canda/thread/status

Canvas save now accepts a compressed SHAKKERDATA:// snapshot payload,
preserves connections, and returns a SaveProject response; blank
successful image nodes are backfilled from generated artifacts. Frontend
designGateway adopts the new save/query flow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 19:10:08 +08:00

79 lines
1.9 KiB
Go

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)
}