|
27 | 27 |
|
28 | 28 |
|
29 | 29 | class LiteLLMCaller: |
30 | | - """Clean interface for all LLM calling patterns using LiteLLM.""" |
| 30 | + """Clean interface for all LLM calling patterns using LiteLLM. |
| 31 | +
|
| 32 | + Note: this class may set provider-specific LLM API key environment |
| 33 | + variables (for example ``OPENAI_API_KEY``) to maintain compatibility |
| 34 | + with LiteLLM's internal provider detection. These mutations are |
| 35 | + best-effort only and are not intended to provide strong isolation |
| 36 | + guarantees in multi-tenant or highly concurrent environments. |
| 37 | + """ |
31 | 38 |
|
32 | 39 | def __init__(self, llm_config=None, debug_mode: bool = False): |
33 | 40 | """Initialize with optional config dependency injection.""" |
@@ -85,20 +92,40 @@ def _get_model_kwargs(self, model_name: str, temperature: Optional[float] = None |
85 | 92 | except ValueError as e: |
86 | 93 | logger.error(f"Failed to resolve API key for model {model_name}: {e}") |
87 | 94 | raise |
88 | | - |
| 95 | + |
89 | 96 | if api_key: |
| 97 | + # Always pass api_key to LiteLLM for all providers |
| 98 | + kwargs["api_key"] = api_key |
| 99 | + |
| 100 | + # Additionally set provider-specific env vars for LiteLLM's internal logic |
| 101 | + def _set_env_var_if_needed(env_key: str, value: str) -> None: |
| 102 | + existing = os.environ.get(env_key) |
| 103 | + if existing is None: |
| 104 | + os.environ[env_key] = value |
| 105 | + elif existing != value: |
| 106 | + logger.warning( |
| 107 | + "Overwriting existing environment variable %s for model %s", |
| 108 | + env_key, |
| 109 | + model_name, |
| 110 | + ) |
| 111 | + os.environ[env_key] = value |
| 112 | + |
90 | 113 | if "openrouter" in model_config.model_url: |
91 | | - kwargs["api_key"] = api_key |
92 | | - # LiteLLM will automatically set the correct env var |
93 | | - os.environ["OPENROUTER_API_KEY"] = api_key |
| 114 | + _set_env_var_if_needed("OPENROUTER_API_KEY", api_key) |
94 | 115 | elif "openai" in model_config.model_url: |
95 | | - os.environ["OPENAI_API_KEY"] = api_key |
| 116 | + _set_env_var_if_needed("OPENAI_API_KEY", api_key) |
96 | 117 | elif "anthropic" in model_config.model_url: |
97 | | - os.environ["ANTHROPIC_API_KEY"] = api_key |
| 118 | + _set_env_var_if_needed("ANTHROPIC_API_KEY", api_key) |
98 | 119 | elif "google" in model_config.model_url: |
99 | | - os.environ["GOOGLE_API_KEY"] = api_key |
| 120 | + _set_env_var_if_needed("GOOGLE_API_KEY", api_key) |
100 | 121 | elif "cerebras" in model_config.model_url: |
101 | | - os.environ["CEREBRAS_API_KEY"] = api_key |
| 122 | + _set_env_var_if_needed("CEREBRAS_API_KEY", api_key) |
| 123 | + else: |
| 124 | + # Custom endpoint - set OPENAI_API_KEY as fallback for |
| 125 | + # OpenAI-compatible endpoints. This is a heuristic and |
| 126 | + # only updates the env var if it is unset or already |
| 127 | + # matches the same value. |
| 128 | + _set_env_var_if_needed("OPENAI_API_KEY", api_key) |
102 | 129 |
|
103 | 130 | # Set custom API base for non-standard endpoints |
104 | 131 | if hasattr(model_config, 'model_url') and model_config.model_url: |
|
0 commit comments