- Remove redundant token fields from StreamEvent::Finished (data already delivered via Usage event) - Remove dead hotkey_adjust_sampling, MAX_HISTORY, now() - Fix unused variable warnings (delta, log) - Suppress deserialization-only field warnings (jsonrpc, role) - Make start_stream/chat_completion_stream_temp pub(crate) - Remove unnecessary pub(crate) re-export of internal types Remaining warnings are TODO items: SkipIndex (scoring not wired), notify (MCP notifications not wired). Co-Authored-By: Proof of Concept <poc@bcachefs.org>
135 lines
5.1 KiB
Rust
135 lines
5.1 KiB
Rust
// thalamus_screen.rs — F5: presence, idle state, and channel status
|
|
|
|
use ratatui::{
|
|
layout::Rect,
|
|
style::{Color, Style},
|
|
text::{Line, Span},
|
|
widgets::{Block, Borders, Paragraph, Wrap},
|
|
Frame,
|
|
crossterm::event::KeyCode,
|
|
};
|
|
|
|
use super::{App, ScreenView, screen_legend};
|
|
|
|
pub(crate) struct ThalamusScreen {
|
|
sampling_selected: usize,
|
|
scroll: u16,
|
|
}
|
|
|
|
impl ThalamusScreen {
|
|
pub fn new() -> Self {
|
|
Self { sampling_selected: 0, scroll: 0 }
|
|
}
|
|
}
|
|
|
|
impl ScreenView for ThalamusScreen {
|
|
fn label(&self) -> &'static str { "thalamus" }
|
|
|
|
fn tick(&mut self, frame: &mut Frame, area: Rect,
|
|
events: &[ratatui::crossterm::event::Event], app: &mut App) {
|
|
// Handle keys
|
|
for event in events {
|
|
if let ratatui::crossterm::event::Event::Key(key) = event {
|
|
if key.kind != ratatui::crossterm::event::KeyEventKind::Press { continue; }
|
|
match key.code {
|
|
KeyCode::Up => { self.sampling_selected = self.sampling_selected.saturating_sub(1); }
|
|
KeyCode::Down => { self.sampling_selected = (self.sampling_selected + 1).min(2); }
|
|
KeyCode::Right => {
|
|
let _delta = match self.sampling_selected {
|
|
0 => 0.05, 1 => 0.05, 2 => 5.0, _ => 0.0,
|
|
};
|
|
}
|
|
KeyCode::Left => {
|
|
let _delta = match self.sampling_selected {
|
|
0 => -0.05, 1 => -0.05, 2 => -5.0, _ => 0.0,
|
|
};
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Draw
|
|
let section = Style::default().fg(Color::Yellow);
|
|
let dim = Style::default().fg(Color::DarkGray);
|
|
let mut lines: Vec<Line> = Vec::new();
|
|
|
|
// Presence / idle state
|
|
lines.push(Line::styled("── Presence ──", section));
|
|
lines.push(Line::raw(""));
|
|
|
|
if let Some(ref idle) = app.idle_info {
|
|
let presence = if idle.user_present {
|
|
Span::styled("present", Style::default().fg(Color::Green))
|
|
} else {
|
|
Span::styled("away", Style::default().fg(Color::DarkGray))
|
|
};
|
|
lines.push(Line::from(vec![
|
|
Span::raw(" User: "), presence,
|
|
Span::raw(format!(" (last {:.0}s ago)", idle.since_activity)),
|
|
]));
|
|
lines.push(Line::raw(format!(" Activity: {:.1}%", idle.activity_ewma * 100.0)));
|
|
lines.push(Line::raw(format!(" Idle state: {}", idle.block_reason)));
|
|
if idle.dreaming {
|
|
lines.push(Line::styled(" ◆ dreaming", Style::default().fg(Color::Magenta)));
|
|
}
|
|
if idle.sleeping {
|
|
lines.push(Line::styled(" ◆ sleeping", Style::default().fg(Color::Blue)));
|
|
}
|
|
} else {
|
|
lines.push(Line::styled(" not initialized", dim));
|
|
}
|
|
lines.push(Line::raw(""));
|
|
|
|
// Sampling parameters
|
|
lines.push(Line::styled("── Sampling (←/→ adjust) ──", section));
|
|
lines.push(Line::raw(""));
|
|
let params = [
|
|
format!("temperature: {:.2}", app.temperature),
|
|
format!("top_p: {:.2}", app.top_p),
|
|
format!("top_k: {}", app.top_k),
|
|
];
|
|
for (i, label) in params.iter().enumerate() {
|
|
let prefix = if i == self.sampling_selected { "▸ " } else { " " };
|
|
let style = if i == self.sampling_selected {
|
|
Style::default().fg(Color::Cyan)
|
|
} else {
|
|
Style::default()
|
|
};
|
|
lines.push(Line::styled(format!("{}{}", prefix, label), style));
|
|
}
|
|
lines.push(Line::raw(""));
|
|
|
|
// Channel status
|
|
lines.push(Line::styled("── Channels ──", section));
|
|
lines.push(Line::raw(""));
|
|
if app.channel_status.is_empty() {
|
|
lines.push(Line::styled(" no channels configured", dim));
|
|
} else {
|
|
for ch in &app.channel_status {
|
|
let (symbol, color) = if ch.connected { ("●", Color::Green) } else { ("○", Color::Red) };
|
|
let unread_str = if ch.unread > 0 { format!(" ({} unread)", ch.unread) } else { String::new() };
|
|
lines.push(Line::from(vec![
|
|
Span::raw(" "),
|
|
Span::styled(symbol, Style::default().fg(color)),
|
|
Span::raw(format!(" {:<24}", ch.name)),
|
|
Span::styled(if ch.connected { "connected" } else { "disconnected" }, Style::default().fg(color)),
|
|
Span::styled(unread_str, Style::default().fg(Color::Yellow)),
|
|
]));
|
|
}
|
|
}
|
|
|
|
let block = Block::default()
|
|
.title_top(Line::from(screen_legend()).left_aligned())
|
|
.title_top(Line::from(" thalamus ").right_aligned())
|
|
.borders(Borders::ALL)
|
|
.border_style(Style::default().fg(Color::Cyan));
|
|
|
|
let para = Paragraph::new(lines)
|
|
.block(block)
|
|
.wrap(Wrap { trim: false })
|
|
.scroll((self.scroll, 0));
|
|
|
|
frame.render_widget(para, area);
|
|
}
|
|
}
|