diff --git a/crates/buzz-acp/src/acp.rs b/crates/buzz-acp/src/acp.rs index 93109fa94d..c4082d02f7 100644 --- a/crates/buzz-acp/src/acp.rs +++ b/crates/buzz-acp/src/acp.rs @@ -2970,28 +2970,51 @@ mod tests { #[cfg(unix)] #[tokio::test] async fn spawn_applies_runtime_env_defaults_with_extra_env_precedence() { - const VAR: &str = "HERMES_ACP_SKIP_CONFIGURED_MCP"; - if std::env::var_os(VAR).is_some() { + const HERMES_VAR: &str = "HERMES_ACP_SKIP_CONFIGURED_MCP"; + const CLAUDE_VAR: &str = "CLAUDE_CODE_AUTO_COMPACT_WINDOW"; + if std::env::var_os(HERMES_VAR).is_some() || std::env::var_os(CLAUDE_VAR).is_some() { // Inherited parent values win over both layers; the default and // override behavior below is unobservable in such an environment. return; } assert_eq!( - spawn_named_and_read_child_env("hermes-acp", VAR, &[]).await, + spawn_named_and_read_child_env("hermes-acp", HERMES_VAR, &[]).await, "1", - "Hermes spawns must default {VAR}=1" + "Hermes spawns must default {HERMES_VAR}=1" ); assert_eq!( - spawn_named_and_read_child_env("hermes-acp", VAR, &[(VAR.into(), "0".into())]).await, + spawn_named_and_read_child_env( + "hermes-acp", + HERMES_VAR, + &[(HERMES_VAR.into(), "0".into())] + ) + .await, "0", "an explicit extra_env entry must override the runtime default" ); assert_eq!( - spawn_named_and_read_child_env("other-agent", VAR, &[]).await, - "", - "non-Hermes spawns must not receive Hermes defaults" + spawn_named_and_read_child_env("claude-agent-acp", CLAUDE_VAR, &[]).await, + "200000", + "Claude spawns must default {CLAUDE_VAR}=200000" ); + assert_eq!( + spawn_named_and_read_child_env( + "claude-agent-acp", + CLAUDE_VAR, + &[(CLAUDE_VAR.into(), "300000".into())] + ) + .await, + "300000", + "an explicit extra_env entry must override the runtime default" + ); + for agent in ["goose", "codex-acp", "other-agent"] { + assert_eq!( + spawn_named_and_read_child_env(agent, CLAUDE_VAR, &[]).await, + "", + "non-Claude spawn {agent} must not receive Claude defaults" + ); + } } #[tokio::test] diff --git a/crates/buzz-acp/src/config.rs b/crates/buzz-acp/src/config.rs index d959685846..38b0b774ce 100644 --- a/crates/buzz-acp/src/config.rs +++ b/crates/buzz-acp/src/config.rs @@ -712,9 +712,17 @@ fn default_agent_args(command: &str) -> Option> { /// startup budget (see block/buzz#3355). Skip that unrelated global startup /// by default; an operator or persona can still opt back in by setting the /// variable explicitly. +/// +/// Claude: set a 200,000-token automatic-compaction window for Buzz-owned +/// children only. Claude Code caps this to the selected model's context +/// capacity. An inherited parent value or explicit persona value wins, so an +/// operator can select a different window without modifying Claude settings. pub(crate) fn default_agent_env(command: &str) -> &'static [(&'static str, &'static str)] { match normalize_agent_command_identity(command).as_str() { "hermes" | "hermes-agent" | "hermes-acp" => &[("HERMES_ACP_SKIP_CONFIGURED_MCP", "1")], + "claude-agent-acp" | "claude-code-acp" | "claude-code" | "claudecode" => { + &[("CLAUDE_CODE_AUTO_COMPACT_WINDOW", "200000")] + } _ => &[], } } @@ -1635,7 +1643,7 @@ mod tests { } #[test] - fn default_agent_env_recognizes_hermes_identities() { + fn default_agent_env_recognizes_runtime_identities() { for command in [ "hermes", "hermes-agent", @@ -1650,10 +1658,24 @@ mod tests { "unexpected env defaults for {command}" ); } - for command in ["goose", "codex-acp", "claude-agent-acp", "buzz-agent", ""] { + for command in [ + "claude-agent-acp", + "claude-code-acp", + "claude-code", + "claudecode", + "/opt/claude/bin/claude-agent-acp", + r"C:\Users\test\AppData\Roaming\npm\CLAUDE-CODE-ACP.cmd", + ] { + assert_eq!( + default_agent_env(command), + &[("CLAUDE_CODE_AUTO_COMPACT_WINDOW", "200000")], + "unexpected env defaults for {command}" + ); + } + for command in ["goose", "codex-acp", "buzz-agent", ""] { assert!( default_agent_env(command).is_empty(), - "non-Hermes command must have no env defaults: {command}" + "unrecognized command must have no env defaults: {command}" ); } }