1use crate::constants::{defaults, instructions, llm_generation, project_doc};
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")]
58 pub todo_planning_mode: bool,
59
60 #[serde(default)]
62 pub ui_surface: UiSurfacePreference,
63
64 #[serde(default = "default_max_conversation_turns")]
66 pub max_conversation_turns: usize,
67
68 #[serde(default = "default_reasoning_effort")]
71 pub reasoning_effort: ReasoningEffortLevel,
72
73 #[serde(default = "default_verbosity")]
76 pub verbosity: VerbosityLevel,
77
78 #[serde(default = "default_temperature")]
83 pub temperature: f32,
84
85 #[serde(default = "default_refine_temperature")]
89 pub refine_temperature: f32,
90
91 #[serde(default = "default_enable_self_review")]
93 pub enable_self_review: bool,
94
95 #[serde(default = "default_max_review_passes")]
97 pub max_review_passes: usize,
98
99 #[serde(default = "default_refine_prompts_enabled")]
101 pub refine_prompts_enabled: bool,
102
103 #[serde(default = "default_refine_max_passes")]
105 pub refine_prompts_max_passes: usize,
106
107 #[serde(default)]
109 pub refine_prompts_model: String,
110
111 #[serde(default)]
115 pub small_model: AgentSmallModelConfig,
116
117 #[serde(default)]
119 pub onboarding: AgentOnboardingConfig,
120
121 #[serde(default = "default_project_doc_max_bytes")]
123 pub project_doc_max_bytes: usize,
124
125 #[serde(
127 default = "default_instruction_max_bytes",
128 alias = "rule_doc_max_bytes"
129 )]
130 pub instruction_max_bytes: usize,
131
132 #[serde(default, alias = "instruction_paths", alias = "instructions")]
134 pub instruction_files: Vec<String>,
135
136 #[serde(default, skip_serializing)]
142 pub custom_api_keys: BTreeMap<String, String>,
143
144 #[serde(default)]
151 pub credential_storage_mode: crate::auth::AuthCredentialsStoreMode,
152
153 #[serde(default)]
155 pub checkpointing: AgentCheckpointingConfig,
156
157 #[serde(default)]
159 pub vibe_coding: AgentVibeCodingConfig,
160
161 #[serde(default = "default_max_task_retries")]
165 pub max_task_retries: u32,
166
167 #[serde(default)]
169 pub harness: AgentHarnessConfig,
170
171 #[serde(default = "default_include_temporal_context")]
174 pub include_temporal_context: bool,
175
176 #[serde(default)]
178 pub temporal_context_use_utc: bool,
179
180 #[serde(default = "default_include_working_directory")]
182 pub include_working_directory: bool,
183
184 #[serde(default)]
194 pub include_structured_reasoning_tags: Option<bool>,
195
196 #[serde(default)]
198 pub user_instructions: Option<String>,
199
200 #[serde(default)]
203 pub default_editing_mode: EditingMode,
204
205 #[serde(default = "default_require_plan_confirmation")]
209 pub require_plan_confirmation: bool,
210
211 #[serde(default = "default_autonomous_mode")]
214 pub autonomous_mode: bool,
215
216 #[serde(default)]
219 pub circuit_breaker: CircuitBreakerConfig,
220
221 #[serde(default)]
224 pub open_responses: OpenResponsesConfig,
225}
226
227#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
228#[derive(Debug, Clone, Deserialize, Serialize)]
229pub struct AgentHarnessConfig {
230 #[serde(default = "default_harness_max_tool_calls_per_turn")]
232 pub max_tool_calls_per_turn: usize,
233 #[serde(default = "default_harness_max_tool_wall_clock_secs")]
235 pub max_tool_wall_clock_secs: u64,
236 #[serde(default = "default_harness_max_tool_retries")]
238 pub max_tool_retries: u32,
239 #[serde(default)]
241 pub event_log_path: Option<String>,
242}
243
244impl Default for AgentHarnessConfig {
245 fn default() -> Self {
246 Self {
247 max_tool_calls_per_turn: default_harness_max_tool_calls_per_turn(),
248 max_tool_wall_clock_secs: default_harness_max_tool_wall_clock_secs(),
249 max_tool_retries: default_harness_max_tool_retries(),
250 event_log_path: None,
251 }
252 }
253}
254
255#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
256#[derive(Debug, Clone, Deserialize, Serialize)]
257pub struct CircuitBreakerConfig {
258 #[serde(default = "default_circuit_breaker_enabled")]
260 pub enabled: bool,
261
262 #[serde(default = "default_failure_threshold")]
264 pub failure_threshold: u32,
265
266 #[serde(default = "default_pause_on_open")]
268 pub pause_on_open: bool,
269
270 #[serde(default = "default_max_open_circuits")]
272 pub max_open_circuits: usize,
273
274 #[serde(default = "default_recovery_cooldown")]
276 pub recovery_cooldown: u64,
277}
278
279impl Default for CircuitBreakerConfig {
280 fn default() -> Self {
281 Self {
282 enabled: default_circuit_breaker_enabled(),
283 failure_threshold: default_failure_threshold(),
284 pause_on_open: default_pause_on_open(),
285 max_open_circuits: default_max_open_circuits(),
286 recovery_cooldown: default_recovery_cooldown(),
287 }
288 }
289}
290
291#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
297#[derive(Debug, Clone, Deserialize, Serialize)]
298pub struct OpenResponsesConfig {
299 #[serde(default)]
303 pub enabled: bool,
304
305 #[serde(default = "default_open_responses_emit_events")]
309 pub emit_events: bool,
310
311 #[serde(default = "default_open_responses_include_extensions")]
314 pub include_extensions: bool,
315
316 #[serde(default = "default_open_responses_map_tool_calls")]
319 pub map_tool_calls: bool,
320
321 #[serde(default = "default_open_responses_include_reasoning")]
324 pub include_reasoning: bool,
325}
326
327impl Default for OpenResponsesConfig {
328 fn default() -> Self {
329 Self {
330 enabled: false, emit_events: default_open_responses_emit_events(),
332 include_extensions: default_open_responses_include_extensions(),
333 map_tool_calls: default_open_responses_map_tool_calls(),
334 include_reasoning: default_open_responses_include_reasoning(),
335 }
336 }
337}
338
339#[inline]
340const fn default_open_responses_emit_events() -> bool {
341 true }
343
344#[inline]
345const fn default_open_responses_include_extensions() -> bool {
346 true }
348
349#[inline]
350const fn default_open_responses_map_tool_calls() -> bool {
351 true }
353
354#[inline]
355const fn default_open_responses_include_reasoning() -> bool {
356 true }
358
359impl Default for AgentConfig {
360 fn default() -> Self {
361 Self {
362 provider: default_provider(),
363 api_key_env: default_api_key_env(),
364 default_model: default_model(),
365 theme: default_theme(),
366 system_prompt_mode: SystemPromptMode::default(),
367 tool_documentation_mode: ToolDocumentationMode::default(),
368 enable_split_tool_results: default_enable_split_tool_results(),
369 todo_planning_mode: default_todo_planning_mode(),
370 ui_surface: UiSurfacePreference::default(),
371 max_conversation_turns: default_max_conversation_turns(),
372 reasoning_effort: default_reasoning_effort(),
373 verbosity: default_verbosity(),
374 temperature: default_temperature(),
375 refine_temperature: default_refine_temperature(),
376 enable_self_review: default_enable_self_review(),
377 max_review_passes: default_max_review_passes(),
378 refine_prompts_enabled: default_refine_prompts_enabled(),
379 refine_prompts_max_passes: default_refine_max_passes(),
380 refine_prompts_model: String::new(),
381 small_model: AgentSmallModelConfig::default(),
382 onboarding: AgentOnboardingConfig::default(),
383 project_doc_max_bytes: default_project_doc_max_bytes(),
384 instruction_max_bytes: default_instruction_max_bytes(),
385 instruction_files: Vec::new(),
386 custom_api_keys: BTreeMap::new(),
387 credential_storage_mode: crate::auth::AuthCredentialsStoreMode::default(),
388 checkpointing: AgentCheckpointingConfig::default(),
389 vibe_coding: AgentVibeCodingConfig::default(),
390 max_task_retries: default_max_task_retries(),
391 harness: AgentHarnessConfig::default(),
392 include_temporal_context: default_include_temporal_context(),
393 temporal_context_use_utc: false, include_working_directory: default_include_working_directory(),
395 include_structured_reasoning_tags: None,
396 user_instructions: None,
397 default_editing_mode: EditingMode::default(),
398 require_plan_confirmation: default_require_plan_confirmation(),
399 autonomous_mode: default_autonomous_mode(),
400 circuit_breaker: CircuitBreakerConfig::default(),
401 open_responses: OpenResponsesConfig::default(),
402 }
403 }
404}
405
406impl AgentConfig {
407 pub fn should_include_structured_reasoning_tags(&self) -> bool {
409 self.include_structured_reasoning_tags.unwrap_or(matches!(
410 self.system_prompt_mode,
411 SystemPromptMode::Default | SystemPromptMode::Specialized
412 ))
413 }
414
415 pub fn validate_llm_params(&self) -> Result<(), String> {
417 if !(0.0..=1.0).contains(&self.temperature) {
419 return Err(format!(
420 "temperature must be between 0.0 and 1.0, got {}",
421 self.temperature
422 ));
423 }
424
425 if !(0.0..=1.0).contains(&self.refine_temperature) {
426 return Err(format!(
427 "refine_temperature must be between 0.0 and 1.0, got {}",
428 self.refine_temperature
429 ));
430 }
431
432 Ok(())
433 }
434}
435
436#[inline]
438fn default_provider() -> String {
439 defaults::DEFAULT_PROVIDER.into()
440}
441
442#[inline]
443fn default_api_key_env() -> String {
444 defaults::DEFAULT_API_KEY_ENV.into()
445}
446
447#[inline]
448fn default_model() -> String {
449 defaults::DEFAULT_MODEL.into()
450}
451
452#[inline]
453fn default_theme() -> String {
454 defaults::DEFAULT_THEME.into()
455}
456
457#[inline]
458const fn default_todo_planning_mode() -> bool {
459 true
460}
461
462#[inline]
463const fn default_enable_split_tool_results() -> bool {
464 true }
466
467#[inline]
468const fn default_max_conversation_turns() -> usize {
469 defaults::DEFAULT_MAX_CONVERSATION_TURNS
470}
471
472#[inline]
473fn default_reasoning_effort() -> ReasoningEffortLevel {
474 ReasoningEffortLevel::default()
475}
476
477#[inline]
478fn default_verbosity() -> VerbosityLevel {
479 VerbosityLevel::default()
480}
481
482#[inline]
483const fn default_temperature() -> f32 {
484 llm_generation::DEFAULT_TEMPERATURE
485}
486
487#[inline]
488const fn default_refine_temperature() -> f32 {
489 llm_generation::DEFAULT_REFINE_TEMPERATURE
490}
491
492#[inline]
493const fn default_enable_self_review() -> bool {
494 false
495}
496
497#[inline]
498const fn default_max_review_passes() -> usize {
499 1
500}
501
502#[inline]
503const fn default_refine_prompts_enabled() -> bool {
504 false
505}
506
507#[inline]
508const fn default_refine_max_passes() -> usize {
509 1
510}
511
512#[inline]
513const fn default_project_doc_max_bytes() -> usize {
514 project_doc::DEFAULT_MAX_BYTES
515}
516
517#[inline]
518const fn default_instruction_max_bytes() -> usize {
519 instructions::DEFAULT_MAX_BYTES
520}
521
522#[inline]
523const fn default_max_task_retries() -> u32 {
524 2 }
526
527#[inline]
528const fn default_harness_max_tool_calls_per_turn() -> usize {
529 defaults::DEFAULT_MAX_TOOL_CALLS_PER_TURN
530}
531
532#[inline]
533const fn default_harness_max_tool_wall_clock_secs() -> u64 {
534 defaults::DEFAULT_MAX_TOOL_WALL_CLOCK_SECS
535}
536
537#[inline]
538const fn default_harness_max_tool_retries() -> u32 {
539 defaults::DEFAULT_MAX_TOOL_RETRIES
540}
541
542#[inline]
543const fn default_include_temporal_context() -> bool {
544 true }
546
547#[inline]
548const fn default_include_working_directory() -> bool {
549 true }
551
552#[inline]
553const fn default_require_plan_confirmation() -> bool {
554 true }
556
557#[inline]
558const fn default_autonomous_mode() -> bool {
559 false }
561
562#[inline]
563const fn default_circuit_breaker_enabled() -> bool {
564 true }
566
567#[inline]
568const fn default_failure_threshold() -> u32 {
569 5 }
571
572#[inline]
573const fn default_pause_on_open() -> bool {
574 true }
576
577#[inline]
578const fn default_max_open_circuits() -> usize {
579 3 }
581
582#[inline]
583const fn default_recovery_cooldown() -> u64 {
584 60 }
586
587#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
588#[derive(Debug, Clone, Deserialize, Serialize)]
589pub struct AgentCheckpointingConfig {
590 #[serde(default = "default_checkpointing_enabled")]
592 pub enabled: bool,
593
594 #[serde(default)]
596 pub storage_dir: Option<String>,
597
598 #[serde(default = "default_checkpointing_max_snapshots")]
600 pub max_snapshots: usize,
601
602 #[serde(default = "default_checkpointing_max_age_days")]
604 pub max_age_days: Option<u64>,
605}
606
607impl Default for AgentCheckpointingConfig {
608 fn default() -> Self {
609 Self {
610 enabled: default_checkpointing_enabled(),
611 storage_dir: None,
612 max_snapshots: default_checkpointing_max_snapshots(),
613 max_age_days: default_checkpointing_max_age_days(),
614 }
615 }
616}
617
618#[inline]
619const fn default_checkpointing_enabled() -> bool {
620 DEFAULT_CHECKPOINTS_ENABLED
621}
622
623#[inline]
624const fn default_checkpointing_max_snapshots() -> usize {
625 DEFAULT_MAX_SNAPSHOTS
626}
627
628#[inline]
629const fn default_checkpointing_max_age_days() -> Option<u64> {
630 Some(DEFAULT_MAX_AGE_DAYS)
631}
632
633#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
634#[derive(Debug, Clone, Deserialize, Serialize)]
635pub struct AgentOnboardingConfig {
636 #[serde(default = "default_onboarding_enabled")]
638 pub enabled: bool,
639
640 #[serde(default = "default_intro_text")]
642 pub intro_text: String,
643
644 #[serde(default = "default_show_project_overview")]
646 pub include_project_overview: bool,
647
648 #[serde(default = "default_show_language_summary")]
650 pub include_language_summary: bool,
651
652 #[serde(default = "default_show_guideline_highlights")]
654 pub include_guideline_highlights: bool,
655
656 #[serde(default = "default_show_usage_tips_in_welcome")]
658 pub include_usage_tips_in_welcome: bool,
659
660 #[serde(default = "default_show_recommended_actions_in_welcome")]
662 pub include_recommended_actions_in_welcome: bool,
663
664 #[serde(default = "default_guideline_highlight_limit")]
666 pub guideline_highlight_limit: usize,
667
668 #[serde(default = "default_usage_tips")]
670 pub usage_tips: Vec<String>,
671
672 #[serde(default = "default_recommended_actions")]
674 pub recommended_actions: Vec<String>,
675
676 #[serde(default)]
678 pub chat_placeholder: Option<String>,
679}
680
681impl Default for AgentOnboardingConfig {
682 fn default() -> Self {
683 Self {
684 enabled: default_onboarding_enabled(),
685 intro_text: default_intro_text(),
686 include_project_overview: default_show_project_overview(),
687 include_language_summary: default_show_language_summary(),
688 include_guideline_highlights: default_show_guideline_highlights(),
689 include_usage_tips_in_welcome: default_show_usage_tips_in_welcome(),
690 include_recommended_actions_in_welcome: default_show_recommended_actions_in_welcome(),
691 guideline_highlight_limit: default_guideline_highlight_limit(),
692 usage_tips: default_usage_tips(),
693 recommended_actions: default_recommended_actions(),
694 chat_placeholder: None,
695 }
696 }
697}
698
699#[inline]
700const fn default_onboarding_enabled() -> bool {
701 true
702}
703
704const DEFAULT_INTRO_TEXT: &str =
705 "Let's get oriented. I preloaded workspace context so we can move fast.";
706
707#[inline]
708fn default_intro_text() -> String {
709 DEFAULT_INTRO_TEXT.into()
710}
711
712#[inline]
713const fn default_show_project_overview() -> bool {
714 true
715}
716
717#[inline]
718const fn default_show_language_summary() -> bool {
719 false
720}
721
722#[inline]
723const fn default_show_guideline_highlights() -> bool {
724 true
725}
726
727#[inline]
728const fn default_show_usage_tips_in_welcome() -> bool {
729 false
730}
731
732#[inline]
733const fn default_show_recommended_actions_in_welcome() -> bool {
734 false
735}
736
737#[inline]
738const fn default_guideline_highlight_limit() -> usize {
739 3
740}
741
742const DEFAULT_USAGE_TIPS: &[&str] = &[
743 "Describe your current coding goal or ask for a quick status overview.",
744 "Reference AGENTS.md guidelines when proposing changes.",
745 "Prefer asking for targeted file reads or diffs before editing.",
746];
747
748const DEFAULT_RECOMMENDED_ACTIONS: &[&str] = &[
749 "Review the highlighted guidelines and share the task you want to tackle.",
750 "Ask for a workspace tour if you need more context.",
751];
752
753fn default_usage_tips() -> Vec<String> {
754 DEFAULT_USAGE_TIPS.iter().map(|s| (*s).into()).collect()
755}
756
757fn default_recommended_actions() -> Vec<String> {
758 DEFAULT_RECOMMENDED_ACTIONS
759 .iter()
760 .map(|s| (*s).into())
761 .collect()
762}
763
764#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
774#[derive(Debug, Clone, Deserialize, Serialize)]
775pub struct AgentSmallModelConfig {
776 #[serde(default = "default_small_model_enabled")]
778 pub enabled: bool,
779
780 #[serde(default)]
783 pub model: String,
784
785 #[serde(default = "default_small_model_temperature")]
787 pub temperature: f32,
788
789 #[serde(default = "default_small_model_for_large_reads")]
791 pub use_for_large_reads: bool,
792
793 #[serde(default = "default_small_model_for_web_summary")]
795 pub use_for_web_summary: bool,
796
797 #[serde(default = "default_small_model_for_git_history")]
799 pub use_for_git_history: bool,
800}
801
802impl Default for AgentSmallModelConfig {
803 fn default() -> Self {
804 Self {
805 enabled: default_small_model_enabled(),
806 model: String::new(),
807 temperature: default_small_model_temperature(),
808 use_for_large_reads: default_small_model_for_large_reads(),
809 use_for_web_summary: default_small_model_for_web_summary(),
810 use_for_git_history: default_small_model_for_git_history(),
811 }
812 }
813}
814
815#[inline]
816const fn default_small_model_enabled() -> bool {
817 true }
819
820#[inline]
821const fn default_small_model_temperature() -> f32 {
822 0.3 }
824
825#[inline]
826const fn default_small_model_for_large_reads() -> bool {
827 true
828}
829
830#[inline]
831const fn default_small_model_for_web_summary() -> bool {
832 true
833}
834
835#[inline]
836const fn default_small_model_for_git_history() -> bool {
837 true
838}
839
840#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
845#[derive(Debug, Clone, Deserialize, Serialize)]
846pub struct AgentVibeCodingConfig {
847 #[serde(default = "default_vibe_coding_enabled")]
849 pub enabled: bool,
850
851 #[serde(default = "default_vibe_min_prompt_length")]
853 pub min_prompt_length: usize,
854
855 #[serde(default = "default_vibe_min_prompt_words")]
857 pub min_prompt_words: usize,
858
859 #[serde(default = "default_vibe_entity_resolution")]
861 pub enable_entity_resolution: bool,
862
863 #[serde(default = "default_vibe_entity_cache")]
865 pub entity_index_cache: String,
866
867 #[serde(default = "default_vibe_max_entity_matches")]
869 pub max_entity_matches: usize,
870
871 #[serde(default = "default_vibe_track_workspace")]
873 pub track_workspace_state: bool,
874
875 #[serde(default = "default_vibe_max_recent_files")]
877 pub max_recent_files: usize,
878
879 #[serde(default = "default_vibe_track_values")]
881 pub track_value_history: bool,
882
883 #[serde(default = "default_vibe_conversation_memory")]
885 pub enable_conversation_memory: bool,
886
887 #[serde(default = "default_vibe_max_memory_turns")]
889 pub max_memory_turns: usize,
890
891 #[serde(default = "default_vibe_pronoun_resolution")]
893 pub enable_pronoun_resolution: bool,
894
895 #[serde(default = "default_vibe_proactive_context")]
897 pub enable_proactive_context: bool,
898
899 #[serde(default = "default_vibe_max_context_files")]
901 pub max_context_files: usize,
902
903 #[serde(default = "default_vibe_max_snippets_per_file")]
905 pub max_context_snippets_per_file: usize,
906
907 #[serde(default = "default_vibe_max_search_results")]
909 pub max_search_results: usize,
910
911 #[serde(default = "default_vibe_value_inference")]
913 pub enable_relative_value_inference: bool,
914}
915
916impl Default for AgentVibeCodingConfig {
917 fn default() -> Self {
918 Self {
919 enabled: default_vibe_coding_enabled(),
920 min_prompt_length: default_vibe_min_prompt_length(),
921 min_prompt_words: default_vibe_min_prompt_words(),
922 enable_entity_resolution: default_vibe_entity_resolution(),
923 entity_index_cache: default_vibe_entity_cache(),
924 max_entity_matches: default_vibe_max_entity_matches(),
925 track_workspace_state: default_vibe_track_workspace(),
926 max_recent_files: default_vibe_max_recent_files(),
927 track_value_history: default_vibe_track_values(),
928 enable_conversation_memory: default_vibe_conversation_memory(),
929 max_memory_turns: default_vibe_max_memory_turns(),
930 enable_pronoun_resolution: default_vibe_pronoun_resolution(),
931 enable_proactive_context: default_vibe_proactive_context(),
932 max_context_files: default_vibe_max_context_files(),
933 max_context_snippets_per_file: default_vibe_max_snippets_per_file(),
934 max_search_results: default_vibe_max_search_results(),
935 enable_relative_value_inference: default_vibe_value_inference(),
936 }
937 }
938}
939
940#[inline]
942const fn default_vibe_coding_enabled() -> bool {
943 false }
945
946#[inline]
947const fn default_vibe_min_prompt_length() -> usize {
948 5
949}
950
951#[inline]
952const fn default_vibe_min_prompt_words() -> usize {
953 2
954}
955
956#[inline]
957const fn default_vibe_entity_resolution() -> bool {
958 true
959}
960
961#[inline]
962fn default_vibe_entity_cache() -> String {
963 ".vtcode/entity_index.json".into()
964}
965
966#[inline]
967const fn default_vibe_max_entity_matches() -> usize {
968 5
969}
970
971#[inline]
972const fn default_vibe_track_workspace() -> bool {
973 true
974}
975
976#[inline]
977const fn default_vibe_max_recent_files() -> usize {
978 20
979}
980
981#[inline]
982const fn default_vibe_track_values() -> bool {
983 true
984}
985
986#[inline]
987const fn default_vibe_conversation_memory() -> bool {
988 true
989}
990
991#[inline]
992const fn default_vibe_max_memory_turns() -> usize {
993 50
994}
995
996#[inline]
997const fn default_vibe_pronoun_resolution() -> bool {
998 true
999}
1000
1001#[inline]
1002const fn default_vibe_proactive_context() -> bool {
1003 true
1004}
1005
1006#[inline]
1007const fn default_vibe_max_context_files() -> usize {
1008 3
1009}
1010
1011#[inline]
1012const fn default_vibe_max_snippets_per_file() -> usize {
1013 20
1014}
1015
1016#[inline]
1017const fn default_vibe_max_search_results() -> usize {
1018 5
1019}
1020
1021#[inline]
1022const fn default_vibe_value_inference() -> bool {
1023 true
1024}
1025
1026#[cfg(test)]
1027mod tests {
1028 use super::*;
1029
1030 #[test]
1031 fn test_editing_mode_config_default() {
1032 let config = AgentConfig::default();
1033 assert_eq!(config.default_editing_mode, EditingMode::Edit);
1034 assert!(config.require_plan_confirmation);
1035 assert!(!config.autonomous_mode);
1036 }
1037
1038 #[test]
1039 fn test_structured_reasoning_defaults_follow_prompt_mode() {
1040 let mut config = AgentConfig::default();
1041
1042 config.system_prompt_mode = SystemPromptMode::Default;
1043 assert!(config.should_include_structured_reasoning_tags());
1044
1045 config.system_prompt_mode = SystemPromptMode::Specialized;
1046 assert!(config.should_include_structured_reasoning_tags());
1047
1048 config.system_prompt_mode = SystemPromptMode::Minimal;
1049 assert!(!config.should_include_structured_reasoning_tags());
1050
1051 config.system_prompt_mode = SystemPromptMode::Lightweight;
1052 assert!(!config.should_include_structured_reasoning_tags());
1053 }
1054
1055 #[test]
1056 fn test_structured_reasoning_explicit_override() {
1057 let mut config = AgentConfig {
1058 system_prompt_mode: SystemPromptMode::Minimal,
1059 include_structured_reasoning_tags: Some(true),
1060 ..AgentConfig::default()
1061 };
1062 assert!(config.should_include_structured_reasoning_tags());
1063
1064 config.include_structured_reasoning_tags = Some(false);
1065 assert!(!config.should_include_structured_reasoning_tags());
1066 }
1067}