Remove obsolete preset API key warning

Stop scanning every global model preset for missing credentials when building Welcome banners. Keep readiness scoped to the effective model configuration so first-send setup remains in the deferred chat gate. Add regression coverage for unused OpenRouter presets and document the boundary.

Alessandro committed Jul 28, 2026 at 21:28 UTC 4b906561cd19ab6b625c69d814ad550b49afe6f3
3 files changed +9 -52
plugins/_model_config/AGENTS.md
+1
@@ -19,6 +19,7 @@
19 - Preserve scoped plugin resolution order and fall back invalid or missing scope/chat references to `Default`.
20 - Project Settings `llm` payloads are owned here through the generic `helpers.projects` project extension-data hooks; keep project helper code agnostic to `_model_config` paths, presets, and inheritance rules.
21 - Keep provider metadata and API-key checks safe around secrets.
22 +- Check API-key readiness only for the effective model configuration; unused global presets must not produce Welcome-screen warnings.
23 - Coordinate OAuth-backed providers with `_oauth` instead of hardcoding provider-specific auth here.
24 - `model_config_get` exposes `model_configured` as a derived chat-model readiness flag from provider, model name, and API-key availability.
25 - Non-default presets may inherit omitted slots or durable tuning from `Default`, but must replace or clear per-slot `kwargs` so provider-specific extra params never leak across model providers.
plugins/_model_config/extensions/python/banners/_20_missing_api_key.py
-48
@@ -5,7 +5,6 @@ from plugins._model_config.helpers import model_config
5 class MissingApiKeyCheck(Extension):
6 """Check if API keys are configured for selected model providers."""
7
8 - LOCAL_PROVIDERS = {"ollama", "lm_studio", "llama_cpp", "omlx", "vllm"}
8 ONBOARDING_MODAL_PATH = "/plugins/_onboarding/webui/onboarding.html"
9 ONBOARDING_CTA_TEXT = "Start Onboarding"
10
@@ -27,50 +26,3 @@ class MissingApiKeyCheck(Extension):
26 # For programmatic clients (e.g. chat composer) reusing this banner pipeline
27 "missing_providers": missing_providers,
28 })
30 -
31 - # Check preset providers for missing API keys (warning level)
32 - preset_missing = []
33 - seen = set()
34 - for preset in model_config.get_presets():
35 - preset_name = preset.get("name", "Unnamed")
36 - for slot_key, slot_label, model_type in [
37 - ("chat", "Main", "chat"),
38 - ("utility", "Utility", "chat"),
39 - ("embedding", "Embedding", "embedding"),
40 - ]:
41 - slot = preset.get(slot_key, {})
42 - provider = slot.get("provider", "")
43 - if not provider:
44 - continue
45 - provider_lower = provider.lower()
46 - identity = (provider_lower, model_type)
47 - if (
48 - provider_lower in self.LOCAL_PROVIDERS
49 - or model_type == "embedding"
50 - and provider_lower in model_config.LOCAL_EMBEDDING
51 - or identity in seen
52 - ):
53 - continue
54 - if slot.get("api_key", "").strip():
55 - continue
56 - if not model_config.has_provider_api_key(
57 - provider_lower,
58 - model_type=model_type,
59 - ):
60 - seen.add(identity)
61 - preset_missing.append(f"{preset_name}/{slot_label} ({provider})")
62 -
63 - if preset_missing:
64 - preset_list = ", ".join(preset_missing)
65 - banners.append({
66 - "id": "missing-preset-api-key",
67 - "type": "warning",
68 - "priority": 90,
69 - "title": "Missing API Key for model presets",
70 - "html": f"""No API key configured for preset models: {preset_list}.<br>
71 - These presets will not work until you provide the required API keys.""",
72 - "cta_text": self.ONBOARDING_CTA_TEXT,
73 - "cta_action": f"open-modal:{self.ONBOARDING_MODAL_PATH}",
74 - "dismissible": True,
75 - "source": "backend"
76 - })
tests/test_model_config_api_keys.py
+8 -4
@@ -90,16 +90,23 @@ def test_chat_model_configured_requires_identity_and_key(monkeypatch):
90
91
92 @pytest.mark.asyncio
93 -async def test_missing_api_key_banner_exposes_missing_providers(monkeypatch):
93 +async def test_missing_api_key_banner_exposes_only_effective_missing_providers(monkeypatch):
94 from plugins._model_config.helpers import model_config
95
96 fake = [{"model_type": "Chat Model", "provider": "openai"}]
97 monkeypatch.setattr(model_config, "get_missing_api_key_providers", lambda: fake)
98 + monkeypatch.setattr(
99 + model_config,
100 + "get_presets",
101 + lambda: [{"name": "Efficiency", "chat": {"provider": "openrouter"}}],
102 + )
103 + monkeypatch.setattr(model_config, "has_provider_api_key", lambda *args, **kwargs: False)
104
105 banners = []
106 await missing_key_banner.MissingApiKeyCheck(agent=None).execute(
107 banners=banners, frontend_context={}
108 )
109 + assert [banner["id"] for banner in banners] == ["missing-api-key"]
110 row = next(b for b in banners if b.get("id") == "missing-api-key")
111 assert row.get("missing_providers") == fake
112 assert row["cta_text"] == "Start Onboarding"
@@ -515,9 +522,6 @@ def test_provider_key_modes_for_local_and_ollama_cloud():
522 assert model_config.provider_requires_api_key("vllm") is False
523 assert model_config.provider_requires_api_key("other") is False
524 assert model_config.provider_requires_api_key("ollama_cloud") is True
518 - assert "llama_cpp" in missing_key_banner.MissingApiKeyCheck.LOCAL_PROVIDERS
519 - assert "omlx" in missing_key_banner.MissingApiKeyCheck.LOCAL_PROVIDERS
520 - assert "vllm" in missing_key_banner.MissingApiKeyCheck.LOCAL_PROVIDERS
525
526
527 def test_local_provider_defaults_are_docker_friendly():