use crate::config::GraphConfig;
use crate::error::Result;
use crate::state::AgentState;
use async_trait::async_trait;
use std::future::Future;
use std::pin::Pin;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RouterOutput {
Next(Option<String>),
FanOut(Vec<String>),
}
impl From<Option<String>> for RouterOutput {
fn from(opt: Option<String>) -> Self {
RouterOutput::Next(opt)
}
}
impl From<String> for RouterOutput {
fn from(s: String) -> Self {
RouterOutput::Next(Some(s))
}
}
impl From<Vec<String>> for RouterOutput {
fn from(v: Vec<String>) -> Self {
RouterOutput::FanOut(v)
}
}
#[async_trait]
pub trait RoutingFunction: Send + Sync {
async fn route(&self, state: &AgentState, config: &GraphConfig) -> Result<RouterOutput>;
fn semantic_digest(&self) -> String {
std::any::type_name::<Self>().to_string()
}
}
pub struct FnRouter<F>
where
F: Fn(&AgentState, &GraphConfig) -> Pin<Box<dyn Future<Output = Result<RouterOutput>> + Send>>
+ Send
+ Sync,
{
func: F,
}
impl<F> FnRouter<F>
where
F: Fn(&AgentState, &GraphConfig) -> Pin<Box<dyn Future<Output = Result<RouterOutput>> + Send>>
+ Send
+ Sync,
{
pub fn new(func: F) -> Self {
Self { func }
}
}
#[async_trait]
impl<F> RoutingFunction for FnRouter<F>
where
F: Fn(&AgentState, &GraphConfig) -> Pin<Box<dyn Future<Output = Result<RouterOutput>> + Send>>
+ Send
+ Sync,
{
async fn route(&self, state: &AgentState, config: &GraphConfig) -> Result<RouterOutput> {
(self.func)(state, config).await
}
}
#[macro_export]
macro_rules! router {
(|$state:ident| async move $body:block) => {
Box::new($crate::router::FnRouter::new(
|__state: &$crate::state::AgentState, __config: &$crate::config::GraphConfig| {
let $state = __state.clone();
let _ = __config;
Box::pin(async move {
let __result = (|| async move { $body })().await;
__result.map(::std::convert::Into::into)
})
},
))
};
(|$state:ident, $config:ident| async move $body:block) => {
Box::new($crate::router::FnRouter::new(
|__state: &$crate::state::AgentState, __config: &$crate::config::GraphConfig| {
let $state = __state.clone();
let $config = __config.clone();
Box::pin(async move {
let __result = (|| async move { $body })().await;
__result.map(::std::convert::Into::into)
})
},
))
};
}