everruns_builtins/
native_async_tools.rs1use async_trait::async_trait;
3use everruns_core::Capability;
4use serde_json::{Value, json};
5use std::collections::BTreeMap;
6
7pub struct NativeAsyncToolsCapability;
8fn selected(config: &Value) -> Result<BTreeMap<String, Option<Value>>, String> {
9 if config.is_null() || config == &json!({}) {
10 return Ok(BTreeMap::from([("web_fetch".into(), None)]));
11 }
12 let tools = config
13 .get("tools")
14 .ok_or("native async requires a tools map")?;
15 let tools: BTreeMap<String, Option<Value>> = serde_json::from_value(tools.clone())
16 .map_err(|_| "native async tools must map names to null or a custom format")?;
17 if tools.is_empty() || tools.keys().any(|name| name.is_empty()) {
18 return Err("native async tools cannot be empty".into());
19 }
20 if tools.values().flatten().any(|format| !format.is_object()) {
21 return Err("custom tool formats must be objects".into());
22 }
23 Ok(tools)
24}
25#[async_trait]
26impl Capability for NativeAsyncToolsCapability {
27 fn id(&self) -> &str {
28 "native_async_tools"
29 }
30 fn name(&self) -> &str {
31 "Native Async Tools"
32 }
33 fn description(&self) -> &str {
34 "Run selected read-only lookups while a supported model continues reasoning. Requires durable worker storage."
35 }
36 fn category(&self) -> Option<&str> {
37 Some("Optimization")
38 }
39 fn native_async_tools(&self, config: &Value) -> Option<BTreeMap<String, Option<Value>>> {
40 selected(config).ok()
41 }
42 fn validate_config(&self, config: &Value) -> Result<(), String> {
43 selected(config).map(|_| ())
44 }
45 fn config_schema(&self) -> Option<Value> {
46 Some(
47 json!({"type":"object","properties":{"tools":{"type":"object","description":"Tool names mapped to null for functions, or a custom tool format object.","default":{"web_fetch":null},"additionalProperties":{"type":["object","null"]}}}}),
48 )
49 }
50}