feat(server): place generated images beside the reference anchor node
Read a "reference anchor node:" agent directive and lay newly generated image nodes immediately to the right of that node, inheriting its row and falling back to its size, for planned, follow-up, and incremental flows. Generalize the directive parser shared with the image-generator target. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -623,6 +623,62 @@ func TestAgentChatImageModeBypassesPlannerAndHidesSettings(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAgentChatPlacesReferenceAnchoredPlaceholdersBesideLastCapsule(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
repo := memory.NewProjectRepository()
|
||||
service := NewDesignService(repo, nil, nil, nil, nil, fakeCreativeChatAgent{
|
||||
decision: design.AgentDecision{Intent: "image"},
|
||||
})
|
||||
service.SetJobQueue(&fakeJobQueue{})
|
||||
project := design.Project{
|
||||
ID: "project-reference-anchor",
|
||||
Title: "Reference anchor",
|
||||
Status: design.StatusReady,
|
||||
Nodes: []design.Node{
|
||||
{ID: "reference-1", Type: design.NodeTypeImage, X: 40, Y: 80, Width: 400, Height: 300, Content: "https://example.com/reference-1.webp", Status: "success"},
|
||||
{ID: "reference-2", Type: design.NodeTypeImage, X: 620, Y: 160, Width: 520, Height: 360, Content: "https://example.com/reference-2.webp", Status: "success"},
|
||||
},
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
if err := repo.Save(ctx, project); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
thread, err := service.AgentChat(ctx, project.ID, design.AgentChatRequest{
|
||||
Mode: "image",
|
||||
ImageSize: "1024x1024",
|
||||
ImageCount: 2,
|
||||
Messages: []design.AgentChatMessage{
|
||||
{
|
||||
Role: "user",
|
||||
Contents: []design.AgentContent{
|
||||
{Type: "image", ImageURL: project.Nodes[0].Content, ImageName: "first"},
|
||||
{Type: "image", ImageURL: project.Nodes[1].Content, ImageName: "last"},
|
||||
{Type: "text", Text: "把最后一张参考图转换成立面效果", TextSource: "input"},
|
||||
{Type: "text", Text: "Reference anchor node: reference-2", TextSource: "settings"},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(thread.Project.Nodes) != 4 {
|
||||
t.Fatalf("expected two references and two placeholders, got %#v", thread.Project.Nodes)
|
||||
}
|
||||
if thread.Project.Nodes[1].Content != project.Nodes[1].Content || thread.Project.Nodes[1].X != project.Nodes[1].X {
|
||||
t.Fatalf("expected last reference to remain unchanged, got %#v", thread.Project.Nodes[1])
|
||||
}
|
||||
first := thread.Project.Nodes[2]
|
||||
second := thread.Project.Nodes[3]
|
||||
if first.X <= project.Nodes[1].X+project.Nodes[1].Width || first.Y != project.Nodes[1].Y {
|
||||
t.Fatalf("expected first placeholder beside last capsule, got %#v", first)
|
||||
}
|
||||
if second.X <= first.X+first.Width || second.Y != project.Nodes[1].Y {
|
||||
t.Fatalf("expected second placeholder after first placeholder, got %#v", second)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAgentChatCreatesPlaceholdersFromModelPlannedImageTasks(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
repo := memory.NewProjectRepository()
|
||||
|
||||
Reference in New Issue
Block a user