/** * Higher-order function that wraps a tool execute() to automatically log * every invocation (success or failure) into agent_activity_log. */ import { randomUUID } from "node:crypto"; import type { DatabaseSync } from "node:sqlite"; import { insertActivityLog } from "../db/repositories.js"; /** * Generic tool execute function signature. * Uses `(...args: never[])` rest params so the wrapper is assignable to any * concrete execute overload the SDK defines (extra optional params like * `signal` and `onUpdate` are passed through transparently). */ // eslint-disable-next-line @typescript-eslint/no-explicit-any type AnyExecuteFn = ( toolCallId: string, params: Record, ...rest: any[] ) => Promise; /** * Wrap a tool execute function with automatic activity logging. * * @param getDb - Lazy database getter (called at execution time, not registration). * @param toolName - Name used as the `action` column value. * @param category - Broad category, e.g. "market-data" or "strategy". * @param fn - The original execute function to wrap. * @param opts - Optional: extract strategy_id from params for context. */ export function withLogging( getDb: () => DatabaseSync, toolName: string, category: string, fn: T, opts?: { strategyIdParam?: string }, ): T { const wrapped: AnyExecuteFn = async (toolCallId, params, ...rest) => { const logId = randomUUID(); const startMs = Date.now(); const strategyId = opts?.strategyIdParam != null ? ((params[opts.strategyIdParam] as string | undefined) ?? null) : null; try { const result = await fn(toolCallId, params, ...rest); insertActivityLog(getDb(), { id: logId, timestamp: new Date().toISOString(), category, action: toolName, strategy_id: strategyId, detail: `OK (${Date.now() - startMs}ms)`, metadata_json: JSON.stringify({ toolCallId, params }), }); return result; } catch (err) { insertActivityLog(getDb(), { id: logId, timestamp: new Date().toISOString(), category, action: toolName, strategy_id: strategyId, detail: `ERROR (${Date.now() - startMs}ms): ${String(err)}`, metadata_json: JSON.stringify({ toolCallId, params }), }); throw err; } }; return wrapped as T; }