1use crate::config::Config;
2use crate::instruction_presets::{PresetType, get_instruction_preset_library};
3use crate::llm;
4use anyhow::Result;
5use clap::Args;
6use std::str::FromStr;
7
8#[derive(Clone, Copy, PartialEq, Eq, Debug)]
9pub enum DetailLevel {
10 Minimal,
11 Standard,
12 Detailed,
13}
14
15impl FromStr for DetailLevel {
16 type Err = anyhow::Error;
17
18 fn from_str(s: &str) -> Result<Self, Self::Err> {
19 match s.to_lowercase().as_str() {
20 "minimal" => Ok(Self::Minimal),
21 "standard" => Ok(Self::Standard),
22 "detailed" => Ok(Self::Detailed),
23 _ => Err(anyhow::anyhow!("Invalid detail level: {}", s)),
24 }
25 }
26}
27
28impl DetailLevel {
29 pub fn as_str(&self) -> &'static str {
30 match self {
31 Self::Minimal => "minimal",
32 Self::Standard => "standard",
33 Self::Detailed => "detailed",
34 }
35 }
36}
37
38#[derive(Args, Clone, Default, Debug)]
39pub struct CommonParams {
40 #[arg(long, help = "Override default LLM provider", value_parser = available_providers_parser)]
42 pub provider: Option<String>,
43
44 #[arg(short, long, help = "Custom instructions for this operation")]
46 pub instructions: Option<String>,
47
48 #[arg(
50 long,
51 help = "Select an instruction preset (use 'git-iris list-presets' to see available presets for commits and reviews)"
52 )]
53 pub preset: Option<String>,
54
55 #[arg(long, help = "Enable or disable Gitmoji")]
57 pub gitmoji: Option<bool>,
58
59 #[arg(
61 long,
62 help = "Set the detail level (minimal, standard, detailed)",
63 default_value = "standard"
64 )]
65 pub detail_level: String,
66}
67
68impl CommonParams {
69 pub fn apply_to_config(&self, config: &mut Config) -> Result<()> {
70 if let Some(provider) = &self.provider {
71 let provider_name = if provider.to_lowercase() == "claude" {
73 "anthropic".to_string()
74 } else {
75 provider.clone()
76 };
77 config.default_provider.clone_from(&provider_name);
78 }
79 if let Some(instructions) = &self.instructions {
80 config.set_temp_instructions(Some(instructions.clone()));
81 }
82 if let Some(preset) = &self.preset {
83 config.set_temp_preset(Some(preset.clone()));
84 }
85 if let Some(use_gitmoji) = self.gitmoji {
86 config.use_gitmoji = use_gitmoji;
87 }
88 Ok(())
89 }
90
91 pub fn is_valid_preset_for_type(&self, preset_type: PresetType) -> bool {
93 if let Some(preset_name) = &self.preset {
94 let library = get_instruction_preset_library();
95 let valid_presets = library.list_valid_presets_for_command(preset_type);
96 return valid_presets.iter().any(|(key, _)| *key == preset_name);
97 }
98 true }
100}
101
102pub fn available_providers_parser(s: &str) -> Result<String, String> {
104 let mut provider_name = s.to_lowercase();
105
106 if provider_name == "claude" {
108 provider_name = "anthropic".to_string();
109 }
110
111 let available_providers = llm::get_available_provider_names();
112
113 if available_providers
114 .iter()
115 .any(|p| p.to_lowercase() == provider_name)
116 {
117 Ok(provider_name)
118 } else {
119 Err(format!(
120 "Invalid provider '{}'. Available providers: {}",
121 s,
122 available_providers.join(", ")
123 ))
124 }
125}
126
127pub fn get_combined_instructions(config: &Config) -> String {
128 let mut prompt = String::from("\n\n");
129
130 if !config.instructions.is_empty() {
131 prompt.push_str(&format!(
132 "\n\nAdditional instructions for the request:\n{}\n\n",
133 config.instructions
134 ));
135 }
136
137 let preset_library = get_instruction_preset_library();
138 if let Some(preset_instructions) = preset_library.get_preset(config.instruction_preset.as_str())
139 {
140 prompt.push_str(&format!(
141 "\n\nIMPORTANT: Use this style for your output:\n{}\n\n",
142 preset_instructions.instructions
143 ));
144 }
145
146 prompt
147}