use std::sync::Arc;
use serde::Deserialize;
use crate::common::Result;
use crate::rag::RagManager;
#[derive(Debug, Deserialize)]
pub struct RagSearchInput {
pub query: String,
#[serde(default)]
pub project: Option<String>,
#[serde(default = "default_max_results")]
pub max_results: usize,
}
fn default_max_results() -> usize {
5
}
pub fn definition() -> serde_json::Value {
serde_json::json!({
"type": "function",
"function": {
"name": "rag_search",
"description": "Search project documentation via RAG (Retrieval-Augmented Generation). Returns relevant document chunks from configured knowledge sources (Alcove docs, HTTP bridge). Use when you need external documentation, design specs, or project context beyond the codebase.",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Natural language search query"
},
"project": {
"type": "string",
"description": "Project name to scope the search (optional, defaults to current project)"
},
"max_results": {
"type": "integer",
"description": "Maximum number of results to return (default: 5)"
}
},
"required": ["query"]
}
}
})
}
pub async fn execute(
input: RagSearchInput,
rag_manager: &Arc<RagManager>,
working_dir: &str,
shared_knowledge: Option<&crate::agent::swarm::knowledge::SharedKnowledge>,
) -> Result<String> {
let chunks = rag_manager
.retrieve(
&input.query,
input.project.as_deref().or(Some(working_dir)),
input.max_results,
)
.await;
if chunks.is_empty() {
return Ok("No relevant documents found.".to_string());
}
let mut output = String::new();
for chunk in &chunks {
let entry = format!(
"## [{}] {} (score: {:.2})\n{}\n\n",
chunk.adapter, chunk.source, chunk.score, chunk.content,
);
output.push_str(&entry);
if let Some(kb) = shared_knowledge {
let topic = format!("rag:{}", chunk.source);
kb.post_fact("rag", &topic, &chunk.content).await;
}
}
Ok(output)
}