1use crate::config::GraphConfig;
2use crate::error::Result;
3use crate::state::AgentState;
4use async_trait::async_trait;
5use std::future::Future;
6use std::pin::Pin;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
10pub enum RouterOutput {
11 Next(Option<String>),
13 FanOut(Vec<String>),
15}
16
17impl From<Option<String>> for RouterOutput {
18 fn from(opt: Option<String>) -> Self {
19 RouterOutput::Next(opt)
20 }
21}
22
23impl From<String> for RouterOutput {
24 fn from(s: String) -> Self {
25 RouterOutput::Next(Some(s))
26 }
27}
28
29impl From<Vec<String>> for RouterOutput {
30 fn from(v: Vec<String>) -> Self {
31 RouterOutput::FanOut(v)
32 }
33}
34
35#[async_trait]
37pub trait RoutingFunction: Send + Sync {
38 async fn route(&self, state: &AgentState, config: &GraphConfig) -> Result<RouterOutput>;
41
42 fn semantic_digest(&self) -> String {
45 std::any::type_name::<Self>().to_string()
46 }
47}
48
49pub struct FnRouter<F>
51where
52 F: Fn(&AgentState, &GraphConfig) -> Pin<Box<dyn Future<Output = Result<RouterOutput>> + Send>>
53 + Send
54 + Sync,
55{
56 func: F,
57}
58
59impl<F> FnRouter<F>
60where
61 F: Fn(&AgentState, &GraphConfig) -> Pin<Box<dyn Future<Output = Result<RouterOutput>> + Send>>
62 + Send
63 + Sync,
64{
65 pub fn new(func: F) -> Self {
66 Self { func }
67 }
68}
69
70#[async_trait]
71impl<F> RoutingFunction for FnRouter<F>
72where
73 F: Fn(&AgentState, &GraphConfig) -> Pin<Box<dyn Future<Output = Result<RouterOutput>> + Send>>
74 + Send
75 + Sync,
76{
77 async fn route(&self, state: &AgentState, config: &GraphConfig) -> Result<RouterOutput> {
78 (self.func)(state, config).await
79 }
80}
81
82#[macro_export]
100macro_rules! router {
101 (|$state:ident| async move $body:block) => {
103 Box::new($crate::router::FnRouter::new(
104 |__state: &$crate::state::AgentState, __config: &$crate::config::GraphConfig| {
105 let $state = __state.clone();
106 let _ = __config;
107 Box::pin(async move {
108 let __result = (|| async move { $body })().await;
109 __result.map(::std::convert::Into::into)
110 })
111 },
112 ))
113 };
114 (|$state:ident, $config:ident| async move $body:block) => {
116 Box::new($crate::router::FnRouter::new(
117 |__state: &$crate::state::AgentState, __config: &$crate::config::GraphConfig| {
118 let $state = __state.clone();
119 let $config = __config.clone();
120 Box::pin(async move {
121 let __result = (|| async move { $body })().await;
122 __result.map(::std::convert::Into::into)
123 })
124 },
125 ))
126 };
127}