From 02d0d6e192d5f5ef92bf46031c37f5380a87f4b7 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 31 Dec 2025 17:12:55 +0100 Subject: [PATCH] Fix hook tool_result event not emitted for tool errors Tools are supposed to throw on error. What needs fixing is that we need to report tool_result for erroneous tool executions as well. Fixes #374 --- packages/coding-agent/CHANGELOG.md | 1 + .../src/core/hooks/tool-wrapper.ts | 56 ++++++++++++------- 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index c891fbc0..ac5ea235 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -198,6 +198,7 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo ### Fixed +- **Hook `tool_result` event ignores errors from custom tools**: The `tool_result` hook event was never emitted when tools threw errors, and always had `isError: false` for successful executions. Now emits the event with correct `isError` value in both success and error cases. ([#374](https://github.com/badlogic/pi-mono/issues/374) by [@nicobailon](https://github.com/nicobailon)) - **Edit tool fails on Windows due to CRLF line endings**: Files with CRLF line endings now match correctly when LLMs send LF-only text. Line endings are normalized before matching and restored to original style on write. ([#355](https://github.com/badlogic/pi-mono/issues/355) by [@Pratham-Dubey](https://github.com/Pratham-Dubey)) - **Use bash instead of sh on Unix**: Fixed shell commands using `/bin/sh` instead of `/bin/bash` on Unix systems. ([#328](https://github.com/badlogic/pi-mono/pull/328) by [@dnouri](https://github.com/dnouri)) - **OAuth login URL clickable**: Made OAuth login URLs clickable in terminal. ([#349](https://github.com/badlogic/pi-mono/pull/349) by [@Cursivez](https://github.com/Cursivez)) diff --git a/packages/coding-agent/src/core/hooks/tool-wrapper.ts b/packages/coding-agent/src/core/hooks/tool-wrapper.ts index c3499d9f..28c718f0 100644 --- a/packages/coding-agent/src/core/hooks/tool-wrapper.ts +++ b/packages/coding-agent/src/core/hooks/tool-wrapper.ts @@ -46,30 +46,46 @@ export function wrapToolWithHooks(tool: AgentTool, hookRunner: HookRu } // Execute the actual tool, forwarding onUpdate for progress streaming - const result = await tool.execute(toolCallId, params, signal, onUpdate); + try { + const result = await tool.execute(toolCallId, params, signal, onUpdate); - // Emit tool_result event - hooks can modify the result - if (hookRunner.hasHandlers("tool_result")) { - const resultResult = (await hookRunner.emit({ - type: "tool_result", - toolName: tool.name, - toolCallId, - input: params, - content: result.content, - details: result.details, - isError: false, - })) as ToolResultEventResult | undefined; + // Emit tool_result event - hooks can modify the result + if (hookRunner.hasHandlers("tool_result")) { + const resultResult = (await hookRunner.emit({ + type: "tool_result", + toolName: tool.name, + toolCallId, + input: params, + content: result.content, + details: result.details, + isError: false, + })) as ToolResultEventResult | undefined; - // Apply modifications if any - if (resultResult) { - return { - content: resultResult.content ?? result.content, - details: (resultResult.details ?? result.details) as T, - }; + // Apply modifications if any + if (resultResult) { + return { + content: resultResult.content ?? result.content, + details: (resultResult.details ?? result.details) as T, + }; + } } - } - return result; + return result; + } catch (err) { + // Emit tool_result event for errors so hooks can observe failures + if (hookRunner.hasHandlers("tool_result")) { + await hookRunner.emit({ + type: "tool_result", + toolName: tool.name, + toolCallId, + input: params, + content: [{ type: "text", text: err instanceof Error ? err.message : String(err) }], + details: undefined, + isError: true, + }); + } + throw err; // Re-throw original error for agent-loop + } }, }; }