Skip to content

feat: Typed Hook Payloads (Phase 2) + Path Parity Tests (Phase 3)#29048

Open
zccyman wants to merge 1 commit into
NousResearch:mainfrom
atyou2happy:feat/typed-hook-payloads
Open

feat: Typed Hook Payloads (Phase 2) + Path Parity Tests (Phase 3)#29048
zccyman wants to merge 1 commit into
NousResearch:mainfrom
atyou2happy:feat/typed-hook-payloads

Conversation

@zccyman

@zccyman zccyman commented May 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements Phase 2 (Typed Hook Payloads) and Phase 3 (Path Parity Tests) of FR #28984.

Phase 1 was submitted separately as PR #28995.


Phase 2 — Typed Hook Payloads

New file: hermes_cli/hook_payloads.py (276 lines)

Defines frozen dataclass payloads for all 14 hook types:

Hook Dataclass
pre_tool_call PreToolCallPayload
post_tool_call PostToolCallPayload
transform_tool_result TransformToolResultPayload
on_session_start SessionStartPayload
on_session_end SessionEndPayload
on_session_finalize SessionFinalizePayload
on_session_reset SessionResetPayload
pre_approval_request PreApprovalRequestPayload
post_approval_response PostApprovalResponsePayload
pre_llm_call PreLlmCallPayload
post_llm_call PostLlmCallPayload
pre_api_request PreApiRequestPayload
post_api_request PostApiRequestPayload
subagent_stop SubagentStopPayload

payload_to_kwargs() converts dataclass → plain dict, preserving cb(**kwargs) compatibility for all existing plugin callbacks.

5 call sites migrated (adds type safety, zero breaking changes):

File Hook
hermes_cli/plugins.py get_pre_tool_call_block_message()
agent/conversation_loop.py on_session_start, pre_llm_call
model_tools.py post_tool_call, transform_tool_result

New tests: tests/hermes_cli/test_hook_payloads.py — 21 tests covering all payloads, frozen immutability, round-trip, registry completeness.


Phase 3 — Path Parity Tests

New file: hermes_cli/path_parity.py (155 lines)

assert_field_parity(
    "fallback_model",
    {
        "gateway_run_agent": lambda: extract_gateway_fields(),
        "tui_make_agent": lambda: extract_tui_fields(),
    },
)

When any path does not consume the field, raises PathParityError with a diff showing which paths are missing it.

3 known divergences documented as failing tests:

  • #28753: TUI doesn't pass fallback_model to AIAgent
  • #28746: idle-expiry path doesn't emit session:end event
  • #28637: /model switch loses per-model token usage

New tests: tests/hermes_cli/test_path_parity.py — 13 tests covering the helper functions and documented divergence patterns.


What This Prevents

Future scenario Without Phase 2 With Phase 2
New param added to pre_tool_call 2 of 3 call sites miss it Dataclass forces all sites to provide it
Hook field renamed Silent breakage in plugins Frozen dataclass catches at construction
Future scenario Without Phase 3 With Phase 3
fallback_model added to gateway but forgotten in TUI Silent divergence (#28753) assert_field_parity fails in CI
session:end forgotten in one exit path Bug hidden until user hits expiry path (#28746) Test documents expected parity

Test Results

tests/hermes_cli/test_hook_payloads.py  21 passed
tests/hermes_cli/test_path_parity.py   13 passed
tests/hermes_cli/test_plugins.py       105 passed
tests/test_model_tools.py               passed
tests/test_transform_tool_result_hook.py passed
tests/agent/test_plugin_llm.py          passed
tests/agent/test_shell_hooks.py         passed
─────────────────────────────────────────────
Total                                     139 passed

Refs: FR #28984 | PR #28995 (Phase 1)

… FR NousResearch#28984

Phase 2 — Typed Hook Payloads:
- New hermes_cli/hook_payloads.py: frozen dataclass payloads for 14 hooks
  (PreToolCall, PostToolCall, TransformToolResult, SessionStart/End/
  Finalize/Reset, PreApproval, PostApproval, PreLlm, PostLlm,
  PreApi, PostApi, SubagentStop)
- payload_to_kwargs() bridges dataclass→plain dict for cb(**kwargs) compat
- HOOK_PAYLOAD_TYPES registry maps hook names to payload classes
- 5 call sites migrated: get_pre_tool_call_block_message (plugins.py),
  on_session_start + pre_llm_call (conversation_loop.py),
  post_tool_call + transform_tool_result (model_tools.py)
- 21 new tests in test_hook_payloads.py

Phase 3 — Path Parity Tests:
- New hermes_cli/path_parity.py: assert_field_parity() helper
  Verifies all execution paths consume the same config fields
  Turns silent divergence bugs into CI failures
- 3 known divergences documented as failing tests (NousResearch#28753, NousResearch#28746, NousResearch#28637)
- 13 new tests in test_path_parity.py

Ref: FR NousResearch#28984 (Typed Config-Runtime Contract)
Closes NousResearch#28961
@alt-glitch alt-glitch added type/feature New feature or request comp/agent Core agent loop, run_agent.py, prompt builder comp/tools Tool registry, model_tools, toolsets comp/plugins Plugin system and bundled plugins comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have labels May 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent loop, run_agent.py, prompt builder comp/cli CLI entry point, hermes_cli/, setup wizard comp/plugins Plugin system and bundled plugins comp/tools Tool registry, model_tools, toolsets P3 Low — cosmetic, nice to have type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants