fix(server): complete generator task when thread settles or project ready

Treat a generator task as completed when it produces artifacts, when a
task message reaches a terminal state, or when the project is ready —
even if the project is still exploring another concurrent thread. Adds
generatorTaskMessageCompleted to classify terminal task messages and
covers ready-without-messages and concurrent-thread cases with tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-09 02:20:23 +08:00
parent 94718553c6
commit a5a35648d7
2 changed files with 97 additions and 6 deletions
+23 -6
View File
@@ -384,7 +384,7 @@ func generatorTaskMetadataFromMessages(messages []design.Message, taskID string)
func generatorTaskStatus(project design.Project, taskID string) string {
messages := project.Messages
status := "submitted"
completed := false
completed := len(generatorTaskArtifacts(messages, taskID)) > 0
for _, message := range messages {
if message.ThreadID != taskID {
continue
@@ -392,9 +392,11 @@ func generatorTaskStatus(project design.Project, taskID string) string {
if message.Role == "error" || message.Status == "failed" {
return "failed"
}
if generatorTaskMessageCompleted(message) {
completed = true
}
switch message.Status {
case "success", "cancelled":
completed = true
case "running", "streaming", "submitted":
status = "submitted"
}
@@ -405,15 +407,30 @@ func generatorTaskStatus(project design.Project, taskID string) string {
if project.Status == design.StatusFailed {
return "failed"
}
if project.Status == design.StatusExploring {
return status
}
if len(generatorTaskArtifacts(messages, taskID)) > 0 || completed {
if completed || project.Status == design.StatusReady {
return "completed"
}
return status
}
func generatorTaskMessageCompleted(message design.Message) bool {
status := strings.ToLower(strings.TrimSpace(message.Status))
if status != "success" && status != "cancelled" {
return false
}
name := strings.TrimSpace(message.Name)
if name == "agent_planner" || name == "generator_task" {
return false
}
if isToolArtifactsMessage(message) {
return true
}
return name == "canvas_action" ||
name == "text_extraction" ||
name == "mockup_model" ||
strings.TrimSpace(message.Role) == "assistant"
}
func generatorTaskHasActiveCanvasWork(project design.Project, taskID string) bool {
taskID = strings.TrimSpace(taskID)
lastThreadID := strings.TrimSpace(project.LastThreadID)