diff --git a/.env.example b/.env.example index 18093ee91..051ece03b 100644 --- a/.env.example +++ b/.env.example @@ -137,8 +137,8 @@ RUST_LOG=sprout_relay=debug,sprout_db=debug,sprout_auth=debug,sprout_pubsub=debu # SPROUT_ACP_MODEL= # ── Timeouts & sessions ────────────────────────────────────────────────────── -# Max seconds per agent turn before timeout (default 300 = 5 min). -# SPROUT_ACP_TURN_TIMEOUT=300 +# Max seconds per agent turn before timeout (default 320 = ~5 min). +# SPROUT_ACP_TURN_TIMEOUT=320 # Max turns per session before proactive rotation. 0 = disabled (rotate only # on MaxTokens / MaxTurnRequests). Recommended: 50 for long-running agents. diff --git a/crates/sprout-acp/src/acp.rs b/crates/sprout-acp/src/acp.rs index f6958b8c3..8b6f1c25d 100644 --- a/crates/sprout-acp/src/acp.rs +++ b/crates/sprout-acp/src/acp.rs @@ -1558,10 +1558,10 @@ mod tests { #[test] fn idle_timeout_error_includes_duration() { - let err = AcpError::IdleTimeout(std::time::Duration::from_secs(300)); + let err = AcpError::IdleTimeout(std::time::Duration::from_secs(320)); let msg = err.to_string(); assert!( - msg.contains("300"), + msg.contains("320"), "IdleTimeout display should include duration: {msg}" ); } diff --git a/crates/sprout-acp/src/config.rs b/crates/sprout-acp/src/config.rs index 0450f273f..cc681b78a 100644 --- a/crates/sprout-acp/src/config.rs +++ b/crates/sprout-acp/src/config.rs @@ -486,7 +486,7 @@ impl Config { }; // Resolve idle_timeout_secs with deprecation handling. - // Precedence: explicit --idle-timeout > --turn-timeout (deprecated) > default 300. + // Precedence: explicit --idle-timeout > --turn-timeout (deprecated) > default 320. let idle_timeout_secs = { let raw = match (args.idle_timeout, args.turn_timeout) { (Some(idle), Some(_turn)) => { @@ -504,7 +504,7 @@ impl Config { ); turn } - (None, None) => 300, // default + (None, None) => 320, // default: 20s buffer over goose's 300s turn timeout }; if raw == 0 { tracing::warn!("idle timeout of 0 is invalid — using 1s minimum"); @@ -889,7 +889,7 @@ mod tests { agent_command: "goose".into(), agent_args: vec!["acp".into()], mcp_command: "sprout-mcp-server".into(), - idle_timeout_secs: 300, + idle_timeout_secs: 320, max_turn_duration_secs: 3600, agents: 1, heartbeat_interval_secs: 0, @@ -1579,13 +1579,13 @@ channels = "ALL" // ── Idle timeout config precedence ───────────────────────────────────── /// Helper: resolve idle_timeout_secs using the same precedence logic as Config::from_args. - /// Precedence: explicit --idle-timeout > --turn-timeout (deprecated) > default 300. + /// Precedence: explicit --idle-timeout > --turn-timeout (deprecated) > default 320. fn resolve_idle_timeout(idle: Option, turn: Option) -> u64 { let raw = match (idle, turn) { (Some(idle), Some(_)) => idle, (Some(idle), None) => idle, (None, Some(turn)) => turn, - (None, None) => 300, + (None, None) => 320, }; if raw == 0 { 1 @@ -1605,8 +1605,8 @@ channels = "ALL" } #[test] - fn idle_timeout_defaults_to_300_when_neither_set() { - assert_eq!(resolve_idle_timeout(None, None), 300); + fn idle_timeout_defaults_to_320_when_neither_set() { + assert_eq!(resolve_idle_timeout(None, None), 320); } #[test] @@ -1624,7 +1624,7 @@ channels = "ALL" let config = test_config(SubscribeMode::Mentions); let summary = config.summary(); assert!( - summary.contains("idle_timeout=300s"), + summary.contains("idle_timeout=320s"), "summary should include idle_timeout: {summary}" ); assert!( diff --git a/desktop/src-tauri/src/commands/agents.rs b/desktop/src-tauri/src/commands/agents.rs index 19944b9c9..4890063e5 100644 --- a/desktop/src-tauri/src/commands/agents.rs +++ b/desktop/src-tauri/src/commands/agents.rs @@ -368,7 +368,7 @@ pub async fn create_managed_agent( .turn_timeout_seconds .filter(|seconds| *seconds > 0) .unwrap_or(DEFAULT_AGENT_TURN_TIMEOUT_SECONDS), - // 0 or None → harness uses its own default (300s idle, 3600s max), and the CLI also clamps 0 → minimum. + // 0 or None → harness uses its own default (320s idle, 3600s max), and the CLI also clamps 0 → minimum. idle_timeout_seconds: input.idle_timeout_seconds.filter(|s| *s > 0), max_turn_duration_seconds: input.max_turn_duration_seconds.filter(|s| *s > 0), parallelism: input diff --git a/desktop/src-tauri/src/managed_agents/types.rs b/desktop/src-tauri/src/managed_agents/types.rs index 6ea75e548..4bd24803c 100644 --- a/desktop/src-tauri/src/managed_agents/types.rs +++ b/desktop/src-tauri/src/managed_agents/types.rs @@ -319,11 +319,11 @@ pub const DEFAULT_ACP_COMMAND: &str = "sprout-acp"; pub const DEFAULT_ADMIN_COMMAND: &str = "sprout-admin"; pub const DEFAULT_AGENT_COMMAND: &str = "goose"; pub const DEFAULT_MCP_COMMAND: &str = "sprout-mcp-server"; -/// 5 min — matches the CLI harness default (SPROUT_ACP_IDLE_TIMEOUT). -pub const DEFAULT_AGENT_TURN_TIMEOUT_SECONDS: u64 = 300; +/// ~5 min (320s) — matches the CLI harness default (SPROUT_ACP_IDLE_TIMEOUT). +pub const DEFAULT_AGENT_TURN_TIMEOUT_SECONDS: u64 = 320; /// 1 hour — absolute wall-clock safety cap per turn. pub const DEFAULT_AGENT_MAX_TURN_DURATION_SECONDS: u64 = 3600; -pub const DEFAULT_AGENT_PARALLELISM: u32 = 1; +pub const DEFAULT_AGENT_PARALLELISM: u32 = 3; fn default_agent_parallelism() -> u32 { DEFAULT_AGENT_PARALLELISM diff --git a/desktop/src/features/agents/ui/CreateAgentDialog.tsx b/desktop/src/features/agents/ui/CreateAgentDialog.tsx index e0d85131f..d47e4c8b7 100644 --- a/desktop/src/features/agents/ui/CreateAgentDialog.tsx +++ b/desktop/src/features/agents/ui/CreateAgentDialog.tsx @@ -63,8 +63,8 @@ export function CreateAgentDialog({ const [selectedScopes, setSelectedScopes] = React.useState>( () => new Set(DEFAULT_MANAGED_AGENT_SCOPES), ); - const [turnTimeoutSeconds, setTurnTimeoutSeconds] = React.useState("300"); - const [parallelism, setParallelism] = React.useState("1"); + const [turnTimeoutSeconds, setTurnTimeoutSeconds] = React.useState("320"); + const [parallelism, setParallelism] = React.useState("3"); const [systemPrompt, setSystemPrompt] = React.useState(""); const [selectedProviderId, setSelectedProviderId] = React.useState("custom"); @@ -212,8 +212,8 @@ export function CreateAgentDialog({ setAgentCommand("goose"); setAgentArgs("acp"); setMcpCommand("sprout-mcp-server"); - setTurnTimeoutSeconds("300"); - setParallelism("1"); + setTurnTimeoutSeconds("320"); + setParallelism("3"); setSystemPrompt(""); setSelectedProviderId("custom"); setHasSyncedProviderSelection(false); diff --git a/desktop/src/testing/e2eBridge.ts b/desktop/src/testing/e2eBridge.ts index 8fdbca9a7..3fdf77dfa 100644 --- a/desktop/src/testing/e2eBridge.ts +++ b/desktop/src/testing/e2eBridge.ts @@ -2578,7 +2578,7 @@ async function handleCreateManagedAgent(args: { ? [...args.input.agentArgs] : ["acp"], mcp_command: args.input.mcpCommand ?? "sprout-mcp-server", - turn_timeout_seconds: args.input.turnTimeoutSeconds ?? 300, + turn_timeout_seconds: args.input.turnTimeoutSeconds ?? 320, idle_timeout_seconds: args.input.idleTimeoutSeconds ?? null, max_turn_duration_seconds: args.input.maxTurnDurationSeconds ?? null, parallelism: args.input.parallelism ?? 1,