Enable parallel shell tools (#10505)

Summary
- mark the shell-related tools as supporting parallel tool calls so
exec_command, shell_command, etc. can run concurrently
- update expectations in tool parallelism tests to reflect the new
parallel behavior
- drop the unused serial duration helper from the suite

Testing
- Not run (not requested)
This commit is contained in:
jif-oai 2026-02-03 18:05:02 +00:00 committed by GitHub
parent d509df676b
commit 33dc93e4d2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 18 additions and 16 deletions

View file

@ -1258,13 +1258,19 @@ pub(crate) fn build_specs(
match &config.shell_type {
ConfigShellToolType::Default => {
builder.push_spec(create_shell_tool(config.request_rule_enabled));
builder.push_spec_with_parallel_support(
create_shell_tool(config.request_rule_enabled),
true,
);
}
ConfigShellToolType::Local => {
builder.push_spec(ToolSpec::LocalShell {});
builder.push_spec_with_parallel_support(ToolSpec::LocalShell {}, true);
}
ConfigShellToolType::UnifiedExec => {
builder.push_spec(create_exec_command_tool(config.request_rule_enabled));
builder.push_spec_with_parallel_support(
create_exec_command_tool(config.request_rule_enabled),
true,
);
builder.push_spec(create_write_stdin_tool());
builder.register_handler("exec_command", unified_exec_handler.clone());
builder.register_handler("write_stdin", unified_exec_handler);
@ -1273,7 +1279,10 @@ pub(crate) fn build_specs(
// Do nothing.
}
ConfigShellToolType::ShellCommand => {
builder.push_spec(create_shell_command_tool(config.request_rule_enabled));
builder.push_spec_with_parallel_support(
create_shell_command_tool(config.request_rule_enabled),
true,
);
}
}
@ -1982,7 +1991,7 @@ mod tests {
});
let (tools, _) = build_specs(&tools_config, None, &[]).build();
assert!(!find_tool(&tools, "exec_command").supports_parallel_tool_calls);
assert!(find_tool(&tools, "exec_command").supports_parallel_tool_calls);
assert!(!find_tool(&tools, "write_stdin").supports_parallel_tool_calls);
assert!(find_tool(&tools, "grep_files").supports_parallel_tool_calls);
assert!(find_tool(&tools, "list_dir").supports_parallel_tool_calls);

View file

@ -77,13 +77,6 @@ fn assert_parallel_duration(actual: Duration) {
);
}
fn assert_serial_duration(actual: Duration) {
assert!(
actual >= Duration::from_millis(500),
"expected serial execution to take longer, got {actual:?}"
);
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn read_file_tools_run_in_parallel() -> anyhow::Result<()> {
skip_if_no_network!(Ok(()));
@ -147,7 +140,7 @@ async fn read_file_tools_run_in_parallel() -> anyhow::Result<()> {
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn non_parallel_tools_run_serially() -> anyhow::Result<()> {
async fn shell_tools_run_in_parallel() -> anyhow::Result<()> {
skip_if_no_network!(Ok(()));
let server = start_mock_server().await;
@ -174,13 +167,13 @@ async fn non_parallel_tools_run_serially() -> anyhow::Result<()> {
mount_sse_sequence(&server, vec![first_response, second_response]).await;
let duration = run_turn_and_measure(&test, "run shell_command twice").await?;
assert_serial_duration(duration);
assert_parallel_duration(duration);
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn mixed_tools_fall_back_to_serial() -> anyhow::Result<()> {
async fn mixed_parallel_tools_run_in_parallel() -> anyhow::Result<()> {
skip_if_no_network!(Ok(()));
let server = start_mock_server().await;
@ -208,7 +201,7 @@ async fn mixed_tools_fall_back_to_serial() -> anyhow::Result<()> {
mount_sse_sequence(&server, vec![first_response, second_response]).await;
let duration = run_turn_and_measure(&test, "mix tools").await?;
assert_serial_duration(duration);
assert_parallel_duration(duration);
Ok(())
}