MCPcopy Create free account
hub / github.com/c4pt0r/pie / execute_tools

Function execute_tools

crates/agent/src/agent_loop.rs:331–704  ·  view source on GitHub ↗

Execute every tool-call block in the assistant's content. Returns the per-call results (in assistant content order) and `all_terminate = true` when every result hints early termination.

(
    inner: &Arc<AgentInner>,
    assistant: &PiAssistantMessage,
    cancel: &CancellationToken,
)

Source from the content-addressed store, hash-verified

329/// (in assistant content order) and `all_terminate = true` when every result hints early
330/// termination.
331async fn execute_tools(
332 inner: &Arc<AgentInner>,
333 assistant: &PiAssistantMessage,
334 cancel: &CancellationToken,
335) -> (Vec<ToolResultMessage>, bool) {
336 // Gather the tool calls + matched AgentTool implementations in assistant content order.
337 let tool_calls: Vec<&pie_ai::ToolCall> = assistant
338 .content
339 .iter()
340 .filter_map(|b| match b {
341 pie_ai::ContentBlock::ToolCall(tc) => Some(tc),
342 _ => None,
343 })
344 .collect();
345 if tool_calls.is_empty() {
346 return (Vec::new(), false);
347 }
348 let tools_snapshot = inner.state.lock().tools.clone();
349
350 // Decide per-call execution mode (parallel default unless any tool requests sequential).
351 let mode = inner.options.tool_execution;
352 let any_sequential = tool_calls.iter().any(|tc| {
353 let matched = tools_snapshot
354 .iter()
355 .find(|t| t.definition().name == tc.name);
356 matched
357 .and_then(|t| t.execution_mode())
358 .map(|m| matches!(m, ToolExecutionMode::Sequential))
359 .unwrap_or(false)
360 });
361 let mode = if any_sequential {
362 ToolExecutionMode::Sequential
363 } else {
364 mode
365 };
366
367 // Pre-flight: run `before_tool_call` for every call. If a hook blocks, synthesize an error
368 // result and skip the actual execute. Returns Vec<Option<execute_input>> in call order.
369 let mut prepared: Vec<PreparedCall> = Vec::with_capacity(tool_calls.len());
370 let agent_context = snapshot_context(inner);
371 for tc in &tool_calls {
372 let tool_id = tc.id.clone();
373 let tool_name = tc.name.clone();
374 let raw_args = serde_json::Value::Object(tc.arguments.clone());
375
376 // Resolve the tool BEFORE normalizing args so we can run its `prepare_arguments`
377 // compatibility shim. Unknown tools keep raw args (the dispatcher will produce a
378 // "no such tool" error result downstream).
379 let tool = tools_snapshot
380 .iter()
381 .find(|t| t.definition().name == tool_name)
382 .cloned();
383 let args = match &tool {
384 Some(t) => t.prepare_arguments(raw_args),
385 None => raw_args,
386 };
387
388 emit(

Callers 1

drive_loopFunction · 0.85

Calls 15

snapshot_contextFunction · 0.85
compute_args_hashFunction · 0.85
default_prompt_payloadFunction · 0.85
run_oneFunction · 0.85
iterMethod · 0.80
lockMethod · 0.80
findMethod · 0.80
emitFunction · 0.70
is_emptyMethod · 0.45
cloneMethod · 0.45
definitionMethod · 0.45
execution_modeMethod · 0.45

Tested by

no test coverage detected