fix: actually set the working dir for extensions from session (#6612)

This commit is contained in:
Zane
2026-01-21 10:03:49 -10:00
committed by GitHub
parent a7699e1607
commit 5bf4cf0463
4 changed files with 44 additions and 14 deletions
+18 -2
View File
@@ -634,6 +634,7 @@ impl Agent {
/// Load extensions from session into the agent
/// Skips extensions that are already loaded
/// Uses the session's working_dir for extension initialization
pub async fn load_extensions_from_session(
self: &Arc<Self>,
session: &Session,
@@ -651,11 +652,15 @@ impl Agent {
}
};
// Capture the session's working_dir to pass to extensions
let working_dir = session.working_dir.clone();
let extension_futures = enabled_configs
.into_iter()
.map(|config| {
let config_clone = config.clone();
let agent_ref = self.clone();
let working_dir_clone = working_dir.clone();
async move {
let name = config_clone.name().to_string();
@@ -674,7 +679,10 @@ impl Agent {
};
}
match agent_ref.add_extension(config_clone).await {
match agent_ref
.add_extension_with_working_dir(config_clone, Some(working_dir_clone))
.await
{
Ok(_) => ExtensionLoadResult {
name,
success: true,
@@ -698,6 +706,14 @@ impl Agent {
}
pub async fn add_extension(&self, extension: ExtensionConfig) -> ExtensionResult<()> {
self.add_extension_with_working_dir(extension, None).await
}
pub async fn add_extension_with_working_dir(
&self,
extension: ExtensionConfig,
working_dir: Option<std::path::PathBuf>,
) -> ExtensionResult<()> {
match &extension {
ExtensionConfig::Frontend {
tools,
@@ -726,7 +742,7 @@ impl Agent {
}
_ => {
self.extension_manager
.add_extension(extension.clone())
.add_extension_with_working_dir(extension.clone(), working_dir)
.await?;
}
}
+22 -10
View File
@@ -466,13 +466,6 @@ impl ExtensionManager {
&self.context
}
/// Resolve the working directory for an extension.
/// Falls back to current_dir when working_dir is not available.
async fn resolve_working_dir(&self) -> PathBuf {
// Fall back to current_dir - working_dir is passed through the call chain from session
std::env::current_dir().unwrap_or_default()
}
pub async fn supports_resources(&self) -> bool {
self.extensions
.lock()
@@ -481,7 +474,14 @@ impl ExtensionManager {
.any(|ext| ext.supports_resources())
}
pub async fn add_extension(self: &Arc<Self>, config: ExtensionConfig) -> ExtensionResult<()> {
/// Add an extension with an optional working directory.
/// If working_dir is None, falls back to current_dir.
#[allow(clippy::too_many_lines)]
pub async fn add_extension_with_working_dir(
self: &Arc<Self>,
config: ExtensionConfig,
working_dir: Option<PathBuf>,
) -> ExtensionResult<()> {
let config_name = config.key().to_string();
let sanitized_name = normalize(&config_name);
@@ -489,8 +489,9 @@ impl ExtensionManager {
return Ok(());
}
// Resolve working_dir: session > current_dir
let effective_working_dir = self.resolve_working_dir().await;
// Resolve working_dir: explicit > current_dir
let effective_working_dir =
working_dir.unwrap_or_else(|| std::env::current_dir().unwrap_or_default());
let mut temp_dir = None;
@@ -555,6 +556,17 @@ impl ExtensionManager {
.ok_or_else(|| {
ExtensionError::ConfigError(format!("Unknown builtin extension: {}", name))
})?;
// Set GOOSE_WORKING_DIR in the current process for builtin extensions
// since they run in-process and read from std::env::var
if effective_working_dir.exists() && effective_working_dir.is_dir() {
std::env::set_var("GOOSE_WORKING_DIR", &effective_working_dir);
tracing::info!(
"Set GOOSE_WORKING_DIR for builtin extension: {:?}",
effective_working_dir
);
}
let (server_read, client_write) = tokio::io::duplex(65536);
let (client_read, server_write) = tokio::io::duplex(65536);
(def.spawn_server)(server_read, server_write);
@@ -211,7 +211,7 @@ impl ExtensionManagerClient {
};
extension_manager
.add_extension(config)
.add_extension_with_working_dir(config, None)
.await
.map(|_| {
vec![Content::text(format!(
+3 -1
View File
@@ -264,7 +264,9 @@ async fn test_replayed_session(
#[allow(clippy::redundant_closure_call)]
let result = (async || -> Result<(), Box<dyn std::error::Error>> {
extension_manager.add_extension(extension_config).await?;
extension_manager
.add_extension_with_working_dir(extension_config, None)
.await?;
let mut results = Vec::new();
for tool_call in tool_calls {
let tool_call = CallToolRequestParam {