deepstrike_core/scheduler/
policy.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
4#[serde(deny_unknown_fields)]
5pub struct SchedulerPolicyConfig {
6 pub critical_path_weight: i64,
7 pub fanout_weight: i64,
8 pub age_weight: i64,
9 pub token_cost_weight: i64,
10 pub deadline_weight: i64,
13 pub process_priority_weight: i64,
14 pub resource_pressure_weight: i64,
15 pub budget_pressure_weight: i64,
16}
17
18impl Default for SchedulerPolicyConfig {
19 fn default() -> Self {
20 Self {
21 critical_path_weight: 1_000_000,
22 fanout_weight: 10_000,
23 age_weight: 1_000,
24 token_cost_weight: 1,
25 deadline_weight: 0,
26 process_priority_weight: 0,
27 resource_pressure_weight: 0,
28 budget_pressure_weight: 0,
29 }
30 }
31}
32
33impl SchedulerPolicyConfig {
34 pub fn validate(&self) -> Result<(), String> {
35 for (name, weight) in [
36 ("critical_path_weight", self.critical_path_weight),
37 ("fanout_weight", self.fanout_weight),
38 ("age_weight", self.age_weight),
39 ("token_cost_weight", self.token_cost_weight),
40 ("deadline_weight", self.deadline_weight),
41 ("process_priority_weight", self.process_priority_weight),
42 ("resource_pressure_weight", self.resource_pressure_weight),
43 ("budget_pressure_weight", self.budget_pressure_weight),
44 ] {
45 if !(0..=1_000_000_000).contains(&weight) {
46 return Err(format!(
47 "scheduler_policy {name} must be between 0 and 1000000000"
48 ));
49 }
50 }
51 Ok(())
52 }
53}
54
55#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
57pub struct SchedulerBudget {
58 pub max_tokens: u32,
60 pub max_turns: u32,
62 pub max_total_tokens: u64,
64 pub max_wall_ms: Option<u64>,
68}
69
70impl Default for SchedulerBudget {
71 fn default() -> Self {
72 Self {
73 max_tokens: 128_000,
74 max_turns: 25,
75 max_total_tokens: 1_000_000,
76 max_wall_ms: None,
77 }
78 }
79}
80
81impl SchedulerBudget {
82 pub fn should_terminate(
85 &self,
86 turns: u32,
87 total_tokens: u64,
88 now_ms: Option<u64>,
89 started_at_ms: Option<u64>,
90 ) -> Option<&'static str> {
91 if turns >= self.max_turns {
92 return Some("max_turns");
93 }
94 if total_tokens >= self.max_total_tokens {
95 return Some("token_budget");
96 }
97 if let (Some(limit), Some(now), Some(start)) = (self.max_wall_ms, now_ms, started_at_ms) {
98 if now.saturating_sub(start) >= limit {
99 return Some("wall_time");
100 }
101 }
102 None
103 }
104}