a3s-code-core 5.3.2

A3S Code Core - Embeddable AI agent library with tool execution
Documentation
use super::execution_state::ExecutionLoopState;
use super::tool_completion_runtime::ToolCompletionInput;
use super::{AgentEvent, AgentLoop};
use crate::llm::ToolCall;
use crate::tools::ToolInvocation;
use tokio::sync::mpsc;
use tokio_util::sync::CancellationToken;

impl AgentLoop {
    pub(super) async fn execute_tool_turn(
        &self,
        tool_calls: Vec<ToolCall>,
        state: &mut ExecutionLoopState,
        event_tx: &Option<mpsc::Sender<AgentEvent>>,
        session_id: Option<&str>,
        effective_prompt: &str,
        cancel_token: &CancellationToken,
    ) -> anyhow::Result<()> {
        if self.can_run_parallel_write_batch(&tool_calls) {
            self.execute_parallel_write_batch(
                &tool_calls,
                state,
                event_tx,
                session_id,
                cancel_token,
            )
            .await;
            return Ok(());
        }

        for tool_call in tool_calls {
            self.execute_sequential_tool_call(
                tool_call,
                state,
                event_tx,
                session_id,
                effective_prompt,
                cancel_token,
            )
            .await?;
        }

        Ok(())
    }

    async fn execute_sequential_tool_call(
        &self,
        tool_call: ToolCall,
        state: &mut ExecutionLoopState,
        event_tx: &Option<mpsc::Sender<AgentEvent>>,
        session_id: Option<&str>,
        effective_prompt: &str,
        cancel_token: &CancellationToken,
    ) -> anyhow::Result<()> {
        state.record_tool_call();
        let tool_start = std::time::Instant::now();
        let turn = state.current_turn();
        self.config.rl_trajectory_recorder.record_tool_call(
            session_id.unwrap_or(""),
            turn,
            &tool_call,
        );

        tracing::info!(
            tool_name = tool_call.name.as_str(),
            tool_id = tool_call.id.as_str(),
            "Tool execution started"
        );

        if self
            .handle_tool_preflight_guard(&tool_call, state, event_tx, session_id)
            .await?
        {
            return Ok(());
        }

        let normalized = self
            .invoke_model_tool(
                ToolInvocation::agent(
                    tool_call.id.clone(),
                    tool_call.name.clone(),
                    tool_call.args.clone(),
                    state.recent_tool_signatures(),
                ),
                session_id,
                event_tx,
                cancel_token,
            )
            .await;

        self.complete_tool_call(
            state,
            ToolCompletionInput {
                tool_call: &tool_call,
                event_tx,
                session_id,
                effective_prompt,
                tool_start,
                normalized,
            },
        )
        .await;
        Ok(())
    }
}