reductool/
lib.rs

1use anyhow::Result;
2use futures::future::BoxFuture;
3use linkme::distributed_slice;
4use serde_json::Value;
5
6// Re-export the proc macro so we can simply do `use reductool::aitool;`
7pub use reductool_proc_macro::aitool;
8
9// Re-export linkme under a stable path for the generated macro code
10pub use linkme as __linkme;
11
12pub type InvokeFuture = BoxFuture<'static, Result<Value>>;
13
14#[derive(Clone)]
15pub struct ToolDefinition {
16    pub name: &'static str,
17    pub description: &'static str,
18    pub json_schema: &'static str,
19    pub invoke: fn(Value) -> InvokeFuture,
20}
21
22#[distributed_slice]
23pub static ALL_TOOLS: [ToolDefinition] = [..];
24
25pub fn tools_to_schema() -> Value {
26    Value::Array(
27        ALL_TOOLS
28            .iter()
29            .map(|t| serde_json::from_str(t.json_schema).unwrap())
30            .collect(),
31    )
32}
33
34pub async fn dispatch_tool(name: &str, args: Value) -> Result<Value> {
35    (ALL_TOOLS
36        .iter()
37        .find(|t| t.name == name)
38        .ok_or_else(|| anyhow::anyhow!("Unknown tool: {name}"))?
39        .invoke)(args)
40    .await
41}