Skip to content

fix(model-catalog): parse bool-ish config values - #35469

Open
Pluviobyte wants to merge 2 commits into
NousResearch:mainfrom
Pluviobyte:fix/model-catalog-config-coercion
Open

Pluviobyte wants to merge 2 commits into
NousResearch:mainfrom
Pluviobyte:fix/model-catalog-config-coercion

Conversation

@Pluviobyte

@Pluviobyte Pluviobyte commented May 30, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Parse model_catalog.enabled with the shared bool-ish config parser so string "false" disables the remote catalog.
  • Parse model_catalog.ttl_hours explicitly so numeric strings work, explicit 0 is preserved, and malformed values fall back safely.

Problem

model_catalog config used raw Python coercion:

  • enabled used bool(value), so "false" was treated as enabled.
  • ttl_hours used float(raw.get("ttl_hours") or DEFAULT_TTL_HOURS), so explicit zero was replaced with the default TTL.
  • malformed TTL values could raise during config loading instead of falling back gracefully.

This made documented config values unreliable, especially when users or UI layers stored scalar values as strings.

Fix approach

  • Parse enabled with the existing is_truthy_value(..., default=True) helper.
  • Add _parse_ttl_hours() to handle None, empty string, numeric strings, explicit 0, non-finite values, and malformed values consistently.
  • Preserve the existing default of 24 hours when TTL is absent or invalid.
  • Add focused tests for enabled: "false", ttl_hours: "0", and invalid TTL fallback.

Why this is safe

The change only normalizes config inputs before the existing catalog/cache logic runs. Default behavior remains unchanged for absent config, while explicit user intent is respected.

Test plan

  • uv run python -m pytest -o addopts='' tests/hermes_cli/test_model_catalog.py -q
  • uv run ruff check hermes_cli/model_catalog.py tests/hermes_cli/test_model_catalog.py

Co-authored-by: Cursor <cursoragent@cursor.com>

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Verdict: Approved (no blocking issues)

Looks Good

  • Clean fix: replaces raw bool() coercion with is_truthy_value() so the string "false" correctly disables the model catalog
  • _parse_ttl_hours() correctly handles the explicit-zero case (float(raw.get(...) or DEFAULT) was broken for 0 since 0 or X yields X)
  • Uses the shared is_truthy_value from utils.py — consistent with the rest of the codebase
  • Good defensive handling of NaN/Inf via math.isfinite()
  • Test coverage for all three branches of _parse_ttl_hours: string zero preserved, string "false" for enabled, and invalid values falling back to default

Suggestions (non-blocking)

  1. The _parse_ttl_hours function could be tested with a case for negative values — float("-5") passes isfinite and would silently return a negative TTL. In practice _load_catalog_config only uses it for downstream comparisons so it's not harmful, but a clamp or explicit guard would be more defensive.
  2. math is imported for a single isfinite call. Python's isfinite is fast, so no issue — just noting it adds one more import to the module's namespace.

Tests

  • test_boolish_disabled_string_is_respected — covers the core bug
  • test_ttl_hours_string_and_zero_are_preserved — covers the 0 edge case
  • test_invalid_ttl_hours_falls_back_to_default — covers the fallback path
  • All three tests use isolated_home fixture + patch on load_config, which is the right pattern

Reviewed by Hermes Agent

def _parse_ttl_hours(value: Any) -> float:
"""Parse ``model_catalog.ttl_hours`` while preserving explicit zero."""
if value is None or value == "":
return float(DEFAULT_TTL_HOURS)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Suggestion (non-blocking): Consider rejecting negative TTL values here. _parse_ttl_hours(-5) returns -5.0 which would produce undefined behavior downstream. A simple max(0.0, ttl) after the isfinite check would handle it.

@alt-glitch alt-glitch added type/bug Something isn't working comp/cli CLI entry point, hermes_cli/, setup wizard area/config Config system, migrations, profiles P3 Low — cosmetic, nice to have labels May 30, 2026
Co-authored-by: Cursor <cursoragent@cursor.com>
@Pluviobyte

Copy link
Copy Markdown
Contributor Author

Thanks for the review. I addressed the non-blocking TTL suggestion in a follow-up commit:

  • _parse_ttl_hours() now clamps negative finite values to 0.0.
  • Added test_negative_ttl_hours_clamps_to_zero.

Validation after the update:

uv run python -m pytest -o addopts='' tests/hermes_cli/test_model_catalog.py -q
32 passed in 5.66s

uv run ruff check hermes_cli/model_catalog.py tests/hermes_cli/test_model_catalog.py
All checks passed!

@teknium1

Copy link
Copy Markdown
Collaborator

Thanks for the focused config-normalization fix. Current main still has the reported behavior at hermes_cli/model_catalog.py:107-110: bool("false") enables the catalog, and float(raw.get("ttl_hours") or DEFAULT_TTL_HOURS) discards explicit zero and can raise on malformed values. The proposed shared-parser use and _parse_ttl_hours() directly address those paths, and the added tests cover string false, zero, invalid input, and the negative-TTL follow-up.

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants