diff --git a/crates/kebab-app/src/lib.rs b/crates/kebab-app/src/lib.rs index 602fdaf..960442b 100644 --- a/crates/kebab-app/src/lib.rs +++ b/crates/kebab-app/src/lib.rs @@ -85,7 +85,7 @@ pub const NO_EXT_SENTINEL: &str = ""; /// `use kebab_app::AskOpts` keeps working without churn. The struct gained /// a `stream_sink` field in P4-3; non-streaming callers (kb-cli today) /// pass `stream_sink: None`. -pub use kebab_rag::AskOpts; +pub use kebab_rag::{AskOpts, StreamEvent}; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct DoctorReport { diff --git a/crates/kebab-tui/src/app.rs b/crates/kebab-tui/src/app.rs index 44ed73c..1d53d0c 100644 --- a/crates/kebab-tui/src/app.rs +++ b/crates/kebab-tui/src/app.rs @@ -186,9 +186,12 @@ impl Default for SearchState { /// Ask pane state — owned by p9-3, extended by p9-fb-16 for /// multi-turn conversation transcript. /// -/// The worker thread (`thread`) owns the `mpsc::Sender` that -/// `kebab-app::ask` writes tokens into. The pane keeps the matching -/// `rx` and drains it once per render frame (no blocking). +/// The worker thread (`thread`) owns the `mpsc::Sender` +/// that `kebab-app::ask` writes events into. The pane keeps the matching +/// `rx` and drains it once per render frame (no blocking). Only the +/// `Token { delta }` variant is consumed for the streaming transcript; +/// `RetrievalDone` and `Final` are ignored (citations render from +/// `last_answer` after the worker join). /// /// p9-fb-16: completed `Turn`s accumulate in `turns`; the worker /// passes a snapshot of `turns` as `history` to @@ -214,7 +217,7 @@ pub struct AskState { pub thread: Option>>, /// Token receiver paired with the worker's `Sender`. Drained /// every render frame. - pub rx: Option>, + pub rx: Option>, /// Vertical scroll offset for the transcript area when content /// exceeds the viewport. Only consulted when `follow_tail` is /// false; otherwise the renderer overrides this with the diff --git a/crates/kebab-tui/src/ask.rs b/crates/kebab-tui/src/ask.rs index dd20917..854a325 100644 --- a/crates/kebab-tui/src/ask.rs +++ b/crates/kebab-tui/src/ask.rs @@ -483,7 +483,7 @@ pub fn handle_key_ask(state: &mut App, key: KeyEvent) -> KeyOutcome { } fn spawn_ask_worker(state: &mut App) { - let (tx, rx) = mpsc::channel::(); + let (tx, rx) = mpsc::channel::(); let cfg = state.config.clone(); let s = state.ask.as_mut().unwrap(); // p9-fb-10: take() consumes the input in one step (no clone + @@ -542,8 +542,18 @@ fn make_conversation_id() -> String { pub(crate) fn drain_stream(state: &mut App) { let Some(s) = state.ask.as_mut() else { return }; if let Some(rx) = &s.rx { - for tok in rx.try_iter() { - s.partial.push_str(&tok); + for ev in rx.try_iter() { + match ev { + kebab_app::StreamEvent::Token { delta, .. } => { + s.partial.push_str(&delta); + } + // p9-fb-33: TUI ignores RetrievalDone (citation + // panel renders after completion via `last_answer`) + // and Final (the worker thread's join already + // delivers the canonical Answer in poll_worker). + kebab_app::StreamEvent::RetrievalDone { .. } + | kebab_app::StreamEvent::Final { .. } => {} + } } } }