@@ -235,26 +235,149 @@ def resolve_provider(
235235 model = cfg ["model" ]
236236
237237 if provider_name is not None :
238+ # Validate configuration before attempting to create provider
239+ warnings = validate_provider_config (provider_name )
240+ if warnings :
241+ for warning in warnings :
242+ err_console .print (f"[yellow]Warning:[/yellow] { warning } " )
243+ # For explicit provider requests, we still try to create it
244+ # The provider constructor will fail if the API key is actually required
245+
238246 kwargs : dict [str , Any ] = {}
239247 if model :
240248 kwargs ["model" ] = model
249+
250+ # Pass API key from environment if available
251+ if provider_name == "anthropic" and os .environ .get ("ANTHROPIC_API_KEY" ):
252+ kwargs ["api_key" ] = os .environ ["ANTHROPIC_API_KEY" ]
253+ elif provider_name == "openai" and os .environ .get ("OPENAI_API_KEY" ):
254+ kwargs ["api_key" ] = os .environ ["OPENAI_API_KEY" ]
255+ elif provider_name == "gemini" and (
256+ os .environ .get ("GEMINI_API_KEY" ) or os .environ .get ("GOOGLE_API_KEY" )
257+ ):
258+ kwargs ["api_key" ] = os .environ .get ("GEMINI_API_KEY" ) or os .environ .get ("GOOGLE_API_KEY" )
259+ elif provider_name == "ollama" and os .environ .get ("OLLAMA_BASE_URL" ):
260+ kwargs ["base_url" ] = os .environ ["OLLAMA_BASE_URL" ]
261+
241262 return get_provider (provider_name , ** kwargs )
242263
243264 # Auto-detect from env vars
244- if os .environ .get ("ANTHROPIC_API_KEY" ):
245- kwargs = {"model" : model } if model else {}
265+ if os .environ .get ("ANTHROPIC_API_KEY" ) and os .environ ["ANTHROPIC_API_KEY" ].strip ():
266+ kwargs = (
267+ {"model" : model , "api_key" : os .environ ["ANTHROPIC_API_KEY" ]}
268+ if model
269+ else {"api_key" : os .environ ["ANTHROPIC_API_KEY" ]}
270+ )
246271 return get_provider ("anthropic" , ** kwargs )
247- if os .environ .get ("OPENAI_API_KEY" ):
248- kwargs = {"model" : model } if model else {}
272+ if os .environ .get ("OPENAI_API_KEY" ) and os .environ ["OPENAI_API_KEY" ].strip ():
273+ kwargs = (
274+ {"model" : model , "api_key" : os .environ ["OPENAI_API_KEY" ]}
275+ if model
276+ else {"api_key" : os .environ ["OPENAI_API_KEY" ]}
277+ )
249278 return get_provider ("openai" , ** kwargs )
250- if os .environ .get ("OLLAMA_BASE_URL" ):
251- kwargs = {"model" : model } if model else {}
279+ if os .environ .get ("OLLAMA_BASE_URL" ) and os .environ ["OLLAMA_BASE_URL" ].strip ():
280+ kwargs = (
281+ {"model" : model , "base_url" : os .environ ["OLLAMA_BASE_URL" ]}
282+ if model
283+ else {"base_url" : os .environ ["OLLAMA_BASE_URL" ]}
284+ )
252285 return get_provider ("ollama" , ** kwargs )
253- if os .environ .get ("GEMINI_API_KEY" ) or os .environ .get ("GOOGLE_API_KEY" ):
254- kwargs = {"model" : model } if model else {}
286+ if (os .environ .get ("GEMINI_API_KEY" ) and os .environ ["GEMINI_API_KEY" ].strip ()) or (
287+ os .environ .get ("GOOGLE_API_KEY" ) and os .environ ["GOOGLE_API_KEY" ].strip ()
288+ ):
289+ api_key = os .environ .get ("GEMINI_API_KEY" ) or os .environ .get ("GOOGLE_API_KEY" )
290+ kwargs = {"model" : model , "api_key" : api_key } if model else {"api_key" : api_key }
255291 return get_provider ("gemini" , ** kwargs )
256292
257293 raise click .ClickException (
258294 "No provider configured. Use --provider, set REPOWISE_PROVIDER, "
259- "or set ANTHROPIC_API_KEY / OPENAI_API_KEY / OLLAMA_BASE_URL / GEMINI_API_KEY."
295+ "or set ANTHROPIC_API_KEY / OPENAI_API_KEY / OLLAMA_BASE_URL / GEMINI_API_KEY / GOOGLE_API_KEY ."
260296 )
297+
298+
299+ # ---------------------------------------------------------------------------
300+ # Provider validation
301+ # ---------------------------------------------------------------------------
302+
303+
304+ def validate_provider_config (provider_name : str | None = None ) -> list [str ]:
305+ """Validate that required API keys/environment variables are set for the provider.
306+
307+ Args:
308+ provider_name: The provider name to validate. If None, checks all possible providers.
309+
310+ Returns:
311+ List of warning messages for missing or invalid configuration.
312+ Empty list means all required config is present.
313+ """
314+ import os
315+
316+ warnings = []
317+
318+ def _is_env_var_set (var_name : str ) -> bool :
319+ """Check if environment variable is set and non-empty."""
320+ value = os .environ .get (var_name )
321+ return value is not None and value .strip () != ""
322+
323+ def _is_env_var_exists (var_name : str ) -> bool :
324+ """Check if environment variable exists (even if empty)."""
325+ return var_name in os .environ
326+
327+ # Define required environment variables for each provider
328+ provider_env_vars = {
329+ "anthropic" : ["ANTHROPIC_API_KEY" ],
330+ "openai" : ["OPENAI_API_KEY" ],
331+ "gemini" : ["GEMINI_API_KEY" , "GOOGLE_API_KEY" ], # Either one
332+ "ollama" : ["OLLAMA_BASE_URL" ],
333+ "litellm" : ["LITELLM_API_KEY" ], # May need others depending on backend
334+ }
335+
336+ if provider_name :
337+ # Validate specific provider
338+ if provider_name not in provider_env_vars :
339+ warnings .append (f"Unknown provider '{ provider_name } ' - cannot validate configuration" )
340+ return warnings
341+
342+ env_vars = provider_env_vars [provider_name ]
343+ missing_vars = []
344+
345+ if provider_name == "gemini" :
346+ # Special case: either GEMINI_API_KEY or GOOGLE_API_KEY
347+ if not (_is_env_var_set ("GEMINI_API_KEY" ) or _is_env_var_set ("GOOGLE_API_KEY" )):
348+ missing_vars = env_vars
349+ else :
350+ for var in env_vars :
351+ if not _is_env_var_set (var ):
352+ missing_vars .append (var )
353+
354+ if missing_vars :
355+ warnings .append (
356+ f"Provider '{ provider_name } ' requires environment variables: { ', ' .join (missing_vars )} "
357+ )
358+ else :
359+ # Check all providers - warn about any that could be configured but are missing keys
360+ for name , env_vars in provider_env_vars .items ():
361+ if name == "gemini" :
362+ if os .environ .get ("REPOWISE_PROVIDER" ) == "gemini" and not (
363+ _is_env_var_set ("GEMINI_API_KEY" ) or _is_env_var_set ("GOOGLE_API_KEY" )
364+ ):
365+ # Only warn if it looks like they might be trying to use gemini
366+ warnings .append (
367+ "Provider 'gemini' requires GEMINI_API_KEY or GOOGLE_API_KEY environment variable"
368+ )
369+ continue
370+
371+ missing = [var for var in env_vars if not _is_env_var_set (var )]
372+ if missing :
373+ # Only warn if this provider is explicitly requested OR
374+ # if the env var exists but is invalid (empty)
375+ env_var_exists = any (_is_env_var_exists (var ) for var in env_vars )
376+ explicitly_requested = os .environ .get ("REPOWISE_PROVIDER" ) == name
377+
378+ if explicitly_requested or env_var_exists :
379+ warnings .append (
380+ f"Provider '{ name } ' requires environment variables: { ', ' .join (missing )} "
381+ )
382+
383+ return warnings
0 commit comments