refactor(errors): surface 57 deferred catch-and-swallow sites via logger
The earlier sweep cleaned the hot path (worker/runtime/automation/api-
server/ipc core — 59 sites). This pass finishes the deferred long tail:
main/* services, database/* CRUD modules, api-server/* routes, ipc-*
handlers, thread-integration, automation helpers, browser, skills.
Default strategy: catch (error) { logger.warn("[module] context:", ...) }
— preserve current behavior, make the failure visible instead of
silently hidden. Widened 3 logger interface signatures to include warn
where callers only passed info/error previously (thread-helpers,
host-environment-service, ipc-domain-common).
Legitimate boundaries left intact: JSON.parse on untrusted input, DNS
resolver no-records paths, explicit safe* helpers (safeJson, parseJson,
parseTriggerDetail), URL-parse predicates, and `<unserialisable>`
fallbacks inside the prompt-builder summarisers. Each kept catch now
either has a reason in context or is a documented safe* helper.
Tests adjusted only where test-constructed no-op loggers needed a warn
stub (message-dispatch, company-mode-switch, ipc-agent-graph-handlers).
With the earlier pass, AgentCompany no longer has silently-swallowing
catch blocks in main-process or renderer business code.
This commit is contained in:
1 parent
ecd1bc2e33
commit
40040b3dd2
46 files changed
+209
-113
No files matched your search
@@ -151,7 +151,8 @@ export function executeAutomationAction(
|
||||
try {
|
||||
const sender = db.getAgent(fromAgentId);
|
||||
channelTargetId = sender.department ?? null;
|
||||
} catch {
|
||||
} catch (err) {
|
||||
logger.warn(`[automation] getAgent failed for sender ${fromAgentId}; dropping department target:`, err instanceof Error ? err.message : String(err));
|
||||
channelTargetId = null;
|
||||
}
|
||||
}
|
||||
@@ -221,21 +222,22 @@ export function executeAutomationAction(
|
||||
let agentName = "an agent";
|
||||
try {
|
||||
agentName = db.getAgent(targetAgentId).name;
|
||||
} catch {
|
||||
// Fall back to the generic label when the agent was deleted mid-flight.
|
||||
} catch (err) {
|
||||
logger.warn(`[automation] getAgent failed for escalation target ${targetAgentId}; using generic label:`, err instanceof Error ? err.message : String(err));
|
||||
}
|
||||
let taskTitle = ctx.taskId ?? "unknown";
|
||||
try {
|
||||
if (ctx.taskId) taskTitle = db.getTask(ctx.taskId).title;
|
||||
} catch {
|
||||
// Keep the fallback title when the task no longer exists.
|
||||
} catch (err) {
|
||||
logger.warn(`[automation] getTask failed for escalation task ${ctx.taskId}; using id as title:`, err instanceof Error ? err.message : String(err));
|
||||
}
|
||||
// Heartbeat tasks are internal system tasks — skip escalation messages to avoid flooding channels.
|
||||
let isHeartbeatTask = false;
|
||||
if (ctx.taskId) {
|
||||
try {
|
||||
isHeartbeatTask = db.getTask(ctx.taskId).isHeartbeat === true;
|
||||
} catch {
|
||||
} catch (err) {
|
||||
logger.warn(`[automation] getTask failed for heartbeat check on ${ctx.taskId}; treating as non-heartbeat:`, err instanceof Error ? err.message : String(err));
|
||||
isHeartbeatTask = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
import type { AppDatabase } from "../database";
|
||||
import type { AutomationEventContext } from "./types";
|
||||
|
||||
type ConditionLogger = {
|
||||
warn: (...args: unknown[]) => void;
|
||||
};
|
||||
|
||||
export function matchesEventConfig(
|
||||
db: AppDatabase,
|
||||
configJson: string,
|
||||
sourceDepartment: string | null,
|
||||
ctx: AutomationEventContext,
|
||||
logger?: ConditionLogger,
|
||||
): boolean {
|
||||
if (sourceDepartment && ctx.department && sourceDepartment !== ctx.department) {
|
||||
return false;
|
||||
@@ -21,8 +26,8 @@ export function matchesEventConfig(
|
||||
const task = ctx.taskId ? db.getTask(ctx.taskId) : null;
|
||||
if (task && task.priority !== conditions.priority) return false;
|
||||
// If task was deleted, skip this condition instead of rejecting the rule.
|
||||
} catch {
|
||||
// Entity missing — treat as condition not applicable, continue matching.
|
||||
} catch (err) {
|
||||
logger?.warn(`[automation-conditions] getTask failed for ${ctx.taskId}; treating priority condition as not applicable:`, err instanceof Error ? err.message : String(err));
|
||||
}
|
||||
}
|
||||
if (typeof conditions.budgetThresholdPct === "number" && ctx.agentId) {
|
||||
@@ -33,8 +38,8 @@ export function matchesEventConfig(
|
||||
if (utilization < (conditions.budgetThresholdPct as number) / 100) return false;
|
||||
}
|
||||
// If budget is 0 (unlimited), skip budget condition instead of rejecting.
|
||||
} catch {
|
||||
// Agent missing — treat as condition not applicable, continue matching.
|
||||
} catch (err) {
|
||||
logger?.warn(`[automation-conditions] getAgent failed for ${ctx.agentId}; treating budget condition as not applicable:`, err instanceof Error ? err.message : String(err));
|
||||
}
|
||||
}
|
||||
if (conditions.taskId && ctx.taskId && conditions.taskId !== ctx.taskId) return false;
|
||||
@@ -47,6 +52,7 @@ export function matchesConditions(
|
||||
db: AppDatabase,
|
||||
rule: { conditionsJson: string; sourceDepartment: string | null },
|
||||
ctx: AutomationEventContext,
|
||||
logger?: ConditionLogger,
|
||||
): boolean {
|
||||
return matchesEventConfig(db, rule.conditionsJson, rule.sourceDepartment, ctx);
|
||||
return matchesEventConfig(db, rule.conditionsJson, rule.sourceDepartment, ctx, logger);
|
||||
}
|
||||
@@ -102,8 +102,8 @@ export function handleTaskStatusChange(
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Parent task may have been deleted or reassigned during completion cascade evaluation.
|
||||
} catch (err) {
|
||||
deps.logger.warn(`[automation] Parent task ${task.parentId} lookup failed during completion cascade:`, err instanceof Error ? err.message : String(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,8 +274,8 @@ export function processRunCompletion(
|
||||
try {
|
||||
const agent = db.getAgent(run.agentId);
|
||||
automationContext.department = agent.department ?? undefined;
|
||||
} catch {
|
||||
// Agent can disappear after a run completes; keep the context without department.
|
||||
} catch (err) {
|
||||
deps.logger.warn(`[automation] getAgent failed for ${run.agentId} during run completion; dropping department from context:`, err instanceof Error ? err.message : String(err));
|
||||
}
|
||||
|
||||
if (isSuccess) {
|
||||
@@ -295,8 +295,8 @@ export function processRunCompletion(
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Parent task may have been deleted or reassigned during cascade evaluation.
|
||||
} catch (err) {
|
||||
deps.logger.warn(`[automation] Parent task ${task.parentId} cascade failed during run completion:`, err instanceof Error ? err.message : String(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -326,8 +326,8 @@ export function processRunCompletion(
|
||||
notify,
|
||||
(en, zh) => localizeNotification(budgetLocale, en, zh),
|
||||
);
|
||||
} catch {
|
||||
// Budget follow-up is best-effort; do not fail run completion if the agent disappeared.
|
||||
} catch (err) {
|
||||
deps.logger.warn(`[automation] Budget follow-up failed for agent ${run.agentId}:`, err instanceof Error ? err.message : String(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,7 +109,7 @@ export function createAutomationService({
|
||||
try {
|
||||
const rules = db.listActiveAutomationRules(ctx.companyId, trigger);
|
||||
for (const rule of rules) {
|
||||
if (!matchesConditions(db, rule, ctx)) continue;
|
||||
if (!matchesConditions(db, rule, ctx, logger)) continue;
|
||||
const executionKey = JSON.stringify({
|
||||
ruleId: rule.id,
|
||||
trigger,
|
||||
@@ -166,7 +166,7 @@ export function createAutomationService({
|
||||
try {
|
||||
const workflows = db.listTriggerableWorkflows(ctx.companyId, trigger);
|
||||
for (const workflow of workflows) {
|
||||
if (!matchesEventConfig(db, workflow.triggerConfigJson, null, ctx)) continue;
|
||||
if (!matchesEventConfig(db, workflow.triggerConfigJson, null, ctx, logger)) continue;
|
||||
const executionKey = JSON.stringify({
|
||||
workflowId: workflow.id,
|
||||
trigger,
|
||||
|
||||
Reference in new issue
Block a user