Skip to main content

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}