wisp/conversation/
turn.rs1use agent_client_protocol::schema::v2::{CompactionId, CompactionStatus, CompactionUpdate};
2use std::collections::HashSet;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub struct ContextUsageDisplay {
7 pub used_tokens: u32,
8 pub limit_tokens: u32,
9}
10
11impl ContextUsageDisplay {
12 pub fn used_ratio(self) -> f64 {
13 if self.limit_tokens == 0 {
14 return 0.0;
15 }
16 (f64::from(self.used_tokens) / f64::from(self.limit_tokens)).clamp(0.0, 1.0)
17 }
18}
19
20#[derive(Debug, Default)]
21pub struct TurnState {
22 active_compactions: HashSet<CompactionId>,
23 context_usage: Option<ContextUsageDisplay>,
24 spinner_tick: usize,
25}
26
27impl TurnState {
28 pub fn is_compaction_active(&self) -> bool {
29 !self.active_compactions.is_empty()
30 }
31
32 pub fn apply_compaction(&mut self, update: &CompactionUpdate) {
33 match update.status {
34 CompactionStatus::InProgress => { self.active_compactions.insert(update.compaction_id.clone()); }
35 CompactionStatus::Completed | CompactionStatus::Failed | CompactionStatus::Cancelled => {
36 self.active_compactions.remove(&update.compaction_id);
37 }
38 _ => {}
39 }
40 }
41
42 pub fn clear_compactions(&mut self) {
43 self.active_compactions.clear();
44 }
45
46 pub fn set_context_usage(&mut self, context_usage: Option<ContextUsageDisplay>) {
47 self.context_usage = context_usage;
48 }
49
50 pub fn context_usage(&self) -> Option<ContextUsageDisplay> {
51 self.context_usage
52 }
53
54 pub fn spinner_tick(&self) -> usize {
55 self.spinner_tick
56 }
57
58 pub fn advance_spinner(&mut self) {
59 self.spinner_tick = self.spinner_tick.wrapping_add(1);
60 }
61
62 pub fn reset(&mut self) {
63 let spinner_tick = self.spinner_tick;
64 *self = Self { spinner_tick, ..Self::default() };
65 }
66}