Skip to main content

everruns_core/
compaction_policy.rs

1//! Neutral execution seam for capability-owned context-compaction policy.
2
3use std::fmt::Debug;
4
5use serde::{Deserialize, Serialize};
6
7use crate::driver_registry::LlmMessage;
8use crate::events::TokenUsage;
9use crate::message::Message;
10
11/// Strategy selected by a configured compaction policy.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
13#[serde(rename_all = "snake_case")]
14pub enum CompactionStrategy {
15    #[default]
16    Auto,
17    Native,
18    ObservationMasking,
19    Summarization,
20}
21
22impl std::fmt::Display for CompactionStrategy {
23    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        match self {
25            Self::Auto => write!(formatter, "auto"),
26            Self::Native => write!(formatter, "native"),
27            Self::ObservationMasking => write!(formatter, "observation_masking"),
28            Self::Summarization => write!(formatter, "summarization"),
29        }
30    }
31}
32
33/// Small execution settings the reason atom needs to orchestrate a policy.
34#[derive(Debug, Clone)]
35pub struct CompactionSettings {
36    pub strategy: CompactionStrategy,
37    pub budget_percent: f32,
38    pub summarization_model: Option<String>,
39}
40
41/// Result of applying policy-owned observation masking.
42#[derive(Debug, Clone)]
43pub struct ObservationMaskingResult {
44    pub messages: Vec<LlmMessage>,
45    pub masked_count: usize,
46}
47
48/// Capability-owned context-compaction behavior consumed by the reason atom.
49///
50/// Core owns orchestration, provider calls, checkpoints, and events. The
51/// implementation bundle owns thresholds and deterministic message transforms.
52pub trait CompactionPolicy: Send + Sync + Debug {
53    fn settings(&self) -> CompactionSettings;
54    fn estimate_total_tokens(&self, messages: &[LlmMessage]) -> usize;
55    fn total_tool_result_bytes(&self, messages: &[Message]) -> usize;
56    fn should_compact_proactively(&self, messages: &[LlmMessage], context_window: usize) -> bool;
57    fn should_compact_for_cost(
58        &self,
59        estimated_input_tokens: usize,
60        raw_tool_result_bytes: usize,
61        usage: Option<&TokenUsage>,
62    ) -> bool;
63    fn apply_observation_masking(&self, messages: &[LlmMessage]) -> ObservationMaskingResult;
64    fn aggressive_trim(
65        &self,
66        messages: &[LlmMessage],
67        target_tokens: usize,
68        preserve_system: bool,
69    ) -> Vec<LlmMessage>;
70    fn summarization_prompt(&self) -> String;
71    fn format_messages_for_summarization(&self, messages: &[LlmMessage]) -> String;
72    fn compose_summary_with_recent(
73        &self,
74        system_message: Option<LlmMessage>,
75        summary_text: &str,
76        recent_messages: &[LlmMessage],
77    ) -> Vec<LlmMessage>;
78}