Add Pydantic validation model for config.json#8
Conversation
Agent-Logs-Url: https://github.com/HiLleywyn/Hydra/sessions/60fe845f-c411-48b8-bef0-7ffef9c2e25f Co-authored-by: HiLleywyn <97213385+HiLleywyn@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces a typed, validated configuration layer (Pydantic v2) for hydra/config.json and updates the runtime/entrypoint to use the validated model instead of raw dict access, so configuration errors surface at startup.
Changes:
- Added
hydra/config_schema.pywith Pydantic models for config sections and adapter discriminated unions. - Updated
hydra/main.pyto load/validate config into aHydraConfigand use typed attribute access. - Updated
hydra/core/runtime.pyto acceptHydraConfigand replace.get()chains with typed access (dumping adapter configs back to dict for existing adapter constructors).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| hydra/config_schema.py | Adds Pydantic schema models for full config validation and typed access. |
| hydra/main.py | Parses config.json into HydraConfig and uses typed config fields. |
| hydra/core/runtime.py | Updates runtime to consume HydraConfig and uses model-backed values throughout initialization. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @field_validator("log_level") | ||
| @classmethod | ||
| def validate_log_level(cls, v: str) -> str: | ||
| valid = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"} | ||
| upper = v.upper() | ||
| if upper not in valid: | ||
| raise ValueError(f"log_level must be one of {valid}, got '{v}'") | ||
| return upper |
There was a problem hiding this comment.
FrameworkConfig.validate_log_level() hard-codes a limited set of level names. This will reject valid logging level aliases like WARN/FATAL (and NOTSET), which were previously accepted by setup_logging() and are part of Python’s logging level name mapping. Consider validating against logging._nameToLevel (or a curated list derived from it) and make the error message deterministic (avoid embedding a set, whose ordering is not stable).
| class HydraConfig(BaseModel): | ||
| framework: FrameworkConfig = FrameworkConfig() | ||
| database: DatabaseConfig = DatabaseConfig() | ||
| dashboard: DashboardConfig = DashboardConfig() | ||
| context_bus: ContextBusConfig = ContextBusConfig() | ||
| profiles: list[ProfileConfig] = [] | ||
| adapters: dict[str, AdapterConfig] = {} |
There was a problem hiding this comment.
The new schema models don’t forbid unknown/extra keys, so typos in config.json (e.g., dashbaord) will be silently ignored by Pydantic’s default extra handling, which undermines the goal of surfacing misconfiguration early. Consider setting model_config = ConfigDict(extra="forbid") on HydraConfig (and/or the section models) so unexpected keys produce a ValidationError.
| with open(path) as f: | ||
| return json.load(f) | ||
| raw = json.load(f) | ||
| try: | ||
| return HydraConfig.model_validate(raw) | ||
| except ValidationError as exc: | ||
| logging.error("Invalid configuration: %s", exc) | ||
| sys.exit(1) |
There was a problem hiding this comment.
load_config() now catches ValidationError, but invalid JSON (e.g., a trailing comma) will still raise json.JSONDecodeError and crash with a stack trace rather than a clear startup error. Consider catching json.JSONDecodeError (and potentially OSError) to log a concise message including the config path before exiting.
config.jsonwas loaded as a rawdictand accessed via.get()chains throughout the codebase, deferring misconfiguration errors to runtime callsites rather than surfacing them at startup.New:
hydra/config_schema.pyTyped Pydantic v2 models for every config section:
FrameworkConfig—log_levelvalidated against Python's logging setDashboardConfig—portboundedge=1, le=65535ContextBusConfig,DatabaseConfig,ProfileConfig"type"(MockAdapterConfig,DiscordAdapterConfig,OpenAIAdapterConfig,MCPAdapterConfig) — with field-level constraints (e.g.temperaturecapped to the OpenAI API range0.0–2.0)HydraConfig— top-level composite with safe defaults for every sectionhydra/main.pyload_config()return type changed fromdicttoHydraConfig; parses viamodel_validateand catchesValidationErrorspecificallyrun()andmain()use typed attribute access (config.dashboard.enabled,config.framework.log_level, etc.)hydra/core/runtime.pyHydraRuntime.__init__signature updated toHydraConfig.get()chains replaced with direct attribute accessmodel_dump()to preserve the adapter interface