1use crate::constants::{defaults, instructions, llm_generation, project_doc, prompts};
2use crate::types::{
3 EditingMode, ReasoningEffortLevel, SystemPromptMode, ToolDocumentationMode,
4 UiSurfacePreference, VerbosityLevel,
5};
6use serde::{Deserialize, Serialize};
7use std::collections::BTreeMap;
8
9const DEFAULT_CHECKPOINTS_ENABLED: bool = true;
10const DEFAULT_MAX_SNAPSHOTS: usize = 50;
11const DEFAULT_MAX_AGE_DAYS: u64 = 30;
12
13#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
15#[derive(Debug, Clone, Deserialize, Serialize)]
16pub struct AgentConfig {
17 #[serde(default = "default_provider")]
19 pub provider: String,
20
21 #[serde(default = "default_api_key_env")]
23 pub api_key_env: String,
24
25 #[serde(default = "default_model")]
27 pub default_model: String,
28
29 #[serde(default = "default_theme")]
31 pub theme: String,
32
33 #[serde(default)]
37 pub system_prompt_mode: SystemPromptMode,
38
39 #[serde(default)]
45 pub tool_documentation_mode: ToolDocumentationMode,
46
47 #[serde(default = "default_enable_split_tool_results")]
54 pub enable_split_tool_results: bool,
55
56 #[serde(default = "default_todo_planning_mode")]
57 pub todo_planning_mode: bool,
58
59 #[serde(default)]
61 pub ui_surface: UiSurfacePreference,
62
63 #[serde(default = "default_max_conversation_turns")]
65 pub max_conversation_turns: usize,
66
67 #[serde(default = "default_reasoning_effort")]
70 pub reasoning_effort: ReasoningEffortLevel,
71
72 #[serde(default = "default_verbosity")]
75 pub verbosity: VerbosityLevel,
76
77 #[serde(default = "default_temperature")]
82 pub temperature: f32,
83
84 #[serde(default = "default_refine_temperature")]
88 pub refine_temperature: f32,
89
90 #[serde(default = "default_enable_self_review")]
92 pub enable_self_review: bool,
93
94 #[serde(default = "default_max_review_passes")]
96 pub max_review_passes: usize,
97
98 #[serde(default = "default_refine_prompts_enabled")]
100 pub refine_prompts_enabled: bool,
101
102 #[serde(default = "default_refine_max_passes")]
104 pub refine_prompts_max_passes: usize,
105
106 #[serde(default)]
108 pub refine_prompts_model: String,
109
110 #[serde(default)]
114 pub small_model: AgentSmallModelConfig,
115
116 #[serde(default)]
118 pub onboarding: AgentOnboardingConfig,
119
120 #[serde(default = "default_project_doc_max_bytes")]
122 pub project_doc_max_bytes: usize,
123
124 #[serde(
126 default = "default_instruction_max_bytes",
127 alias = "rule_doc_max_bytes"
128 )]
129 pub instruction_max_bytes: usize,
130
131 #[serde(default, alias = "instruction_paths", alias = "instructions")]
133 pub instruction_files: Vec<String>,
134
135 #[serde(default)]
137 pub custom_prompts: AgentCustomPromptsConfig,
138
139 #[serde(default)]
141 pub custom_slash_commands: AgentCustomSlashCommandsConfig,
142
143 #[serde(default)]
145 pub custom_api_keys: BTreeMap<String, String>,
146
147 #[serde(default)]
149 pub checkpointing: AgentCheckpointingConfig,
150
151 #[serde(default)]
153 pub vibe_coding: AgentVibeCodingConfig,
154
155 #[serde(default = "default_max_task_retries")]
159 pub max_task_retries: u32,
160
161 #[serde(default = "default_include_temporal_context")]
164 pub include_temporal_context: bool,
165
166 #[serde(default)]
168 pub temporal_context_use_utc: bool,
169
170 #[serde(default = "default_include_working_directory")]
172 pub include_working_directory: bool,
173
174 #[serde(default)]
176 pub user_instructions: Option<String>,
177
178 #[serde(default)]
184 pub default_editing_mode: EditingMode,
185
186 #[serde(default = "default_require_plan_confirmation")]
191 pub require_plan_confirmation: bool,
192
193 #[serde(default = "default_autonomous_mode")]
198 pub autonomous_mode: bool,
199
200 #[serde(default)]
203 pub circuit_breaker: CircuitBreakerConfig,
204}
205
206#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
207#[derive(Debug, Clone, Deserialize, Serialize)]
208pub struct CircuitBreakerConfig {
209 #[serde(default = "default_circuit_breaker_enabled")]
211 pub enabled: bool,
212
213 #[serde(default = "default_failure_threshold")]
215 pub failure_threshold: u32,
216
217 #[serde(default = "default_pause_on_open")]
219 pub pause_on_open: bool,
220
221 #[serde(default = "default_max_open_circuits")]
223 pub max_open_circuits: usize,
224
225 #[serde(default = "default_recovery_cooldown")]
227 pub recovery_cooldown: u64,
228}
229
230impl Default for CircuitBreakerConfig {
231 fn default() -> Self {
232 Self {
233 enabled: default_circuit_breaker_enabled(),
234 failure_threshold: default_failure_threshold(),
235 pause_on_open: default_pause_on_open(),
236 max_open_circuits: default_max_open_circuits(),
237 recovery_cooldown: default_recovery_cooldown(),
238 }
239 }
240}
241
242impl Default for AgentConfig {
243 fn default() -> Self {
244 Self {
245 provider: default_provider(),
246 api_key_env: default_api_key_env(),
247 default_model: default_model(),
248 theme: default_theme(),
249 system_prompt_mode: SystemPromptMode::default(),
250 tool_documentation_mode: ToolDocumentationMode::default(),
251 enable_split_tool_results: default_enable_split_tool_results(),
252 todo_planning_mode: default_todo_planning_mode(),
253 ui_surface: UiSurfacePreference::default(),
254 max_conversation_turns: default_max_conversation_turns(),
255 reasoning_effort: default_reasoning_effort(),
256 verbosity: default_verbosity(),
257 temperature: default_temperature(),
258 refine_temperature: default_refine_temperature(),
259 enable_self_review: default_enable_self_review(),
260 max_review_passes: default_max_review_passes(),
261 refine_prompts_enabled: default_refine_prompts_enabled(),
262 refine_prompts_max_passes: default_refine_max_passes(),
263 refine_prompts_model: String::new(),
264 small_model: AgentSmallModelConfig::default(),
265 onboarding: AgentOnboardingConfig::default(),
266 project_doc_max_bytes: default_project_doc_max_bytes(),
267 instruction_max_bytes: default_instruction_max_bytes(),
268 instruction_files: Vec::new(),
269 custom_prompts: AgentCustomPromptsConfig::default(),
270 custom_slash_commands: AgentCustomSlashCommandsConfig::default(),
271 custom_api_keys: BTreeMap::new(),
272 checkpointing: AgentCheckpointingConfig::default(),
273 vibe_coding: AgentVibeCodingConfig::default(),
274 max_task_retries: default_max_task_retries(),
275 include_temporal_context: default_include_temporal_context(),
276 temporal_context_use_utc: false, include_working_directory: default_include_working_directory(),
278 user_instructions: None,
279 default_editing_mode: EditingMode::default(),
280 require_plan_confirmation: default_require_plan_confirmation(),
281 autonomous_mode: default_autonomous_mode(),
282 circuit_breaker: CircuitBreakerConfig::default(),
283 }
284 }
285}
286
287impl AgentConfig {
288 pub fn validate_llm_params(&self) -> Result<(), String> {
290 if !(0.0..=1.0).contains(&self.temperature) {
292 return Err(format!(
293 "temperature must be between 0.0 and 1.0, got {}",
294 self.temperature
295 ));
296 }
297
298 if !(0.0..=1.0).contains(&self.refine_temperature) {
299 return Err(format!(
300 "refine_temperature must be between 0.0 and 1.0, got {}",
301 self.refine_temperature
302 ));
303 }
304
305 Ok(())
306 }
307}
308
309#[inline]
311fn default_provider() -> String {
312 defaults::DEFAULT_PROVIDER.into()
313}
314
315#[inline]
316fn default_api_key_env() -> String {
317 defaults::DEFAULT_API_KEY_ENV.into()
318}
319
320#[inline]
321fn default_model() -> String {
322 defaults::DEFAULT_MODEL.into()
323}
324
325#[inline]
326fn default_theme() -> String {
327 defaults::DEFAULT_THEME.into()
328}
329
330#[inline]
331const fn default_todo_planning_mode() -> bool {
332 true
333}
334
335#[inline]
336const fn default_enable_split_tool_results() -> bool {
337 true }
339
340#[inline]
341const fn default_max_conversation_turns() -> usize {
342 150
343}
344
345#[inline]
346fn default_reasoning_effort() -> ReasoningEffortLevel {
347 ReasoningEffortLevel::default()
348}
349
350#[inline]
351fn default_verbosity() -> VerbosityLevel {
352 VerbosityLevel::default()
353}
354
355#[inline]
356const fn default_temperature() -> f32 {
357 llm_generation::DEFAULT_TEMPERATURE
358}
359
360#[inline]
361const fn default_refine_temperature() -> f32 {
362 llm_generation::DEFAULT_REFINE_TEMPERATURE
363}
364
365#[inline]
366const fn default_enable_self_review() -> bool {
367 false
368}
369
370#[inline]
371const fn default_max_review_passes() -> usize {
372 1
373}
374
375#[inline]
376const fn default_refine_prompts_enabled() -> bool {
377 false
378}
379
380#[inline]
381const fn default_refine_max_passes() -> usize {
382 1
383}
384
385#[inline]
386const fn default_project_doc_max_bytes() -> usize {
387 project_doc::DEFAULT_MAX_BYTES
388}
389
390#[inline]
391const fn default_instruction_max_bytes() -> usize {
392 instructions::DEFAULT_MAX_BYTES
393}
394
395#[inline]
396const fn default_max_task_retries() -> u32 {
397 2 }
399
400#[inline]
401const fn default_include_temporal_context() -> bool {
402 true }
404
405#[inline]
406const fn default_include_working_directory() -> bool {
407 true }
409
410#[inline]
411const fn default_require_plan_confirmation() -> bool {
412 true }
414
415#[inline]
416const fn default_autonomous_mode() -> bool {
417 false }
419
420#[inline]
421const fn default_circuit_breaker_enabled() -> bool {
422 true }
424
425#[inline]
426const fn default_failure_threshold() -> u32 {
427 5 }
429
430#[inline]
431const fn default_pause_on_open() -> bool {
432 true }
434
435#[inline]
436const fn default_max_open_circuits() -> usize {
437 3 }
439
440#[inline]
441const fn default_recovery_cooldown() -> u64 {
442 60 }
444
445#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
446#[derive(Debug, Clone, Deserialize, Serialize)]
447pub struct AgentCustomPromptsConfig {
448 #[serde(default = "default_custom_prompts_enabled")]
450 pub enabled: bool,
451
452 #[serde(default = "default_custom_prompts_directory")]
454 pub directory: String,
455
456 #[serde(default)]
458 pub extra_directories: Vec<String>,
459
460 #[serde(default = "default_custom_prompts_max_file_size_kb")]
462 pub max_file_size_kb: usize,
463}
464
465impl Default for AgentCustomPromptsConfig {
466 fn default() -> Self {
467 Self {
468 enabled: default_custom_prompts_enabled(),
469 directory: default_custom_prompts_directory(),
470 extra_directories: Vec::new(),
471 max_file_size_kb: default_custom_prompts_max_file_size_kb(),
472 }
473 }
474}
475
476#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
478#[derive(Debug, Clone, Deserialize, Serialize, Default)]
479pub struct AgentCustomSlashCommandsConfig {
480 #[serde(default = "default_custom_slash_commands_enabled")]
482 pub enabled: bool,
483
484 #[serde(default = "default_custom_slash_commands_directory")]
486 pub directory: String,
487
488 #[serde(default)]
490 pub extra_directories: Vec<String>,
491
492 #[serde(default = "default_custom_slash_commands_max_file_size_kb")]
494 pub max_file_size_kb: usize,
495}
496
497#[inline]
498const fn default_custom_slash_commands_enabled() -> bool {
499 true
500}
501
502fn default_custom_slash_commands_directory() -> String {
503 crate::constants::prompts::DEFAULT_CUSTOM_SLASH_COMMANDS_DIR.into()
504}
505
506const fn default_custom_slash_commands_max_file_size_kb() -> usize {
507 64 }
509
510#[inline]
511const fn default_custom_prompts_enabled() -> bool {
512 true
513}
514
515#[inline]
516fn default_custom_prompts_directory() -> String {
517 prompts::DEFAULT_CUSTOM_PROMPTS_DIR.into()
518}
519
520#[inline]
521const fn default_custom_prompts_max_file_size_kb() -> usize {
522 prompts::DEFAULT_CUSTOM_PROMPT_MAX_FILE_SIZE_KB
523}
524
525#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
526#[derive(Debug, Clone, Deserialize, Serialize)]
527pub struct AgentCheckpointingConfig {
528 #[serde(default = "default_checkpointing_enabled")]
530 pub enabled: bool,
531
532 #[serde(default)]
534 pub storage_dir: Option<String>,
535
536 #[serde(default = "default_checkpointing_max_snapshots")]
538 pub max_snapshots: usize,
539
540 #[serde(default = "default_checkpointing_max_age_days")]
542 pub max_age_days: Option<u64>,
543}
544
545impl Default for AgentCheckpointingConfig {
546 fn default() -> Self {
547 Self {
548 enabled: default_checkpointing_enabled(),
549 storage_dir: None,
550 max_snapshots: default_checkpointing_max_snapshots(),
551 max_age_days: default_checkpointing_max_age_days(),
552 }
553 }
554}
555
556#[inline]
557const fn default_checkpointing_enabled() -> bool {
558 DEFAULT_CHECKPOINTS_ENABLED
559}
560
561#[inline]
562const fn default_checkpointing_max_snapshots() -> usize {
563 DEFAULT_MAX_SNAPSHOTS
564}
565
566#[inline]
567const fn default_checkpointing_max_age_days() -> Option<u64> {
568 Some(DEFAULT_MAX_AGE_DAYS)
569}
570
571#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
572#[derive(Debug, Clone, Deserialize, Serialize)]
573pub struct AgentOnboardingConfig {
574 #[serde(default = "default_onboarding_enabled")]
576 pub enabled: bool,
577
578 #[serde(default = "default_intro_text")]
580 pub intro_text: String,
581
582 #[serde(default = "default_show_project_overview")]
584 pub include_project_overview: bool,
585
586 #[serde(default = "default_show_language_summary")]
588 pub include_language_summary: bool,
589
590 #[serde(default = "default_show_guideline_highlights")]
592 pub include_guideline_highlights: bool,
593
594 #[serde(default = "default_show_usage_tips_in_welcome")]
596 pub include_usage_tips_in_welcome: bool,
597
598 #[serde(default = "default_show_recommended_actions_in_welcome")]
600 pub include_recommended_actions_in_welcome: bool,
601
602 #[serde(default = "default_guideline_highlight_limit")]
604 pub guideline_highlight_limit: usize,
605
606 #[serde(default = "default_usage_tips")]
608 pub usage_tips: Vec<String>,
609
610 #[serde(default = "default_recommended_actions")]
612 pub recommended_actions: Vec<String>,
613
614 #[serde(default)]
616 pub chat_placeholder: Option<String>,
617}
618
619impl Default for AgentOnboardingConfig {
620 fn default() -> Self {
621 Self {
622 enabled: default_onboarding_enabled(),
623 intro_text: default_intro_text(),
624 include_project_overview: default_show_project_overview(),
625 include_language_summary: default_show_language_summary(),
626 include_guideline_highlights: default_show_guideline_highlights(),
627 include_usage_tips_in_welcome: default_show_usage_tips_in_welcome(),
628 include_recommended_actions_in_welcome: default_show_recommended_actions_in_welcome(),
629 guideline_highlight_limit: default_guideline_highlight_limit(),
630 usage_tips: default_usage_tips(),
631 recommended_actions: default_recommended_actions(),
632 chat_placeholder: None,
633 }
634 }
635}
636
637#[inline]
638const fn default_onboarding_enabled() -> bool {
639 true
640}
641
642const DEFAULT_INTRO_TEXT: &str =
643 "Let's get oriented. I preloaded workspace context so we can move fast.";
644
645#[inline]
646fn default_intro_text() -> String {
647 DEFAULT_INTRO_TEXT.into()
648}
649
650#[inline]
651const fn default_show_project_overview() -> bool {
652 true
653}
654
655#[inline]
656const fn default_show_language_summary() -> bool {
657 false
658}
659
660#[inline]
661const fn default_show_guideline_highlights() -> bool {
662 true
663}
664
665#[inline]
666const fn default_show_usage_tips_in_welcome() -> bool {
667 false
668}
669
670#[inline]
671const fn default_show_recommended_actions_in_welcome() -> bool {
672 false
673}
674
675#[inline]
676const fn default_guideline_highlight_limit() -> usize {
677 3
678}
679
680const DEFAULT_USAGE_TIPS: &[&str] = &[
681 "Describe your current coding goal or ask for a quick status overview.",
682 "Reference AGENTS.md guidelines when proposing changes.",
683 "Prefer asking for targeted file reads or diffs before editing.",
684];
685
686const DEFAULT_RECOMMENDED_ACTIONS: &[&str] = &[
687 "Review the highlighted guidelines and share the task you want to tackle.",
688 "Ask for a workspace tour if you need more context.",
689];
690
691fn default_usage_tips() -> Vec<String> {
692 DEFAULT_USAGE_TIPS.iter().map(|s| (*s).into()).collect()
693}
694
695fn default_recommended_actions() -> Vec<String> {
696 DEFAULT_RECOMMENDED_ACTIONS
697 .iter()
698 .map(|s| (*s).into())
699 .collect()
700}
701
702#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
712#[derive(Debug, Clone, Deserialize, Serialize)]
713pub struct AgentSmallModelConfig {
714 #[serde(default = "default_small_model_enabled")]
716 pub enabled: bool,
717
718 #[serde(default)]
721 pub model: String,
722
723 #[serde(default = "default_small_model_temperature")]
725 pub temperature: f32,
726
727 #[serde(default = "default_small_model_for_large_reads")]
729 pub use_for_large_reads: bool,
730
731 #[serde(default = "default_small_model_for_web_summary")]
733 pub use_for_web_summary: bool,
734
735 #[serde(default = "default_small_model_for_git_history")]
737 pub use_for_git_history: bool,
738}
739
740impl Default for AgentSmallModelConfig {
741 fn default() -> Self {
742 Self {
743 enabled: default_small_model_enabled(),
744 model: String::new(),
745 temperature: default_small_model_temperature(),
746 use_for_large_reads: default_small_model_for_large_reads(),
747 use_for_web_summary: default_small_model_for_web_summary(),
748 use_for_git_history: default_small_model_for_git_history(),
749 }
750 }
751}
752
753#[inline]
754const fn default_small_model_enabled() -> bool {
755 true }
757
758#[inline]
759const fn default_small_model_temperature() -> f32 {
760 0.3 }
762
763#[inline]
764const fn default_small_model_for_large_reads() -> bool {
765 true
766}
767
768#[inline]
769const fn default_small_model_for_web_summary() -> bool {
770 true
771}
772
773#[inline]
774const fn default_small_model_for_git_history() -> bool {
775 true
776}
777
778#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
783#[derive(Debug, Clone, Deserialize, Serialize)]
784pub struct AgentVibeCodingConfig {
785 #[serde(default = "default_vibe_coding_enabled")]
787 pub enabled: bool,
788
789 #[serde(default = "default_vibe_min_prompt_length")]
791 pub min_prompt_length: usize,
792
793 #[serde(default = "default_vibe_min_prompt_words")]
795 pub min_prompt_words: usize,
796
797 #[serde(default = "default_vibe_entity_resolution")]
799 pub enable_entity_resolution: bool,
800
801 #[serde(default = "default_vibe_entity_cache")]
803 pub entity_index_cache: String,
804
805 #[serde(default = "default_vibe_max_entity_matches")]
807 pub max_entity_matches: usize,
808
809 #[serde(default = "default_vibe_track_workspace")]
811 pub track_workspace_state: bool,
812
813 #[serde(default = "default_vibe_max_recent_files")]
815 pub max_recent_files: usize,
816
817 #[serde(default = "default_vibe_track_values")]
819 pub track_value_history: bool,
820
821 #[serde(default = "default_vibe_conversation_memory")]
823 pub enable_conversation_memory: bool,
824
825 #[serde(default = "default_vibe_max_memory_turns")]
827 pub max_memory_turns: usize,
828
829 #[serde(default = "default_vibe_pronoun_resolution")]
831 pub enable_pronoun_resolution: bool,
832
833 #[serde(default = "default_vibe_proactive_context")]
835 pub enable_proactive_context: bool,
836
837 #[serde(default = "default_vibe_max_context_files")]
839 pub max_context_files: usize,
840
841 #[serde(default = "default_vibe_max_snippets_per_file")]
843 pub max_context_snippets_per_file: usize,
844
845 #[serde(default = "default_vibe_max_search_results")]
847 pub max_search_results: usize,
848
849 #[serde(default = "default_vibe_value_inference")]
851 pub enable_relative_value_inference: bool,
852}
853
854impl Default for AgentVibeCodingConfig {
855 fn default() -> Self {
856 Self {
857 enabled: default_vibe_coding_enabled(),
858 min_prompt_length: default_vibe_min_prompt_length(),
859 min_prompt_words: default_vibe_min_prompt_words(),
860 enable_entity_resolution: default_vibe_entity_resolution(),
861 entity_index_cache: default_vibe_entity_cache(),
862 max_entity_matches: default_vibe_max_entity_matches(),
863 track_workspace_state: default_vibe_track_workspace(),
864 max_recent_files: default_vibe_max_recent_files(),
865 track_value_history: default_vibe_track_values(),
866 enable_conversation_memory: default_vibe_conversation_memory(),
867 max_memory_turns: default_vibe_max_memory_turns(),
868 enable_pronoun_resolution: default_vibe_pronoun_resolution(),
869 enable_proactive_context: default_vibe_proactive_context(),
870 max_context_files: default_vibe_max_context_files(),
871 max_context_snippets_per_file: default_vibe_max_snippets_per_file(),
872 max_search_results: default_vibe_max_search_results(),
873 enable_relative_value_inference: default_vibe_value_inference(),
874 }
875 }
876}
877
878#[inline]
880const fn default_vibe_coding_enabled() -> bool {
881 false }
883
884#[inline]
885const fn default_vibe_min_prompt_length() -> usize {
886 5
887}
888
889#[inline]
890const fn default_vibe_min_prompt_words() -> usize {
891 2
892}
893
894#[inline]
895const fn default_vibe_entity_resolution() -> bool {
896 true
897}
898
899#[inline]
900fn default_vibe_entity_cache() -> String {
901 ".vtcode/entity_index.json".into()
902}
903
904#[inline]
905const fn default_vibe_max_entity_matches() -> usize {
906 5
907}
908
909#[inline]
910const fn default_vibe_track_workspace() -> bool {
911 true
912}
913
914#[inline]
915const fn default_vibe_max_recent_files() -> usize {
916 20
917}
918
919#[inline]
920const fn default_vibe_track_values() -> bool {
921 true
922}
923
924#[inline]
925const fn default_vibe_conversation_memory() -> bool {
926 true
927}
928
929#[inline]
930const fn default_vibe_max_memory_turns() -> usize {
931 50
932}
933
934#[inline]
935const fn default_vibe_pronoun_resolution() -> bool {
936 true
937}
938
939#[inline]
940const fn default_vibe_proactive_context() -> bool {
941 true
942}
943
944#[inline]
945const fn default_vibe_max_context_files() -> usize {
946 3
947}
948
949#[inline]
950const fn default_vibe_max_snippets_per_file() -> usize {
951 20
952}
953
954#[inline]
955const fn default_vibe_max_search_results() -> usize {
956 5
957}
958
959#[inline]
960const fn default_vibe_value_inference() -> bool {
961 true
962}
963
964#[cfg(test)]
965mod tests {
966 use super::*;
967
968 #[test]
969 fn test_editing_mode_config_default() {
970 let config = AgentConfig::default();
971 assert_eq!(config.default_editing_mode, EditingMode::Edit);
972 assert!(config.require_plan_confirmation);
973 assert!(!config.autonomous_mode);
974 }
975}