Preset API key missing warning banner

keyboardstaff committed Mar 16, 2026 at 03:17 UTC b012fd25ae7a175a4a1b72df0d1e5bb0d131c05f
1 file changed +57 -19
extensions/python/banners/_20_missing_api_key.py
+57 -19
@@ -35,22 +35,60 @@ class MissingApiKeyCheck(Extension):
35 "provider": provider,
36 })
37
38 - if not missing_providers:
39 - return
40 -
41 - model_list = ", ".join(
42 - f"{p['model_type']} ({p['provider']})" for p in missing_providers
43 - )
44 -
45 - banners.append({
46 - "id": "missing-api-key",
47 - "type": "error",
48 - "priority": 100,
49 - "title": "Missing LLM API Key for current settings",
50 - "html": f"""No API key configured for: {model_list}.<br>
51 - Agent Zero will not be able to function properly unless you provide an API key or change your settings.<br>
52 - <a href="#" onclick="(async()=>{{await import('/components/plugins/plugin-settings-store.js');const s=Alpine.store('pluginSettingsPrototype');if(s&amp;&amp;s.open){{await s.open('_model_config',{{perProjectConfig:true,perAgentConfig:true}});}}openModal('components/plugins/plugin-settings.html');}})();return false;">
53 - Configure model settings</a>""",
54 - "dismissible": False,
55 - "source": "backend"
56 - })
38 + if missing_providers:
39 + model_list = ", ".join(
40 + f"{p['model_type']} ({p['provider']})" for p in missing_providers
41 + )
42 +
43 + banners.append({
44 + "id": "missing-api-key",
45 + "type": "error",
46 + "priority": 100,
47 + "title": "Missing LLM API Key for current settings",
48 + "html": f"""No API key configured for: {model_list}.<br>
49 + Agent Zero will not be able to function properly unless you provide an API key or change your settings.<br>
50 + <a href="#" onclick="(async()=>{{await import('/components/plugins/plugin-settings-store.js');const s=Alpine.store('pluginSettingsPrototype');if(s&amp;&amp;s.open){{await s.open('_model_config',{{perProjectConfig:true,perAgentConfig:true}});}}openModal('components/plugins/plugin-settings.html');}})();return false;">
51 + Configure model settings</a>""",
52 + "dismissible": False,
53 + "source": "backend"
54 + })
55 +
56 + # Check preset providers for missing API keys (warning level)
57 + if cfg.get("chat_model", {}).get("allow_chat_override"):
58 + preset_missing = []
59 + seen = set()
60 + for preset in cfg.get("model_presets", []):
61 + preset_name = preset.get("name", "Unnamed")
62 + for slot_key, slot_label in [("chat", "Main"), ("utility", "Utility")]:
63 + slot = preset.get(slot_key, {})
64 + provider = slot.get("provider", "")
65 + if not provider:
66 + continue
67 + provider_lower = provider.lower()
68 + if provider_lower in self.LOCAL_PROVIDERS:
69 + continue
70 + # Skip if already covered by default checks
71 + if provider_lower in seen:
72 + continue
73 + # Skip if preset has its own api_key
74 + if slot.get("api_key", "").strip():
75 + continue
76 + api_key = models.get_api_key(provider_lower)
77 + if not (api_key and api_key.strip() and api_key != "None"):
78 + seen.add(provider_lower)
79 + preset_missing.append(f"{preset_name}/{slot_label} ({provider})")
80 +
81 + if preset_missing:
82 + preset_list = ", ".join(preset_missing)
83 + banners.append({
84 + "id": "missing-preset-api-key",
85 + "type": "warning",
86 + "priority": 90,
87 + "title": "Missing API Key for model presets",
88 + "html": f"""No API key configured for preset models: {preset_list}.<br>
89 + These presets will not work until you provide the required API keys.<br>
90 + <a href="#" onclick="openModal('/plugins/_model_config/webui/api-keys.html');return false;">
91 + Manage API Keys</a>""",
92 + "dismissible": True,
93 + "source": "backend"
94 + })