vtcode_llm/providers/gemini/
provider.rs1use super::*;
2use vtcode_config::core::ModelConfig;
3
4pub struct GeminiProvider {
5 pub(super) api_key: Arc<str>,
6 pub(super) http_client: HttpClient,
7 pub(super) base_url: Arc<str>,
8 pub(super) model: Arc<str>,
9 pub(super) prompt_cache_enabled: bool,
10 pub(super) prompt_cache_settings: GeminiPromptCacheSettings,
11 pub(super) timeouts: TimeoutsConfig,
12 pub(super) model_behavior: Option<ModelConfig>,
13 pub(super) explicit_cache: explicit_cache::ExplicitCacheState,
15}
16
17impl GeminiProvider {
18 pub fn new(api_key: String) -> Self {
19 Self::with_model_internal(
20 api_key,
21 models::google::GEMINI_3_FLASH_PREVIEW.to_string(),
22 None,
23 None,
24 TimeoutsConfig::default(),
25 None,
26 )
27 }
28
29 pub fn with_model(api_key: String, model: String) -> Self {
30 Self::with_model_internal(api_key, model, None, None, TimeoutsConfig::default(), None)
31 }
32
33 pub fn new_with_client(
34 api_key: String,
35 model: String,
36 http_client: reqwest::Client,
37 base_url: String,
38 timeouts: TimeoutsConfig,
39 prompt_cache_enabled: bool,
40 prompt_cache_settings: GeminiPromptCacheSettings,
41 ) -> Self {
42 Self {
43 api_key: Arc::from(api_key.as_str()),
44 http_client,
45 base_url: Arc::from(base_url.as_str()),
46 model: Arc::from(model.as_str()),
47 prompt_cache_enabled,
48 prompt_cache_settings,
49 timeouts,
50 model_behavior: None,
51 explicit_cache: explicit_cache::ExplicitCacheState::default(),
52 }
53 }
54
55 pub fn from_config(
56 api_key: Option<String>,
57 model: Option<String>,
58 base_url: Option<String>,
59 prompt_cache: Option<PromptCachingConfig>,
60 timeouts: Option<TimeoutsConfig>,
61 _anthropic: Option<AnthropicConfig>,
62 model_behavior: Option<ModelConfig>,
63 ) -> Self {
64 let api_key_value = api_key.unwrap_or_default();
65 let model_value = resolve_model(model, models::google::GEMINI_3_FLASH_PREVIEW);
66
67 Self::with_model_internal(
68 api_key_value,
69 model_value,
70 prompt_cache,
71 base_url,
72 timeouts.unwrap_or_default(),
73 model_behavior,
74 )
75 }
76
77 fn with_model_internal(
78 api_key: String,
79 model: String,
80 prompt_cache: Option<PromptCachingConfig>,
81 base_url: Option<String>,
82 timeouts: TimeoutsConfig,
83 model_behavior: Option<ModelConfig>,
84 ) -> Self {
85 use crate::http_client::HttpClientFactory;
86
87 let (prompt_cache_enabled, prompt_cache_settings) = extract_prompt_cache_settings(
88 prompt_cache,
89 |providers| &providers.gemini,
90 |cfg, provider_settings| {
91 cfg.enabled && provider_settings.enabled && provider_settings.mode != GeminiPromptCacheMode::Off
92 },
93 );
94
95 Self {
96 api_key: Arc::from(api_key.as_str()),
97 http_client: HttpClientFactory::for_llm(&timeouts),
98 base_url: Arc::from(
99 override_base_url(urls::GEMINI_API_BASE, base_url, Some(env_vars::GEMINI_BASE_URL)).as_str(),
100 ),
101 model: Arc::from(model.as_str()),
102 prompt_cache_enabled,
103 prompt_cache_settings,
104 timeouts,
105 model_behavior,
106 explicit_cache: explicit_cache::ExplicitCacheState::default(),
107 }
108 }
109
110 #[inline]
113 pub(super) fn handle_http_error(status: reqwest::StatusCode, error_text: &str) -> LLMError {
114 let status_code = status.as_u16();
115
116 if status_code == 401 || status_code == 403 {
118 let formatted_error = error_display::format_llm_error(
119 "Gemini",
120 &format!(
121 "Authentication failed: {error_text}. Check your GOOGLE_API_KEY or GEMINI_API_KEY environment variable."
122 ),
123 );
124 return LLMError::Authentication { message: formatted_error, metadata: None };
125 }
126
127 if is_rate_limit_error(status_code, error_text) {
129 return LLMError::RateLimit { metadata: None };
130 }
131
132 if status_code == 400 {
134 let formatted_error = error_display::format_llm_error("Gemini", &format!("Invalid request: {error_text}"));
135 return LLMError::InvalidRequest { message: formatted_error, metadata: None };
136 }
137
138 let formatted_error = error_display::format_llm_error("Gemini", &format!("HTTP {status}: {error_text}"));
140 LLMError::Provider { message: formatted_error, metadata: None }
141 }
142}