import type { AgentTool, AgentToolResult, AgentToolUpdateCallback, } from "@mariozechner/pi-agent-core"; import type { ToolDefinition } from "@mariozechner/pi-coding-agent"; 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"; return { name, label: tool.label ?? name, description: tool.description ?? "", // biome-ignore lint/suspicious/noExplicitAny: TypeBox schema from pi-agent-core uses a different module instance. parameters: tool.parameters as any, execute: async ( toolCallId, params, onUpdate: AgentToolUpdateCallback | undefined, _ctx, signal, ): Promise> => { // KNOWN: pi-coding-agent `ToolDefinition.execute` has a different signature/order // than pi-agent-core `AgentTool.execute`. This adapter keeps our existing tools intact. try { return await tool.execute(toolCallId, params, signal, onUpdate); } catch (err) { if (signal?.aborted) throw err; const name = err && typeof err === "object" && "name" in err ? String((err as { name?: unknown }).name) : ""; if (name === "AbortError") throw err; 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: described.message, }); } }, } satisfies ToolDefinition; }); }