Skip to main content

enact_core/policy/
long_running.rs

1//! Long-running execution policy
2//!
3//! Defines policies for executions that can run for extended periods,
4//! including checkpointing, memory management, and cost controls.
5
6use serde::{Deserialize, Serialize};
7
8/// Policy configuration for long-running agentic executions
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct LongRunningExecutionPolicy {
11    /// Maximum number of dynamically discovered steps before intervention
12    pub max_discovered_steps: Option<u32>,
13    /// Maximum depth of discovery chains
14    pub max_discovery_depth: Option<u32>,
15    /// Alert threshold for cumulative cost in USD
16    pub cost_alert_threshold_usd: Option<f64>,
17    /// Maximum time without activity before idle timeout (seconds)
18    pub idle_timeout_seconds: Option<u64>,
19    /// Maximum repetitions of same methodology before loop detection
20    pub max_same_step_repetitions: Option<u32>,
21    /// Checkpointing strategy
22    pub checkpointing: CheckpointPolicy,
23    /// Memory management strategy
24    pub memory: WorkingMemoryPolicy,
25}
26
27impl Default for LongRunningExecutionPolicy {
28    fn default() -> Self {
29        Self::standard()
30    }
31}
32
33impl LongRunningExecutionPolicy {
34    /// Standard preset
35    pub fn standard() -> Self {
36        Self {
37            max_discovered_steps: Some(50),
38            max_discovery_depth: Some(5),
39            cost_alert_threshold_usd: Some(5.0),
40            idle_timeout_seconds: Some(1800),
41            max_same_step_repetitions: Some(3),
42            checkpointing: CheckpointPolicy::default(),
43            memory: WorkingMemoryPolicy::default(),
44        }
45    }
46
47    /// Extended preset
48    pub fn extended() -> Self {
49        Self {
50            max_discovered_steps: Some(300),
51            max_discovery_depth: Some(10),
52            cost_alert_threshold_usd: Some(50.0),
53            idle_timeout_seconds: Some(14400),
54            max_same_step_repetitions: Some(5),
55            checkpointing: CheckpointPolicy {
56                interval_steps: Some(10),
57                on_discovery: true,
58                ..Default::default()
59            },
60            memory: WorkingMemoryPolicy {
61                strategy: ContextStrategy::Summarize {
62                    summarize_after: 50,
63                    keep_recent: 10,
64                },
65                max_tokens: Some(100_000),
66                ..Default::default()
67            },
68        }
69    }
70}
71
72/// Policy for checkpointing execution state
73#[derive(Debug, Clone, Serialize, Deserialize)]
74pub struct CheckpointPolicy {
75    /// Checkpoint every N steps
76    pub interval_steps: Option<u32>,
77    /// Checkpoint every N seconds
78    pub interval_seconds: Option<u64>,
79    /// Checkpoint on every new step discovery
80    pub on_discovery: bool,
81    /// Maximum checkpoints to retain
82    pub max_checkpoints: Option<u32>,
83}
84
85impl Default for CheckpointPolicy {
86    fn default() -> Self {
87        Self {
88            interval_steps: Some(10),
89            interval_seconds: Some(300),
90            on_discovery: false,
91            max_checkpoints: Some(50),
92        }
93    }
94}
95
96/// Policy for working memory management
97#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct WorkingMemoryPolicy {
99    /// Strategy to use when context fills up
100    pub strategy: ContextStrategy,
101    /// Maximum tokens allowed in working memory
102    pub max_tokens: Option<u32>,
103    /// Whether to auto-compact when near limit
104    pub auto_compact: bool,
105}
106
107impl Default for WorkingMemoryPolicy {
108    fn default() -> Self {
109        Self {
110            strategy: ContextStrategy::SlidingWindow { size: 20 },
111            max_tokens: Some(32_000),
112            auto_compact: true,
113        }
114    }
115}
116
117/// Strategy for managing context window
118#[derive(Debug, Clone, Serialize, Deserialize)]
119pub enum ContextStrategy {
120    /// Keep all history (risk of overflow)
121    KeepAll,
122    /// Keep only the last N messages
123    SlidingWindow { size: u32 },
124    /// Summarize older history, keep recent raw
125    Summarize {
126        summarize_after: u32,
127        keep_recent: u32,
128    },
129    /// Move older history to episodic memory
130    Archive {
131        archive_after: u32,
132        keep_recent: u32,
133    },
134}