use super::messages::PendingToolCall;
use crate::agent::{Agent, ToolUse};
use crate::provider::{ContentPart, Message, Role};
use crate::session::Session;
use crate::tool::ToolResult;
use crate::tool::readonly::is_read_only;
impl Agent {
pub(super) async fn execute_tool_calls(
&self,
session: &mut Session,
tool_calls: Vec<PendingToolCall>,
) {
let results = if can_parallelize(&tool_calls) {
self.execute_parallel(&tool_calls).await
} else {
self.execute_sequential(&tool_calls).await
};
record_results(session, tool_calls, results);
}
async fn execute_sequential(&self, calls: &[PendingToolCall]) -> Vec<ToolResult> {
let mut out = Vec::with_capacity(calls.len());
for (_, name, arguments) in calls {
out.push(self.execute_tool(name, arguments).await);
}
out
}
async fn execute_parallel(&self, calls: &[PendingToolCall]) -> Vec<ToolResult> {
let futures = calls
.iter()
.map(|(_, name, arguments)| self.execute_tool(name, arguments));
futures::future::join_all(futures).await
}
}
fn can_parallelize(calls: &[PendingToolCall]) -> bool {
calls.len() > 1 && calls.iter().all(|(_, name, _)| is_read_only(name))
}
fn record_results(
session: &mut Session,
tool_calls: Vec<PendingToolCall>,
results: Vec<ToolResult>,
) {
for ((id, name, arguments), result) in tool_calls.into_iter().zip(results) {
session.tool_uses.push(ToolUse {
id: id.clone(),
name: name.clone(),
input: arguments.clone(),
output: result.output.clone(),
success: result.success,
});
session.add_message(Message {
role: Role::Tool,
content: vec![ContentPart::ToolResult {
tool_call_id: id,
content: result.output,
}],
});
}
}