feat(config): derive _KNOWN_ROOT_KEYS from DEFAULT_CONFIG + warn on unknown root keys

Extracted from the config-validation portion of PR #67345 (the token-cost
half was not salvaged). Unknown top-level config keys now warn (naming the
key) instead of being silently ignored; known roots derive from
DEFAULT_CONFIG.keys() plus a small extras set for valid-on-disk roots
absent from defaults.
This commit is contained in:
loes5050 2026-07-19 00:48:53 -07:00 committed by Teknium
parent 336c3b13aa
commit f5bacee274

View file

@ -5493,14 +5493,17 @@ def check_config_version() -> Tuple[int, int]:
# Config structure validation
# =============================================================================
# Fields that are valid at root level of config.yaml
_KNOWN_ROOT_KEYS = {
"_config_version", "model", "providers", "fallback_model",
"fallback_providers", "credential_pool_strategies", "toolsets",
"agent", "terminal", "display", "compression", "delegation",
"auxiliary", "moa", "custom_providers", "context", "memory", "gateway",
"sessions", "streaming", "updates", "mcp_servers",
# Fields that are valid at root level of config.yaml.
# DEFAULT_CONFIG is the single source of truth for documented roots; keep this
# set derived so new defaults (skills, security, browser, …) are accepted
# automatically. A few optional/legacy roots are valid on disk but intentionally
# absent from DEFAULT_CONFIG (omitted when unused / alternate schema forms).
_EXTRA_KNOWN_ROOT_KEYS = {
"custom_providers", # legacy list form; modern equivalent is providers: {}
"fallback_model", # optional single dict or chain list; omitted when disabled
"mcp_servers", # MCP server definitions written by setup/tools flows
}
_KNOWN_ROOT_KEYS = frozenset(DEFAULT_CONFIG.keys()) | _EXTRA_KNOWN_ROOT_KEYS
# Valid fields inside a custom_providers list entry
_VALID_CUSTOM_PROVIDER_FIELDS = {
@ -5655,16 +5658,28 @@ def validate_config_structure(config: Optional[Dict[str, Any]] = None) -> List["
" base_url: https://...",
))
# ── Root-level keys that look misplaced ──────────────────────────────
# ── Unknown / misplaced root-level keys ──────────────────────────────
# Typos like skillz:/secrity: were previously silent (only provider-like
# fields were flagged). Warn on any unknown top-level key so config
# hygiene surfaces without breaking startup.
for key in config:
if key.startswith("_"):
continue
if key not in _KNOWN_ROOT_KEYS and key in _CUSTOM_PROVIDER_LIKE_FIELDS:
if key in _KNOWN_ROOT_KEYS:
continue
if key in _CUSTOM_PROVIDER_LIKE_FIELDS:
issues.append(ConfigIssue(
"warning",
f"Root-level key '{key}' looks misplaced — should it be under 'model:' or inside a 'custom_providers' entry?",
f"Move '{key}' under the appropriate section",
))
else:
issues.append(ConfigIssue(
"warning",
f"Unknown top-level config key '{key}' — it will be ignored",
"Check for typos, or remove the key if it is not a supported config root. "
"Run 'hermes doctor' for more detail.",
))
return issues