1use std::path::PathBuf;
7
8use claude_agent_sdk_rs::PermissionMode;
9use serde::{Deserialize, Serialize};
10use typed_builder::TypedBuilder;
11
12use gba_pm::PromptManager;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
18#[serde(rename_all = "camelCase")]
19pub enum TaskPermissionMode {
20 AcceptEdits,
22 BypassPermissions,
24 Default,
26}
27
28impl From<TaskPermissionMode> for PermissionMode {
29 fn from(mode: TaskPermissionMode) -> Self {
30 match mode {
31 TaskPermissionMode::AcceptEdits => PermissionMode::AcceptEdits,
32 TaskPermissionMode::BypassPermissions => PermissionMode::BypassPermissions,
33 TaskPermissionMode::Default => PermissionMode::Default,
34 }
35 }
36}
37
38#[derive(Debug, Clone, Default, Serialize, Deserialize)]
54#[serde(rename_all = "camelCase")]
55#[non_exhaustive]
56pub struct TaskConfig {
57 #[serde(default)]
62 pub preset: bool,
63
64 #[serde(default)]
68 pub tools: Vec<String>,
69
70 #[serde(default)]
74 pub disallowed_tools: Vec<String>,
75
76 #[serde(default)]
81 pub permission_mode: Option<TaskPermissionMode>,
82}
83
84#[derive(TypedBuilder)]
89#[builder(doc)]
90pub struct EngineConfig<'a> {
91 #[builder(setter(into))]
95 pub workdir: PathBuf,
96
97 pub prompts: PromptManager<'a>,
99
100 #[builder(default)]
102 pub agent_options: Option<claude_agent_sdk_rs::ClaudeAgentOptions>,
103}
104
105impl std::fmt::Debug for EngineConfig<'_> {
106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 f.debug_struct("EngineConfig")
108 .field("workdir", &self.workdir)
109 .field("prompts", &self.prompts)
110 .field("agent_options", &"<ClaudeAgentOptions>")
111 .finish()
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
120 fn test_should_deserialize_task_config_with_defaults() {
121 let yaml = "preset: true";
122 let config: TaskConfig = serde_yaml::from_str(yaml).unwrap();
123
124 assert!(config.preset);
125 assert!(config.tools.is_empty());
126 assert!(config.disallowed_tools.is_empty());
127 assert!(config.permission_mode.is_none());
128 }
129
130 #[test]
131 fn test_should_deserialize_task_config_with_permission_mode() {
132 let yaml = r#"
133preset: true
134permissionMode: bypassPermissions
135"#;
136 let config: TaskConfig = serde_yaml::from_str(yaml).unwrap();
137
138 assert!(config.preset);
139 assert_eq!(
140 config.permission_mode,
141 Some(TaskPermissionMode::BypassPermissions)
142 );
143 }
144
145 #[test]
146 fn test_should_deserialize_task_config_with_tools() {
147 let yaml = r#"
148preset: true
149tools:
150 - Read
151 - Write
152disallowedTools:
153 - Bash
154"#;
155 let config: TaskConfig = serde_yaml::from_str(yaml).unwrap();
156
157 assert!(config.preset);
158 assert_eq!(config.tools, vec!["Read", "Write"]);
159 assert_eq!(config.disallowed_tools, vec!["Bash"]);
160 }
161
162 #[test]
163 fn test_should_deserialize_review_task_config() {
164 let yaml = r#"
165preset: true
166tools: []
167disallowedTools:
168 - Write
169 - Edit
170 - NotebookEdit
171"#;
172 let config: TaskConfig = serde_yaml::from_str(yaml).unwrap();
173
174 assert!(config.preset);
175 assert!(config.tools.is_empty());
176 assert_eq!(
177 config.disallowed_tools,
178 vec!["Write", "Edit", "NotebookEdit"]
179 );
180 }
181
182 #[test]
183 fn test_should_build_engine_config() {
184 let prompts = PromptManager::new();
185 let config = EngineConfig::builder()
186 .workdir("/tmp/test")
187 .prompts(prompts)
188 .build();
189
190 assert_eq!(config.workdir, PathBuf::from("/tmp/test"));
191 assert!(config.agent_options.is_none());
192 }
193}