Skip to main content

ag_agent/model/
permission.rs

1use std::fmt;
2use std::str::FromStr;
3
4/// Supported permission mode values for agent execution workflows.
5#[derive(Clone, Copy, PartialEq, Eq, Debug, Default, Hash)]
6pub enum PermissionMode {
7    /// Allows the agent to edit files automatically within its sandbox.
8    #[default]
9    AutoEdit,
10    /// Restricts the agent to repository inspection without filesystem writes
11    /// or mutating command approvals.
12    ReadOnly,
13}
14
15impl PermissionMode {
16    /// Returns the wire label used for persistence and display.
17    pub fn label(self) -> &'static str {
18        match self {
19            Self::AutoEdit => "auto_edit",
20            Self::ReadOnly => "read_only",
21        }
22    }
23
24    /// Returns the user-facing label shown in the UI.
25    pub fn display_label(self) -> &'static str {
26        match self {
27            Self::AutoEdit => "Auto Edit",
28            Self::ReadOnly => "Read Only",
29        }
30    }
31
32    /// Returns whether the provider must deny repository mutations.
33    pub fn is_read_only(self) -> bool {
34        self == Self::ReadOnly
35    }
36}
37
38impl fmt::Display for PermissionMode {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        write!(f, "{}", self.label())
41    }
42}
43
44impl FromStr for PermissionMode {
45    type Err = String;
46
47    fn from_str(s: &str) -> Result<Self, Self::Err> {
48        match s {
49            "auto_edit" => Ok(PermissionMode::AutoEdit),
50            "read_only" => Ok(PermissionMode::ReadOnly),
51            _ => Err(format!("Unknown permission mode: {s}")),
52        }
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn test_from_str_accepts_supported_modes() {
62        // Arrange
63        let permission_modes = ["auto_edit", "read_only"];
64
65        // Act
66        let parsed_permission_modes = permission_modes.map(PermissionMode::from_str);
67
68        // Assert
69        assert_eq!(
70            parsed_permission_modes,
71            [Ok(PermissionMode::AutoEdit), Ok(PermissionMode::ReadOnly)]
72        );
73    }
74
75    #[test]
76    fn test_from_str_rejects_removed_permission_modes() {
77        // Arrange
78        let removed_mode = "autonomous";
79
80        // Act
81        let parsed_permission_mode = PermissionMode::from_str(removed_mode);
82
83        // Assert
84        assert_eq!(
85            parsed_permission_mode,
86            Err("Unknown permission mode: autonomous".to_string())
87        );
88    }
89
90    #[test]
91    fn test_default_uses_auto_edit_mode() {
92        // Arrange, Act
93        let permission_mode = PermissionMode::default();
94
95        // Assert
96        assert_eq!(permission_mode, PermissionMode::AutoEdit);
97    }
98
99    #[test]
100    fn test_label_and_display_label_return_persisted_and_user_facing_text() {
101        // Arrange
102        let permission_modes = [PermissionMode::AutoEdit, PermissionMode::ReadOnly];
103
104        // Act
105        let labels = permission_modes.map(PermissionMode::label);
106        let display_labels = permission_modes.map(PermissionMode::display_label);
107        let read_only = permission_modes.map(PermissionMode::is_read_only);
108
109        // Assert
110        assert_eq!(labels, ["auto_edit", "read_only"]);
111        assert_eq!(display_labels, ["Auto Edit", "Read Only"]);
112        assert_eq!(read_only, [false, true]);
113    }
114
115    #[test]
116    fn test_display_uses_persisted_label() {
117        // Arrange
118        let permission_mode = PermissionMode::AutoEdit;
119
120        // Act
121        let formatted = permission_mode.to_string();
122
123        // Assert
124        assert_eq!(formatted, "auto_edit");
125    }
126}