feat(piagent): bypass planner for direct image generation modes
For image / pure-image / image-generator / image-action modes, skip the task-planning round trip and hand the prompt straight to the image model, deriving the requested image count from the composer settings. Also normalize completed image-generator nodes back into regular image nodes (clearing the image-generator layer role and defaulting Tone to "visual") when merging generated results and when restoring finished nodes, so a finished generator node is not re-appended as a duplicate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -554,6 +554,75 @@ func TestAgentChatRequiresTextPrompt(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAgentChatImageModeBypassesPlannerAndHidesSettings(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
repo := memory.NewProjectRepository()
|
||||
planner := &recordingTaskPlanner{
|
||||
fakeCreativeChatAgent: fakeCreativeChatAgent{
|
||||
decision: design.AgentDecision{Intent: "image"},
|
||||
},
|
||||
}
|
||||
service := NewDesignService(repo, nil, nil, nil, nil, planner)
|
||||
queue := &fakeJobQueue{}
|
||||
service.SetJobQueue(queue)
|
||||
project := design.Project{
|
||||
ID: "project-direct-image",
|
||||
Title: "Direct image",
|
||||
Status: design.StatusReady,
|
||||
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: "1536x1024",
|
||||
Messages: []design.AgentChatMessage{
|
||||
{
|
||||
Role: "user",
|
||||
Contents: []design.AgentContent{
|
||||
{Type: "text", Text: "a cute bird flatten ui", TextSource: "input"},
|
||||
{Type: "text", Text: "图片生成参数:质量 自动,尺寸 1536x1024,比例 3:2,数量 3 张。纯生图模式,请直接围绕用户输入生成图片,不展开额外聊天。", TextSource: "settings"},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if thread.Status != "running" {
|
||||
t.Fatalf("expected running thread, got %s", thread.Status)
|
||||
}
|
||||
if planner.called != 0 {
|
||||
t.Fatalf("expected image mode to bypass planner, got %d calls", planner.called)
|
||||
}
|
||||
if len(queue.jobs) != 1 {
|
||||
t.Fatalf("expected one image job, got %#v", queue.jobs)
|
||||
}
|
||||
job := queue.jobs[0]
|
||||
if job.TaskPlan.ImageCount != 3 || len(job.TaskPlan.ImageTasks) != 3 {
|
||||
t.Fatalf("expected direct image count from settings, got %#v", job.TaskPlan)
|
||||
}
|
||||
if job.ImageSize != "1536x1024" {
|
||||
t.Fatalf("expected image size to be preserved, got %s", job.ImageSize)
|
||||
}
|
||||
|
||||
saved, err := repo.Get(ctx, project.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(saved.Messages) != 1 {
|
||||
t.Fatalf("expected only the user message before generation starts, got %#v", saved.Messages)
|
||||
}
|
||||
if saved.Messages[0].Content != "a cute bird flatten ui" {
|
||||
t.Fatalf("expected settings to stay out of visible messages, got %q", saved.Messages[0].Content)
|
||||
}
|
||||
if len(saved.Nodes) != 3 {
|
||||
t.Fatalf("expected three direct image placeholders, got %#v", saved.Nodes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAgentChatCreatesPlaceholdersFromModelPlannedImageTasks(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
repo := memory.NewProjectRepository()
|
||||
|
||||
Reference in New Issue
Block a user