feat(server): persist node semantic context and retain CAD agent context

Add a semantic_context column to canvas_nodes (schema, sqlc queries,
generated models, repository upserts) and thread SemanticContext through the
domain node, API type, and mappers so CAD-derived context survives canvas
saves.

Treat agent text parts with textSource "cad-context" like settings: keep
them for planning, memory, and image-generation prompts but exclude them
from the persisted user-visible message copy. Add coverage for the CAD
context visibility and mapper behavior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-16 16:40:47 +08:00
parent 57a9aba03e
commit 29b3bd222c
13 changed files with 249 additions and 137 deletions
+17 -3
View File
@@ -669,6 +669,10 @@ func (s *DesignService) AgentChat(ctx context.Context, projectID string, req des
if prompt == "" {
return design.AgentThread{}, fmt.Errorf("%w: prompt is required", design.ErrInvalidInput)
}
visiblePrompt := design.NormalizePrompt(visiblePromptFromAgentMessages(req.Messages))
if visiblePrompt == "" {
visiblePrompt = prompt
}
mode := strings.TrimSpace(req.Mode)
if mode == "" {
@@ -703,7 +707,7 @@ func (s *DesignService) AgentChat(ctx context.Context, projectID string, req des
Role: "user",
Type: "user",
Title: "新的设计需求",
Content: prompt,
Content: visiblePrompt,
ThreadID: threadID,
ActionID: actionID,
StepID: newID(),
@@ -5153,6 +5157,14 @@ func isGeneratedImageContent(value string) bool {
}
func promptFromAgentMessages(messages []design.AgentChatMessage) string {
return promptFromAgentMessagesWithVisibility(messages, false)
}
func visiblePromptFromAgentMessages(messages []design.AgentChatMessage) string {
return promptFromAgentMessagesWithVisibility(messages, true)
}
func promptFromAgentMessagesWithVisibility(messages []design.AgentChatMessage, visibleOnly bool) string {
var builder strings.Builder
for _, message := range messages {
if strings.TrimSpace(message.Role) != "" && strings.ToLower(strings.TrimSpace(message.Role)) != "user" {
@@ -5161,7 +5173,8 @@ func promptFromAgentMessages(messages []design.AgentChatMessage) string {
for _, content := range message.Contents {
switch strings.ToLower(strings.TrimSpace(content.Type)) {
case "text":
if strings.EqualFold(strings.TrimSpace(content.TextSource), "settings") {
textSource := strings.TrimSpace(content.TextSource)
if strings.EqualFold(textSource, "settings") || (visibleOnly && strings.EqualFold(textSource, "cad-context")) {
continue
}
if text := strings.TrimSpace(content.Text); text != "" {
@@ -5207,7 +5220,8 @@ func hasUserPromptTextInAgentMessages(messages []design.AgentChatMessage) bool {
if strings.ToLower(strings.TrimSpace(content.Type)) != "text" {
continue
}
if strings.EqualFold(strings.TrimSpace(content.TextSource), "settings") {
textSource := strings.TrimSpace(content.TextSource)
if strings.EqualFold(textSource, "settings") || strings.EqualFold(textSource, "cad-context") {
continue
}
text := stripPromptReferenceDirectives(stripImageGeneratorDirectiveLines(content.Text))