systemprompt_cli/commands/admin/setup/secrets/
prompts.rs1use anyhow::{Result, anyhow};
13use systemprompt_identifiers::ProviderId;
14use systemprompt_logging::CliService;
15
16use super::SecretsData;
17use crate::interactive::Prompter;
18
19pub fn select_provider_keys(
22 prompter: &dyn Prompter,
23 secrets: &mut SecretsData,
24) -> Result<Option<ProviderId>> {
25 let providers = vec![
26 "Google AI (Gemini) - https://aistudio.google.com/app/apikey".to_owned(),
27 "Anthropic (Claude) - https://console.anthropic.com/api-keys".to_owned(),
28 "OpenAI (GPT) - https://platform.openai.com/api-keys".to_owned(),
29 "Enter multiple keys".to_owned(),
30 ];
31
32 let selection = prompter.select("Select your AI provider", &providers)?;
33
34 match selection {
35 0 => {
36 secrets.gemini = Some(prompt_api_key(prompter, "Gemini API Key")?);
37 Ok(Some(ProviderId::new("gemini")))
38 },
39 1 => {
40 secrets.anthropic = Some(prompt_api_key(prompter, "Anthropic API Key")?);
41 Ok(Some(ProviderId::new("anthropic")))
42 },
43 2 => {
44 secrets.openai = Some(prompt_api_key(prompter, "OpenAI API Key")?);
45 Ok(Some(ProviderId::new("openai")))
46 },
47 3 => {
48 CliService::info("Enter API keys (press Enter to skip any):");
49 if let Some(key) = prompt_optional_api_key(prompter, "Gemini API Key")? {
50 secrets.gemini = Some(key);
51 }
52 if let Some(key) = prompt_optional_api_key(prompter, "Anthropic API Key")? {
53 secrets.anthropic = Some(key);
54 }
55 if let Some(key) = prompt_optional_api_key(prompter, "OpenAI API Key")? {
56 secrets.openai = Some(key);
57 }
58 if let Some(key) = prompt_optional_api_key(prompter, "GitHub Token (optional)")? {
59 secrets.github = Some(key);
60 }
61 Ok(None)
62 },
63 _ => Err(anyhow!("Invalid AI provider option selected")),
64 }
65}
66
67pub fn resolve_interactive_primary(
68 prompter: &dyn Prompter,
69 explicit: Option<ProviderId>,
70 secrets: &SecretsData,
71) -> Result<Option<ProviderId>> {
72 if explicit.is_some() {
73 return Ok(explicit);
74 }
75 match secrets.present_providers().as_slice() {
76 [] => Ok(None),
77 [only] => Ok(Some(ProviderId::new(*only))),
78 present => {
79 let items: Vec<String> = present.iter().map(|p| (*p).to_owned()).collect();
80 let idx = prompter.select("Which provider should be the default?", &items)?;
81 Ok(Some(ProviderId::new(present[idx])))
82 },
83 }
84}
85
86fn prompt_api_key(prompter: &dyn Prompter, prompt: &str) -> Result<String> {
87 let key = prompter.password(prompt)?;
88
89 if key.is_empty() {
90 anyhow::bail!("API key is required");
91 }
92
93 Ok(key)
94}
95
96fn prompt_optional_api_key(prompter: &dyn Prompter, prompt: &str) -> Result<Option<String>> {
97 let key = prompter.password(prompt)?;
98
99 if key.is_empty() {
100 Ok(None)
101 } else {
102 Ok(Some(key))
103 }
104}