From 43c7f5036a94572567ab6159ded32dd87ea88764 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 7 Jan 2026 19:04:04 +0000 Subject: [PATCH] fix(tools): keep tool errors concise --- CHANGELOG.md | 1 + src/agents/pi-embedded-helpers.test.ts | 3 +-- src/agents/pi-tool-definition-adapter.test.ts | 3 ++- src/agents/pi-tool-definition-adapter.ts | 23 +++++++++++++++---- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d76591cb..3bb6b2e1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - ClawdbotKit: fix SwiftPM resource bundling path for `tool-display.json`. Thanks @fcatuhe for PR #398. - Tools: add Telegram/WhatsApp reaction tools (with per-provider gating). Thanks @zats for PR #353. - Tools: flatten literal-union schemas for Claude on Vertex AI. Thanks @carlulsoe for PR #409. +- Tools: keep tool failure logs concise (no stack traces); full stack only in debug logs. - Tools: unify reaction removal semantics across Discord/Slack/Telegram/WhatsApp and allow WhatsApp reaction routing across accounts. - Android: fix APK output filename renaming after AGP updates. Thanks @Syhids for PR #410. - Android: rotate camera photos by EXIF orientation. Thanks @fcatuhe for PR #403. diff --git a/src/agents/pi-embedded-helpers.test.ts b/src/agents/pi-embedded-helpers.test.ts index 726c34565..69a93430a 100644 --- a/src/agents/pi-embedded-helpers.test.ts +++ b/src/agents/pi-embedded-helpers.test.ts @@ -1,6 +1,5 @@ -import { describe, expect, it } from "vitest"; - import type { AssistantMessage } from "@mariozechner/pi-ai"; +import { describe, expect, it } from "vitest"; import { buildBootstrapContextFiles, diff --git a/src/agents/pi-tool-definition-adapter.test.ts b/src/agents/pi-tool-definition-adapter.test.ts index 27a101002..48700ad28 100644 --- a/src/agents/pi-tool-definition-adapter.test.ts +++ b/src/agents/pi-tool-definition-adapter.test.ts @@ -22,6 +22,7 @@ describe("pi tool definition adapter", () => { status: "error", tool: "boom", }); - expect(JSON.stringify(result.details)).toContain("nope"); + expect(result.details).toMatchObject({ error: "nope" }); + expect(JSON.stringify(result.details)).not.toContain("\n at "); }); }); diff --git a/src/agents/pi-tool-definition-adapter.ts b/src/agents/pi-tool-definition-adapter.ts index df8b64d8d..9f4451625 100644 --- a/src/agents/pi-tool-definition-adapter.ts +++ b/src/agents/pi-tool-definition-adapter.ts @@ -4,12 +4,23 @@ import type { AgentToolUpdateCallback, } from "@mariozechner/pi-agent-core"; import type { ToolDefinition } from "@mariozechner/pi-coding-agent"; -import { logError } from "../logger.js"; +import { logDebug, logError } from "../logger.js"; import { jsonResult } from "./tools/common.js"; // biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-agent-core uses a different module instance. type AnyAgentTool = AgentTool; +function describeToolExecutionError(err: unknown): { + message: string; + stack?: string; +} { + if (err instanceof Error) { + const message = err.message?.trim() ? err.message : String(err); + return { message, stack: err.stack }; + } + return { message: String(err) }; +} + export function toToolDefinitions(tools: AnyAgentTool[]): ToolDefinition[] { return tools.map((tool) => { const name = tool.name || "tool"; @@ -37,13 +48,15 @@ export function toToolDefinitions(tools: AnyAgentTool[]): ToolDefinition[] { ? String((err as { name?: unknown }).name) : ""; if (name === "AbortError") throw err; - const message = - err instanceof Error ? (err.stack ?? err.message) : String(err); - logError(`[tools] ${tool.name} failed: ${message}`); + const described = describeToolExecutionError(err); + if (described.stack && described.stack !== described.message) { + logDebug(`tools: ${tool.name} failed stack:\n${described.stack}`); + } + logError(`[tools] ${tool.name} failed: ${described.message}`); return jsonResult({ status: "error", tool: tool.name, - error: message, + error: described.message, }); } },