use super::lifecycle::{Methods, Phase, advance};
use crate::components::tool::{Call, Evaluation, Tool, prepare_call};
use crate::{Cancellation, Error, Message};
pub async fn execute<T: Tool>(
tool: &T,
call: Call,
cancellation: &Cancellation,
) -> Result<(Message, Evaluation), Error> {
let (call, message) = call_once(tool, call, cancellation).await?;
let evaluation =
super::operation::cancellable(tool.eval(&call, &message, cancellation), cancellation)
.await?;
Ok((message, evaluation))
}
pub(crate) async fn call_once<T: Tool>(
tool: &T,
call: Call,
cancellation: &Cancellation,
) -> Result<(Call, Message), Error> {
call_from(
tool,
Phase::Before,
call,
None,
|_, _, _| async { Ok(()) },
cancellation,
)
.await
}
pub(crate) async fn call_from<T, K, KF>(
tool: &T,
phase: Phase,
call: Call,
message: Option<Message>,
commit: K,
cancellation: &Cancellation,
) -> Result<(Call, Message), Error>
where
T: Tool,
K: FnMut(Phase, &Call, Option<&Message>) -> KF,
KF: std::future::Future<Output = Result<(), Error>>,
{
let (call, message) = advance(
phase,
Phase::Complete,
call,
message,
Methods {
before: |call| prepare_call(tool, call, cancellation),
call: |call: Call| async move { tool.call(&call, cancellation).await },
after: |call: Call, mut message: Message| async move {
tool.after(&call, &mut message, cancellation).await?;
Ok(message)
},
commit,
},
cancellation,
)
.await?;
Ok((call, message.expect("completed Tool call has a result")))
}