Skip to main content

systemprompt_cli/commands/cloud/profile/
api_keys.rs

1//! Provider API-key collection during profile creation.
2//!
3//! Copyright (c) systemprompt.io — Business Source License 1.1.
4//! See <https://systemprompt.io> for licensing details.
5
6use anyhow::{Result, bail};
7use systemprompt_logging::CliService;
8
9use crate::interactive::Prompter;
10
11#[derive(Debug)]
12pub struct ApiKeys {
13    pub gemini: Option<String>,
14    pub anthropic: Option<String>,
15    pub openai: Option<String>,
16}
17
18impl ApiKeys {
19    pub fn from_options(
20        gemini: Option<String>,
21        anthropic: Option<String>,
22        openai: Option<String>,
23    ) -> Result<Self> {
24        if gemini.is_none() && anthropic.is_none() && openai.is_none() {
25            bail!(
26                "At least one AI provider API key is required.\nProvide: --anthropic-key, \
27                 --openai-key, or --gemini-key"
28            );
29        }
30        Ok(Self {
31            gemini,
32            anthropic,
33            openai,
34        })
35    }
36
37    pub const fn selected_provider(&self) -> &'static str {
38        if self.anthropic.is_some() {
39            "anthropic"
40        } else if self.openai.is_some() {
41            "openai"
42        } else if self.gemini.is_some() {
43            "gemini"
44        } else {
45            "anthropic"
46        }
47    }
48}
49
50pub fn collect_api_keys(prompter: &dyn Prompter) -> Result<ApiKeys> {
51    CliService::info("At least one AI provider API key is required.");
52
53    let providers = vec![
54        "Google AI (Gemini) - https://aistudio.google.com/app/apikey".to_owned(),
55        "Anthropic (Claude) - https://console.anthropic.com/api-keys".to_owned(),
56        "OpenAI (GPT) - https://platform.openai.com/api-keys".to_owned(),
57    ];
58
59    let selection = prompter.select("Select your AI provider", &providers)?;
60
61    match selection {
62        0 => {
63            let key = prompter.password("Gemini API Key")?;
64            if key.is_empty() {
65                bail!("API key is required");
66            }
67            Ok(ApiKeys {
68                gemini: Some(key),
69                anthropic: None,
70                openai: None,
71            })
72        },
73        1 => {
74            let key = prompter.password("Anthropic API Key")?;
75            if key.is_empty() {
76                bail!("API key is required");
77            }
78            Ok(ApiKeys {
79                gemini: None,
80                anthropic: Some(key),
81                openai: None,
82            })
83        },
84        2 => {
85            let key = prompter.password("OpenAI API Key")?;
86            if key.is_empty() {
87                bail!("API key is required");
88            }
89            Ok(ApiKeys {
90                gemini: None,
91                anthropic: None,
92                openai: Some(key),
93            })
94        },
95        _ => bail!("Invalid selection"),
96    }
97}