use crate::sink::UiEvent;
use crate::tui_context::TuiContext;
use crate::tui_types::TuiState;
use koda_core::engine::EngineEvent;
use koda_core::persistence::Persistence;
use ratatui::{
style::{Color, Style},
text::{Line, Span},
};
use tokio::sync::mpsc;
impl TuiContext {
pub(super) async fn post_turn_cleanup(
&mut self,
ui_rx: &mut mpsc::UnboundedReceiver<UiEvent>,
turn_cancel: &tokio_util::sync::CancellationToken,
) {
if turn_cancel.is_cancelled() && !self.later_queue.is_empty() {
let n = self.later_queue.len();
self.later_queue.clear();
self.scroll_buffer.push(Line::from(vec![
Span::raw(" "),
Span::styled(
format!("\u{1f6ab} Cleared {n} deferred message(s)"),
Style::default().fg(Color::DarkGray),
),
]));
}
self.tui_state = TuiState::Idle;
self.inference_start = None;
if let Ok(mut undo) = self.agent.tools.undo.lock() {
undo.commit_turn();
}
while let Ok(UiEvent::Engine(e)) = ui_rx.try_recv() {
if let EngineEvent::ContextUsage { used, max } = &e {
self.context_pct = if *max > 0 {
(used * 100 / max) as u32
} else {
0
};
}
if let EngineEvent::ContextWindowChanged { tokens } = &e {
self.learned_context_window = Some(*tokens);
}
if let EngineEvent::ChildAgentActivity { task_id, kind, .. } = &e {
self.child_activity.record_activity(*task_id, kind);
}
self.renderer.render_to_buffer(e, &mut self.scroll_buffer);
}
if let Some(tokens) = self.learned_context_window.take() {
self.config.max_context_tokens = tokens;
self.config.model_settings.max_context_tokens = tokens;
}
self.maybe_auto_compact().await;
}
async fn maybe_auto_compact(&mut self) {
let ctx_pct = self.context_pct as usize;
if ctx_pct < koda_core::inference_helpers::AUTO_COMPACT_THRESHOLD {
return;
}
let pending = self
.session
.db
.has_pending_tool_calls(&self.session.id)
.await
.unwrap_or(false);
if pending {
if !self.silent_compact_deferred {
self.scroll_buffer.push(
Line::from(vec![
Span::raw(" "),
Span::styled(
format!(
"\u{1f43b} Context at {ctx_pct}% \u{2014} deferring compact (tool calls pending)"
),
Style::default().fg(Color::Yellow),
),
]),
);
self.silent_compact_deferred = true;
}
return;
}
self.silent_compact_deferred = false;
self.scroll_buffer.push(Line::from(vec![
Span::raw(" "),
Span::styled(
format!("\u{1f43b} Context at {ctx_pct}% \u{2014} auto-compacting..."),
Style::default().fg(Color::Cyan),
),
]));
match koda_core::compact::compact_session(
&self.session.db,
&self.session.id,
self.config.max_context_tokens,
&self.config.model_settings,
&self.provider,
)
.await
{
Ok(Ok(result)) => {
self.scroll_buffer.push(Line::styled(
format!(
" \u{2713} Compacted {} messages \u{2192} ~{} tokens",
result.deleted, result.summary_tokens
),
Style::default().fg(Color::Green),
));
}
Ok(Err(_skip)) => {} Err(e) => {
self.scroll_buffer.push(Line::styled(
format!(" \u{2717} Auto-compact failed: {e:#}"),
Style::default().fg(Color::Red),
));
}
}
}
}