Split tui/mod.rs up into multiple files. (#3)
The mod.rs file was too large, split it up. Reviewed-on: #3 Co-authored-by: Drew Galbraith <drew@tiramisu.one> Co-committed-by: Drew Galbraith <drew@tiramisu.one>
This commit is contained in:
parent
3fd448d431
commit
6b85ff3cb8
4 changed files with 983 additions and 954 deletions
72
src/tui/events.rs
Normal file
72
src/tui/events.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
//! Server event draining: applies incoming [`UIEvent`]s to the TUI state.
|
||||
|
||||
use tokio::sync::mpsc;
|
||||
use tracing::debug;
|
||||
|
||||
use super::AppState;
|
||||
use crate::core::types::{Role, UIEvent};
|
||||
|
||||
/// Drain all pending [`UIEvent`]s from `event_rx` and apply them to `state`.
|
||||
///
|
||||
/// This is non-blocking: it processes all currently-available events and returns
|
||||
/// immediately when the channel is empty.
|
||||
///
|
||||
/// | Event | Effect |
|
||||
/// |--------------------|------------------------------------------------------------|
|
||||
/// | `StreamDelta(s)` | Append `s` to last message if it's `Assistant`; else push new |
|
||||
/// | `TurnComplete` | No structural change; logged at debug level |
|
||||
/// | `Error(msg)` | Push `(Assistant, "[error] {msg}")` |
|
||||
pub(super) fn drain_ui_events(event_rx: &mut mpsc::Receiver<UIEvent>, state: &mut AppState) {
|
||||
while let Ok(event) = event_rx.try_recv() {
|
||||
match event {
|
||||
UIEvent::StreamDelta(chunk) => {
|
||||
if let Some((Role::Assistant, content)) = state.messages.last_mut() {
|
||||
content.push_str(&chunk);
|
||||
} else {
|
||||
state.messages.push((Role::Assistant, chunk));
|
||||
}
|
||||
}
|
||||
UIEvent::TurnComplete => {
|
||||
debug!("turn complete");
|
||||
}
|
||||
UIEvent::Error(msg) => {
|
||||
state
|
||||
.messages
|
||||
.push((Role::Assistant, format!("[error] {msg}")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn drain_appends_to_existing_assistant() {
|
||||
let (tx, mut rx) = tokio::sync::mpsc::channel(8);
|
||||
let mut state = AppState::new();
|
||||
state.messages.push((Role::Assistant, "hello".to_string()));
|
||||
tx.send(UIEvent::StreamDelta(" world".to_string()))
|
||||
.await
|
||||
.unwrap();
|
||||
drop(tx);
|
||||
drain_ui_events(&mut rx, &mut state);
|
||||
assert_eq!(state.messages.last().unwrap().1, "hello world");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn drain_creates_assistant_on_user_last() {
|
||||
let (tx, mut rx) = tokio::sync::mpsc::channel(8);
|
||||
let mut state = AppState::new();
|
||||
state.messages.push((Role::User, "hi".to_string()));
|
||||
tx.send(UIEvent::StreamDelta("hello".to_string()))
|
||||
.await
|
||||
.unwrap();
|
||||
drop(tx);
|
||||
drain_ui_events(&mut rx, &mut state);
|
||||
assert_eq!(state.messages.len(), 2);
|
||||
assert_eq!(state.messages[1].0, Role::Assistant);
|
||||
assert_eq!(state.messages[1].1, "hello");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue