#18889: feat(hooks): add agent and tool lifecycle boundaries
docs
agents
size: L
Cluster:
Plugin Hook Enhancements
## Why
Agent execution lacked complete lifecycle boundaries around thinking, response generation, and tool execution, reducing traceability for observability and policy systems. This PR adds those boundaries and ensures tool lifecycle hooks carry `toolCallId` context when available. lobster-biscuit
## Split Context
This PR was accidentally closed after a messed up rebase https://github.com/openclaw/openclaw/pull/12583 which was originally split from closed umbrella PR #9761: https://github.com/openclaw/openclaw/pull/9761.
## Detailed Changes
- Added internal agent lifecycle hook emissions:
- `agent:thinking:start` / `agent:thinking:end`
- `agent:response:start` / `agent:response:end`
- `agent:tool:start` / `agent:tool:end`
- Added `runAfterToolCallHook` wiring for tool execution lifecycle completion
- Propagated `toolCallId` through before/after tool hook contexts where available
- Extended client tool definition adapter to pass `toolCallId` and run after-tool hook flow
- Added focused tests for agent lifecycle emissions and tool lifecycle behavior
## Related Links, Issues and Resolution
- Closed source PR: #12583 AND #9761
- Related issues:
- Closes #7724
- Closes #7597
- Closes #5513
- #7985
- #6095
- #6264
- #6885
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR adds complete lifecycle boundaries for agent execution (thinking, response generation, and tool execution), improving observability and traceability for policy systems. The implementation propagates `toolCallId` through tool lifecycle hooks and ensures consistent hook firing across different execution paths.
Key improvements:
- Split lifecycle hook logic into dedicated `lifecycle-hooks.ts` module
- Ensured `agent:thinking:start/end` fire for all agent runs
- Added conditional `agent:response:start/end` hooks that only fire when response output is generated
- Propagated `toolCallId` to `before_tool_call` and `after_tool_call` hooks
- Added `runAfterToolCallHook` wiring for both success and error paths in tool execution
- Comprehensive test coverage validates hook emissions in different scenarios
<h3>Confidence Score: 5/5</h3>
- Safe to merge - well-structured refactoring with comprehensive test coverage
- The changes are well-architected with proper error handling throughout. The new `lifecycle-hooks.ts` module cleanly separates concerns, all hook emission paths include error handling that logs warnings without failing execution, and the test coverage validates the core lifecycle hook behavior. The `toolCallId` propagation is handled consistently with proper fallbacks.
- No files require special attention
<sub>Last reviewed commit: d48824c</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#10678: feat(hooks): wire after_tool_call hook into tool execution pipeline
by yassinebkr · 2026-02-06
78.4%
#7771: Hooks: wire lifecycle events and tests
by rabsef-bicrym · 2026-02-03
78.2%
#20580: feat(hooks): bridge after_tool_call to internal hook handler system
by CryptoKrad · 2026-02-19
78.1%
#22068: Add tool:before/tool:after internal hook events
by yhindy · 2026-02-20
77.7%
#19422: fix: pass session context to plugin tool hooks in toToolDefinitions
by namabile · 2026-02-17
77.4%
#20268: feat(hooks): emit subagent:complete internal hook event
by AytuncYildizli · 2026-02-18
77.4%
#8332: fix: add per-tool-call timeout to prevent agent hangs (v2 - fixes m...
by vishaltandale00 · 2026-02-03
77.2%
#15571: feat: infrastructure foundation — hooks, model failover, sessions, ...
by tangcruz · 2026-02-13
77.0%
#17667: feat: tool-hooks extension — run shell commands on tool calls
by FaradayHunt · 2026-02-16
76.4%
#21224: Introduce optional runtime lifecycle hooks for tool and model bound...
by mikeholownych · 2026-02-19
76.1%