mod assembly;
mod citation;
mod evidence;
mod narration;
mod render;
mod synthesis;
#[cfg(test)]
mod test_support;
use gobby_core::config::AiRouting;
use crate::commands::search;
use crate::{CommandOutcome, ScopeSelection, WikiError};
const DEFAULT_ASK_HIT_LIMIT: usize = 10;
pub(crate) fn execute(
query: String,
selection: ScopeSelection,
llm: bool,
ai: AiRouting,
require_ai: bool,
token_budget: Option<usize>,
) -> Result<CommandOutcome, WikiError> {
if llm && ai == AiRouting::Off {
return Err(WikiError::InvalidInput {
field: "ask",
message: "--llm cannot be combined with --ai off".to_string(),
});
}
let retrieval = search::retrieve(query, selection, DEFAULT_ASK_HIT_LIMIT, true, token_budget)?;
let plan = evidence::plan_evidence(&retrieval);
let mut output = assembly::ask_output_from_retrieval(retrieval.output, &plan);
if llm {
synthesis::synthesize(&mut output, &plan, ai, require_ai)?;
}
render::render(output)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn llm_ai_off_is_invalid_input() {
let error = execute(
"Question?".to_string(),
ScopeSelection::detect(),
true,
AiRouting::Off,
false,
None,
)
.expect_err("ask --llm --ai off should fail before retrieval");
assert!(matches!(
error,
WikiError::InvalidInput { field: "ask", .. }
));
}
}