feat: add debug logging for silently caught errors (#809)

Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
jnjpng
2026-02-03 17:47:22 -08:00
committed by GitHub
parent 5ddce473e6
commit 0b5a4549a6
5 changed files with 66 additions and 21 deletions

View File

@@ -386,8 +386,8 @@ function sendDesktopNotification(
// Send terminal bell for native notification
process.stdout.write("\x07");
// Run Notification hooks (fire-and-forget, don't block)
runNotificationHooks(message, level).catch(() => {
// Silently ignore hook errors
runNotificationHooks(message, level).catch((error) => {
debugLog("hooks", "Notification hook error", error);
});
}

View File

@@ -7,6 +7,7 @@
import type { LettaStreamingResponse } from "@letta-ai/letta-client/resources/agents/messages";
import { INTERRUPTED_BY_USER } from "../../constants";
import { runPostToolUseHooks, runPreToolUseHooks } from "../../hooks";
import { debugLog } from "../../utils/debug";
import { extractCompactionSummary } from "./backfill";
import { findLastSafeSplitPoint } from "./markdownSplit";
import { isShellTool } from "./toolNameMapping";
@@ -652,7 +653,9 @@ export function onChunk(b: Buffers, chunk: LettaStreamingResponse) {
toolCallId,
undefined,
b.agentId,
).catch(() => {});
).catch((error) => {
debugLog("hooks", "PreToolUse hook error (accumulator)", error);
});
}
}
@@ -748,7 +751,9 @@ export function onChunk(b: Buffers, chunk: LettaStreamingResponse) {
b.agentId,
precedingReasoning,
precedingAssistantMessage,
).catch(() => {});
).catch((error) => {
debugLog("hooks", "PostToolUse hook error (accumulator)", error);
});
b.serverToolCalls.delete(toolCallId);
}

View File

@@ -2,6 +2,7 @@
// Loads and matches hooks from settings-manager
import { settingsManager } from "../settings-manager";
import { debugLog } from "../utils/debug";
import {
type HookCommand,
type HookEvent,
@@ -27,8 +28,9 @@ export function clearHooksCache(): void {
export function loadGlobalHooks(): HooksConfig {
try {
return settingsManager.getSettings().hooks || {};
} catch {
} catch (error) {
// Settings not initialized yet
debugLog("hooks", "loadGlobalHooks: Settings not initialized yet", error);
return {};
}
}
@@ -48,8 +50,9 @@ export async function loadProjectHooks(
await settingsManager.loadProjectSettings(workingDirectory);
}
return settingsManager.getProjectSettings(workingDirectory)?.hooks || {};
} catch {
} catch (error) {
// Settings not available
debugLog("hooks", "loadProjectHooks: Settings not available", error);
return {};
}
}
@@ -71,8 +74,9 @@ export async function loadProjectLocalHooks(
return (
settingsManager.getLocalProjectSettings(workingDirectory)?.hooks || {}
);
} catch {
} catch (error) {
// Settings not available
debugLog("hooks", "loadProjectLocalHooks: Settings not available", error);
return {};
}
}
@@ -162,8 +166,13 @@ export function matchesTool(pattern: string, toolName: string): boolean {
try {
const regex = new RegExp(`^(?:${pattern})$`);
return regex.test(toolName);
} catch {
} catch (error) {
// Invalid regex, fall back to exact match
debugLog(
"hooks",
`matchesTool: Invalid regex pattern "${pattern}", falling back to exact match`,
error,
);
return pattern === toolName;
}
}
@@ -270,8 +279,13 @@ export function areHooksDisabled(
if (projectDisabled === true) {
return true;
}
} catch {
} catch (error) {
// Project settings not loaded, skip
debugLog(
"hooks",
"areHooksDisabled: Project settings not loaded, skipping",
error,
);
}
// Check project-local settings
@@ -282,12 +296,22 @@ export function areHooksDisabled(
if (localDisabled === true) {
return true;
}
} catch {
} catch (error) {
// Local project settings not loaded, skip
debugLog(
"hooks",
"areHooksDisabled: Local project settings not loaded, skipping",
error,
);
}
return false;
} catch {
} catch (error) {
debugLog(
"hooks",
"areHooksDisabled: Failed to check hooks disabled status",
error,
);
return false;
}
}

View File

@@ -2,6 +2,7 @@
// Functions to write hooks to settings files via settings-manager
import { settingsManager } from "../settings-manager";
import { debugLog } from "../utils/debug";
import {
type HookEvent,
type HookMatcher,
@@ -37,8 +38,9 @@ export function loadHooksFromLocation(
settingsManager.getLocalProjectSettings(workingDirectory)?.hooks || {}
);
}
} catch {
} catch (error) {
// Settings not loaded yet, return empty
debugLog("hooks", "loadHooksFromLocation: Settings not loaded yet", error);
return {};
}
}
@@ -374,7 +376,12 @@ export function countHooksForEvent(
export function isUserHooksDisabled(): boolean {
try {
return settingsManager.getSettings().hooks?.disabled === true;
} catch {
} catch (error) {
debugLog(
"hooks",
"isUserHooksDisabled: Failed to check user hooks disabled status",
error,
);
return false;
}
}

View File

@@ -8,6 +8,7 @@ import {
runPreToolUseHooks,
} from "../hooks";
import { telemetry } from "../telemetry";
import { debugLog } from "../utils/debug";
import { TOOL_DEFINITIONS, type ToolName } from "./toolDefinitions";
export const TOOL_NAMES = Object.keys(TOOL_DEFINITIONS) as ToolName[];
@@ -976,8 +977,8 @@ export async function executeTool(
undefined, // precedingAssistantMessage - not available in tool manager context
);
postToolUseFeedback = postHookResult.feedback;
} catch {
// Silently ignore hook errors - don't affect tool execution
} catch (error) {
debugLog("hooks", "PostToolUse hook error (success path)", error);
}
// Run PostToolUseFailure hooks when tool returns error status
@@ -1000,8 +1001,12 @@ export async function executeTool(
undefined, // precedingAssistantMessage - not available in tool manager context
);
postToolUseFailureFeedback = failureHookResult.feedback;
} catch {
// Silently ignore hook execution errors
} catch (error) {
debugLog(
"hooks",
"PostToolUseFailure hook error (tool returned error)",
error,
);
}
}
@@ -1079,8 +1084,8 @@ export async function executeTool(
undefined, // precedingAssistantMessage - not available in tool manager context
);
postToolUseFeedback = postHookResult.feedback;
} catch {
// Silently ignore hook errors
} catch (error) {
debugLog("hooks", "PostToolUse hook error (error path)", error);
}
// Run PostToolUseFailure hooks - exit 2 injects stderr
@@ -1098,8 +1103,12 @@ export async function executeTool(
undefined, // precedingAssistantMessage - not available in tool manager context
);
postToolUseFailureFeedback = failureHookResult.feedback;
} catch {
// Silently ignore hook execution errors
} catch (error) {
debugLog(
"hooks",
"PostToolUseFailure hook error (exception path)",
error,
);
}
// Combine feedback from both hook types