Skip to content

fix(config): coerce list/dict literals in 'hermes config set' - #79479

Closed
cadamec wants to merge 1 commit into
NousResearch:mainfrom
cadamec:fix/config-set-list-coercion
Closed

fix(config): coerce list/dict literals in 'hermes config set'#79479
cadamec wants to merge 1 commit into
NousResearch:mainfrom
cadamec:fix/config-set-list-coercion

Conversation

@cadamec

@cadamec cadamec commented Aug 5, 2026

Copy link
Copy Markdown

What does this PR do?

hermes config set stores list/dict literals as raw strings, silently defeating every list-gated reader.

The bug

set_config_value (hermes_cli/config.py) only coerces bool/int/float. A list literal like

hermes config set platform_toolsets.discord '["clarify","file"]'

is written to config.yaml as the string '["clarify","file"]'. Every reader gated on isinstance(..., list)_get_platform_tools, _get_enabled_set, _get_disabled_set — silently ignores it and falls back to its default. The setting looks saved (the echo says ✓, it's in the YAML) but never takes effect. This is the config half of #57063, which reported a deployment running for weeks with a zero-tool agent because platform_toolsets had been set this way.

The fix

Values whose first non-whitespace char is [ or { are parsed with yaml.safe_load. Only real list/dict results are accepted; anything else (malformed YAML, a string like "[unterminated" that happens to parse to a scalar) warns on stderr and keeps the legacy string behavior. Bool/int/float coercion and string-typed defaults (approvals.mode: off staying a string) are untouched.

Tests

tests/hermes_cli/test_config_set_list_values.py:

  • list literals stored as real lists (double-quoted, single-quoted, YAML flow style)
  • dict literals stored as real dicts
  • malformed literals warn and keep legacy string behavior (7 parametrized cases)
  • bool/int/float coercion preserved

Affected suites: 95 passed (test_config_set_list_values.py + test_set_config_value.py).

Related

set_config_value only coerced bool/int/float. `hermes config set
platform_toolsets.discord '["clarify","file"]'` was stored as a raw
string, and every reader gated on isinstance(..., list)
(_get_platform_tools, _get_enabled_set, _get_disabled_set) silently
ignored it and fell back to its default — the setting looked saved but
never took effect (NousResearch#57063).

Values starting with [ or { are now parsed with yaml.safe_load; only real
list/dict results are accepted. Non-list/dict results and YAML errors warn
on stderr and keep the legacy string behavior. Scalar coercion
(bool/int/float) is unchanged.
cadamec added a commit to cadamec/hermes-agent that referenced this pull request Aug 5, 2026
The a2a client-tool fix and the config coercion fix are unrelated bugs
that happened to land in one PR. Per triage feedback, this PR is now
a2a-only; the config half lives in NousResearch#79479.
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/cli CLI entry point, hermes_cli/, setup wizard area/config Config system, migrations, profiles sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades duplicate This issue or pull request already exists labels Aug 5, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Duplicate of #57063: both patches correct hermes config set persisting list/dict literals as strings, which silently defeats list-gated configuration readers.

@cadamec

cadamec commented Aug 5, 2026

Copy link
Copy Markdown
Author

Fair flag, but this isn't a clean duplicate of #57063 — and my own empirical check on #57063 (Aug 5) shows why.

#57063 bundles two distinct failure modes, and the primary one no longer reproduces on current main. Commit 52d9e57 ("feat: dynamic toolset generation for plugin platforms") already fixed the "eight platforms resolve to zero tools" case — I verified all eight now resolve to the full 61-tool core toolset after discovery, in any process. That half of #57063 is dead.

What still reproduces live are the two remaining halves, and #79479 targets one of them: hermes config set persisting list/dict literals as strings (config.py:4903-4914, bool/int/float-only coercion), which silently defeats every list-gated reader. #57063 is also sitting CONFLICTING (stale) and its body still describes the now-obsolete zero-tools mode.

So rather than a duplicate of a healthy PR, this is the current, rebased, tested fix for the one live half of #57063 — a successor, not a clone. The a2a half is tracked separately in #78050. Happy to rebase/retarget or close #57063-scope accordingly; goal is the fix landing on current main.

@cadamec

cadamec commented Aug 5, 2026

Copy link
Copy Markdown
Author

Correction: the triage bot was right and my earlier reply was wrong. I checked #57063's diff (not just its body/merge state) and it already contains this exact fix — same yaml.safe_load + isinstance(parsed, (list, dict)) approach in hermes_cli/config.py, same test file. I duplicated it without knowing.

Closing this as a duplicate. The real gap is that #57063 is stale (CONFLICTING with main) and its body still describes the 8-bundle half that 52d9e57 already made obsolete — I'm going to rebase it onto current main and narrow it to the live config half, preserving the original author's work per the contribution rubric.

@cadamec

cadamec commented Aug 5, 2026

Copy link
Copy Markdown
Author

Closing as duplicate of #57063 (see correction above).

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 duplicate This issue or pull request already exists P2 Medium — degraded but workaround exists 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.

2 participants