Skip to main content

deepstrike_core/context/
summarizer.rs

1use crate::context::pressure::PressureAction;
2use crate::types::message::{Message, Role};
3
4/// Deterministic rule-based summariser — no LLM required. The compression
5/// pipeline is its only consumer; richer (LLM) summaries are an SDK concern.
6pub struct RuleSummarizer;
7
8impl RuleSummarizer {
9    /// Produce a summary of `messages` (the `max_tokens` budget is currently advisory).
10    pub fn summarize(&self, messages: &[Message], action: PressureAction, _max_tokens: u32) -> String {
11        let n = messages.len();
12        let tokens: u32 = messages.iter().map(|m| m.token_count.unwrap_or(0)).sum();
13        let mut tool_names: Vec<String> = messages
14            .iter()
15            .flat_map(|m| m.tool_calls.iter().map(|tc| tc.name.to_string()))
16            .collect();
17        tool_names.sort();
18        tool_names.dedup();
19
20        let last_assistant = messages
21            .iter()
22            .rev()
23            .find(|m| m.role == Role::Assistant)
24            .and_then(|m| m.content.as_text())
25            .map(|t| {
26                if t.len() > 200 {
27                    format!("{}...", &t[..200])
28                } else {
29                    t.to_string()
30                }
31            })
32            .unwrap_or_default();
33
34        let action_str = action.label();
35
36        let mut s =
37            format!("[Compressed: {action_str}]\n{n} messages / {tokens} tokens archived\n");
38        if !tool_names.is_empty() {
39            s.push_str(&format!("tools used: {}\n", tool_names.join(", ")));
40        }
41        if !last_assistant.is_empty() {
42            s.push_str(&format!("last assistant output: {last_assistant}"));
43        }
44        s
45    }
46}