fix(graph): build peer retirement guards before spawning their tasks

A task aborted before its first poll never runs its body, so a guard
constructed inside the future did not exist yet and the pre-provisioned
teammate identity stayed messageable. Built outside and moved in, the
guard drops with the unpolled future on both the frontier and map items.

Also rewords the two timeout: 0 validator warnings: the graph-level one
no longer claims max_loop_iterations always applies (it may be 0 too),
and the node-level one names the enclosing bounds that still end the
node instead of saying it runs until it returns.
This commit is contained in:
Dark-Alex-17 committed 2026-09-11 10:56:28 -06:00
1 parent 02e2227aa0
commit 24b5504e21
3 files changed
+82 -32

No files matched your search

+13 -8
View File
@@ -628,8 +628,8 @@ impl GraphValidator {
if graph.settings.timeout == Some(0) {
result.warning(ValidationError::new(
"settings.timeout: 0 disables the graph wall-clock bound; the run \
ends only when the graph completes, is aborted, or hits \
max_loop_iterations",
ends only when the graph completes, is aborted, or another \
limit stops it",
));
}
for (node_id, node) in &graph.nodes {
@@ -655,7 +655,8 @@ impl GraphValidator {
node_id,
format!(
"timeout: 0 disables the wall-clock bound for {kind} node \
'{node_id}'; it runs until it returns"
'{node_id}'; it runs until it returns or an enclosing bound \
(settings.timeout, an outer agent node's timeout, or abort) ends it"
),
));
}
@@ -3293,7 +3294,7 @@ mod tests {
assert_eq!(
w[0].message,
"settings.timeout: 0 disables the graph wall-clock bound; the run ends only when \
the graph completes, is aborted, or hits max_loop_iterations"
the graph completes, is aborted, or another limit stops it"
);
}
@@ -3312,7 +3313,8 @@ mod tests {
assert_eq!(w[0].node_id.as_deref(), Some("a"));
assert_eq!(
w[0].message,
"timeout: 0 disables the wall-clock bound for agent node 'a'; it runs until it returns"
"timeout: 0 disables the wall-clock bound for agent node 'a'; it runs until it returns \
or an enclosing bound (settings.timeout, an outer agent node's timeout, or abort) ends it"
);
}
@@ -3332,7 +3334,8 @@ mod tests {
assert_eq!(w[0].node_id.as_deref(), Some("s"));
assert_eq!(
w[0].message,
"timeout: 0 disables the wall-clock bound for script node 's'; it runs until it returns"
"timeout: 0 disables the wall-clock bound for script node 's'; it runs until it returns \
or an enclosing bound (settings.timeout, an outer agent node's timeout, or abort) ends it"
);
}
@@ -3352,7 +3355,8 @@ mod tests {
assert_eq!(w[0].node_id.as_deref(), Some("l"));
assert_eq!(
w[0].message,
"timeout: 0 disables the wall-clock bound for llm node 'l'; it runs until it returns"
"timeout: 0 disables the wall-clock bound for llm node 'l'; it runs until it returns \
or an enclosing bound (settings.timeout, an outer agent node's timeout, or abort) ends it"
);
}
@@ -3372,7 +3376,8 @@ mod tests {
assert_eq!(w[0].node_id.as_deref(), Some("r"));
assert_eq!(
w[0].message,
"timeout: 0 disables the wall-clock bound for rag node 'r'; it runs until it returns"
"timeout: 0 disables the wall-clock bound for rag node 'r'; it runs until it returns \
or an enclosing bound (settings.timeout, an outer agent node's timeout, or abort) ends it"
);
}