use crate::core::Result;
use crate::ollama::OllamaClient;
use serde::{Deserialize, Serialize};
pub struct QueryPlanner {
client: OllamaClient,
}
#[derive(Debug, Serialize, Deserialize)]
struct DecompositionResponse {
sub_queries: Vec<String>,
}
impl QueryPlanner {
pub fn new(client: OllamaClient) -> Self {
Self { client }
}
pub async fn decompose(&self, query: &str) -> Result<Vec<String>> {
let prompt = format!(
"You are an expert query planner for a RAG system. \
Your task is to decompose the following complex user query into a list of simple, independent sub-queries \
that can be answered using vector search. \
\
Return ONLY a raw JSON object with a single key 'sub_queries' containing the list of strings. \
Do not include any explanation, markdown formatting, or preamble. \
\
Query: '{}' \
\
JSON Response:",
query
);
let response_text = self.client.generate(&prompt).await?;
let cleaned_json = response_text
.trim()
.trim_start_matches("```json")
.trim_start_matches("```")
.trim_end_matches("```")
.trim();
let response: DecompositionResponse = serde_json::from_str(cleaned_json).map_err(|e| {
crate::core::GraphRAGError::Generation {
message: format!(
"Failed to parse planner response: {}. Text: {}",
e, cleaned_json
),
}
})?;
Ok(response.sub_queries)
}
}