lash-core 0.1.0-alpha.37

Sans-IO turn machine and runtime kernel for the lash agent runtime.
Documentation
use std::sync::Arc;

use crate::{ToolInvocation, ToolInvocationReply};

use super::ToolContext;

#[derive(Clone)]
pub struct ToolDispatchControl<'run> {
    pub(super) context: ToolContext<'run>,
}

impl<'run> ToolDispatchControl<'run> {
    pub async fn batch(&self, calls: Vec<ToolInvocation>) -> Vec<ToolInvocationReply> {
        let Some(dispatch) = self.context.runtime_dispatch.clone() else {
            return calls
                .into_iter()
                .map(|_| {
                    ToolInvocationReply::error(serde_json::json!(
                        "tool batch dispatch is unavailable outside runtime tool execution"
                    ))
                })
                .collect();
        };
        let indexed_calls = calls.into_iter().enumerate().collect::<Vec<_>>();
        crate::tool_dispatch::schedule_tool_batch(
            indexed_calls,
            |(index, _)| *index,
            {
                let dispatch = Arc::clone(&dispatch);
                move |(_, call)| {
                    crate::tool_dispatch::resolve_tool_scheduling(&dispatch, &call.name)
                }
            },
            |(_, call)| {
                let dispatch = Arc::clone(&dispatch);
                let mut child_context = self.context.clone();
                async move {
                    child_context.tool_call_id = Some(call.id.clone());
                    child_context.prepared_payload = serde_json::Value::Null;
                    let outcome = crate::tool_dispatch::dispatch_tool_call_with_execution_context(
                        dispatch.as_ref(),
                        call.name,
                        call.args,
                        None,
                        child_context,
                    )
                    .await;
                    let mut record = outcome.record;
                    record.call_id = Some(call.id);
                    ToolInvocationReply::from_output(record.output.clone()).with_record(record)
                }
            },
        )
        .await
    }
}