use std::collections::HashMap;
use std::sync::Arc;
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)]
#[serde(rename_all = "snake_case")]
pub enum ToolExecutionClass {
Workflow,
CommandSpawnTimeout,
WeatherSpawnTimeout,
WebSearchSpawnTimeout,
HttpFetchSpawnTimeout,
BlockingSync,
}
#[derive(Debug, Clone, Copy, serde::Serialize)]
pub struct ToolDispatchMeta {
pub name: &'static str,
pub requires_workspace: bool,
pub class: ToolExecutionClass,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum HandlerId {
Workflow,
RunCommand,
TerminalSession,
GetWeather,
WebSearch,
HttpFetch,
HttpRequest,
SyncDefault,
}
macro_rules! tool_dispatch_registry {
( $( ( $name:literal, $reqws:expr, $class:ident, $handler:ident ) ),* $(,)? ) => {
static DISPATCH_METADATA: &[ToolDispatchMeta] = &[
$(
ToolDispatchMeta {
name: $name,
requires_workspace: $reqws,
class: ToolExecutionClass::$class,
},
)*
];
fn handler_dispatch_map_build() -> HashMap<&'static str, HandlerId> {
let mut m = HashMap::new();
$(
m.insert($name, HandlerId::$handler);
)*
m
}
};
}
tool_dispatch_registry! {
("workflow_execute", false, Workflow, Workflow),
("run_command", true, CommandSpawnTimeout, RunCommand),
("terminal_session", true, CommandSpawnTimeout, TerminalSession),
("get_weather", false, WeatherSpawnTimeout, GetWeather),
("web_search", false, WebSearchSpawnTimeout, WebSearch),
("http_fetch", false, HttpFetchSpawnTimeout, HttpFetch),
("http_request", false, HttpFetchSpawnTimeout, HttpRequest),
}
pub fn all_dispatch_metadata() -> &'static [ToolDispatchMeta] {
DISPATCH_METADATA
}
#[derive(Debug, Clone)]
pub struct HandlerLookupTable {
map: Arc<HashMap<&'static str, HandlerId>>,
}
impl HandlerLookupTable {
pub fn default_dispatch() -> Self {
Self {
map: Arc::new(handler_dispatch_map_build()),
}
}
pub fn id_for(&self, name: &str) -> HandlerId {
self.map
.get(name)
.copied()
.unwrap_or(HandlerId::SyncDefault)
}
}
fn meta_by_name(name: &str) -> Option<&'static ToolDispatchMeta> {
all_dispatch_metadata().iter().find(|m| m.name == name)
}
pub fn try_dispatch_meta(name: &str) -> Option<&'static ToolDispatchMeta> {
meta_by_name(name)
}
pub fn execution_class_for_tool(name: &str) -> ToolExecutionClass {
try_dispatch_meta(name)
.map(|m| m.class)
.unwrap_or(ToolExecutionClass::BlockingSync)
}