Repository navigation
Conversation
…ce that never reaches the model A plugin or shell hook could only speak to the model: a `context` string, a block message, a transformed result. A formatter that wanted to say "reformatted 3 files" either stayed silent or spent model context on it. Any hook result may now carry `notice` (Hermes) or `systemMessage` (the field existing third-party hook scripts already emit, so they work unchanged). The dispatcher routes it to the agent whose session the payload names: CLI prints a `⚑ hook <event>: …` status line, TUI/Desktop get a 30 s AgentNotice toast, the messaging gateway a one-shot line. Nothing is appended to `messages`, so history, compaction and export never see it. The text is ANSI-stripped and capped at 2000 chars. A notice alone is never a decision: a fail_closed pre_tool_call gate that exits non-zero with only a notice still blocks, and a block directive keeps its notice. Live repro (real `hermes chat -q` on gpt-5-mini with a post_tool_call shell hook, isolated HOME): origin/main prints nothing; this branch prints the hook line and the session's persisted messages contain 0 rows of the notice text.
૮ >ﻌ< ა ci reviewran on c026324 — Port from MiniMax-AI/minimax-code#376: hooks can show the us debug infoCI timingsCI timings · View report · View jobWall time 6m37s vs 23m22s (-71.7%). 9 job(s) slower, 8 faster,
|
Reviewed at head Two gaps in the delivery path, same shape: a value reaches 1.
blk = _fail_closed_block(spec, f"hook exited {r['returncode']} with no directive")
notice = parsed.get("notice") if isinstance(parsed, dict) else None
return {**blk, **({"notice": notice} if notice else {})}The exit-2 branch 10 lines above already does exactly this merge, as do the docs ( 2.
live = [a for a in candidates if not getattr(a, "_persist_disabled", False)]
return (live or candidates)[0] if candidates else None |
A plugin or shell hook can now tell the user something without telling the model: any hook result may carry
notice(Hermes) orsystemMessage(the field existing third-party hook scripts already emit, so they work unchanged), and the text is shown on the session's surface while never entering model context. Port of MiniMax-AI/minimax-code#376.Changes
agent/hook_notices.py(new, 70 LOC): extracts the notice from a hook result (ANSI-stripped, 2,000-char cap), routes it to the liveAIAgentwhosesession_idthe hook payload names (WeakSet registry; agents register at construction).hermes_cli/plugins_dispatch.py: bothinvoke_hookpaths deliver notices after collecting results — every event, plugin and shell hooks alike, one seam.agent/status_output.py::_emit_hook_notice: CLI prints⚑ hook <event>: …on the status lane; TUI/Desktop get a 30 sAgentNoticetoast; the messaging gateway a one-shot line (all three drivers already renderAgentNotice).agent/shell_hooks.py:_parse_responsecarriesnotice/systemMessagethrough every event's parser. A notice alone is never a decision: afail_closedgate that exits non-zero with only a notice still blocks, and an exit-2 block keeps its notice.hooks.md(plugin hooks intro + shell stdout block),observer-hooks.mdreturn table.Validation
Live repro — real
hermes chat -qongpt-5-mini, isolated HOME, apost_tool_callshell hook printing{"systemMessage": "LIVE-NOTICE after <tool> …"}:messages⚑ hook post_tool_call: LIVE-NOTICE after terminal (never for the model)Tests (2 invariants, red on base): a plugin hook's
systemMessage/noticereaches the Desktop agent as an info toast and the CLI agent as ahook_noticestatus line, with ANSI stripped, nothing inmessages, and nothing for an agent whose session is not named; a real shell-hook subprocess'ssystemMessagesurfaces frompost_tool_callwhile the same script on afail_closedpre_tool_callexiting 3 still blocks. 163 tests acrossshell_hooks,plugins,plugin_host,status_outputgreen.Root cause: hook return values could only carry model-facing directives; no key reached the user, so hook authors either stayed silent or spent model context on status text.
Not reached live: TUI/Desktop toast rendering (unit-tested via the
AgentNoticepath all three drivers share).Infographic