Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 35 additions & 5 deletions crates/buzz-acp/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -691,10 +691,19 @@ pub(crate) fn normalize_agent_command_identity(command: &str) -> String {
}

fn default_agent_args(command: &str) -> Option<Vec<String>> {
// Empty agent_args / clap's sole "acp" default must still launch Grok in
// ACP mode — bare `grok` opens the TUI and fails with ENXIO when Buzz has
// no controlling TTY (block/buzz#3457).
match normalize_agent_command_identity(command).as_str() {
"goose" => Some(vec!["acp".to_string()]),
"codex" | "codex-acp" | "claude-agent-acp" | "claude-code-acp" | "claude-code"
| "claudecode" | "buzz-agent" => Some(Vec::new()),
// Grok Build: `grok agent --always-approve stdio`
"grok" => Some(vec![
"agent".to_string(),
"--always-approve".to_string(),
"stdio".to_string(),
]),
Comment on lines +702 to +706

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Apply the Grok default when CLI args are omitted

When BUZZ_ACP_AGENT_COMMAND=grok (or --agent-command grok) is used without explicitly setting agent args, both CliArgs and AuthAgentArgs supply the legacy default "acp", so normalize_agent_args sees a nonempty vector and preserves it instead of selecting this new default. Standalone relay, models, and authentication launches therefore execute grok acp rather than grok agent --always-approve stdio; represent omitted args as empty before normalization or treat the legacy sole acp value as absent for Grok.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — fixed in d82a729.

normalize_agent_args now treats a sole bare "acp" as omitted for any command that has a known default (not only when the default is empty). So:

  • BUZZ_ACP_AGENT_COMMAND=grok with clap/env default agent_args=["acp"]agent --always-approve stdio
  • goose still gets ["acp"]
  • zero-arg adapters still get []
  • explicit multi-arg lists are unchanged

Also added DCO Signed-off-by on the commit.

_ => None,
}
}
Expand Down Expand Up @@ -786,11 +795,10 @@ pub fn normalize_agent_args(command: &str, agent_args: Vec<String>) -> Vec<Strin
return default_args;
}

// Older callers relied on the Goose-specific default even for runtimes like
// Codex and Claude. Treat that legacy fallback as "no args" for zero-arg
// providers so desktop- and env-based launches behave the same way.
if normalized.len() == 1 && normalized[0].eq_ignore_ascii_case("acp") && default_args.is_empty()
{
// Clap/env historically defaulted agent args to a sole `"acp"` (Goose's
// entrypoint). Treat that sentinel as omitted for known defaults so Grok
// gets `agent --always-approve stdio` rather than `grok acp` (#3457).
if normalized.len() == 1 && normalized[0].eq_ignore_ascii_case("acp") {
return default_args;
}

Expand Down Expand Up @@ -1592,6 +1600,28 @@ mod tests {
);
}

#[test]
fn normalizes_grok_empty_args_to_agent_stdio() {
assert_eq!(
normalize_agent_args("grok", Vec::new()),
vec!["agent", "--always-approve", "stdio"]
);
assert_eq!(
normalize_agent_args("/Users/test/.local/bin/grok", Vec::new()),
vec!["agent", "--always-approve", "stdio"]
);
// clap/env default is a sole "acp" when --agent-args is omitted
assert_eq!(
normalize_agent_args("grok", vec!["acp".into()]),
vec!["agent", "--always-approve", "stdio"]
);
assert_eq!(
normalize_agent_args("grok", vec!["agent".into(), "stdio".into()]),
vec!["agent", "stdio"]
);
}


#[test]
fn normalize_agent_command_identity_variants() {
assert_eq!(normalize_agent_command_identity("goose"), "goose");
Expand Down
16 changes: 14 additions & 2 deletions desktop/src-tauri/src/managed_agents/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -461,10 +461,20 @@ pub fn try_record_agent_command(
}

fn default_agent_args(command: &str) -> Option<Vec<String>> {
// Empty `agent_args` on managed-agent records is intentional (see
// instanceInputForDefinition): spawn fills defaults from this table.
// Grok must be included or a command override alone launches bare `grok`
// (interactive TUI → ENXIO under the desktop, block/buzz#3457).
match normalize_command_identity(command).as_str() {
"goose" => Some(vec!["acp".to_string()]),
"codex" | "codex-acp" | "claude-agent-acp" | "claude-code-acp" | "claude-code"
| "claudecode" | "buzz-agent" => Some(Vec::new()),
// Grok Build: `grok agent --always-approve stdio` (matches PRESET_HARNESSES).
"grok" => Some(vec![
"agent".to_string(),
"--always-approve".to_string(),
"stdio".to_string(),
]),
_ => None,
}
}
Expand All @@ -484,8 +494,10 @@ pub fn normalize_agent_args(command: &str, agent_args: Vec<String>) -> Vec<Strin
return default_args;
}

if normalized.len() == 1 && normalized[0].eq_ignore_ascii_case("acp") && default_args.is_empty()
{
// Clap/env historically defaulted agent args to a sole `"acp"` (Goose's
// entrypoint). Treat that sentinel as omitted for known defaults so Grok
// gets `agent --always-approve stdio` rather than `grok acp` (#3457).
if normalized.len() == 1 && normalized[0].eq_ignore_ascii_case("acp") {
return default_args;
}

Expand Down
25 changes: 25 additions & 0 deletions desktop/src-tauri/src/managed_agents/discovery/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,31 @@ fn normalizes_buzz_agent_args_to_empty() {
);
}

#[test]
fn normalizes_grok_empty_args_to_agent_stdio() {
// Managed records intentionally store empty agent_args; spawn must still
// enter ACP mode (block/buzz#3457).
assert_eq!(
normalize_agent_args("grok", Vec::new()),
vec!["agent", "--always-approve", "stdio"]
);
assert_eq!(
normalize_agent_args("/Users/test/.local/bin/grok", Vec::new()),
vec!["agent", "--always-approve", "stdio"]
);
// Legacy clap/env default is a sole "acp" when args are omitted.
assert_eq!(
normalize_agent_args("grok", vec!["acp".into()]),
vec!["agent", "--always-approve", "stdio"]
);
// Explicit non-empty args are preserved.
assert_eq!(
normalize_agent_args("grok", vec!["agent".into(), "stdio".into()]),
vec!["agent", "stdio"]
);
}


#[test]
fn login_shell_lookup_treats_command_as_data() {
let marker =
Expand Down