feat(models): add @extensible decorator to get_api_key()

Add @extensible decorator to get_api_key() in models.py, enabling plugins to intercept or replace the API key resolution logic for any LLM provider. Currently, get_api_key() resolves API keys exclusively from OS environment variables via os.getenv(). This means external secrets backends (OpenBao/Vault, AWS Secrets Manager, Azure Key Vault, etc.) cannot provide API keys without injecting them into the process environment. With @extensible, a plugin can intercept the start hook to resolve API keys from any backend, falling through to the default dotenv behaviour when no plugin is active. No behavioural change for existing users — the decorator only adds extension hooks around the existing function. Note: the companion fix for the circular import this previously required (deferred import in settings.py) is submitted separately in PR #1295.

Deimos AI committed Mar 14, 2026 at 09:01 UTC 7d9ec2ce51f8f4ec701fa64b08f804e2d748094a
1 file changed +2
models.py
+2
@@ -26,6 +26,7 @@ from helpers.providers import ModelType as ProviderModelType, get_provider_confi
26 from helpers.rate_limiter import RateLimiter
27 from helpers.tokens import approximate_tokens
28 from helpers import dirty_json
29 +from helpers.extension import extensible # extensible: allows plugins to intercept get_api_key()
30
31 from langchain_core.language_models.chat_models import SimpleChatModel
32 from langchain_core.outputs.chat_generation import ChatGenerationChunk
@@ -198,6 +199,7 @@ rate_limiters: dict[str, RateLimiter] = {}
199 api_keys_round_robin: dict[str, int] = {}
200
201
202 +@extensible
203 def get_api_key(service: str) -> str:
204 # get api key for the service
205 key = (