feat: add debug logging for silently caught errors (#809)
Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user