Skip to main content

codetether_agent/search/
dispatch.rs

1//! Dispatch a [`BackendChoice`] to the underlying tool implementation and
2//! return its [`ToolResult`]. Each backend is invoked inline so the router
3//! does not require access to the full `ToolRegistry`.
4
5use anyhow::Result;
6use serde_json::{Value, json};
7
8use crate::tool::{Tool, ToolResult, file, memory, search, webfetch, websearch};
9
10use super::types::{Backend, BackendChoice};
11
12/// Execute one backend choice and return its raw [`ToolResult`].
13///
14/// The `query` is forwarded when the router omits an explicit
15/// `pattern`/`query` arg in `choice.args`.
16pub async fn run_choice(choice: &BackendChoice, query: &str) -> Result<ToolResult> {
17    let args = enrich_args(choice, query);
18    match choice.backend {
19        Backend::Grep => search::GrepTool::new().execute(args).await,
20        Backend::Glob => file::GlobTool::new().execute(args).await,
21        Backend::Websearch => websearch::WebSearchTool::new().execute(args).await,
22        Backend::Webfetch => webfetch::WebFetchTool::new().execute(args).await,
23        Backend::Memory => memory::MemoryTool::new().execute(args).await,
24        Backend::Rlm => Ok(ToolResult::error(
25            "rlm backend requires a provider; wire RlmTool before requesting semantic search",
26        )),
27    }
28}
29
30fn enrich_args(choice: &BackendChoice, query: &str) -> Value {
31    let mut args = choice.args.clone();
32    if !args.is_object() {
33        args = Value::Object(Default::default());
34    }
35    let obj = args.as_object_mut().expect("args normalized above");
36    match choice.backend {
37        Backend::Grep if obj.get("pattern").is_none() => {
38            obj.insert("pattern".into(), json!(query));
39        }
40        Backend::Glob if obj.get("pattern").is_none() => {
41            obj.insert("pattern".into(), json!(query));
42        }
43        Backend::Websearch if obj.get("query").is_none() => {
44            obj.insert("query".into(), json!(query));
45        }
46        Backend::Memory if obj.get("query").is_none() => {
47            obj.insert("action".into(), json!("search"));
48            obj.insert("query".into(), json!(query));
49        }
50        _ => {}
51    }
52    args
53}