feat(desktop): default agent CWD to user home directory, increase turn timeout (#180)

This commit is contained in:
tlongwell-block
2026-03-25 15:28:44 -04:00
committed by GitHub
parent 7ec5ebbb9c
commit 400937db17
7 changed files with 33 additions and 6 deletions

View File

@@ -4328,6 +4328,7 @@ dependencies = [
"atomic-write-file",
"base64 0.22.1",
"chrono",
"dirs",
"hex",
"infer 0.16.0",
"libc",

View File

@@ -25,6 +25,7 @@ windows-sys = { version = "0.59", features = ["Win32_Storage_FileSystem"] }
[dependencies]
atomic-write-file = "0.3"
dirs = "6"
tauri = { version = "2", features = [] }
tauri-plugin-opener = "2"
tauri-plugin-window-state = "2"

View File

@@ -5,8 +5,8 @@ use tauri::{AppHandle, State};
use crate::{
app_state::AppState,
managed_agents::{
build_managed_agent_summary, find_managed_agent_mut, load_managed_agents,
missing_command_message, resolve_command, save_managed_agents,
build_managed_agent_summary, default_agent_workdir, find_managed_agent_mut,
load_managed_agents, missing_command_message, resolve_command, save_managed_agents,
sync_managed_agent_processes, AgentModelInfo, AgentModelsResponse, ManagedAgentSummary,
UpdateManagedAgentRequest, DEFAULT_AGENT_ARG,
},
@@ -63,8 +63,11 @@ pub async fn get_agent_models(
// tokio's `process` feature. std::process::Command is synchronous
// but fine for a short-lived subprocess (~2-5s).
let output = tokio::task::spawn_blocking(move || {
std::process::Command::new(&resolved_acp)
.arg("models")
let mut cmd = std::process::Command::new(&resolved_acp);
if let Some(home) = default_agent_workdir() {
cmd.current_dir(home);
}
cmd.arg("models")
.arg("--json")
.env("SPROUT_ACP_AGENT_COMMAND", &agent_command)
.env("SPROUT_ACP_AGENT_ARGS", agent_args.join(","))

View File

@@ -26,7 +26,11 @@ pub fn invoke_provider(
serde_json::to_string(request).map_err(|e| e.to_string())?
);
let mut child = std::process::Command::new(binary)
let mut cmd = std::process::Command::new(binary);
if let Some(home) = super::default_agent_workdir() {
cmd.current_dir(home);
}
let mut child = cmd
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())

View File

@@ -15,3 +15,17 @@ pub use runtime::*;
pub use storage::*;
pub use teams::*;
pub use types::*;
/// Returns the user's home directory if it can be resolved and exists.
/// Used as the default working directory for spawned agent processes.
///
/// Cached for the process lifetime — home directory doesn't change at runtime.
/// Returns `None` in sandboxed/containerized environments where `$HOME` is
/// unset or points to a non-existent path; callers fall back to inheriting
/// the parent's CWD.
pub fn default_agent_workdir() -> Option<std::path::PathBuf> {
use std::sync::OnceLock;
static HOME: OnceLock<Option<std::path::PathBuf>> = OnceLock::new();
HOME.get_or_init(|| dirs::home_dir().filter(|p| p.is_dir()))
.clone()
}

View File

@@ -283,6 +283,9 @@ pub fn start_managed_agent_process(
.ok_or_else(|| missing_command_message(&record.mcp_command, "MCP server command"))?;
let mut command = std::process::Command::new(&resolved_acp_command);
if let Some(home) = super::default_agent_workdir() {
command.current_dir(home);
}
command.stdin(std::process::Stdio::null());
command.stdout(std::process::Stdio::from(stdout));
command.stderr(std::process::Stdio::from(stderr));

View File

@@ -310,7 +310,8 @@ pub const DEFAULT_ADMIN_COMMAND: &str = "sprout-admin";
pub const DEFAULT_AGENT_COMMAND: &str = "goose";
pub const DEFAULT_MCP_COMMAND: &str = "sprout-mcp-server";
pub const DEFAULT_AGENT_ARG: &str = "acp";
pub const DEFAULT_AGENT_TURN_TIMEOUT_SECONDS: u64 = 300;
/// 10 min — agents with tool-heavy turns regularly exceed the previous 5 min default.
pub const DEFAULT_AGENT_TURN_TIMEOUT_SECONDS: u64 = 600;
pub const DEFAULT_AGENT_PARALLELISM: u32 = 1;
fn default_agent_parallelism() -> u32 {