use std::sync::Arc;
use async_trait::async_trait;
use serde_json::Value;
use crate::core::{DynTool, ToolContext};
use crate::error::Result;
use crate::genai_types::{FunctionDeclaration, Schema};
type Handler = Arc<
dyn Fn(Value, &mut ToolContext) -> futures::future::BoxFuture<'static, Result<Value>>
+ Send
+ Sync
+ 'static,
>;
pub struct LongRunningFunctionTool {
name: String,
description: String,
schema: Option<Schema>,
handler: Handler,
}
impl std::fmt::Debug for LongRunningFunctionTool {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LongRunningFunctionTool")
.field("name", &self.name)
.field("description", &self.description)
.finish_non_exhaustive()
}
}
impl LongRunningFunctionTool {
pub fn new<F, Fut>(
name: impl Into<String>,
description: impl Into<String>,
schema: Option<Schema>,
handler: F,
) -> Arc<Self>
where
F: Fn(Value, &mut ToolContext) -> Fut + Send + Sync + 'static,
Fut: std::future::Future<Output = Result<Value>> + Send + 'static,
{
let handler: Handler = Arc::new(move |args, ctx| Box::pin(handler(args, ctx)));
Arc::new(Self {
name: name.into(),
description: description.into(),
schema,
handler,
})
}
}
#[async_trait]
impl DynTool for LongRunningFunctionTool {
fn name(&self) -> &str {
&self.name
}
fn description(&self) -> &str {
&self.description
}
fn is_long_running(&self) -> bool {
true
}
fn declaration(&self) -> Option<FunctionDeclaration> {
Some({
let d = FunctionDeclaration::new(&self.name, &self.description);
match &self.schema {
Some(s) => d.with_parameters(s.clone()),
None => d,
}
})
}
async fn run(&self, args: Value, ctx: &mut ToolContext) -> Result<Value> {
ctx.long_running = true;
(self.handler)(args, ctx).await
}
}