#15732: [AI-assisted] feat: emit agent:response internal hook after replies
stale
size: S
## Summary
Adds an `agent:response` event on the internal hook bus, emitted after each completed reply dispatch. This enables internal consumers (bundled hooks, future features) to react to agent responses with session context stats.
### What changed
- **New `agent:response` internal hook event** in `dispatch-from-config.ts` — fires after `dispatcher.waitForIdle()` with reply content, channel info, and session stats (context tokens, model, compaction count, etc.)
- **Fixed session store resolution** — uses `cfg.session.store` and resolved `agentId` instead of defaults (was broken for multi-agent / custom store configs)
- **Fixed session store key lookup** — adds lowercase fallback matching the existing pattern in `resolveSessionTtsAuto()`
### Context
While building a Discord presence feature that shows live context usage, I discovered:
1. `message_sent` plugin hook already exists in `deliverOutboundPayloads()` with proper delivery status tracking
2. There was no post-reply internal hook for accessing session stats — this PR adds that
The presence feature itself will be a separate PR pending design discussion.
### AI Disclosure
- [x] This PR was developed with AI assistance (Claude via OpenClaw)
- [x] All changes reviewed and tested by a human contributor
- [x] No AI-generated test fixtures or snapshots
### Testing
- All 12 existing tests in `dispatch-from-config.test.ts` pass
- Build, lint, and format checks pass
- Manually verified `agent:response` hook fires with correct session stats
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR adds a new internal hook emission (`agent:response`) from `dispatchReplyFromConfig` after replies have been dispatched and the dispatcher has gone idle. The event includes aggregated reply text, a channel/to identifier, and (when available) session stats loaded from the configured session store (including multi-agent store resolution and a lowercase session-key fallback).
Tests were updated to include a `runMessageSent` mock reset, but the hook behavior itself is not directly exercised in the unit tests in this PR.
<h3>Confidence Score: 3/5</h3>
- This PR is likely safe to merge once the internal hook semantics are aligned with existing dispatch behavior.
- Core changes are localized and largely additive, but the new `agent:response` event currently (1) omits fast-abort replies and (2) can report a channel value that doesn’t consistently reflect the dispatch/routing channel, which will break internal consumers relying on accurate attribution.
- src/auto-reply/reply/dispatch-from-config.ts
<sub>Last reviewed commit: 6afed29</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#7580: feat: add message:received internal hook with prompt injection
by rodrigoschott · 2026-02-03
79.6%
#19565: feat: add agent lifecycle hook events (session, message, error)
by tag-assistant · 2026-02-17
79.0%
#7771: Hooks: wire lifecycle events and tests
by rabsef-bicrym · 2026-02-03
78.9%
#19922: feat(hooks): add message:received and message:sent hook events
by NOVA-Openclaw · 2026-02-18
78.5%
#6630: feat(hooks): add agent:turn_start and agent:turn_end lifecycle events
by drdigital13 · 2026-02-01
78.5%
#11597: feat(hooks): implement message:received hook
by gnufoo · 2026-02-08
78.3%
#20268: feat(hooks): emit subagent:complete internal hook event
by AytuncYildizli · 2026-02-18
76.7%
#7301: fix(hooks): use resolveAgentIdFromSessionKey instead of split(":")[0]
by tsukhani · 2026-02-02
76.2%
#7545: feat(hooks): add message:received hook for pre-turn automation
by wangtian24 · 2026-02-02
75.7%
#9677: feat: expose incomingMessage in bootstrap hook context
by speedbal · 2026-02-05
75.6%