Skip to content

Commit f338e36

Browse files
feat: expose AGENT_SESSION_ID env var to extension child processes (#7072)
1 parent 584f710 commit f338e36

File tree

6 files changed

+42
-9
lines changed

6 files changed

+42
-9
lines changed

crates/goose-acp/src/server.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ async fn add_builtins(agent: &Agent, builtins: Vec<String>) {
251251

252252
match agent
253253
.extension_manager
254-
.add_extension(config, None, None)
254+
.add_extension(config, None, None, None)
255255
.await
256256
{
257257
Ok(_) => info!(extension = %builtin, "extension loaded"),
@@ -264,7 +264,7 @@ async fn add_extensions(agent: &Agent, extensions: Vec<ExtensionConfig>) {
264264
let name = extension.name().to_string();
265265
match agent
266266
.extension_manager
267-
.add_extension(extension, None, None)
267+
.add_extension(extension, None, None, None)
268268
.await
269269
{
270270
Ok(_) => info!(extension = %name, "extension loaded"),

crates/goose-mcp/src/developer/rmcp_developer.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,27 @@ use rmcp::{
1818
tool, tool_handler, tool_router, RoleServer, ServerHandler,
1919
};
2020

21-
/// Header name for passing working directory through MCP request metadata
2221
const WORKING_DIR_HEADER: &str = "agent-working-dir";
22+
const SESSION_ID_HEADER: &str = "agent-session-id";
2323

24-
/// Extract working directory from MCP request metadata
2524
fn extract_working_dir_from_meta(meta: &Meta) -> Option<PathBuf> {
2625
meta.0
2726
.get(WORKING_DIR_HEADER)
2827
.and_then(|v| v.as_str())
2928
.filter(|s| !s.is_empty())
29+
.filter(|s| !s.contains('\0'))
3030
.map(PathBuf::from)
3131
}
3232

33+
fn extract_session_id_from_meta(meta: &Meta) -> Option<String> {
34+
meta.0
35+
.get(SESSION_ID_HEADER)
36+
.and_then(|v| v.as_str())
37+
.filter(|s| !s.is_empty())
38+
.filter(|s| !s.contains('\0'))
39+
.map(String::from)
40+
}
41+
3342
use serde::{Deserialize, Serialize};
3443
use std::{
3544
collections::HashMap,
@@ -887,6 +896,7 @@ impl DeveloperServer {
887896
let request_id = context.id;
888897

889898
let working_dir = extract_working_dir_from_meta(&context.meta);
899+
let session_id = extract_session_id_from_meta(&context.meta);
890900

891901
// Validate the shell command
892902
self.validate_shell_command(command)?;
@@ -901,7 +911,13 @@ impl DeveloperServer {
901911

902912
// Execute the command and capture output
903913
let output_result = self
904-
.execute_shell_command(command, &peer, cancellation_token.clone(), working_dir)
914+
.execute_shell_command(
915+
command,
916+
&peer,
917+
cancellation_token.clone(),
918+
working_dir,
919+
session_id,
920+
)
905921
.await;
906922

907923
// Clean up the process from tracking
@@ -986,6 +1002,7 @@ impl DeveloperServer {
9861002
peer: &rmcp::service::Peer<RoleServer>,
9871003
cancellation_token: CancellationToken,
9881004
working_dir: Option<PathBuf>,
1005+
session_id: Option<String>,
9891006
) -> Result<String, ErrorData> {
9901007
let mut shell_config = ShellConfig::default();
9911008
let shell_name = std::path::Path::new(&shell_config.executable)
@@ -1002,6 +1019,12 @@ impl DeveloperServer {
10021019
}
10031020
}
10041021

1022+
if let Some(sid) = session_id {
1023+
shell_config
1024+
.envs
1025+
.push((OsString::from("AGENT_SESSION_ID"), OsString::from(sid)));
1026+
}
1027+
10051028
let mut command = configure_shell_command(&shell_config, command, working_dir.as_deref());
10061029

10071030
if self.extend_path_with_shell {

crates/goose/src/agents/agent.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,12 @@ impl Agent {
783783
_ => {
784784
let container = self.container.lock().await;
785785
self.extension_manager
786-
.add_extension(extension.clone(), working_dir, container.as_ref())
786+
.add_extension(
787+
extension.clone(),
788+
working_dir,
789+
container.as_ref(),
790+
Some(session_id),
791+
)
787792
.await?;
788793
}
789794
}

crates/goose/src/agents/extension_manager.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ impl ExtensionManager {
482482
config: ExtensionConfig,
483483
working_dir: Option<PathBuf>,
484484
container: Option<&Container>,
485+
session_id: Option<&str>,
485486
) -> ExtensionResult<()> {
486487
let config_name = config.key().to_string();
487488
let sanitized_name = name_to_key(&config_name);
@@ -530,7 +531,11 @@ impl ExtensionManager {
530531
timeout,
531532
..
532533
} => {
533-
let all_envs = merge_environments(envs, env_keys, &sanitized_name).await?;
534+
let mut all_envs = merge_environments(envs, env_keys, &sanitized_name).await?;
535+
536+
if let Some(sid) = session_id {
537+
all_envs.insert("AGENT_SESSION_ID".to_string(), sid.to_string());
538+
}
534539

535540
// Check for malicious packages before launching the process
536541
extension_malware_check::deny_if_malicious_cmd_args(cmd, args).await?;

crates/goose/src/agents/extension_manager_extension.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ impl ExtensionManagerClient {
211211
};
212212

213213
extension_manager
214-
.add_extension(config, None, None)
214+
.add_extension(config, None, None, None)
215215
.await
216216
.map(|_| {
217217
vec![Content::text(format!(

crates/goose/tests/mcp_integration_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ async fn test_replayed_session(
256256
#[allow(clippy::redundant_closure_call)]
257257
let result = (async || -> Result<(), Box<dyn std::error::Error>> {
258258
extension_manager
259-
.add_extension(extension_config, None, None)
259+
.add_extension(extension_config, None, None, None)
260260
.await?;
261261
let mut results = Vec::new();
262262
for tool_call in tool_calls {

0 commit comments

Comments
 (0)