use async_trait::async_trait;
use crate::models::graph::Agent;
use crate::models::tools::ToolRegistryTrait;
use regex::Regex;
#[derive(Clone)]
pub struct RouteRule {
pub pattern: String,
pub target_node: i32,
pub description: Option<String>,
}
pub struct RouterAgent {
routes: Vec<RouteRule>,
default_route: Option<i32>,
case_sensitive: bool,
name: String,
}
impl RouterAgent {
pub fn new() -> Self {
Self {
routes: Vec::new(),
default_route: None,
case_sensitive: false,
name: "Router".to_string(),
}
}
pub fn add_route(mut self, rule: RouteRule) -> Self {
self.routes.push(rule);
self
}
pub fn set_default(mut self, node_id: i32) -> Self {
self.default_route = Some(node_id);
self
}
pub fn set_case_sensitive(mut self, sensitive: bool) -> Self {
self.case_sensitive = sensitive;
self
}
pub fn with_name(mut self, name: String) -> Self {
self.name = name;
self
}
fn find_route(&self, input: &str) -> Option<i32> {
let test_input = if self.case_sensitive {
input.to_string()
} else {
input.to_lowercase()
};
for rule in &self.routes {
let pattern = if self.case_sensitive {
&rule.pattern
} else {
&rule.pattern.to_lowercase()
};
if let Ok(re) = Regex::new(pattern) {
if re.is_match(&test_input) {
return Some(rule.target_node);
}
}
}
self.default_route
}
}
impl Default for RouterAgent {
fn default() -> Self {
Self::new()
}
}
#[async_trait]
impl Agent for RouterAgent {
async fn run(
&mut self,
input: &str,
_tool_registry: &(dyn ToolRegistryTrait + Send + Sync),
) -> (String, Option<i32>) {
let route = self.find_route(input);
let response = match route {
Some(node_id) => {
format!("Routing to node {}: {}", node_id, input)
}
None => {
format!("No matching route found for: {}", input)
}
};
(response, route)
}
fn get_name(&self) -> &str {
&self.name
}
}