vtcode 0.99.1

A Rust-based terminal coding agent with modular architecture supporting multiple LLM providers
use crate::agent::runloop::unified::turn::context::{
    PreparedAssistantToolCall, TurnHandlerOutcome,
};
use anyhow::Result;
use call::{handle_prepared_tool_call_dispatch, push_invalid_tool_args_response};
use std::time::Instant;

mod call;

pub(crate) async fn handle_tool_calls<'a, 'b>(
    t_ctx: &mut super::handlers::ToolOutcomeContext<'a, 'b>,
    tool_calls: &[PreparedAssistantToolCall],
) -> Result<Option<TurnHandlerOutcome>> {
    if tool_calls.is_empty() {
        return Ok(None);
    }

    let planning_started = Instant::now();
    let mut valid_calls = 0usize;
    let mut parallel_safe_calls = 0usize;
    for tool_call in tool_calls {
        if tool_call.args().is_some() {
            valid_calls += 1;
        }
        if tool_call.is_parallel_safe() {
            parallel_safe_calls += 1;
        }
    }

    if valid_calls == 0 {
        for tool_call in tool_calls {
            if let Some(err) = tool_call.args_error() {
                push_invalid_tool_args_response(
                    t_ctx.ctx.working_history,
                    tool_call.call_id(),
                    tool_call.tool_name(),
                    err,
                );
            }
        }
        return Ok(None);
    }

    let batch_candidate = t_ctx.ctx.full_auto && valid_calls > 1;
    tracing::debug!(
        target: "vtcode.turn.metrics",
        metric = "tool_dispatch_plan",
        total_calls = valid_calls,
        batch_candidate,
        parallel_safe_calls,
        planning_ms = planning_started.elapsed().as_millis(),
        "turn metric"
    );

    if batch_candidate {
        let outcome = crate::agent::runloop::unified::turn::tool_outcomes::handlers::handle_tool_call_batch_prepared(t_ctx, tool_calls).await?;
        if let Some(o) = outcome {
            return Ok(Some(o));
        }
    } else {
        for tool_call in tool_calls {
            if let Some(err) = tool_call.args_error() {
                push_invalid_tool_args_response(
                    t_ctx.ctx.working_history,
                    tool_call.call_id(),
                    tool_call.tool_name(),
                    err,
                );
                continue;
            }

            let outcome = handle_prepared_tool_call_dispatch(t_ctx, tool_call).await?;
            if let Some(o) = outcome {
                return Ok(Some(o));
            }
        }
    }

    Ok(None)
}