fix(agent): prevent disconnected Message nodes from executing (#21549)

This commit is contained in:
Sbaaoui Idriss authored and GitHub committed 2026-10-27 16:37:23 +08:00
1 parent 076d428396
commit 66d4d4f2fb
2 files changed
+21 -3

No files matched your search

+16
View File
@@ -742,7 +742,15 @@ func BuildWorkflow(ctx context.Context, c *Canvas) (*compose.Workflow[map[string
// (a downstream that's also a sub-graph member doesn't count — that
// node is part of the loop's body, not the outer graph's edge).
terminals := make([]string, 0, len(c.Components))
roots := make(map[string]bool)
entries := make(map[string]bool)
for cpnID, comp := range c.Components {
if !macroMembers[cpnID] && len(comp.Upstream) == 0 && !first[cpnID] {
roots[cpnID] = true
if strings.EqualFold(comp.Obj.ComponentName, "Begin") || strings.EqualFold(comp.Obj.ComponentName, "File") {
entries[cpnID] = true
}
}
if node, isMacro := macroNodes[cpnID]; isMacro {
// Macro parents with no upstream are START nodes. Parents
// with upstream had their AddInput wired in Pass 2 already.
@@ -773,6 +781,14 @@ func BuildWorkflow(ctx context.Context, c *Canvas) (*compose.Workflow[map[string
}
}
if len(entries) > 0 && len(entries) < len(roots) {
// Branch pruning skips disconnected roots and their terminal dependencies.
wf.AddBranch(compose.START, compose.NewGraphMultiBranch(
func(context.Context, map[string]any) (map[string]bool, error) {
return entries, nil
}, roots))
}
if err := wireWorkflowTerminals(wf, terminals, "", true); err != nil {
return nil, err
}
+5 -3
View File
@@ -548,20 +548,21 @@ func TestRunAgent_RealCanvas_WaitForUserResume(t *testing.T) {
"component_name": "Begin",
"params": map[string]any{},
},
"downstream": []any{"message_0"},
"downstream": []any{"user_fill_up_0"},
},
"message_0": map[string]any{
"obj": map[string]any{
"component_name": "Message",
"params": map[string]any{"text": "got: {{user_fill_up_0@user_input}}"},
},
"upstream": []any{"begin_0", "user_fill_up_0"},
"upstream": []any{"user_fill_up_0"},
},
"user_fill_up_0": map[string]any{
"obj": map[string]any{
"component_name": "UserFillUp",
"params": map[string]any{"enable_tips": true},
},
"upstream": []any{"begin_0"},
"downstream": []any{"message_0"},
},
},
@@ -782,6 +783,7 @@ func TestRunAgent_RealCanvas_WaitForUserResume_EventSemantics(t *testing.T) {
"component_name": "UserFillUp",
"params": map[string]any{"enable_tips": true},
},
"upstream": []any{"begin_0"},
"downstream": []any{"message_0"},
},
"message_0": map[string]any{
@@ -789,7 +791,7 @@ func TestRunAgent_RealCanvas_WaitForUserResume_EventSemantics(t *testing.T) {
"component_name": "Message",
"params": map[string]any{"text": "got: {{user_fill_up_0@user_input}}"},
},
"upstream": []any{"begin_0", "user_fill_up_0"},
"upstream": []any{"user_fill_up_0"},
},
},
"path": []any{"begin_0", "user_fill_up_0", "message_0"},