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