Skip to main content

stakpak_shared/models/
overrides.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4#[serde(untagged)]
5pub enum AutoApproveOverride {
6    /// "all" | "none"
7    Mode(String),
8    /// Explicit allowlist for auto-approval.
9    AllowList(Vec<String>),
10}
11
12/// Per-request run overrides merged with runtime defaults.
13#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
14pub struct RunOverrides {
15    #[serde(default, skip_serializing_if = "Option::is_none")]
16    pub model: Option<String>,
17    #[serde(default, skip_serializing_if = "Option::is_none")]
18    pub auto_approve: Option<AutoApproveOverride>,
19    #[serde(default, skip_serializing_if = "Option::is_none")]
20    pub system_prompt: Option<String>,
21    #[serde(default, skip_serializing_if = "Option::is_none")]
22    pub max_turns: Option<usize>,
23}
24
25impl RunOverrides {
26    pub fn is_empty(&self) -> bool {
27        self.model.is_none()
28            && self.auto_approve.is_none()
29            && self.system_prompt.is_none()
30            && self.max_turns.is_none()
31    }
32}
33
34#[cfg(test)]
35mod tests {
36    use super::{AutoApproveOverride, RunOverrides};
37
38    #[test]
39    fn run_overrides_is_empty_only_when_all_fields_absent() {
40        let empty = RunOverrides::default();
41        assert!(empty.is_empty());
42
43        let with_model = RunOverrides {
44            model: Some("openai/gpt-4o-mini".to_string()),
45            ..RunOverrides::default()
46        };
47        assert!(!with_model.is_empty());
48
49        let with_allowlist = RunOverrides {
50            auto_approve: Some(AutoApproveOverride::AllowList(vec!["view".to_string()])),
51            ..RunOverrides::default()
52        };
53        assert!(!with_allowlist.is_empty());
54    }
55
56    #[test]
57    fn run_overrides_serde_round_trip() {
58        let overrides = RunOverrides {
59            model: Some("anthropic/claude-sonnet-4-5".to_string()),
60            auto_approve: Some(AutoApproveOverride::AllowList(vec![
61                "view".to_string(),
62                "search_docs".to_string(),
63            ])),
64            system_prompt: Some("hello".to_string()),
65            max_turns: Some(24),
66        };
67
68        let encoded = serde_json::to_string(&overrides).expect("serialize overrides");
69        let decoded: RunOverrides = serde_json::from_str(&encoded).expect("deserialize overrides");
70        assert_eq!(decoded, overrides);
71    }
72}