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>
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user