mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-25 07:30:03 +00:00
refactor: dedupe hook gateway error formatting
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { resolveAgentTimeoutMs } from "../../agents/timeout.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { logVerbose } from "../../globals.js";
|
||||
import { formatErrorMessage } from "../../infra/errors.js";
|
||||
import { normalizeAgentId } from "../../routing/session-key.js";
|
||||
import { isAcpSessionKey } from "../../sessions/session-key-utils.js";
|
||||
import {
|
||||
@@ -1291,7 +1292,7 @@ export class AcpSessionManager {
|
||||
});
|
||||
} catch (recoveryError) {
|
||||
logVerbose(
|
||||
`acp close recovery: unable to prepare fresh session for ${sessionKey}: ${recoveryError instanceof Error ? recoveryError.message : String(recoveryError)}`,
|
||||
`acp close recovery: unable to prepare fresh session for ${sessionKey}: ${formatErrorMessage(recoveryError)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1665,7 +1666,7 @@ export class AcpSessionManager {
|
||||
});
|
||||
} catch (error) {
|
||||
logVerbose(
|
||||
`acp-manager: failed preparing a fresh persistent session for ${params.sessionKey}: ${error instanceof Error ? error.message : String(error)}`,
|
||||
`acp-manager: failed preparing a fresh persistent session for ${params.sessionKey}: ${formatErrorMessage(error)}`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import type { SessionAcpMeta } from "../config/sessions/types.js";
|
||||
import { logVerbose } from "../globals.js";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import { getAcpSessionManager } from "./control-plane/manager.js";
|
||||
import { resolveConfiguredAcpBindingSpecBySessionKey } from "./persistent-bindings.resolve.js";
|
||||
import {
|
||||
@@ -98,7 +99,7 @@ export async function ensureConfiguredAcpBindingSession(params: {
|
||||
sessionKey,
|
||||
};
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
const message = formatErrorMessage(error);
|
||||
logVerbose(
|
||||
`acp-configured-binding: failed ensuring ${params.spec.channel}:${params.spec.accountId}:${params.spec.conversationId} -> ${sessionKey}: ${message}`,
|
||||
);
|
||||
@@ -192,7 +193,7 @@ export async function resetAcpSessionInPlace(params: {
|
||||
// on the next turn through the normal binding readiness path.
|
||||
return { ok: true };
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
const message = formatErrorMessage(error);
|
||||
logVerbose(`acp-configured-binding: failed reset for ${sessionKey}: ${message}`);
|
||||
return {
|
||||
ok: false,
|
||||
|
||||
@@ -7,6 +7,7 @@ import JSON5 from "json5";
|
||||
import { ensureOwnerDisplaySecret } from "../agents/owner-display.js";
|
||||
import { applyRuntimeLegacyConfigMigrations } from "../commands/doctor/shared/runtime-compat-api.js";
|
||||
import { loadDotEnv } from "../infra/dotenv.js";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import { resolveRequiredHomeDir } from "../infra/home-dir.js";
|
||||
import {
|
||||
loadShellEnvFallback,
|
||||
@@ -2550,7 +2551,7 @@ export async function writeConfigFile(
|
||||
} catch {
|
||||
// Keep the original refresh failure as the surfaced error.
|
||||
}
|
||||
const detail = error instanceof Error ? error.message : String(error);
|
||||
const detail = formatErrorMessage(error);
|
||||
throw new ConfigRuntimeRefreshError(
|
||||
`Config was written to ${io.configPath}, but runtime snapshot refresh failed: ${detail}`,
|
||||
{ cause: error },
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { CURRENT_SESSION_VERSION, SessionManager } from "@mariozechner/pi-coding-agent";
|
||||
import { formatErrorMessage } from "../../infra/errors.js";
|
||||
import { emitSessionTranscriptUpdate } from "../../sessions/transcript-events.js";
|
||||
import {
|
||||
resolveDefaultSessionStorePath,
|
||||
@@ -184,7 +185,7 @@ export async function appendExactAssistantMessageToSessionTranscript(params: {
|
||||
} catch (err) {
|
||||
return {
|
||||
ok: false,
|
||||
reason: err instanceof Error ? err.message : String(err),
|
||||
reason: formatErrorMessage(err),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
import { resolveStorePath } from "../config/sessions/paths.js";
|
||||
import { loadSessionStore, updateSessionStore } from "../config/sessions/store.js";
|
||||
import type { SessionEntry } from "../config/sessions/types.js";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import { type RuntimeEnv, defaultRuntime } from "../runtime.js";
|
||||
|
||||
@@ -131,7 +132,7 @@ async function restoreMainSessionMapping(
|
||||
);
|
||||
return undefined;
|
||||
} catch (err) {
|
||||
return err instanceof Error ? err.message : String(err);
|
||||
return formatErrorMessage(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +151,7 @@ export async function runBootOnce(params: {
|
||||
try {
|
||||
result = await loadBootFile(params.workspaceDir);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
const message = formatErrorMessage(err);
|
||||
log.error(`boot: failed to read ${BOOT_FILENAME}: ${message}`);
|
||||
return { status: "failed", reason: message };
|
||||
}
|
||||
@@ -183,7 +184,7 @@ export async function runBootOnce(params: {
|
||||
params.deps,
|
||||
);
|
||||
} catch (err) {
|
||||
agentFailure = err instanceof Error ? err.message : String(err);
|
||||
agentFailure = formatErrorMessage(err);
|
||||
log.error(`boot: agent run failed: ${agentFailure}`);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import { estimateBase64DecodedBytes } from "../media/base64.js";
|
||||
import type { PromptImageOrderEntry } from "../media/prompt-image-order.js";
|
||||
import { sniffMimeFromBase64 } from "../media/sniff-mime-from-base64.js";
|
||||
@@ -428,7 +429,7 @@ export async function parseMessageWithAttachments(
|
||||
|
||||
isOffloaded = true;
|
||||
} catch (err) {
|
||||
const errorMessage = err instanceof Error ? err.message : String(err);
|
||||
const errorMessage = formatErrorMessage(err);
|
||||
throw new MediaOffloadError(
|
||||
`[Gateway Error] Failed to save intercepted media to disk: ${errorMessage}`,
|
||||
{ cause: err },
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
type DeviceAuthToken,
|
||||
type PairedDevice,
|
||||
} from "../infra/device-pairing.js";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import type { ExecApprovalRequest, ExecApprovalResolved } from "../infra/exec-approvals.js";
|
||||
import {
|
||||
clearApnsRegistrationIfCurrent,
|
||||
@@ -208,8 +209,7 @@ async function sendRequestedPushes(params: {
|
||||
);
|
||||
for (const result of results) {
|
||||
if (result.status === "rejected") {
|
||||
const message =
|
||||
result.reason instanceof Error ? result.reason.message : String(result.reason);
|
||||
const message = formatErrorMessage(result.reason);
|
||||
params.log.warn?.(`exec approvals: iOS request push threw error: ${message}`);
|
||||
}
|
||||
}
|
||||
@@ -274,7 +274,7 @@ export function createExecApprovalIosPushDelivery(params: { log: GatewayLikeLogg
|
||||
nodeIds: plan.targets.map((target) => target.nodeId),
|
||||
requestPushPromise: sendRequestedPushes({ request, plan, log: params.log }).catch(
|
||||
(err) => {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
const message = formatErrorMessage(err);
|
||||
params.log.error?.(`exec approvals: iOS request push failed: ${message}`);
|
||||
return { attempted: plan.targets.length, delivered: 0 };
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import crypto from "node:crypto";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import {
|
||||
MCP_LOOPBACK_SERVER_NAME,
|
||||
MCP_LOOPBACK_SERVER_VERSION,
|
||||
@@ -75,7 +76,7 @@ export async function handleMcpJsonRpc(params: {
|
||||
isError: false,
|
||||
});
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
const message = formatErrorMessage(error);
|
||||
return jsonRpcResult(id, {
|
||||
content: [{ type: "text", text: message || "tool execution failed" }],
|
||||
isError: true,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import crypto from "node:crypto";
|
||||
import { createServer as createHttpServer } from "node:http";
|
||||
import { loadConfig } from "../config/config.js";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import { logDebug, logWarn } from "../logger.js";
|
||||
import { handleMcpJsonRpc } from "./mcp-http.handlers.js";
|
||||
import {
|
||||
@@ -72,9 +73,7 @@ export async function startMcpLoopbackServer(port = 0): Promise<{
|
||||
res.writeHead(200, { "Content-Type": "application/json" });
|
||||
res.end(payload);
|
||||
} catch (error) {
|
||||
logWarn(
|
||||
`mcp loopback: request handling failed: ${error instanceof Error ? error.message : String(error)}`,
|
||||
);
|
||||
logWarn(`mcp loopback: request handling failed: ${formatErrorMessage(error)}`);
|
||||
if (!res.headersSent) {
|
||||
res.writeHead(400, { "Content-Type": "application/json" });
|
||||
res.end(JSON.stringify(jsonRpcError(null, -32700, "Parse error")));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import type { PromptImageOrderEntry } from "../media/prompt-image-order.js";
|
||||
import type { NodeEvent, NodeEventContext } from "./server-node-events-types.js";
|
||||
import {
|
||||
@@ -408,7 +409,7 @@ export const handleNodeEvent = async (ctx: NodeEventContext, nodeId: string, evt
|
||||
await deleteMediaBuffer(ref.id);
|
||||
} catch (cleanupErr) {
|
||||
ctx.logGateway.warn(
|
||||
`Failed to cleanup orphaned media ${ref.id}: ${cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr)}`,
|
||||
`Failed to cleanup orphaned media ${ref.id}: ${formatErrorMessage(cleanupErr)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -416,9 +417,7 @@ export const handleNodeEvent = async (ctx: NodeEventContext, nodeId: string, evt
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
ctx.logGateway.warn(
|
||||
`agent.request attachment parse failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
);
|
||||
ctx.logGateway.warn(`agent.request attachment parse failed: ${formatErrorMessage(err)}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { getChannelPlugin, normalizeChannelId } from "../channels/plugins/index.
|
||||
import type { CliDeps } from "../cli/deps.js";
|
||||
import { resolveMainSessionKeyFromConfig } from "../config/sessions.js";
|
||||
import { parseSessionThreadInfo } from "../config/sessions/thread-info.js";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import { requestHeartbeatNow } from "../infra/heartbeat-wake.js";
|
||||
import { deliverOutboundPayloads } from "../infra/outbound/deliver.js";
|
||||
import { ackDelivery, enqueueDelivery, failDelivery } from "../infra/outbound/delivery-queue.js";
|
||||
@@ -105,11 +106,9 @@ async function deliverRestartSentinelNotice(params: {
|
||||
});
|
||||
if (!retrying) {
|
||||
if (queueId) {
|
||||
await failDelivery(queueId, err instanceof Error ? err.message : String(err)).catch(
|
||||
() => {
|
||||
// Best-effort queue bookkeeping.
|
||||
},
|
||||
);
|
||||
await failDelivery(queueId, formatErrorMessage(err)).catch(() => {
|
||||
// Best-effort queue bookkeeping.
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import {
|
||||
disableTailscaleFunnel,
|
||||
disableTailscaleServe,
|
||||
@@ -33,9 +34,7 @@ export async function startGatewayTailscaleExposure(params: {
|
||||
params.logTailscale.info(`${params.tailscaleMode} enabled`);
|
||||
}
|
||||
} catch (err) {
|
||||
params.logTailscale.warn(
|
||||
`${params.tailscaleMode} failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
);
|
||||
params.logTailscale.warn(`${params.tailscaleMode} failed: ${formatErrorMessage(err)}`);
|
||||
}
|
||||
|
||||
if (!params.resetOnExit) {
|
||||
@@ -51,7 +50,7 @@ export async function startGatewayTailscaleExposure(params: {
|
||||
}
|
||||
} catch (err) {
|
||||
params.logTailscale.warn(
|
||||
`${params.tailscaleMode} cleanup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`${params.tailscaleMode} cleanup failed: ${formatErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { hasBinary } from "../agents/skills.js";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import { runCommandWithTimeout, type SpawnResult } from "../process/exec.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
import { normalizeServePath } from "./gmail.js";
|
||||
@@ -52,7 +53,7 @@ function formatCommandResult(command: string, result: SpawnResult): string {
|
||||
}
|
||||
|
||||
function formatJsonParseFailure(command: string, result: SpawnResult, err: unknown): string {
|
||||
const reason = err instanceof Error ? err.message : String(err);
|
||||
const reason = formatErrorMessage(err);
|
||||
return `${command} returned invalid JSON: ${reason}\n${formatCommandResult(command, result)}`;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { openBoundaryFile } from "../infra/boundary-file-read.js";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import { sanitizeForLog } from "../terminal/ansi.js";
|
||||
import { shouldIncludeHook } from "./config.js";
|
||||
@@ -143,14 +144,12 @@ export async function loadInternalHooks(
|
||||
loadedCount++;
|
||||
} catch (err) {
|
||||
log.error(
|
||||
`Failed to load hook ${safeLogValue(entry.hook.name)}: ${safeLogValue(err instanceof Error ? err.message : String(err))}`,
|
||||
`Failed to load hook ${safeLogValue(entry.hook.name)}: ${safeLogValue(formatErrorMessage(err))}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
log.error(
|
||||
`Failed to load directory-based hooks: ${safeLogValue(err instanceof Error ? err.message : String(err))}`,
|
||||
);
|
||||
log.error(`Failed to load directory-based hooks: ${safeLogValue(formatErrorMessage(err))}`);
|
||||
}
|
||||
|
||||
// 2. Load legacy config handlers (backwards compatibility)
|
||||
@@ -232,7 +231,7 @@ export async function loadInternalHooks(
|
||||
loadedCount++;
|
||||
} catch (err) {
|
||||
log.error(
|
||||
`Failed to load hook handler from ${safeLogValue(handlerConfig.module)}: ${safeLogValue(err instanceof Error ? err.message : String(err))}`,
|
||||
`Failed to load hook handler from ${safeLogValue(handlerConfig.module)}: ${safeLogValue(formatErrorMessage(err))}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import { listBundledPluginMetadata } from "../plugins/bundled-plugin-metadata.js";
|
||||
import { loadBundledPluginPublicArtifactModuleSync } from "../plugins/public-surface-loader.js";
|
||||
import type { ResolverContext, SecretDefaults } from "./runtime-shared.js";
|
||||
@@ -45,7 +46,7 @@ function loadBundledChannelPublicArtifact(
|
||||
});
|
||||
} catch (error) {
|
||||
if (process.env.OPENCLAW_DEBUG_CHANNEL_CONTRACT_API === "1") {
|
||||
const detail = error instanceof Error ? error.message : String(error);
|
||||
const detail = formatErrorMessage(error);
|
||||
process.stderr.write(
|
||||
`[channel-contract-api] failed to load ${channelId} via ${metadata.dirName}/${artifactBasename}: ${detail}\n`,
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@ import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { listAgentIds, resolveAgentDir } from "../agents/agent-scope.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
import { listAuthProfileStorePaths as listAuthProfileStorePathsFromAuthStorePaths } from "./auth-store-paths.js";
|
||||
import { parseEnvValue } from "./shared.js";
|
||||
@@ -126,7 +127,7 @@ export function readJsonObjectIfExists(
|
||||
} catch (err) {
|
||||
return {
|
||||
value: null,
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: formatErrorMessage(err),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user