use crate::streaming::StreamEvent;
use async_trait::async_trait;
use std::sync::Arc;
use tokio::sync::mpsc;
#[async_trait]
pub trait Callable: Send + Sync {
fn name(&self) -> &str;
fn description(&self) -> Option<&str> {
None
}
async fn run(&self, input: &str) -> anyhow::Result<String>;
async fn run_streaming(
&self,
input: &str,
event_tx: mpsc::Sender<StreamEvent>,
) -> anyhow::Result<String> {
let _ = event_tx;
self.run(input).await
}
fn last_usage(&self) -> Option<crate::kernel::LlmTokenUsage> {
None
}
}
pub type DynCallable = Arc<dyn Callable>;
#[allow(dead_code)]
pub struct FnCallable<F>
where
F: Fn(&str) -> anyhow::Result<String> + Send + Sync,
{
name: String,
description: Option<String>,
func: F,
}
#[allow(dead_code)]
impl<F> FnCallable<F>
where
F: Fn(&str) -> anyhow::Result<String> + Send + Sync,
{
pub fn new(name: impl Into<String>, func: F) -> Self {
Self {
name: name.into(),
description: None,
func,
}
}
pub fn with_description(mut self, desc: impl Into<String>) -> Self {
self.description = Some(desc.into());
self
}
}
#[async_trait]
impl<F> Callable for FnCallable<F>
where
F: Fn(&str) -> anyhow::Result<String> + Send + Sync,
{
fn name(&self) -> &str {
&self.name
}
fn description(&self) -> Option<&str> {
self.description.as_deref()
}
async fn run(&self, input: &str) -> anyhow::Result<String> {
(self.func)(input)
}
}
#[allow(dead_code)]
pub struct AsyncFnCallable<F, Fut>
where
F: Fn(String) -> Fut + Send + Sync,
Fut: std::future::Future<Output = anyhow::Result<String>> + Send + Sync,
{
name: String,
description: Option<String>,
func: F,
_phantom: std::marker::PhantomData<fn() -> Fut>,
}
#[allow(dead_code)]
impl<F, Fut> AsyncFnCallable<F, Fut>
where
F: Fn(String) -> Fut + Send + Sync,
Fut: std::future::Future<Output = anyhow::Result<String>> + Send + Sync,
{
pub fn new(name: impl Into<String>, func: F) -> Self {
Self {
name: name.into(),
description: None,
func,
_phantom: std::marker::PhantomData,
}
}
pub fn with_description(mut self, desc: impl Into<String>) -> Self {
self.description = Some(desc.into());
self
}
}
#[async_trait]
impl<F, Fut> Callable for AsyncFnCallable<F, Fut>
where
F: Fn(String) -> Fut + Send + Sync,
Fut: std::future::Future<Output = anyhow::Result<String>> + Send + Sync,
{
fn name(&self) -> &str {
&self.name
}
fn description(&self) -> Option<&str> {
self.description.as_deref()
}
async fn run(&self, input: &str) -> anyhow::Result<String> {
(self.func)(input.to_string()).await
}
}