codetether_agent/tui/app/ask/mod.rs
1//! `/ask` — ephemeral side question handler.
2//!
3//! Runs a single, tool-less completion against the session's current
4//! provider using the full conversation as context, renders the answer
5//! as an in-chat system message, and **never mutates session history**.
6//! Mirrors Claude Code's `/btw`: full context, no tools, single reply,
7//! ephemeral. Works across every provider in the registry.
8
9mod build;
10mod execute;
11mod extract;
12
13use std::sync::Arc;
14
15use crate::provider::ProviderRegistry;
16use crate::session::Session;
17use crate::tui::app::state::App;
18
19/// Run the `/ask` side question and render the answer inline.
20///
21/// # Arguments
22///
23/// * `app` — TUI state; receives the answer + status updates.
24/// * `session` — current conversation; **read-only**, never mutated.
25/// * `registry` — provider registry. [`None`] ⇒ status-only error.
26/// * `question` — trimmed text after `/ask`. Empty ⇒ usage hint.
27///
28/// # Errors
29///
30/// Provider errors are surfaced via `app.state.status`; this function
31/// does not return a `Result`.
32pub(super) async fn run_ask(
33 app: &mut App,
34 session: &Session,
35 registry: Option<&Arc<ProviderRegistry>>,
36 question: &str,
37) {
38 if question.is_empty() {
39 app.state.status =
40 "Usage: /ask <question> — ephemeral, full context, no tools, not saved.".to_string();
41 return;
42 }
43 let Some(registry) = registry else {
44 app.state.status = "/ask: no provider configured".to_string();
45 return;
46 };
47 let Some((provider, request)) = build::build_request(session, registry, question) else {
48 app.state.status = "/ask: cannot resolve provider".to_string();
49 return;
50 };
51 execute::run(app, provider, request).await;
52}