Skip to content

fix(gateway/hooks): normalize scalar events to single-item list - #37486

Open
developers-universe-1 wants to merge 1 commit into
NousResearch:mainfrom
developers-universe-1:fix/hooks-scalar-events-normalize
Open

fix(gateway/hooks): normalize scalar events to single-item list#37486
developers-universe-1 wants to merge 1 commit into
NousResearch:mainfrom
developers-universe-1:fix/hooks-scalar-events-normalize

Conversation

@developers-universe-1

Copy link
Copy Markdown

Summary

Fixes #11902

When a HOOK.yaml declared events as a scalar string (e.g. events: agent:start), the loader iterated over the string character-by-character, registering handlers for individual characters instead of the intended event name.

Changes

  • gateway/hooks.py: After reading manifest.get('events', []), check isinstance(events, str) and wrap in a list before iterating.
  • tests/test_gateway_hooks.py: Regression tests covering scalar string, list, and empty/missing events cases.

Verification

python -m pytest tests/test_gateway_hooks.py -v
# 3 passed

Issue NousResearch#11902: When a HOOK.yaml declared events as a scalar string
(e.g. events: agent:start), the loader iterated over the string
character-by-character, registering handlers for individual chars
instead of the intended event name.

Fix: After reading manifest.get('events', []), check isinstance(events, str)
and wrap in a list before iterating.

Also adds regression tests covering scalar string, list, and empty/missing
events cases.

Fixes NousResearch#11902

@combatsheep combatsheep 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.

Scalar values are normalized only when needed, and the regression tests cover scalar/list/missing manifest cases cleanly. Approving.

@alt-glitch alt-glitch added type/bug Something isn't working comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins P2 Medium — degraded but workaround exists labels Jun 2, 2026

@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

Clean fix: normalizes scalar string events values in HOOK.yaml manifests to single-item lists, preventing the character-by-character iteration bug. Includes a comprehensive new test file (test_gateway_hooks.py) with 3 well-written tests covering scalar, list, and empty events.

✅ Looks Good

  • One-line fix in gateway/hooks.py — elegant
  • 100-line test file covering the regression
  • Test verifies both the fix and that existing list behavior is preserved
  • Well-documented test with regression reference (Issue #11902)

Reviewed by Hermes Agent

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the focused regression fix. The premise still holds on current main: gateway/hooks.py:113 reads events without normalization and gateway/hooks.py:147 iterates it directly, so a scalar YAML string is registered character-by-character.

Problems

  • The new tests/test_gateway_hooks.py duplicates the existing HookRegistry discovery suite in tests/gateway/test_hooks.py:35-112, which already owns list-event and missing-event coverage.

Suggested changes

  • Fold the scalar-string regression into tests/gateway/test_hooks.py, reusing _create_hook() and the existing HOOKS_DIR patching pattern. Preserve the assertion that agent:start is registered without character keys.

Automated hermes-sweeper review.

assert "agent:start" in registry._handlers
# Ensure no character-level keys were registered
for char in "agent:start":
assert char not in registry._handlers, f"unexpected char key: {char!r}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please place this regression in the existing HookRegistry suite at tests/gateway/test_hooks.py (which already covers list and missing events) so hook-loader fixtures and behavior coverage remain consolidated.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users labels Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins P2 Medium — degraded but workaround exists sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users 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.

Hook loader mis-registers scalar HOOK.yaml events values character-by-character

5 participants