From 33399203778d1897ac7db418541dca8d09aaf77f Mon Sep 17 00:00:00 2001 From: Alex Clarke Date: Mon, 14 Sep 2026 00:31:34 -0600 Subject: [PATCH] fix(TASK-028): pin global-template exclusion, tighten timeout boundary test, reword stale hint --- src/config/agent.rs | 1 + src/config/mod.rs | 6 ++++++ src/function/agents.rs | 2 +- src/function/user_interaction.rs | 7 ++++++- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/config/agent.rs b/src/config/agent.rs index d0a4a32..18bf661 100644 --- a/src/config/agent.rs +++ b/src/config/agent.rs @@ -1341,6 +1341,7 @@ variables: assert_eq!(config.max_concurrent_agents, 4); assert_eq!(config.max_agent_depth, 3); assert_eq!(config.max_auto_continues, 10); + assert_eq!(config.escalation_timeout, 0); assert!(config.mcp_servers.is_empty()); assert!(config.global_tools.is_empty()); assert!(config.conversation_starters.is_empty()); diff --git a/src/config/mod.rs b/src/config/mod.rs index efacc93..1016014 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1383,6 +1383,12 @@ clients: assert_eq!(cfg.clients.len(), 1); } + #[test] + fn config_template_does_not_carry_the_per_agent_escalation_timeout_key() { + // `escalation_timeout` is a per-agent setting; the global template must never grow it. + assert!(!CONFIG_TEMPLATE.contains("escalation_timeout")); + } + #[test] fn config_enabled_macros_empty_string_is_some_empty() { let cfg: Config = serde_yaml::from_str("enabled_macros: \"\"").unwrap(); diff --git a/src/function/agents.rs b/src/function/agents.rs index 77ca043..5637a86 100644 --- a/src/function/agents.rs +++ b/src/function/agents.rs @@ -1711,7 +1711,7 @@ fn handle_reply_escalation(ctx: &mut RequestContext, args: &Value) -> Result Ok(json!({ "status": "error", - "message": format!("No pending escalation found with id '{escalation_id}'. It may have already been replied to or timed out."), + "message": format!("No pending escalation found with id '{escalation_id}'. It may have already been replied to, or the child is no longer waiting (aborted, or its configured `escalation_timeout` expired)."), })), } } diff --git a/src/function/user_interaction.rs b/src/function/user_interaction.rs index 6900091..f9a2923 100644 --- a/src/function/user_interaction.rs +++ b/src/function/user_interaction.rs @@ -389,8 +389,12 @@ mod tests { async fn nonzero_timeout_still_expires_with_the_existing_message() { let (tx, rx) = oneshot::channel::(); let wait = tokio::spawn(await_escalation_reply(rx, 5)); + tokio::task::yield_now().await; - tokio::time::advance(Duration::from_secs(6)).await; + tokio::time::advance(Duration::from_secs(4)).await; + assert!(!wait.is_finished()); + + tokio::time::advance(Duration::from_secs(2)).await; let v = wait.await.unwrap().unwrap(); assert_eq!( v["error"], @@ -421,6 +425,7 @@ mod tests { #[test] fn stale_timeout_wording_is_gone_from_shipped_text() { + // Split so this file does not match its own needles. let needles = [ concat!("(5-minute", " timeout)"), concat!("escalation_timeout:", " 300"),