From d9fa5c29851ef9f67a1cbf45440468ed1fd97704 Mon Sep 17 00:00:00 2001 From: harmoon Date: Tue, 31 Mar 2026 15:04:18 +0800 Subject: [PATCH] feat(agent): emit tool events and feedback for hook results Add ToolExecStart event emission and tool feedback for hook results to ensure consistent behavior between normal tool execution and hook bypass scenarios. This maintains parity in event tracking and user feedback when tools are executed via hooks. --- pkg/agent/loop.go | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 532714f82..001fea7fc 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -2260,6 +2260,36 @@ turnLoop: // Hook returns result directly, skip tool execution if toolReq != nil && toolReq.HookResult != nil { hookResult := toolReq.HookResult + + // Emit ToolExecStart event (same as normal tool execution) + al.emitEvent( + EventKindToolExecStart, + ts.eventMeta("runTurn", "turn.tool.start"), + ToolExecStartPayload{ + Tool: toolName, + Arguments: cloneEventArguments(toolArgs), + }, + ) + + // Send tool feedback to chat channel if enabled (same as normal tool execution) + if al.cfg.Agents.Defaults.IsToolFeedbackEnabled() && + ts.channel != "" && + !ts.opts.SuppressToolFeedback { + argsJSON, _ := json.Marshal(toolArgs) + feedbackPreview := utils.Truncate( + string(argsJSON), + al.cfg.Agents.Defaults.GetToolFeedbackMaxArgsLength(), + ) + feedbackMsg := fmt.Sprintf("\U0001f527 `%s`\n```\n%s\n```", toolName, feedbackPreview) + fbCtx, fbCancel := context.WithTimeout(turnCtx, 3*time.Second) + _ = al.bus.PublishOutbound(fbCtx, bus.OutboundMessage{ + Channel: ts.channel, + ChatID: ts.chatID, + Content: feedbackMsg, + }) + fbCancel() + } + toolDuration := time.Duration(0) // Hook execution time unknown // Emit ToolExecEnd event @@ -2285,6 +2315,11 @@ turnLoop: }) } + // Track response handling status (same as normal tool execution) + if !hookResult.ResponseHandled { + allResponsesHandled = false + } + // Build tool message contentForLLM := hookResult.ContentForLLM() if al.cfg.Tools.IsFilterSensitiveDataEnabled() {