mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-03 23:51:35 +00:00
refactor(errors): consolidate message formatting (#117818)
This commit is contained in:
committed by
GitHub
parent
4b26a15a1f
commit
e98fdeefdf
@@ -30,6 +30,7 @@ import type {
|
||||
PermissionRequest as SdkPermissionRequest,
|
||||
PermissionRequestResult as SdkPermissionRequestResult,
|
||||
} from "@github/copilot-sdk";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
|
||||
/** Request shape forwarded to host-implemented policies. */
|
||||
interface CopilotPermissionContext {
|
||||
@@ -83,20 +84,9 @@ export function createPermissionBridge(
|
||||
} catch (error) {
|
||||
return {
|
||||
kind: "reject",
|
||||
feedback: `copilot permission policy threw: ${formatError(error)}`,
|
||||
feedback: `copilot permission policy threw: ${formatErrorMessage(error)}`,
|
||||
};
|
||||
}
|
||||
return { kind: "reject", feedback: REJECT_ALL_FEEDBACK };
|
||||
};
|
||||
}
|
||||
|
||||
function formatError(error: unknown): string {
|
||||
if (error instanceof Error) {
|
||||
return error.message;
|
||||
}
|
||||
try {
|
||||
return JSON.stringify(error);
|
||||
} catch {
|
||||
return String(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
type ChannelIngressMonitorDeliveryResult,
|
||||
type ChannelIngressMonitorLifecycle,
|
||||
} from "openclaw/plugin-sdk/channel-outbound";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { danger, type RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { normalizeNullableString as nonEmptyString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import type { Client } from "../internal/discord.js";
|
||||
@@ -82,10 +83,6 @@ function decodeDiscordIngressPayload(
|
||||
};
|
||||
}
|
||||
|
||||
function errorText(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
function isDiscordAuthenticationFailure(error: unknown): boolean {
|
||||
let current: unknown = error;
|
||||
const seen = new Set<unknown>();
|
||||
@@ -155,14 +152,14 @@ export function createDiscordIngressMonitor(params: {
|
||||
return { reason: "invalid-event", message: error.message };
|
||||
}
|
||||
if (isDiscordAuthenticationFailure(error)) {
|
||||
return { reason: "authentication-failed", message: errorText(error) };
|
||||
return { reason: "authentication-failed", message: formatErrorMessage(error) };
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onLog: (message) => params.runtime.error?.(danger(`discord ingress: ${message}`)),
|
||||
},
|
||||
onError: (error) =>
|
||||
params.runtime.error?.(danger(`discord ingress drain failed: ${errorText(error)}`)),
|
||||
params.runtime.error?.(danger(`discord ingress drain failed: ${formatErrorMessage(error)}`)),
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Discord plugin module implements send.messages behavior.
|
||||
import type { APIChannel, APIMessage } from "discord-api-types/v10";
|
||||
import { ChannelType } from "discord-api-types/v10";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import {
|
||||
createChannelMessage,
|
||||
createThread,
|
||||
@@ -26,10 +27,6 @@ import type {
|
||||
DiscordThreadList,
|
||||
} from "./send.types.js";
|
||||
|
||||
function formatDiscordThreadInitialMessageError(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
function assertDiscordResponseArray<T>(value: unknown, label: string): T[] {
|
||||
if (!Array.isArray(value)) {
|
||||
throw new Error(`Unexpected Discord response for ${label}: expected array.`);
|
||||
@@ -56,7 +53,7 @@ export class DiscordThreadInitialMessageError extends Error {
|
||||
readonly thread: APIChannel;
|
||||
|
||||
constructor(thread: APIChannel, error: unknown) {
|
||||
const initialMessageError = formatDiscordThreadInitialMessageError(error);
|
||||
const initialMessageError = formatErrorMessage(error);
|
||||
super(
|
||||
`Discord thread was created, but sending the initial message failed: ${initialMessageError}`,
|
||||
);
|
||||
|
||||
@@ -259,10 +259,6 @@ function assertResourceArray<T extends { name?: string }>(
|
||||
return resources;
|
||||
}
|
||||
|
||||
export function getErrorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
async function requestGoogleMeetApi(params: {
|
||||
accessToken: string;
|
||||
path: string;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { exportGoogleDriveDocumentText, extractGoogleDriveDocumentId } from "./drive.js";
|
||||
import {
|
||||
@@ -5,7 +6,6 @@ import {
|
||||
endGoogleMeetActiveConference,
|
||||
fetchGoogleMeetSpace,
|
||||
fetchLatestGoogleMeetConferenceRecord,
|
||||
getErrorMessage,
|
||||
listGoogleMeetParticipants,
|
||||
listGoogleMeetParticipantSessions,
|
||||
listGoogleMeetRecordings,
|
||||
@@ -82,7 +82,7 @@ async function attachDocumentText<T extends { docsDestination?: Record<string, u
|
||||
} catch (error) {
|
||||
return {
|
||||
...params.resource,
|
||||
documentTextError: getErrorMessage(error),
|
||||
documentTextError: formatErrorMessage(error),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -278,7 +278,7 @@ export async function fetchGoogleMeetArtifacts(params: {
|
||||
.then<GoogleMeetSmartNotesListResult>((smartNotes) => ({ smartNotes }))
|
||||
.catch((error: unknown) => ({
|
||||
smartNotes: [],
|
||||
smartNotesError: getErrorMessage(error),
|
||||
smartNotesError: formatErrorMessage(error),
|
||||
})),
|
||||
]);
|
||||
const transcriptEntries =
|
||||
@@ -299,7 +299,7 @@ export async function fetchGoogleMeetArtifacts(params: {
|
||||
return {
|
||||
transcript: transcript.name,
|
||||
entries: [],
|
||||
entriesError: getErrorMessage(error),
|
||||
entriesError: formatErrorMessage(error),
|
||||
};
|
||||
}
|
||||
}),
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
DEFAULT_INGRESS_RETRY_MAX_ATTEMPTS,
|
||||
type ChannelIngressQueue,
|
||||
} from "openclaw/plugin-sdk/channel-outbound";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { danger, type RuntimeEnv, warn } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { normalizeNullableString as nonEmptyString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { runDetachedWebhookWork } from "openclaw/plugin-sdk/webhook-request-guards";
|
||||
@@ -126,10 +127,6 @@ function parseStoredEvent(rawEvent: string): webhook.Event {
|
||||
return event as webhook.Event;
|
||||
}
|
||||
|
||||
function errorText(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
function isLineAuthenticationFailure(error: unknown): boolean {
|
||||
if (!error || typeof error !== "object") {
|
||||
return false;
|
||||
@@ -226,7 +223,9 @@ export function createLineWebhookSpool(options: LineWebhookSpoolOptions): LineWe
|
||||
.then(() => boundLifecycle.onAbandoned())
|
||||
.catch((error: unknown) => {
|
||||
options.runtime.error?.(
|
||||
danger(`line: failed to abandon a late webhook delivery: ${errorText(error)}`),
|
||||
danger(
|
||||
`line: failed to abandon a late webhook delivery: ${formatErrorMessage(error)}`,
|
||||
),
|
||||
);
|
||||
});
|
||||
return;
|
||||
@@ -285,7 +284,7 @@ export function createLineWebhookSpool(options: LineWebhookSpoolOptions): LineWe
|
||||
return { reason: error.reason, message: error.message };
|
||||
}
|
||||
if (isLineAuthenticationFailure(error)) {
|
||||
return { reason: "authentication-failed", message: errorText(error) };
|
||||
return { reason: "authentication-failed", message: formatErrorMessage(error) };
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -293,7 +292,9 @@ export function createLineWebhookSpool(options: LineWebhookSpoolOptions): LineWe
|
||||
},
|
||||
createStoppedError: () => new Error("LINE webhook spool is stopped."),
|
||||
onError: (error) =>
|
||||
options.runtime.error?.(danger(`line: webhook spool drain failed: ${errorText(error)}`)),
|
||||
options.runtime.error?.(
|
||||
danger(`line: webhook spool drain failed: ${formatErrorMessage(error)}`),
|
||||
),
|
||||
});
|
||||
let stopTask: Promise<void> | undefined;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createRequire } from "node:module";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
|
||||
export type NodeLlamaCppModule = typeof import("node-llama-cpp");
|
||||
|
||||
@@ -11,10 +12,6 @@ function isNodeLlamaCppMissing(error: unknown): boolean {
|
||||
return code === "ERR_MODULE_NOT_FOUND" && error.message.includes("node-llama-cpp");
|
||||
}
|
||||
|
||||
function formatErrorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
export function formatLlamaCppSetupError(error: unknown): string {
|
||||
const detail = formatErrorMessage(error);
|
||||
const missing = isNodeLlamaCppMissing(error);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Matrix plugin module implements channel account paths behavior.
|
||||
import { createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
|
||||
import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import type { PinnedDispatcherPolicy, SsrFPolicy } from "openclaw/plugin-sdk/ssrf-dispatcher";
|
||||
import { formatMatrixErrorMessage } from "./matrix/errors.js";
|
||||
import type { MatrixProbe } from "./matrix/probe.js";
|
||||
import type { CoreConfig } from "./types.js";
|
||||
|
||||
@@ -66,7 +66,7 @@ export function createMatrixProbeAccount(params: {
|
||||
} catch (err) {
|
||||
return {
|
||||
ok: false,
|
||||
error: formatMatrixErrorMessage(err),
|
||||
error: formatErrorMessage(err),
|
||||
elapsedMs: 0,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Command } from "commander";
|
||||
import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import * as cli from "./cli-shared.js";
|
||||
import { resolveMatrixAccountConfig } from "./matrix/accounts.js";
|
||||
import { listMatrixOwnDevices } from "./matrix/actions/devices.js";
|
||||
@@ -162,7 +163,7 @@ async function addMatrixAccount(params: {
|
||||
avatarUpdated: false,
|
||||
resolvedAvatarUrl: null,
|
||||
convertedAvatarFromHttp: false,
|
||||
error: cli.formatMatrixErrorMessage(err),
|
||||
error: formatErrorMessage(err),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -180,7 +181,7 @@ async function addMatrixAccount(params: {
|
||||
deviceHealth = {
|
||||
currentDeviceId: null,
|
||||
staleOpenClawDeviceIds: [],
|
||||
error: cli.formatMatrixErrorMessage(err),
|
||||
error: formatErrorMessage(err),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { parseStrictInteger } from "openclaw/plugin-sdk/number-runtime";
|
||||
import { readByteStreamWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
|
||||
import { resolveMatrixRoomKeyBackupIssue } from "./matrix/backup-health.js";
|
||||
import { resolveMatrixAuthContext } from "./matrix/client.js";
|
||||
import { setMatrixSdkConsoleLogging, setMatrixSdkLogMode } from "./matrix/client/logging.js";
|
||||
import { formatMatrixErrorMessage } from "./matrix/errors.js";
|
||||
import type { MatrixOwnDeviceVerificationStatus, MatrixRoomKeyBackupStatus } from "./matrix/sdk.js";
|
||||
import type { MatrixVerificationSummary } from "./matrix/sdk/verification-manager.js";
|
||||
import { formatZonedTimestamp } from "./runtime-api.js";
|
||||
import { getMatrixRuntime } from "./runtime.js";
|
||||
import type { CoreConfig } from "./types.js";
|
||||
|
||||
export { formatMatrixErrorMessage };
|
||||
|
||||
let matrixCliExitScheduled = false;
|
||||
const MATRIX_CLI_RECOVERY_KEY_STDIN_MAX_BYTES = 1024 * 1024;
|
||||
|
||||
@@ -202,7 +200,7 @@ export async function runMatrixCliCommand<TResult>(
|
||||
markCliFailure();
|
||||
}
|
||||
} catch (err) {
|
||||
const message = formatMatrixErrorMessage(err);
|
||||
const message = formatErrorMessage(err);
|
||||
if (config.json) {
|
||||
printJson(config.onJsonError ? config.onJsonError(message) : { error: message });
|
||||
} else {
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
|
||||
export function formatMatrixErrorMessage(err: unknown): string {
|
||||
return formatErrorMessage(err);
|
||||
}
|
||||
|
||||
export function formatMatrixErrorReason(err: unknown): string {
|
||||
return normalizeLowercaseStringOrEmpty(formatMatrixErrorMessage(err));
|
||||
return normalizeLowercaseStringOrEmpty(formatErrorMessage(err));
|
||||
}
|
||||
|
||||
export function isMatrixNotFoundError(err: unknown): boolean {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { resolveInboundMentionDecision } from "openclaw/plugin-sdk/channel-inbound";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { buildInboundHistoryFromEntries } from "openclaw/plugin-sdk/reply-history";
|
||||
import { formatMatrixErrorMessage } from "../errors.js";
|
||||
import { isMatrixMediaSizeLimitError } from "../media-errors.js";
|
||||
import { isLikelyBareFilename } from "../media-text.js";
|
||||
import { fetchMatrixPollSnapshot, type MatrixPollSnapshot } from "../poll-summary.js";
|
||||
@@ -218,7 +218,7 @@ export async function resolveMatrixIngressContent(config: {
|
||||
if (isMatrixMediaSizeLimitError(err)) {
|
||||
preflightMediaSizeLimitExceeded = true;
|
||||
}
|
||||
const errorText = formatMatrixErrorMessage(err);
|
||||
const errorText = formatErrorMessage(err);
|
||||
logVerboseMessage(
|
||||
`matrix: media download failed room=${roomId} id=${event.event_id ?? "unknown"} type=${content.msgtype} error=${errorText}`,
|
||||
);
|
||||
@@ -413,7 +413,7 @@ export async function resolveMatrixIngressContent(config: {
|
||||
if (isMatrixMediaSizeLimitError(err)) {
|
||||
mediaSizeLimitExceeded = true;
|
||||
}
|
||||
const errorText = formatMatrixErrorMessage(err);
|
||||
const errorText = formatErrorMessage(err);
|
||||
logVerboseMessage(
|
||||
`matrix: media download failed room=${roomId} id=${event.event_id ?? "unknown"} type=${content.msgtype} error=${errorText}`,
|
||||
);
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { readJsonFileWithFallback } from "openclaw/plugin-sdk/json-store";
|
||||
import { timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
|
||||
import { getMatrixRuntime } from "../../runtime.js";
|
||||
import type { MatrixConfig } from "../../types.js";
|
||||
import { recordCurrentStorageMetaDeviceId, resolveMatrixStoragePaths } from "../client/storage.js";
|
||||
import type { MatrixAuth } from "../client/types.js";
|
||||
import { formatMatrixErrorMessage } from "../errors.js";
|
||||
import type { MatrixClient, MatrixOwnDeviceVerificationStatus } from "../sdk.js";
|
||||
import { resolveMatrixSqliteStateEnv } from "../sqlite-state.js";
|
||||
|
||||
@@ -388,7 +388,7 @@ export async function ensureMatrixStartupVerification(params: {
|
||||
transactionId: request.transactionId ?? undefined,
|
||||
};
|
||||
} catch (err) {
|
||||
const error = formatMatrixErrorMessage(err);
|
||||
const error = formatErrorMessage(err);
|
||||
await writeStartupVerificationState({
|
||||
auth: params.auth,
|
||||
env: params.env,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// Matrix plugin module implements status behavior.
|
||||
import type { ChannelAccountSnapshot } from "openclaw/plugin-sdk/channel-contract";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import {
|
||||
createConnectedChannelStatusPatch,
|
||||
createTransportActivityStatusPatch,
|
||||
} from "openclaw/plugin-sdk/gateway-runtime";
|
||||
import { formatMatrixErrorMessage } from "../errors.js";
|
||||
import {
|
||||
isMatrixDisconnectedSyncState,
|
||||
isMatrixReadySyncState,
|
||||
@@ -29,7 +29,7 @@ function formatSyncError(error: unknown): string | null {
|
||||
if (error instanceof Error) {
|
||||
return error.message || error.name || "unknown";
|
||||
}
|
||||
return formatMatrixErrorMessage(error);
|
||||
return formatErrorMessage(error);
|
||||
}
|
||||
|
||||
export type MatrixMonitorStatusController = ReturnType<typeof createMatrixMonitorStatusController>;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// Matrix plugin module implements sdk behavior.
|
||||
import type { Room } from "matrix-js-sdk/lib/models/room.js";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { normalizeStringEntries, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { resolveMatrixRoomKeyBackupReadinessError } from "./backup-health.js";
|
||||
import { formatMatrixErrorMessage, isMatrixNotFoundError } from "./errors.js";
|
||||
import { isMatrixNotFoundError } from "./errors.js";
|
||||
import {
|
||||
listMatrixOwnDevices,
|
||||
resolveMatrixCrossSigningPublicationStatus,
|
||||
@@ -104,7 +105,7 @@ export class MatrixClient extends MatrixClientVerification {
|
||||
keyId: stagedKeyId,
|
||||
});
|
||||
} catch (err) {
|
||||
return await fail(formatMatrixErrorMessage(err));
|
||||
return await fail(formatErrorMessage(err));
|
||||
}
|
||||
|
||||
const storedRecoveryKeyMatches =
|
||||
@@ -260,7 +261,7 @@ export class MatrixClient extends MatrixClientVerification {
|
||||
};
|
||||
} catch (err) {
|
||||
this.recoveryKeyStore.discardStagedRecoveryKey();
|
||||
return await fail(formatMatrixErrorMessage(err));
|
||||
return await fail(formatErrorMessage(err));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,7 +336,7 @@ export class MatrixClient extends MatrixClientVerification {
|
||||
};
|
||||
} catch (err) {
|
||||
this.recoveryKeyStore.discardStagedRecoveryKey();
|
||||
return await fail(formatMatrixErrorMessage(err));
|
||||
return await fail(formatErrorMessage(err));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,7 +438,7 @@ export class MatrixClient extends MatrixClientVerification {
|
||||
backup,
|
||||
};
|
||||
} catch (err) {
|
||||
return await fail(formatMatrixErrorMessage(err));
|
||||
return await fail(formatErrorMessage(err));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -510,7 +511,7 @@ export class MatrixClient extends MatrixClientVerification {
|
||||
await this.ensureRoomKeyBackupEnabled(crypto);
|
||||
} catch (err) {
|
||||
this.recoveryKeyStore.discardStagedRecoveryKey();
|
||||
bootstrapError = formatMatrixErrorMessage(err);
|
||||
bootstrapError = formatErrorMessage(err);
|
||||
}
|
||||
|
||||
const verification = await this.getOwnDeviceVerificationStatus();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { normalizeNullableString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { formatMatrixErrorMessage } from "../errors.js";
|
||||
import { loadMatrixCryptoRuntime } from "./client-base.js";
|
||||
import { MatrixClientCore } from "./client-core.js";
|
||||
import {
|
||||
@@ -65,7 +65,7 @@ export abstract class MatrixClientVerification extends MatrixClientCore {
|
||||
try {
|
||||
await crypto.loadSessionBackupPrivateKeyFromSecretStorage(); // pragma: allowlist secret
|
||||
} catch (err) {
|
||||
keyLoadError = formatMatrixErrorMessage(err);
|
||||
keyLoadError = formatErrorMessage(err);
|
||||
}
|
||||
} else {
|
||||
keyLoadError =
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import path from "node:path";
|
||||
// Matrix plugin module implements recovery key store behavior.
|
||||
import { decodeRecoveryKey } from "matrix-js-sdk/lib/crypto-api/recovery-key.js";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import {
|
||||
migrateLegacyMatrixRecoveryKeyFilePathToStore,
|
||||
readLegacyMatrixRecoveryKeyFile,
|
||||
readMatrixRecoveryKeyStateForPath,
|
||||
writeMatrixRecoveryKeyStateForPath,
|
||||
} from "../crypto-state-store.js";
|
||||
import { formatMatrixErrorMessage, formatMatrixErrorReason } from "../errors.js";
|
||||
import { formatMatrixErrorReason } from "../errors.js";
|
||||
import { LogService } from "./logger.js";
|
||||
import type {
|
||||
MatrixCryptoBootstrapApi,
|
||||
@@ -174,7 +175,7 @@ export class MatrixRecoveryKeyStore {
|
||||
try {
|
||||
privateKey = decodeRecoveryKey(encodedPrivateKey);
|
||||
} catch (err) {
|
||||
throw new Error(`Invalid Matrix recovery key: ${formatMatrixErrorMessage(err)}`, {
|
||||
throw new Error(`Invalid Matrix recovery key: ${formatErrorMessage(err)}`, {
|
||||
cause: err,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ import {
|
||||
VerifierEvent,
|
||||
} from "matrix-js-sdk/lib/crypto-api/verification.js";
|
||||
import { VerificationMethod } from "matrix-js-sdk/lib/types.js";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
// Matrix plugin module implements verification manager behavior.
|
||||
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
||||
import {
|
||||
resolveDateTimestampMs,
|
||||
resolveTimestampMsToIsoString,
|
||||
} from "openclaw/plugin-sdk/number-runtime";
|
||||
import { formatMatrixErrorMessage } from "../errors.js";
|
||||
|
||||
export type MatrixVerificationMethod = "sas" | "show-qr" | "scan-qr";
|
||||
type MatrixVerificationPhase = VerificationPhase | -1;
|
||||
@@ -398,7 +398,7 @@ export class MatrixVerificationManager {
|
||||
})
|
||||
.catch((err: unknown) => {
|
||||
session.acceptRequested = false;
|
||||
session.error = formatMatrixErrorMessage(err);
|
||||
session.error = formatErrorMessage(err);
|
||||
this.touchVerificationSession(session);
|
||||
});
|
||||
}
|
||||
@@ -483,7 +483,7 @@ export class MatrixVerificationManager {
|
||||
});
|
||||
verifier.on(VerifierEvent.Cancel, (err) => {
|
||||
this.clearSasAutoConfirmTimer(session);
|
||||
session.error = formatMatrixErrorMessage(err);
|
||||
session.error = formatErrorMessage(err);
|
||||
this.touchVerificationSession(session);
|
||||
});
|
||||
this.ensureVerificationStarted(session);
|
||||
@@ -519,7 +519,7 @@ export class MatrixVerificationManager {
|
||||
this.touchVerificationSession(session);
|
||||
})
|
||||
.catch((err: unknown) => {
|
||||
session.error = formatMatrixErrorMessage(err);
|
||||
session.error = formatErrorMessage(err);
|
||||
this.touchVerificationSession(session);
|
||||
});
|
||||
}, SAS_AUTO_CONFIRM_DELAY_MS);
|
||||
@@ -548,7 +548,7 @@ export class MatrixVerificationManager {
|
||||
this.touchVerificationSession(session);
|
||||
})
|
||||
.catch((err: unknown) => {
|
||||
session.error = formatMatrixErrorMessage(err);
|
||||
session.error = formatErrorMessage(err);
|
||||
this.touchVerificationSession(session);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
// Matrix plugin module implements plugin entry behavior.
|
||||
import type { GatewayRequestHandlerOptions } from "openclaw/plugin-sdk/gateway-runtime";
|
||||
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
||||
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { formatMatrixErrorMessage } from "./matrix/errors.js";
|
||||
|
||||
const loadMatrixVerificationRuntime = createLazyRuntimeModule(
|
||||
() => import("./matrix/actions/verification.js"),
|
||||
);
|
||||
|
||||
function sendError(respond: (ok: boolean, payload?: unknown) => void, err: unknown) {
|
||||
respond(false, { error: formatMatrixErrorMessage(err) });
|
||||
respond(false, { error: formatErrorMessage(err) });
|
||||
}
|
||||
|
||||
export async function handleVerifyRecoveryKey({
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
// Matrix plugin module implements setup bootstrap behavior.
|
||||
import { hasExplicitMatrixAccountConfig } from "./matrix/account-config.js";
|
||||
import { resolveMatrixAccountConfig } from "./matrix/accounts.js";
|
||||
import { bootstrapMatrixVerification } from "./matrix/actions/verification.js";
|
||||
import { formatMatrixErrorMessage } from "./matrix/errors.js";
|
||||
import type { RuntimeEnv } from "./runtime-api.js";
|
||||
import type { CoreConfig } from "./types.js";
|
||||
|
||||
@@ -61,7 +61,7 @@ export async function maybeBootstrapNewEncryptedMatrixAccount(params: {
|
||||
success: false,
|
||||
recoveryKeyCreatedAt: null,
|
||||
backupVersion: null,
|
||||
error: formatMatrixErrorMessage(err),
|
||||
error: formatErrorMessage(err),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Buffer } from "node:buffer";
|
||||
import type { AgentToolResult } from "openclaw/plugin-sdk/agent-core";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
|
||||
import { toErrorObject } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { formatErrorMessage, toErrorObject } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { resolveGlobalSingleton } from "openclaw/plugin-sdk/global-singleton";
|
||||
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
||||
import { canonicalizeBase64 } from "openclaw/plugin-sdk/media-runtime";
|
||||
@@ -383,10 +383,6 @@ export async function runWithTimeout<T>(params: {
|
||||
}
|
||||
}
|
||||
|
||||
export function formatMemoryRecallError(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
export function isMemoryRecallTimeoutError(error: unknown): boolean {
|
||||
let current: unknown = error;
|
||||
for (let depth = 0; depth < 3 && current !== undefined; depth += 1) {
|
||||
@@ -433,7 +429,7 @@ export function buildMemoryRecallUnavailableResult(error: string): AgentToolResu
|
||||
|
||||
export class MemoryRecallEmbeddingError extends Error {
|
||||
constructor(readonly originalError: unknown) {
|
||||
super(formatMemoryRecallError(originalError));
|
||||
super(formatErrorMessage(originalError));
|
||||
this.name = "MemoryRecallEmbeddingError";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
optionalPositiveIntegerSchema,
|
||||
} from "openclaw/plugin-sdk/channel-actions";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
||||
import { readFiniteNumberParam, readPositiveIntegerParam } from "openclaw/plugin-sdk/param-readers";
|
||||
import { resolveLivePluginConfigObject } from "openclaw/plugin-sdk/plugin-config-runtime";
|
||||
@@ -24,7 +25,6 @@ import {
|
||||
import {
|
||||
buildMemoryRecallUnavailableResult,
|
||||
createEmbeddings,
|
||||
formatMemoryRecallError,
|
||||
isMemoryRecallTimeoutError,
|
||||
MemoryRecallEmbeddingError,
|
||||
runWithTimeout,
|
||||
@@ -250,7 +250,7 @@ export default definePluginEntry({
|
||||
if (!(error instanceof MemoryRecallEmbeddingError)) {
|
||||
throw error;
|
||||
}
|
||||
const message = formatMemoryRecallError(error.originalError);
|
||||
const message = formatErrorMessage(error.originalError);
|
||||
if (isMemoryRecallTimeoutError(error.originalError)) {
|
||||
recordMemoryRecallCooldown(agentId, message);
|
||||
}
|
||||
@@ -587,7 +587,7 @@ export default definePluginEntry({
|
||||
err instanceof MemoryRecallEmbeddingError &&
|
||||
isMemoryRecallTimeoutError(err.originalError)
|
||||
) {
|
||||
recordMemoryRecallCooldown(agentId, formatMemoryRecallError(err.originalError));
|
||||
recordMemoryRecallCooldown(agentId, formatErrorMessage(err.originalError));
|
||||
}
|
||||
api.logger.warn(`memory-lancedb: recall failed: ${String(err)}`);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
type ChannelIngressMonitorDeliveryResult,
|
||||
type ChannelIngressMonitorLifecycle,
|
||||
} from "openclaw/plugin-sdk/channel-outbound";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { normalizeNullableString as nonEmptyString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { classifyMSTeamsSendError } from "./errors.js";
|
||||
@@ -132,10 +133,6 @@ function parseClaimedActivity(
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function errorText(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
export function createMSTeamsIngress(options: MSTeamsIngressOptions): MSTeamsIngress {
|
||||
const queue =
|
||||
options.queue ??
|
||||
@@ -193,14 +190,14 @@ export function createMSTeamsIngress(options: MSTeamsIngressOptions): MSTeamsIng
|
||||
}
|
||||
const classification = classifyMSTeamsSendError(error);
|
||||
return classification.kind === "auth"
|
||||
? { reason: "authentication-failed", message: errorText(error) }
|
||||
? { reason: "authentication-failed", message: formatErrorMessage(error) }
|
||||
: null;
|
||||
},
|
||||
onLog: (message) => options.runtime.error?.(`msteams: ${message}`),
|
||||
},
|
||||
createStoppedError: () => new Error("Microsoft Teams ingress stopped."),
|
||||
onError: (error) =>
|
||||
options.runtime.error?.(`msteams ingress drain failed: ${errorText(error)}`),
|
||||
options.runtime.error?.(`msteams ingress drain failed: ${formatErrorMessage(error)}`),
|
||||
});
|
||||
let stopTask: Promise<void> | undefined;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { readFileSync, statSync } from "node:fs";
|
||||
import { win32 } from "node:path";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
DEFAULT_SANDBOX_BASELINE,
|
||||
@@ -278,7 +279,7 @@ function assertConfiguredPathExists(pathValue: string, source: string): void {
|
||||
);
|
||||
}
|
||||
throw new Error(
|
||||
`Sandbox policy path ${pathValue} configured by ${source} is not accessible on the host: ${formatError(err)}`,
|
||||
`Sandbox policy path ${pathValue} configured by ${source} is not accessible on the host: ${formatErrorMessage(err)}`,
|
||||
{ cause: err },
|
||||
);
|
||||
}
|
||||
@@ -306,9 +307,12 @@ function policyFileError(policyPath: string, err: unknown): Error {
|
||||
{ cause: err },
|
||||
);
|
||||
}
|
||||
return new Error(`Failed to load sandbox policy file at ${policyPath}: ${formatError(err)}`, {
|
||||
cause: err instanceof Error ? err : undefined,
|
||||
});
|
||||
return new Error(
|
||||
`Failed to load sandbox policy file at ${policyPath}: ${formatErrorMessage(err)}`,
|
||||
{
|
||||
cause: err instanceof Error ? err : undefined,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function formatSandboxPolicyIssue(sourceLabel: string, issue: z.ZodIssue | undefined): string {
|
||||
@@ -347,13 +351,6 @@ function formatIssuePath(pathSegments: readonly PropertyKey[]): string {
|
||||
return label;
|
||||
}
|
||||
|
||||
function formatError(err: unknown): string {
|
||||
if (err instanceof Error && err.message) {
|
||||
return err.message;
|
||||
}
|
||||
return String(err);
|
||||
}
|
||||
|
||||
function isNodeError(err: unknown): err is NodeJS.ErrnoException {
|
||||
return err instanceof Error && "code" in err;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Nextcloud Talk plugin module implements monitor behavior.
|
||||
import { createServer, type IncomingMessage, type Server, type ServerResponse } from "node:http";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import {
|
||||
WEBHOOK_RATE_LIMIT_DEFAULTS,
|
||||
createAuthRateLimiter,
|
||||
@@ -27,13 +28,6 @@ const WEBHOOK_ERRORS = {
|
||||
internalServerError: "Internal server error",
|
||||
} as const;
|
||||
|
||||
function formatError(err: unknown): string {
|
||||
if (err instanceof Error) {
|
||||
return err.message;
|
||||
}
|
||||
return typeof err === "string" ? err : JSON.stringify(err);
|
||||
}
|
||||
|
||||
function writeJsonResponse(
|
||||
res: ServerResponse,
|
||||
status: number,
|
||||
@@ -206,7 +200,7 @@ export function createNextcloudTalkWebhookServer(opts: NextcloudTalkWebhookServe
|
||||
writeWebhookError(res, 400, WEBHOOK_ERRORS.invalidPayloadFormat);
|
||||
return;
|
||||
}
|
||||
const error = err instanceof Error ? err : new Error(formatError(err));
|
||||
const error = err instanceof Error ? err : new Error(formatErrorMessage(err));
|
||||
onError?.(error);
|
||||
writeWebhookError(res, 500, WEBHOOK_ERRORS.internalServerError);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
// Qa Lab plugin module implements app behavior.
|
||||
import { defaultQaModelForMode, isQaFastModeEnabled } from "../../model-selection.js";
|
||||
import { normalizeCaptureSavedView, normalizeCaptureSavedViews } from "./capture-saved-view.js";
|
||||
import { formatErrorMessage } from "./errors.js";
|
||||
import { getJson, getJsonNoStore, postJson, QaLabHttpError } from "./http.js";
|
||||
import { conversationSelectionKey, findConversationBySelectionKey } from "./ui-conversation-key.js";
|
||||
import {
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
// Qa Lab plugin module implements errors behavior.
|
||||
export function formatErrorMessage(err: unknown): string {
|
||||
if (err instanceof Error) {
|
||||
let formatted = err.message || err.name || "Error";
|
||||
let cause: unknown = err.cause;
|
||||
const seen = new Set<unknown>([err]);
|
||||
while (cause && !seen.has(cause)) {
|
||||
seen.add(cause);
|
||||
if (cause instanceof Error) {
|
||||
if (cause.message) {
|
||||
formatted += ` | ${cause.message}`;
|
||||
}
|
||||
cause = cause.cause;
|
||||
continue;
|
||||
}
|
||||
if (typeof cause === "string") {
|
||||
formatted += ` | ${cause}`;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return formatted;
|
||||
}
|
||||
if (typeof err === "string") {
|
||||
return err;
|
||||
}
|
||||
if (typeof err === "number" || typeof err === "boolean" || typeof err === "bigint") {
|
||||
return String(err);
|
||||
}
|
||||
try {
|
||||
return JSON.stringify(err);
|
||||
} catch {
|
||||
return Object.prototype.toString.call(err);
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
* - `redactBodyKeys` replaces the hardcoded `file_data` redaction.
|
||||
*/
|
||||
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import {
|
||||
readProviderTextResponse,
|
||||
readResponseTextLimited,
|
||||
@@ -16,7 +17,6 @@ import {
|
||||
import { fetchWithSsrFGuard, type SsrFPolicy } from "openclaw/plugin-sdk/ssrf-runtime";
|
||||
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
||||
import { ApiError, type ApiClientConfig, type EngineLogger } from "../types.js";
|
||||
import { formatErrorMessage } from "../utils/format.js";
|
||||
|
||||
const DEFAULT_BASE_URL = "https://api.sgroup.qq.com";
|
||||
const DEFAULT_TIMEOUT_MS = 30_000;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* - Markdown support flag is per-instance, not a global Map.
|
||||
*/
|
||||
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import type {
|
||||
ChatScope,
|
||||
MessageResponse,
|
||||
@@ -15,7 +16,6 @@ import type {
|
||||
InlineKeyboard,
|
||||
StreamMessageRequest,
|
||||
} from "../types.js";
|
||||
import { formatErrorMessage } from "../utils/format.js";
|
||||
import { ApiClient } from "./api-client.js";
|
||||
import {
|
||||
messagePath,
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
* parameterized by `RetryPolicy` and optional `PersistentRetryPolicy`.
|
||||
*/
|
||||
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { createChannelApiRetryRunner, resolveRetryConfig } from "openclaw/plugin-sdk/retry-runtime";
|
||||
import { sleep } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
||||
import type { EngineLogger } from "../types.js";
|
||||
import { formatErrorMessage } from "../utils/format.js";
|
||||
|
||||
/** Standard retry policy with exponential or fixed backoff. */
|
||||
interface RetryPolicy {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* globals, fully supporting multi-account concurrent operation.
|
||||
*/
|
||||
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import {
|
||||
asDateTimestampMs,
|
||||
parseStrictPositiveInteger,
|
||||
@@ -16,7 +17,6 @@ import { readResponseTextLimited } from "openclaw/plugin-sdk/provider-http";
|
||||
import { sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { fetchWithSsrFGuard, type SsrFPolicy } from "openclaw/plugin-sdk/ssrf-runtime";
|
||||
import type { EngineLogger } from "../types.js";
|
||||
import { formatErrorMessage } from "../utils/format.js";
|
||||
|
||||
const TOKEN_URL = "https://bots.qq.com/app/getAppAccessToken";
|
||||
const DEFAULT_TOKEN_EXPIRES_IN_SECONDS = 7200;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
// Qqbot plugin module implements message queue behavior.
|
||||
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
||||
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
||||
import { formatErrorMessage } from "../utils/format.js";
|
||||
import { isQQBotAuthenticationFailure } from "./ingress-errors.js";
|
||||
import { buildQQBotMergedIngressLifecycle } from "./message-queue-ingress.js";
|
||||
import type { QQBotIngressLifecycle } from "./types.js";
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
*/
|
||||
|
||||
import { createTypingKeepaliveLoop } from "openclaw/plugin-sdk/channel-outbound";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { claimMessageReply } from "../messaging/outbound-reply.js";
|
||||
import type { ReplyLimitResult } from "../messaging/reply-limiter.js";
|
||||
import { formatErrorMessage } from "../utils/format.js";
|
||||
|
||||
/** Function that sends a typing indicator to one user. */
|
||||
type SendInputNotifyFn = (
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
* `DeliverDeps.mediaSender`.
|
||||
*/
|
||||
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import {
|
||||
sendPayloadMediaSequence,
|
||||
sendPayloadTextChunkSequence,
|
||||
} from "openclaw/plugin-sdk/reply-payload";
|
||||
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
||||
import type { GatewayAccount } from "../types.js";
|
||||
import { formatErrorMessage } from "../utils/format.js";
|
||||
import { getImageSize, formatQQBotMarkdownImage, hasQQBotImageSize } from "../utils/image-size.js";
|
||||
import { normalizeMediaTags } from "../utils/media-tags.js";
|
||||
import { isLocalPath as isLocalFilePath } from "../utils/platform.js";
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { mkdir, writeFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { extensionForMime, type MediaKind } from "openclaw/plugin-sdk/media-mime";
|
||||
import { loadOutboundMediaFromUrl } from "openclaw/plugin-sdk/outbound-media";
|
||||
import {
|
||||
@@ -23,7 +24,6 @@ import {
|
||||
getMaxUploadSize,
|
||||
readFileAsync,
|
||||
} from "../utils/file-utils.js";
|
||||
import { formatErrorMessage } from "../utils/format.js";
|
||||
import { debugError, debugLog, debugWarn } from "../utils/log.js";
|
||||
import {
|
||||
getQQBotDataDir,
|
||||
|
||||
@@ -33,10 +33,10 @@ export {
|
||||
sendVoice,
|
||||
} from "./outbound-media-send.js";
|
||||
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
||||
import type { GatewayAccount } from "../types.js";
|
||||
import type { EngineLogger } from "../types.js";
|
||||
import { formatErrorMessage } from "../utils/format.js";
|
||||
import { debugError, debugLog, debugWarn } from "../utils/log.js";
|
||||
import { normalizeMediaTags } from "../utils/media-tags.js";
|
||||
import { decodeCronPayload } from "../utils/payload.js";
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
|
||||
import crypto from "node:crypto";
|
||||
import path from "node:path";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { resolveLocalPathFromRootsSync } from "openclaw/plugin-sdk/security-runtime";
|
||||
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
||||
import { MediaFileType, type GatewayAccount } from "../types.js";
|
||||
import { formatFileSize, getImageMimeType, getMaxUploadSize } from "../utils/file-utils.js";
|
||||
import { formatErrorMessage } from "../utils/format.js";
|
||||
import {
|
||||
parseQQBotPayload,
|
||||
encodePayloadForCron,
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
import os from "node:os";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
||||
import { ApiClient } from "../api/api-client.js";
|
||||
import { ChunkedMediaApi as ChunkedMediaApiClass } from "../api/media-chunked.js";
|
||||
@@ -43,7 +44,6 @@ import {
|
||||
type UploadMediaResponse,
|
||||
} from "../types.js";
|
||||
import { getMaxUploadSize, LARGE_FILE_THRESHOLD } from "../utils/file-utils.js";
|
||||
import { formatErrorMessage } from "../utils/format.js";
|
||||
import { debugLog, debugError, debugWarn } from "../utils/log.js";
|
||||
import { sanitizeFileName } from "../utils/string-normalize.js";
|
||||
import { computeFileHash, getCachedFileInfo, setCachedFileInfo } from "../utils/upload-cache.js";
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* it is treated as a new message.
|
||||
*/
|
||||
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
||||
import { getNextMsgSeq } from "../api/routes.js";
|
||||
import type { GatewayAccount } from "../types.js";
|
||||
@@ -37,10 +38,6 @@ import {
|
||||
type MediaSendContext,
|
||||
} from "./streaming-media-send.js";
|
||||
|
||||
function formatStreamErr(e: unknown): string {
|
||||
return e instanceof Error ? e.message : String(e);
|
||||
}
|
||||
|
||||
// ============ 常量 ============
|
||||
|
||||
/** 流式消息节流常量(毫秒) */
|
||||
@@ -485,7 +482,7 @@ export class StreamingController {
|
||||
() => this.handlePartialReply(payload),
|
||||
(err: unknown) => {
|
||||
// 上一次如果异常,不阻塞后续调用
|
||||
this.logError(`onPartialReply chain error: ${formatStreamErr(err)}`);
|
||||
this.logError(`onPartialReply chain error: ${formatErrorMessage(err)}`);
|
||||
return this.handlePartialReply(payload);
|
||||
},
|
||||
);
|
||||
@@ -590,7 +587,7 @@ export class StreamingController {
|
||||
this.callbackChain = this.callbackChain.then(
|
||||
() => this.handleIdle(payload),
|
||||
(err: unknown) => {
|
||||
this.logError(`onIdle chain error: ${formatStreamErr(err)}`);
|
||||
this.logError(`onIdle chain error: ${formatErrorMessage(err)}`);
|
||||
return this.handleIdle(payload);
|
||||
},
|
||||
);
|
||||
@@ -674,7 +671,7 @@ export class StreamingController {
|
||||
await this.sendStreamChunk(safeText, StreamInputState.DONE, "onIdle");
|
||||
this.logInfo(`streaming completed, final text length: ${safeText.length}`);
|
||||
} catch (err) {
|
||||
this.logError(`failed to send final stream chunk: ${formatStreamErr(err)}`);
|
||||
this.logError(`failed to send final stream chunk: ${formatErrorMessage(err)}`);
|
||||
}
|
||||
} else if (this.sentStreamChunkCount > 0) {
|
||||
// 没有活跃流式会话,但之前发过流式分片或媒体 → 正常完成
|
||||
@@ -693,7 +690,7 @@ export class StreamingController {
|
||||
* 处理错误
|
||||
*/
|
||||
async onError(err: unknown): Promise<void> {
|
||||
this.logError(`reply error: ${formatStreamErr(err)}`);
|
||||
this.logError(`reply error: ${formatErrorMessage(err)}`);
|
||||
|
||||
if (this.isTerminalPhase) {
|
||||
return;
|
||||
@@ -726,7 +723,7 @@ export class StreamingController {
|
||||
: "**Error**: 生成响应时发生错误。";
|
||||
await this.sendStreamChunk(errorText, StreamInputState.DONE, "onError");
|
||||
} catch (sendErr) {
|
||||
this.logError(`failed to send error stream chunk: ${formatStreamErr(sendErr)}`);
|
||||
this.logError(`failed to send error stream chunk: ${formatErrorMessage(sendErr)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -759,7 +756,7 @@ export class StreamingController {
|
||||
await this.sendStreamChunk(abortText, StreamInputState.DONE, "abortStreaming");
|
||||
this.logInfo(`streaming aborted, sent final chunk`);
|
||||
} catch (err) {
|
||||
this.logError(`abort send failed: ${formatStreamErr(err)}`);
|
||||
this.logError(`abort send failed: ${formatErrorMessage(err)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -871,7 +868,7 @@ export class StreamingController {
|
||||
}
|
||||
await this.flush.throttledUpdate(this.throttleMs);
|
||||
} catch (err) {
|
||||
this.logError(`processMediaTags failed: ${formatStreamErr(err)}`);
|
||||
this.logError(`processMediaTags failed: ${formatErrorMessage(err)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -907,7 +904,7 @@ export class StreamingController {
|
||||
await this.sendStreamChunk(safeText, StreamInputState.DONE, caller);
|
||||
this.logDebug(`${caller}: current stream session ended`);
|
||||
} catch (err) {
|
||||
this.logError(`${caller}: failed to end stream: ${formatStreamErr(err)}`);
|
||||
this.logError(`${caller}: failed to end stream: ${formatErrorMessage(err)}`);
|
||||
}
|
||||
} else if (safeText && safeText.trim()) {
|
||||
// 没有活跃流式会话,但有非空白文本未发送 → 启动流式 → 立即终结
|
||||
@@ -926,7 +923,7 @@ export class StreamingController {
|
||||
await this.sendStreamChunk(safeText, StreamInputState.DONE, caller);
|
||||
this.logDebug(`${caller}: started and ended stream for pre-tag text`);
|
||||
} catch (err) {
|
||||
this.logError(`${caller}: failed to send pre-tag text: ${formatStreamErr(err)}`);
|
||||
this.logError(`${caller}: failed to send pre-tag text: ${formatErrorMessage(err)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1023,7 +1020,7 @@ export class StreamingController {
|
||||
this.flush.setReady(true);
|
||||
this.logInfo(`stream started, stream_msg_id=${resp.id}`);
|
||||
} catch (err) {
|
||||
this.logError(`failed to start streaming: ${formatStreamErr(err)}`);
|
||||
this.logError(`failed to start streaming: ${formatErrorMessage(err)}`);
|
||||
this.transition("idle", "doStartStreaming", "start_failed_will_retry");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* 拆分、路径编码修复,以及统一的发送队列执行器。
|
||||
*/
|
||||
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
||||
import type { GatewayAccount } from "../types.js";
|
||||
import { normalizePath } from "../utils/platform.js";
|
||||
@@ -21,10 +22,6 @@ import {
|
||||
} from "./outbound.js";
|
||||
import { raceWithTimeout } from "./race-with-timeout.js";
|
||||
|
||||
function formatStreamSendErr(e: unknown): string {
|
||||
return e instanceof Error ? e.message : String(e);
|
||||
}
|
||||
|
||||
// ============ 类型定义 ============
|
||||
|
||||
/** 发送队列项 */
|
||||
@@ -119,7 +116,7 @@ function fixPathEncoding(
|
||||
}
|
||||
}
|
||||
} catch (decodeErr) {
|
||||
log?.error?.(`Path decode error: ${formatStreamSendErr(decodeErr)}`);
|
||||
log?.error?.(`Path decode error: ${formatErrorMessage(decodeErr)}`);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -282,7 +279,7 @@ export async function executeSendQueue(
|
||||
await options.onSendText(errorMsg);
|
||||
} catch (fallbackErr) {
|
||||
log?.error(
|
||||
`${prefix} executeSendQueue: fallback text send failed: ${formatStreamSendErr(fallbackErr)}`,
|
||||
`${prefix} executeSendQueue: fallback text send failed: ${formatErrorMessage(fallbackErr)}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -329,7 +326,7 @@ export async function executeSendQueue(
|
||||
await sendFallbackText(resolveUserFacingMediaError(result));
|
||||
}
|
||||
} catch (err) {
|
||||
log?.error(`${prefix} sendVoice unexpected error: ${formatStreamSendErr(err)}`);
|
||||
log?.error(`${prefix} sendVoice unexpected error: ${formatErrorMessage(err)}`);
|
||||
await sendFallbackText(DEFAULT_MEDIA_SEND_ERROR);
|
||||
}
|
||||
} else if (item.type === "video") {
|
||||
@@ -363,7 +360,7 @@ export async function executeSendQueue(
|
||||
}
|
||||
} catch (err) {
|
||||
log?.error(
|
||||
`${prefix} executeSendQueue: failed to send ${item.type}: ${formatStreamSendErr(err)}`,
|
||||
`${prefix} executeSendQueue: failed to send ${item.type}: ${formatErrorMessage(err)}`,
|
||||
);
|
||||
await sendFallbackText(DEFAULT_MEDIA_SEND_ERROR);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Ref-index store — SQLite KV-backed store for message reference index.
|
||||
*/
|
||||
|
||||
import { formatErrorMessage } from "../utils/format.js";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { debugError } from "../utils/log.js";
|
||||
import { buildQQBotStateKey, openQQBotSyncKeyedStore } from "../utils/sqlite-state.js";
|
||||
import type { RefAttachmentSummary, RefIndexEntry } from "./types.js";
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
|
||||
import crypto from "node:crypto";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import type { ChatScope } from "../types.js";
|
||||
import { formatErrorMessage } from "../utils/format.js";
|
||||
import { debugLog, debugError } from "../utils/log.js";
|
||||
import { openQQBotSyncKeyedStore } from "../utils/sqlite-state.js";
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Gateway session persistence — SQLite KV-backed store.
|
||||
*/
|
||||
|
||||
import { formatErrorMessage } from "../utils/format.js";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { debugLog, debugError } from "../utils/log.js";
|
||||
import { buildQQBotStateKey, openQQBotSyncKeyedStore } from "../utils/sqlite-state.js";
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
|
||||
import { resolveChannelGroupPolicy } from "openclaw/plugin-sdk/channel-policy";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import {
|
||||
readProviderTextResponse,
|
||||
readResponseTextLimited,
|
||||
} from "openclaw/plugin-sdk/provider-http";
|
||||
import { fetchWithSsrFGuard, type SsrFPolicy } from "openclaw/plugin-sdk/ssrf-runtime";
|
||||
import { jsonResult as json } from "openclaw/plugin-sdk/tool-results";
|
||||
import { formatErrorMessage } from "../utils/format.js";
|
||||
import { debugLog, debugError } from "../utils/log.js";
|
||||
|
||||
const API_BASE = "https://api.sgroup.qq.com";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
// Qqbot plugin module implements remind logic behavior.
|
||||
import { resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
|
||||
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
||||
@@ -270,10 +271,6 @@ function formatDelay(ms: number): string {
|
||||
return `${hours}h${minutes}m`;
|
||||
}
|
||||
|
||||
function formatSchedulerError(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
function prepareRemindCronAction(
|
||||
params: RemindParams,
|
||||
ctx: RemindExecuteContext = {},
|
||||
@@ -363,7 +360,7 @@ export async function executeScheduledRemind(
|
||||
});
|
||||
} catch (error) {
|
||||
return json({
|
||||
error: `Failed to run Gateway cron action: ${formatSchedulerError(error)}`,
|
||||
error: `Failed to run Gateway cron action: ${formatErrorMessage(error)}`,
|
||||
action: plan.action,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
||||
import { readRegularFileSync } from "openclaw/plugin-sdk/security-runtime";
|
||||
import { formatErrorMessage } from "./format.js";
|
||||
import { debugLog, debugError, debugWarn } from "./log.js";
|
||||
import { normalizeLowercaseStringOrEmpty as normalizeLowercase } from "./string-normalize.js";
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import crypto from "node:crypto";
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { mimeTypeFromFilePath } from "openclaw/plugin-sdk/media-mime";
|
||||
import { formatByteSize } from "openclaw/plugin-sdk/number-runtime";
|
||||
import {
|
||||
@@ -12,7 +13,6 @@ import {
|
||||
import { getPlatformAdapter } from "../adapter/index.js";
|
||||
import type { SsrfPolicyConfig } from "../adapter/types.js";
|
||||
import { MediaFileType } from "../types.js";
|
||||
import { formatErrorMessage } from "./format.js";
|
||||
import { normalizeOptionalString } from "./string-normalize.js";
|
||||
|
||||
/** Maximum file size accepted by the QQ Bot one-shot upload API (base64 direct). */
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
// Qqbot tests cover format plugin behavior.
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { formatErrorMessage, formatDuration } from "./format.js";
|
||||
import { formatDuration } from "./format.js";
|
||||
|
||||
describe("engine/utils/format", () => {
|
||||
describe("formatErrorMessage", () => {
|
||||
@@ -36,7 +37,7 @@ describe("engine/utils/format", () => {
|
||||
});
|
||||
|
||||
it("JSON-stringifies plain objects", () => {
|
||||
expect(formatErrorMessage({ code: 500 })).toBe('{"code":500}');
|
||||
expect(formatErrorMessage({ code: 500 })).toBe("status=unknown code=500");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -3,60 +3,9 @@
|
||||
* 通用格式化与字符串工具。
|
||||
*
|
||||
* Pure utility functions, with duration presentation from the plugin-local dependency.
|
||||
*
|
||||
* NOTE: The framework `formatErrorMessage` also applies `redactSensitiveText()`
|
||||
* for token masking. We intentionally omit that here — the framework's log
|
||||
* pipeline handles redaction at a higher level.
|
||||
*/
|
||||
import prettyMilliseconds from "pretty-ms";
|
||||
|
||||
/**
|
||||
* Format any error object into a readable string.
|
||||
* 将任意错误对象格式化为可读字符串。
|
||||
*
|
||||
* Traverses the `.cause` chain for nested Error objects to include
|
||||
* the full error context (e.g. network errors wrapped inside HTTP errors).
|
||||
*/
|
||||
export function formatErrorMessage(err: unknown): string {
|
||||
if (err instanceof Error) {
|
||||
let formatted = err.message || err.name || "Error";
|
||||
let cause: unknown = err.cause;
|
||||
const seen = new Set<unknown>([err]);
|
||||
while (cause && !seen.has(cause)) {
|
||||
seen.add(cause);
|
||||
if (cause instanceof Error) {
|
||||
if (cause.message) {
|
||||
formatted += ` | ${cause.message}`;
|
||||
}
|
||||
cause = cause.cause;
|
||||
} else if (typeof cause === "string") {
|
||||
formatted += ` | ${cause}`;
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return formatted;
|
||||
}
|
||||
if (typeof err === "string") {
|
||||
return err;
|
||||
}
|
||||
if (
|
||||
err === null ||
|
||||
err === undefined ||
|
||||
typeof err === "number" ||
|
||||
typeof err === "boolean" ||
|
||||
typeof err === "bigint"
|
||||
) {
|
||||
return String(err);
|
||||
}
|
||||
try {
|
||||
return JSON.stringify(err);
|
||||
} catch {
|
||||
return Object.prototype.toString.call(err);
|
||||
}
|
||||
}
|
||||
|
||||
/** Format a millisecond duration into a human-readable string (e.g. "5m 30s"). */
|
||||
export function formatDuration(durationMs: number): string {
|
||||
if (durationMs <= 0) {
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
*/
|
||||
|
||||
import { Buffer } from "node:buffer";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
||||
import { getPlatformAdapter } from "../adapter/index.js";
|
||||
import type { SsrfPolicyConfig } from "../adapter/types.js";
|
||||
import { formatErrorMessage } from "./format.js";
|
||||
import { debugLog } from "./log.js";
|
||||
|
||||
interface ImageSize {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* Zero external dependencies.
|
||||
*/
|
||||
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import type { ChatScope } from "../types.js";
|
||||
|
||||
/** Structured reminder payload emitted by the model. */
|
||||
@@ -40,10 +41,6 @@ interface ParseResult {
|
||||
const PAYLOAD_PREFIX = "QQBOT_PAYLOAD:";
|
||||
const CRON_PREFIX = "QQBOT_CRON:";
|
||||
|
||||
function formatErr(e: unknown): string {
|
||||
return e instanceof Error ? e.message : String(e);
|
||||
}
|
||||
|
||||
function normalizeBase64ForCompare(value: string): string {
|
||||
return value.replace(/=+$/u, "").replace(/-/gu, "+").replace(/_/gu, "/");
|
||||
}
|
||||
@@ -96,7 +93,7 @@ export function parseQQBotPayload(text: string): ParseResult {
|
||||
|
||||
return { isPayload: true, payload };
|
||||
} catch (e) {
|
||||
return { isPayload: true, error: `Failed to parse JSON: ${formatErr(e)}` };
|
||||
return { isPayload: true, error: `Failed to parse JSON: ${formatErrorMessage(e)}` };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +139,10 @@ export function decodeCronPayload(message: string): {
|
||||
|
||||
return { isCronPayload: true, payload };
|
||||
} catch (e) {
|
||||
return { isCronPayload: true, error: `Failed to decode cron payload: ${formatErr(e)}` };
|
||||
return {
|
||||
isCronPayload: true,
|
||||
error: `Failed to decode cron payload: ${formatErrorMessage(e)}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
import * as fs from "node:fs";
|
||||
import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { getPlatformAdapter } from "../adapter/index.js";
|
||||
import { formatErrorMessage } from "./format.js";
|
||||
import { debugLog, debugWarn } from "./log.js";
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* only need to change their import path.
|
||||
*/
|
||||
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import type { SignalTransportConfig } from "./account-types.js";
|
||||
import { containerCheck, containerRpcRequest, streamContainerEvents } from "./client-container.js";
|
||||
import type { SignalRpcOptions } from "./client.js";
|
||||
@@ -24,10 +25,6 @@ export type SignalSseEvent = {
|
||||
|
||||
export type SignalTransportKind = SignalTransportConfig["kind"];
|
||||
|
||||
function formatErrorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
function usesContainer(kind: SignalTransportKind | undefined): boolean {
|
||||
return kind === "container";
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Telegram plugin module implements polling transport state behavior.
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import type { TelegramTransport } from "./fetch.js";
|
||||
|
||||
type TelegramPollingTransportStateOpts = {
|
||||
@@ -60,7 +61,7 @@ export class TelegramPollingTransportState {
|
||||
await transport.close();
|
||||
} catch (err) {
|
||||
this.opts.log(
|
||||
`[telegram][diag] failed to close transport during dispose: ${formatCloseError(err)}`,
|
||||
`[telegram][diag] failed to close transport during dispose: ${formatErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -70,15 +71,8 @@ export class TelegramPollingTransportState {
|
||||
#closeTransportAsync(transport: TelegramTransport, context: string) {
|
||||
void transport.close().catch((err: unknown) => {
|
||||
this.opts.log(
|
||||
`[telegram][diag] failed to close transport (${context}): ${formatCloseError(err)}`,
|
||||
`[telegram][diag] failed to close transport (${context}): ${formatErrorMessage(err)}`,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function formatCloseError(err: unknown): string {
|
||||
if (err instanceof Error) {
|
||||
return err.message;
|
||||
}
|
||||
return String(err);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Telegram plugin module implements telegram ingress worker behavior.
|
||||
import { parentPort, workerData } from "node:worker_threads";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
|
||||
import {
|
||||
computeBackoff,
|
||||
@@ -70,13 +71,6 @@ type TelegramIngressWorkerRuntimeData = TelegramIngressWorkerOptions & {
|
||||
runtime: typeof TELEGRAM_INGRESS_WORKER_RUNTIME_MARKER;
|
||||
};
|
||||
|
||||
function formatErrorMessage(err: unknown): string {
|
||||
if (err instanceof Error) {
|
||||
return err.message || err.name;
|
||||
}
|
||||
return String(err);
|
||||
}
|
||||
|
||||
function readTelegramErrorCode(err: unknown): number | undefined {
|
||||
if (err && typeof err === "object" && "error_code" in err) {
|
||||
const code = (err as { error_code: unknown }).error_code;
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
type ChannelIngressQueue,
|
||||
} from "openclaw/plugin-sdk/channel-outbound";
|
||||
import { isRecord } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { normalizeNullableString as nonEmptyString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { runDetachedWebhookWork } from "openclaw/plugin-sdk/webhook-request-guards";
|
||||
import { ZaloApiError, type ZaloUpdate } from "./api.js";
|
||||
@@ -111,10 +112,6 @@ function parseClaimedUpdate(payload: ZaloWebhookSpoolPayload, claimedId: string)
|
||||
return facts.update as unknown as ZaloUpdate;
|
||||
}
|
||||
|
||||
function errorText(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
function isZaloAuthenticationFailure(error: unknown): boolean {
|
||||
let current: unknown = error;
|
||||
const seen = new Set<unknown>();
|
||||
@@ -194,14 +191,15 @@ function createZaloWebhookIngress(options: {
|
||||
return { reason: "invalid-event", message: error.message };
|
||||
}
|
||||
if (isZaloAuthenticationFailure(error)) {
|
||||
return { reason: "authentication-failed", message: errorText(error) };
|
||||
return { reason: "authentication-failed", message: formatErrorMessage(error) };
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onLog: (message) => options.runtime.error?.(`zalo ingress: ${message}`),
|
||||
},
|
||||
createStoppedError: () => new Error("Zalo ingress stopped."),
|
||||
onError: (error) => options.runtime.error?.(`zalo ingress drain failed: ${errorText(error)}`),
|
||||
onError: (error) =>
|
||||
options.runtime.error?.(`zalo ingress drain failed: ${formatErrorMessage(error)}`),
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
@@ -7,7 +7,11 @@ import {
|
||||
type ChannelIngressQueue,
|
||||
} from "openclaw/plugin-sdk/channel-outbound";
|
||||
import { isRecord } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
|
||||
import { collectErrorGraphCandidates, extractErrorCode } from "openclaw/plugin-sdk/error-runtime";
|
||||
import {
|
||||
collectErrorGraphCandidates,
|
||||
extractErrorCode,
|
||||
formatErrorMessage,
|
||||
} from "openclaw/plugin-sdk/error-runtime";
|
||||
import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime";
|
||||
import { normalizeNullableString as nonEmptyString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { getZalouserRuntime } from "./runtime.js";
|
||||
@@ -118,10 +122,6 @@ function isZalouserAuthenticationFailure(error: unknown): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
function errorText(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
export function createZalouserIngressMonitor(options: {
|
||||
accountId: string;
|
||||
ownUserId: string;
|
||||
@@ -196,7 +196,7 @@ export function createZalouserIngressMonitor(options: {
|
||||
return { reason: "invalid-event", message: error.message };
|
||||
}
|
||||
if (isZalouserAuthenticationFailure(error)) {
|
||||
return { reason: "authentication-failed", message: errorText(error) };
|
||||
return { reason: "authentication-failed", message: formatErrorMessage(error) };
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -204,7 +204,7 @@ export function createZalouserIngressMonitor(options: {
|
||||
},
|
||||
createStoppedError: () => new Error("Zalouser ingress monitor is stopped."),
|
||||
onError: (error) =>
|
||||
options.runtime.error?.(`zalouser ingress drain failed: ${errorText(error)}`),
|
||||
options.runtime.error?.(`zalouser ingress drain failed: ${formatErrorMessage(error)}`),
|
||||
});
|
||||
monitor.start();
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import path from "node:path";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
// Zalouser plugin module implements zalo js behavior.
|
||||
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
||||
import { extensionForMime } from "openclaw/plugin-sdk/media-mime";
|
||||
@@ -103,13 +104,6 @@ function normalizeProfile(profile?: string | null): string {
|
||||
return trimmed && trimmed.length > 0 ? trimmed : "default";
|
||||
}
|
||||
|
||||
function toErrorMessage(error: unknown): string {
|
||||
if (error instanceof Error) {
|
||||
return error.message;
|
||||
}
|
||||
return String(error);
|
||||
}
|
||||
|
||||
function clampTextStyles(
|
||||
text: string,
|
||||
styles?: ZaloSendOptions["textStyles"],
|
||||
@@ -1288,7 +1282,7 @@ export async function sendZaloTextMessage(
|
||||
} catch (error) {
|
||||
return {
|
||||
ok: false,
|
||||
error: toErrorMessage(error),
|
||||
error: formatErrorMessage(error),
|
||||
receipt: createZalouserSendReceipt({ threadId: trimmedThreadId, kind: "unknown" }),
|
||||
};
|
||||
}
|
||||
@@ -1373,7 +1367,7 @@ export async function sendZaloReaction(params: {
|
||||
{ shouldPersist: (result) => result.ok },
|
||||
);
|
||||
} catch (error) {
|
||||
return { ok: false, error: toErrorMessage(error) };
|
||||
return { ok: false, error: formatErrorMessage(error) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1451,7 +1445,7 @@ export async function sendZaloLink(
|
||||
} catch (error) {
|
||||
return {
|
||||
ok: false,
|
||||
error: toErrorMessage(error),
|
||||
error: formatErrorMessage(error),
|
||||
receipt: createZalouserSendReceipt({ threadId: trimmedThreadId, kind: "card" }),
|
||||
};
|
||||
}
|
||||
@@ -1593,7 +1587,7 @@ export async function startZaloQrLogin(params: {
|
||||
} catch (error) {
|
||||
const current = activeQrLogins.get(profile);
|
||||
if (current && current.id === login.id) {
|
||||
current.error = toErrorMessage(error);
|
||||
current.error = formatErrorMessage(error);
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -5,6 +5,7 @@ import { DEFAULT_LOCAL_MODEL } from "./embedding-defaults.js";
|
||||
import { sanitizeAndNormalizeEmbedding } from "./embedding-vectors.js";
|
||||
import { createLocalEmbeddingWorkerProvider } from "./embeddings-worker.js";
|
||||
import type { EmbeddingProvider, EmbeddingProviderOptions } from "./embeddings.types.js";
|
||||
import { formatErrorMessage } from "./error-utils.js";
|
||||
import {
|
||||
attachLocalEmbeddingRuntimeFacts,
|
||||
type LocalEmbeddingRuntimeFacts,
|
||||
@@ -85,10 +86,6 @@ async function readLlamaRuntimeFacts(llama: Llama): Promise<LocalEmbeddingRuntim
|
||||
return facts;
|
||||
}
|
||||
|
||||
function formatRuntimeLoadError(err: unknown): string {
|
||||
return err instanceof Error ? err.message : String(err);
|
||||
}
|
||||
|
||||
export async function createLocalEmbeddingProvider(
|
||||
options: EmbeddingProviderOptions,
|
||||
runtimeOptions?: LocalEmbeddingProviderRuntimeOptions,
|
||||
@@ -216,7 +213,7 @@ export async function createLocalEmbeddingProviderInProcess(
|
||||
engine: "llama.cpp",
|
||||
state: "failed",
|
||||
context: { requestedSize: contextSize },
|
||||
loadError: formatRuntimeLoadError(err),
|
||||
loadError: formatErrorMessage(err),
|
||||
};
|
||||
initPromise = null;
|
||||
throw err;
|
||||
|
||||
@@ -3,6 +3,7 @@ import { spawn } from "node:child_process";
|
||||
import { statSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { resolveSafeTimeoutDelayMs } from "../../../gateway-client/src/timeouts.js";
|
||||
import { formatErrorMessage } from "./error-utils.js";
|
||||
import { materializeWindowsSpawnProgram, resolveWindowsSpawnProgram } from "./windows-spawn.js";
|
||||
|
||||
type CliSpawnInvocation = {
|
||||
@@ -76,7 +77,7 @@ export async function checkQmdBinaryAvailability(params: {
|
||||
packageName: "qmd",
|
||||
});
|
||||
} catch (err) {
|
||||
return { available: false, reason: "binary", error: formatQmdAvailabilityError(err) };
|
||||
return { available: false, reason: "binary", error: formatErrorMessage(err) };
|
||||
}
|
||||
|
||||
const cwd = params.cwd ?? process.cwd();
|
||||
@@ -118,7 +119,7 @@ export async function checkQmdBinaryAvailability(params: {
|
||||
}, timeoutMs);
|
||||
|
||||
child.once("error", (err) => {
|
||||
finish({ available: false, reason: "binary", error: formatQmdAvailabilityError(err) });
|
||||
finish({ available: false, reason: "binary", error: formatErrorMessage(err) });
|
||||
});
|
||||
child.once("spawn", () => {
|
||||
didSpawn = true;
|
||||
@@ -156,7 +157,7 @@ function validateQmdProbeCwd(cwd: string): QmdBinaryAvailability | null {
|
||||
return {
|
||||
available: false,
|
||||
reason: "workspace-cwd",
|
||||
error: `workspace directory unavailable: ${cwd} (${formatQmdAvailabilityError(err)})`,
|
||||
error: `workspace directory unavailable: ${cwd} (${formatErrorMessage(err)})`,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -503,10 +504,3 @@ function appendOutputWithCap(
|
||||
}
|
||||
return { text: chars.slice(-maxChars).join(""), truncated: true };
|
||||
}
|
||||
|
||||
function formatQmdAvailabilityError(err: unknown): string {
|
||||
if (err instanceof Error && err.message) {
|
||||
return err.message;
|
||||
}
|
||||
return String(err);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
getAgentEventLifecycleGeneration,
|
||||
isAgentEventLifecycleGenerationCurrent,
|
||||
} from "../../infra/agent-events.js";
|
||||
import { formatErrorMessage } from "../../infra/errors.js";
|
||||
import {
|
||||
getDiagnosticSessionActivitySnapshot,
|
||||
markDiagnosticEmbeddedRunEnded,
|
||||
@@ -343,7 +344,7 @@ export function queueEmbeddedAgentMessageWithOutcome(
|
||||
.queueMessage(text, options ?? { steeringMode: "all" })
|
||||
.catch((err: unknown) => {
|
||||
diag.debug(
|
||||
`queue message rejected after enqueue: sessionId=${sessionId} err=${formatQueueError(err)}`,
|
||||
`queue message rejected after enqueue: sessionId=${sessionId} err=${formatErrorMessage(err)}`,
|
||||
);
|
||||
});
|
||||
return {
|
||||
@@ -355,10 +356,6 @@ export function queueEmbeddedAgentMessageWithOutcome(
|
||||
};
|
||||
}
|
||||
|
||||
function formatQueueError(err: unknown): string {
|
||||
return err instanceof Error ? err.message : String(err);
|
||||
}
|
||||
|
||||
function logActiveRunMessageAccepted(sessionId: string): void {
|
||||
// Active-run steering is consumed by the current turn, not queued as another
|
||||
// turn for the single idle transition to drain. Keep the event and activity.
|
||||
@@ -463,7 +460,7 @@ export async function queueEmbeddedAgentMessageWithOutcomeAsync(
|
||||
enqueuedAtMs,
|
||||
};
|
||||
} catch (err) {
|
||||
const errorMessage = formatQueueError(err);
|
||||
const errorMessage = formatErrorMessage(err);
|
||||
diag.debug(`queue message rejected: sessionId=${sessionId} err=${errorMessage}`);
|
||||
return createQueueFailureOutcome(sessionId, "runtime_rejected", errorMessage);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
} from "../../agents/tools/sessions-helpers.js";
|
||||
import type { SessionEntry } from "../../config/sessions.js";
|
||||
import { logVerbose } from "../../globals.js";
|
||||
import { formatErrorMessage } from "../../infra/errors.js";
|
||||
import { isNativeCommandTurn, resolveCommandTurnContext } from "../command-turn-context.js";
|
||||
import { applyCommandTextToParams } from "./command-context-rewrite.js";
|
||||
import { commandReply, defineAuthorizedTextCommand } from "./command-gates.js";
|
||||
@@ -92,10 +93,6 @@ function resolveSteerSessionId(params: {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function formatSteerError(err: unknown): string {
|
||||
return err instanceof Error ? err.message : String(err);
|
||||
}
|
||||
|
||||
function continueWithSteerFallback(
|
||||
params: HandleCommandsParams,
|
||||
message: string,
|
||||
@@ -143,7 +140,7 @@ export const handleSteerCommand: CommandHandler = defineAuthorizedTextCommand(
|
||||
return continueWithSteerFallback(
|
||||
params,
|
||||
message,
|
||||
`steer: active session ${sessionId} threw while steering: ${formatSteerError(err)}; continuing with /steer payload as a normal prompt`,
|
||||
`steer: active session ${sessionId} threw while steering: ${formatErrorMessage(err)}; continuing with /steer payload as a normal prompt`,
|
||||
);
|
||||
});
|
||||
if ("shouldContinue" in queueOutcome) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* Models ack/nack policy and idempotent receive state transitions for inbound events.
|
||||
*/
|
||||
import { formatErrorMessage } from "../../infra/errors.js";
|
||||
import type { ChannelMessageReceiveAckPolicy } from "./types.js";
|
||||
|
||||
/** Public alias for channel receive acknowledgement policy names. */
|
||||
@@ -48,10 +49,6 @@ function shouldAckMessageAfterStage(policy: MessageAckPolicy, stage: MessageAckS
|
||||
return false;
|
||||
}
|
||||
|
||||
function normalizeAckErrorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
/** Creates a receive context with idempotent ack and explicit nack state transitions. */
|
||||
export function createMessageReceiveContext<TMessage>(params: {
|
||||
id: string;
|
||||
@@ -97,7 +94,7 @@ export function createMessageReceiveContext<TMessage>(params: {
|
||||
nackInFlight = (async () => {
|
||||
await params.onNack?.(error);
|
||||
ctx.ackState = "nacked";
|
||||
ctx.nackErrorMessage = normalizeAckErrorMessage(error);
|
||||
ctx.nackErrorMessage = formatErrorMessage(error);
|
||||
})();
|
||||
try {
|
||||
await nackInFlight;
|
||||
|
||||
@@ -16,6 +16,7 @@ import type {
|
||||
} from "../../../cron/store.js";
|
||||
import type { CronStoreFile } from "../../../cron/types.js";
|
||||
import { syncDirectoryIfSupported } from "../../../infra/directory-durability.js";
|
||||
import { formatErrorMessage } from "../../../infra/errors.js";
|
||||
import { parseJsonWithJson5Fallback } from "../../../utils/parse-json-compat.js";
|
||||
|
||||
const LEGACY_CRON_ARCHIVE_SUFFIX = ".migrated";
|
||||
@@ -90,10 +91,6 @@ async function legacyCronFileExists(filePath: string): Promise<boolean> {
|
||||
|
||||
type ArchiveOutcome = { ok: true; archivePath?: string } | { ok: false; reason: string };
|
||||
|
||||
function formatArchiveError(err: unknown): string {
|
||||
return err instanceof Error ? err.message : String(err);
|
||||
}
|
||||
|
||||
async function sha256File(filePath: string): Promise<string> {
|
||||
return createHash("sha256")
|
||||
.update(await fs.readFile(filePath))
|
||||
@@ -131,7 +128,7 @@ async function restoreArchivedSource(
|
||||
} catch (err) {
|
||||
return {
|
||||
ok: false,
|
||||
reason: `archive remains at ${archivePath} because the source path could not be checked: ${formatArchiveError(err)}`,
|
||||
reason: `archive remains at ${archivePath} because the source path could not be checked: ${formatErrorMessage(err)}`,
|
||||
};
|
||||
}
|
||||
try {
|
||||
@@ -148,7 +145,7 @@ async function restoreArchivedSource(
|
||||
}
|
||||
return {
|
||||
ok: false,
|
||||
reason: `archive remains at ${archivePath} because restoration failed: ${formatArchiveError(err)}`,
|
||||
reason: `archive remains at ${archivePath} because restoration failed: ${formatErrorMessage(err)}`,
|
||||
};
|
||||
}
|
||||
try {
|
||||
@@ -157,7 +154,7 @@ async function restoreArchivedSource(
|
||||
} catch (err) {
|
||||
return {
|
||||
ok: false,
|
||||
reason: `the source was restored, but rollback directory sync failed: ${formatArchiveError(err)}`,
|
||||
reason: `the source was restored, but rollback directory sync failed: ${formatErrorMessage(err)}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -228,7 +225,7 @@ async function copyLegacyCronFileAcrossDevices(
|
||||
if (sourceRemoved) {
|
||||
return {
|
||||
ok: false,
|
||||
reason: `${formatArchiveError(err)}; the durable archive is preserved at ${archivePath} because the source was already removed`,
|
||||
reason: `${formatErrorMessage(err)}; the durable archive is preserved at ${archivePath} because the source was already removed`,
|
||||
};
|
||||
}
|
||||
const cleanupFailures: string[] = [];
|
||||
@@ -247,13 +244,13 @@ async function copyLegacyCronFileAcrossDevices(
|
||||
} catch (cleanupErr) {
|
||||
cleanupFailures.push(
|
||||
archiveRemoved
|
||||
? `the partial archive was removed, but cleanup directory sync failed: ${formatArchiveError(cleanupErr)}`
|
||||
: `partial archive remains at ${archivePath} because cleanup failed: ${formatArchiveError(cleanupErr)}`,
|
||||
? `the partial archive was removed, but cleanup directory sync failed: ${formatErrorMessage(cleanupErr)}`
|
||||
: `partial archive remains at ${archivePath} because cleanup failed: ${formatErrorMessage(cleanupErr)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
const cleanupReason = cleanupFailures.length > 0 ? `; ${cleanupFailures.join("; ")}` : "";
|
||||
return { ok: false, reason: `${formatArchiveError(err)}${cleanupReason}` };
|
||||
return { ok: false, reason: `${formatErrorMessage(err)}${cleanupReason}` };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,7 +268,7 @@ export async function archiveLegacyCronFile(
|
||||
archivePath = `${filePath}${LEGACY_CRON_ARCHIVE_SUFFIX}.${index}`;
|
||||
}
|
||||
} catch (err) {
|
||||
return { ok: false, reason: formatArchiveError(err) };
|
||||
return { ok: false, reason: formatErrorMessage(err) };
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -280,7 +277,7 @@ export async function archiveLegacyCronFile(
|
||||
// A cross-device rename can occur when the configured store is a mounted file.
|
||||
// Fsync before source removal and roll back failed cleanup so retries stay idempotent.
|
||||
if ((err as { code?: unknown })?.code !== "EXDEV") {
|
||||
return { ok: false, reason: formatArchiveError(err) };
|
||||
return { ok: false, reason: formatErrorMessage(err) };
|
||||
}
|
||||
return await copyLegacyCronFileAcrossDevices(filePath, archivePath, expectedSha256);
|
||||
}
|
||||
@@ -302,8 +299,8 @@ export async function archiveLegacyCronFile(
|
||||
return {
|
||||
ok: false,
|
||||
reason: restoreFailure.ok
|
||||
? formatArchiveError(err)
|
||||
: `${formatArchiveError(err)}; ${restoreFailure.reason}`,
|
||||
? formatErrorMessage(err)
|
||||
: `${formatErrorMessage(err)}; ${restoreFailure.reason}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -519,7 +516,7 @@ export async function archiveLegacyCronStoreForMigration(
|
||||
? "legacy cron state appeared after the store was imported; refusing to archive it"
|
||||
: undefined;
|
||||
} catch (err) {
|
||||
return `legacy cron state path could not be checked: ${formatArchiveError(err)}`;
|
||||
return `legacy cron state path could not be checked: ${formatErrorMessage(err)}`;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// OpenClaw command gate: prove inference before starting conversational setup.
|
||||
|
||||
import { requestExitAfterOneShotOutput } from "../cli/one-shot-exit.js";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import { withConsoleSubsystemsSuppressed } from "../logging/console.js";
|
||||
import { defaultRuntime, writeRuntimeJson, type RuntimeEnv } from "../runtime.js";
|
||||
import type { BoundVerifySetupInferenceResult } from "../system-agent/setup-inference.js";
|
||||
@@ -32,16 +33,12 @@ function isOneShotRequest(opts: SystemAgentCommandOptions): boolean {
|
||||
return Boolean(opts.json || opts.message?.trim() || opts.interactive === false);
|
||||
}
|
||||
|
||||
function formatOneShotExecutionError(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
function failOneShotExecution(
|
||||
opts: SystemAgentCommandOptions,
|
||||
runtime: RuntimeEnv,
|
||||
error: unknown,
|
||||
): void {
|
||||
const message = formatOneShotExecutionError(error);
|
||||
const message = formatErrorMessage(error);
|
||||
if (opts.json) {
|
||||
writeRuntimeJson(runtime, { ok: false, error: message });
|
||||
} else {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import { executeSqliteQuerySync, getNodeSqliteKysely } from "../infra/kysely-sync.js";
|
||||
// Stores config health fingerprints in shared SQLite state.
|
||||
import type { DB as OpenClawStateKyselyDatabase } from "../state/openclaw-state-db.generated.js";
|
||||
@@ -65,10 +66,6 @@ function stringifyConfigHealthFingerprint(
|
||||
return value ? JSON.stringify(value) : null;
|
||||
}
|
||||
|
||||
function formatConfigHealthStateError(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
export function readConfigHealthStateFromStore(deps: ConfigHealthStateDeps): ConfigHealthState {
|
||||
try {
|
||||
const database = openOpenClawStateDatabase({ env: resolveConfigHealthStateEnv(deps) });
|
||||
@@ -142,6 +139,6 @@ export function writeConfigHealthStateToStore(
|
||||
{ env: resolveConfigHealthStateEnv(deps) },
|
||||
);
|
||||
} catch (error) {
|
||||
deps.logger.warn(`Config health-state write failed: ${formatConfigHealthStateError(error)}`);
|
||||
deps.logger.warn(`Config health-state write failed: ${formatErrorMessage(error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { EventEmitter } from "node:events";
|
||||
import { Worker, type WorkerOptions } from "node:worker_threads";
|
||||
import { isVitestRuntimeEnv } from "../infra/env.js";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
|
||||
const SYSTEM_CA_WARMUP_TIMEOUT_MS = 10_000;
|
||||
const SYSTEM_CA_WORKER_SOURCE = String.raw`
|
||||
@@ -54,10 +55,6 @@ function isWorkerPermissionDenied(error: unknown): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
function describeError(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
/** Warm Node's effective default CA set without blocking the gateway event loop on macOS. */
|
||||
export async function warmMacOSSystemCaOffMainThread(
|
||||
options: SystemCaWarmupOptions = {},
|
||||
@@ -80,7 +77,7 @@ export async function warmMacOSSystemCaOffMainThread(
|
||||
// CA prewarming is an optimization. Node can still load trust settings lazily.
|
||||
const reason = isWorkerPermissionDenied(error)
|
||||
? "Node denied worker-thread permission"
|
||||
: `worker creation failed: ${describeError(error)}`;
|
||||
: `worker creation failed: ${formatErrorMessage(error)}`;
|
||||
options.log?.warn(`macOS CA warmup skipped because ${reason}; trust settings will load lazily`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
import { resolveMainSessionKey } from "../config/sessions.js";
|
||||
import { resolveSessionEntryAccessTarget } from "../config/sessions/session-accessor.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import { logWarn } from "../logger.js";
|
||||
import { isTestDefaultMemorySlotDisabled } from "../plugins/config-state.js";
|
||||
import { defaultSlotIdForKey } from "../plugins/slots.js";
|
||||
@@ -121,16 +122,6 @@ function mergeActionIntoArgsIfSupported(params: {
|
||||
return hasAction ? { ...args, action } : args;
|
||||
}
|
||||
|
||||
function getErrorMessage(err: unknown): string {
|
||||
if (err instanceof Error) {
|
||||
return err.message || String(err);
|
||||
}
|
||||
if (typeof err === "string") {
|
||||
return err;
|
||||
}
|
||||
return String(err);
|
||||
}
|
||||
|
||||
function resolveToolInputErrorStatus(err: unknown): number | null {
|
||||
if (err instanceof ToolInputError) {
|
||||
const status = (err as { status?: unknown }).status;
|
||||
@@ -337,7 +328,7 @@ export async function invokeGatewayTool(params: {
|
||||
toolName,
|
||||
error: {
|
||||
type: "tool_error",
|
||||
message: getErrorMessage(err) || "invalid tool arguments",
|
||||
message: formatErrorMessage(err) || "invalid tool arguments",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import type { ProxyConfig } from "../../../config/zod-schema.proxy.js";
|
||||
import { formatErrorMessage } from "../../errors.js";
|
||||
|
||||
/** TLS trust material passed to proxy clients for OpenClaw-managed HTTPS proxies. */
|
||||
export type ManagedProxyTlsOptions = Readonly<{
|
||||
@@ -14,10 +15,6 @@ function normalizeOptionalPath(value: string | undefined): string | undefined {
|
||||
return trimmed ? trimmed : undefined;
|
||||
}
|
||||
|
||||
function formatReadError(err: unknown): string {
|
||||
return err instanceof Error ? err.message : String(err);
|
||||
}
|
||||
|
||||
function isHttpsProxyUrl(value: string | undefined): boolean {
|
||||
if (!value) {
|
||||
return false;
|
||||
@@ -65,7 +62,7 @@ export async function loadManagedProxyTlsOptions(
|
||||
try {
|
||||
return { ca: await readFile(caFile, "utf8") };
|
||||
} catch (err) {
|
||||
throw new Error(`proxy CA file could not be read (${caFile}): ${formatReadError(err)}`, {
|
||||
throw new Error(`proxy CA file could not be read (${caFile}): ${formatErrorMessage(err)}`, {
|
||||
cause: err,
|
||||
});
|
||||
}
|
||||
@@ -81,7 +78,7 @@ export function loadManagedProxyTlsOptionsSync(
|
||||
try {
|
||||
return { ca: readFileSync(caFile, "utf8") };
|
||||
} catch (err) {
|
||||
throw new Error(`proxy CA file could not be read (${caFile}): ${formatReadError(err)}`, {
|
||||
throw new Error(`proxy CA file could not be read (${caFile}): ${formatErrorMessage(err)}`, {
|
||||
cause: err,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { spawn, spawnSync, type ChildProcess } from "node:child_process";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import { decodeMeetingAudioBase64 } from "./audio-base64.js";
|
||||
import { terminateMeetingBridgeProcess } from "./bridge-process.js";
|
||||
import { MeetingNodeAudioPullWaiters } from "./node-audio-pull-waiters.js";
|
||||
@@ -83,10 +84,6 @@ function readString(value: unknown): string | undefined {
|
||||
return typeof value === "string" && value.length > 0 ? value : undefined;
|
||||
}
|
||||
|
||||
function formatErrorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
function readNumber(value: unknown, fallback: number): number {
|
||||
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { normalizeOptionalString } from "@openclaw/normalization-core/string-coe
|
||||
import { uniqueStrings } from "@openclaw/normalization-core/string-normalization";
|
||||
import { MANIFEST_KEY } from "../compat/legacy-names.js";
|
||||
import { normalizeClawHubSha256Integrity } from "../infra/clawhub.js";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import { readResponseWithLimit } from "../infra/http-body.js";
|
||||
import { isRecord } from "../utils.js";
|
||||
import type {
|
||||
@@ -694,10 +695,6 @@ function resolveOfficialExternalPluginCatalogEntryKey(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function formatHostedCatalogError(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
function bundledFallbackResult(
|
||||
error: unknown,
|
||||
metadata?: HostedOfficialExternalPluginCatalogLoadResult["metadata"],
|
||||
@@ -705,7 +702,7 @@ function bundledFallbackResult(
|
||||
return {
|
||||
source: "bundled-fallback",
|
||||
entries: listOfficialExternalPluginCatalogEntries(),
|
||||
error: formatHostedCatalogError(error),
|
||||
error: formatErrorMessage(error),
|
||||
...(metadata ? { metadata } : {}),
|
||||
};
|
||||
}
|
||||
@@ -714,7 +711,7 @@ function emptyBundledFallbackResult(error: unknown): HostedOfficialExternalPlugi
|
||||
return {
|
||||
source: "bundled-fallback",
|
||||
entries: [],
|
||||
error: formatHostedCatalogError(error),
|
||||
error: formatErrorMessage(error),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -912,8 +909,8 @@ async function loadHostedCatalogSnapshotResult(params: {
|
||||
snapshot: params.snapshot,
|
||||
...(parsed.trust ? { trust: parsed.trust } : {}),
|
||||
error: parsed.expired
|
||||
? `${formatHostedCatalogError(params.error)}; ${parsed.feed.expiresAt ? `hosted catalog signed feed expired at ${parsed.feed.expiresAt}` : "hosted catalog signed feed has no expiresAt"}`
|
||||
: formatHostedCatalogError(params.error),
|
||||
? `${formatErrorMessage(params.error)}; ${parsed.feed.expiresAt ? `hosted catalog signed feed expired at ${parsed.feed.expiresAt}` : "hosted catalog signed feed has no expiresAt"}`
|
||||
: formatErrorMessage(params.error),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -999,11 +996,11 @@ async function snapshotOrBundledFallbackResult(params: {
|
||||
} catch (snapshotErr) {
|
||||
if (params.verification?.mode === "signed") {
|
||||
return emptyBundledFallbackResult(
|
||||
`${formatHostedCatalogError(params.error)}; snapshot fallback failed: ${formatHostedCatalogError(snapshotErr)}`,
|
||||
`${formatErrorMessage(params.error)}; snapshot fallback failed: ${formatErrorMessage(snapshotErr)}`,
|
||||
);
|
||||
}
|
||||
return bundledFallbackResult(
|
||||
`${formatHostedCatalogError(params.error)}; snapshot fallback failed: ${formatHostedCatalogError(snapshotErr)}`,
|
||||
`${formatErrorMessage(params.error)}; snapshot fallback failed: ${formatErrorMessage(snapshotErr)}`,
|
||||
params.metadata,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/string-coerce";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import { resolveRequiredHomeDir } from "../infra/home-dir.js";
|
||||
import { tryReadJsonSync } from "../infra/json-files.js";
|
||||
import { resolveOpenClawPackageRootSync } from "../infra/openclaw-root.js";
|
||||
@@ -354,10 +355,6 @@ function listArgvRuntimeFallbackStartDirs(argv1: string | undefined): string[] {
|
||||
return dedupeResolvedPaths(starts);
|
||||
}
|
||||
|
||||
function formatResolutionError(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
function resolveDevSourceRootParam(params: { devSourceRoot?: string | null }): string | null {
|
||||
return params.devSourceRoot !== undefined
|
||||
? params.devSourceRoot
|
||||
@@ -1564,7 +1561,7 @@ export function resolvePluginRuntimeModulePathWithDiagnostics(
|
||||
packageRoot,
|
||||
candidates: dedupeResolvedPaths(candidates),
|
||||
resolvedPath: null,
|
||||
error: formatResolutionError(error),
|
||||
error: formatErrorMessage(error),
|
||||
};
|
||||
}
|
||||
return {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { existsSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import type { DatabaseSync } from "node:sqlite";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import {
|
||||
clearNodeSqliteKyselyCacheForDatabase,
|
||||
executeSqliteQuerySync,
|
||||
@@ -88,10 +89,6 @@ function readRegisteredAgentDatabases(database: DatabaseSync): Array<{
|
||||
);
|
||||
}
|
||||
|
||||
function errorReason(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
/** Read schema headers; report unreadable existing files without diagnosing or repairing them. */
|
||||
export function preflightOpenClawDatabaseSchemas(options: {
|
||||
env: NodeJS.ProcessEnv;
|
||||
@@ -128,7 +125,7 @@ export function preflightOpenClawDatabaseSchemas(options: {
|
||||
result.indeterminate.push({
|
||||
kind: "state",
|
||||
path: statePath,
|
||||
reason: `agent database registry query failed: ${errorReason(error)}`,
|
||||
reason: `agent database registry query failed: ${formatErrorMessage(error)}`,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
@@ -161,7 +158,7 @@ export function preflightOpenClawDatabaseSchemas(options: {
|
||||
result.indeterminate.push({
|
||||
kind: "agent",
|
||||
path: agentPath,
|
||||
reason: errorReason(error),
|
||||
reason: formatErrorMessage(error),
|
||||
});
|
||||
} finally {
|
||||
agentDatabase?.close();
|
||||
@@ -169,7 +166,11 @@ export function preflightOpenClawDatabaseSchemas(options: {
|
||||
}
|
||||
return result;
|
||||
} catch (error) {
|
||||
result.indeterminate.push({ kind: "state", path: statePath, reason: errorReason(error) });
|
||||
result.indeterminate.push({
|
||||
kind: "state",
|
||||
path: statePath,
|
||||
reason: formatErrorMessage(error),
|
||||
});
|
||||
return result;
|
||||
} finally {
|
||||
if (stateDatabase) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Control UI module implements gateway behavior.
|
||||
import {
|
||||
buildGatewayConnectAuth,
|
||||
buildDeviceAuthPayload,
|
||||
@@ -31,6 +30,9 @@ import {
|
||||
MIN_CLIENT_PROTOCOL_VERSION,
|
||||
PROTOCOL_VERSION,
|
||||
} from "@openclaw/gateway-client/browser";
|
||||
// Control UI module implements gateway behavior.
|
||||
import { formatErrorMessage } from "@openclaw/normalization-core";
|
||||
import { redactToolDetail } from "../lib/browser-redact.ts";
|
||||
import {
|
||||
clearDeviceAuthToken,
|
||||
loadDeviceAuthToken,
|
||||
@@ -209,10 +211,6 @@ const BROWSER_WEBSOCKET_CONSTRUCTOR_ERROR_CODE = "BROWSER_WEBSOCKET_CONSTRUCTOR_
|
||||
const BROWSER_WEBSOCKET_SECURITY_ERROR_CODE = "BROWSER_WEBSOCKET_SECURITY_ERROR";
|
||||
const DEFAULT_GATEWAY_TICK_INTERVAL_MS = 30_000;
|
||||
const MIN_GATEWAY_TICK_WATCH_INTERVAL_MS = 1_000;
|
||||
function getErrorMessage(err: unknown): string {
|
||||
return err instanceof Error && err.message ? err.message : String(err);
|
||||
}
|
||||
|
||||
function toGatewayErrorInfo(error: GatewayRequestError): GatewayErrorInfo {
|
||||
const { gatewayCode: code, message, details, retryable, retryAfterMs } = error;
|
||||
return { code, message, details, retryable, retryAfterMs };
|
||||
@@ -226,7 +224,7 @@ function getErrorName(err: unknown): string | undefined {
|
||||
|
||||
function isBrowserWebSocketSecurityError(err: unknown): boolean {
|
||||
const name = getErrorName(err)?.toLowerCase();
|
||||
const message = getErrorMessage(err).toLowerCase();
|
||||
const message = formatErrorMessage(err, { redact: redactToolDetail }).toLowerCase();
|
||||
return (
|
||||
name === "securityerror" ||
|
||||
message.includes("security error") ||
|
||||
@@ -237,7 +235,7 @@ function isBrowserWebSocketSecurityError(err: unknown): boolean {
|
||||
|
||||
function formatBrowserWebSocketConstructorError(err: unknown, url: string): GatewayErrorInfo {
|
||||
const securityError = isBrowserWebSocketSecurityError(err);
|
||||
const browserMessage = getErrorMessage(err);
|
||||
const browserMessage = formatErrorMessage(err, { redact: redactToolDetail });
|
||||
const isPlaintextWs = url.trim().toLowerCase().startsWith("ws://");
|
||||
const details = {
|
||||
code: securityError
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// Application-owned browser push subscription lifecycle.
|
||||
import { formatErrorMessage } from "@openclaw/normalization-core";
|
||||
import type { GatewayBrowserClient } from "../api/gateway.ts";
|
||||
import { redactToolDetail } from "../lib/browser-redact.ts";
|
||||
import type { ApplicationGateway } from "./gateway.ts";
|
||||
|
||||
type WebPushSnapshot = {
|
||||
@@ -29,10 +31,6 @@ function isWebPushSupported(): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
function webPushError(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
export function createWebPushCapability(gateway: ApplicationGateway): WebPushCapability {
|
||||
const supported = isWebPushSupported();
|
||||
let snapshot: WebPushSnapshot = {
|
||||
@@ -91,7 +89,7 @@ export function createWebPushCapability(gateway: ApplicationGateway): WebPushCap
|
||||
publish({ loading: true, error: null });
|
||||
operation = action(client)
|
||||
.catch((error: unknown) => {
|
||||
publish({ error: webPushError(error) });
|
||||
publish({ error: formatErrorMessage(error, { redact: redactToolDetail }) });
|
||||
})
|
||||
.finally(() => {
|
||||
operation = null;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { formatErrorMessage } from "@openclaw/normalization-core";
|
||||
import {
|
||||
ClawHubTrustErrorCodes,
|
||||
readClawHubTrustErrorDetails,
|
||||
@@ -9,6 +10,7 @@ import type {
|
||||
SkillStatusEntry,
|
||||
SkillStatusReport,
|
||||
} from "../../api/types.ts";
|
||||
import { redactToolDetail } from "../browser-redact.ts";
|
||||
import {
|
||||
normalizeSkillApiKeyReplacement,
|
||||
runSkillConfigMutation,
|
||||
@@ -155,8 +157,6 @@ function setSkillMessage(state: SkillsState, key: string, message: SkillMessage)
|
||||
state.skillMessages = { ...state.skillMessages, [key]: message };
|
||||
}
|
||||
|
||||
const getErrorMessage = (err: unknown) => (err instanceof Error ? err.message : String(err));
|
||||
|
||||
function getClawHubTrustDetailsFromError(err: unknown) {
|
||||
if (!err || typeof err !== "object" || !("details" in err)) {
|
||||
return undefined;
|
||||
@@ -342,7 +342,7 @@ export async function loadSkills(
|
||||
if (!isCurrent()) {
|
||||
return;
|
||||
}
|
||||
state.skillsError = getErrorMessage(err);
|
||||
state.skillsError = formatErrorMessage(err, { redact: redactToolDetail });
|
||||
} finally {
|
||||
// A transient disconnect invalidates the result, not this invocation's
|
||||
// loading ownership. Source/scope identity still protects newer loads.
|
||||
@@ -453,7 +453,10 @@ export async function loadSkillCard(state: SkillsState, skillKey: string) {
|
||||
}
|
||||
} catch (err) {
|
||||
if (isSkillsAgentScopeCurrent(state, agentScope)) {
|
||||
state.skillCardErrors = { ...state.skillCardErrors, [skillKey]: getErrorMessage(err) };
|
||||
state.skillCardErrors = {
|
||||
...state.skillCardErrors,
|
||||
[skillKey]: formatErrorMessage(err, { redact: redactToolDetail }),
|
||||
};
|
||||
}
|
||||
} finally {
|
||||
if (isSkillsAgentScopeCurrent(state, agentScope) && state.skillCardLoadingKey === skillKey) {
|
||||
@@ -496,7 +499,7 @@ async function loadClawHubSecurityVerdicts(state: SkillsState, report: SkillStat
|
||||
return;
|
||||
}
|
||||
state.clawhubVerdicts = {};
|
||||
state.clawhubVerdictsError = getErrorMessage(err);
|
||||
state.clawhubVerdictsError = formatErrorMessage(err, { redact: redactToolDetail });
|
||||
} finally {
|
||||
if (isSkillsAgentScopeCurrent(state, agentScope)) {
|
||||
state.clawhubVerdictsLoading = false;
|
||||
@@ -549,7 +552,7 @@ async function runSkillMutation(
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const message = getErrorMessage(err);
|
||||
const message = formatErrorMessage(err, { redact: redactToolDetail });
|
||||
state.skillsError = message;
|
||||
setSkillMessage(state, skillKey, {
|
||||
kind: "error",
|
||||
@@ -652,7 +655,7 @@ export async function loadClawHubDetail(state: SkillsState, slug: string) {
|
||||
state.clawhubDetail = res ?? null;
|
||||
},
|
||||
(err) => {
|
||||
state.clawhubDetailError = getErrorMessage(err);
|
||||
state.clawhubDetailError = formatErrorMessage(err, { redact: redactToolDetail });
|
||||
},
|
||||
() => {
|
||||
state.clawhubDetailLoading = false;
|
||||
@@ -718,7 +721,10 @@ export async function installFromClawHub(
|
||||
kind: "error",
|
||||
text: needsAcknowledgement
|
||||
? formatClawHubAcknowledgementMessage(trustDetails?.warning)
|
||||
: formatClawHubInstallMessage(getErrorMessage(err), trustDetails?.warning),
|
||||
: formatClawHubInstallMessage(
|
||||
formatErrorMessage(err, { redact: redactToolDetail }),
|
||||
trustDetails?.warning,
|
||||
),
|
||||
...(needsAcknowledgement ? { acknowledgeSlug: slug } : {}),
|
||||
...(needsAcknowledgement && trustDetails?.version
|
||||
? { acknowledgeVersion: trustDetails.version }
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// Agent identity draft state and persistence, split out of agents-page.ts.
|
||||
import { formatErrorMessage } from "@openclaw/normalization-core";
|
||||
import type { GatewayBrowserClient } from "../../api/gateway.ts";
|
||||
import type { ApplicationContext, ApplicationNavigationPreferences } from "../../app/context.ts";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { updateAgentIdentity } from "../../lib/agents/index.ts";
|
||||
import { redactToolDetail } from "../../lib/browser-redact.ts";
|
||||
import { fileToAvatarDataUrl } from "./avatar-image.ts";
|
||||
import type { AgentIdentityDraft } from "./panels-overview.ts";
|
||||
|
||||
@@ -12,10 +14,6 @@ type AgentIdentityEditorHost = {
|
||||
identityError: string | null;
|
||||
};
|
||||
|
||||
function errorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
const avatarSelectionEpochs = new WeakMap<AgentIdentityEditorHost, number>();
|
||||
|
||||
function advanceAvatarSelectionEpoch(host: AgentIdentityEditorHost): number {
|
||||
@@ -99,14 +97,14 @@ export async function saveIdentityDraft(params: {
|
||||
await agents.refreshList();
|
||||
} catch (error) {
|
||||
refreshErrors.push(
|
||||
`Agent identity was saved, but the agent list refresh failed: ${errorMessage(error)}`,
|
||||
`Agent identity was saved, but the agent list refresh failed: ${formatErrorMessage(error, { redact: redactToolDetail })}`,
|
||||
);
|
||||
}
|
||||
try {
|
||||
await agentIdentity.ensure([agentId]);
|
||||
} catch (error) {
|
||||
refreshErrors.push(
|
||||
`Agent identity was saved, but the identity refresh failed: ${errorMessage(error)}`,
|
||||
`Agent identity was saved, but the identity refresh failed: ${formatErrorMessage(error, { redact: redactToolDetail })}`,
|
||||
);
|
||||
}
|
||||
if (params.isCurrent()) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { formatErrorMessage } from "@openclaw/normalization-core";
|
||||
import { asNullableRecord as asRecord } from "@openclaw/normalization-core/record-coerce";
|
||||
import { html, nothing } from "lit";
|
||||
import type { GatewayBrowserClient } from "../../api/gateway.ts";
|
||||
@@ -17,6 +18,7 @@ import {
|
||||
buildToolsEffectiveRequestKey,
|
||||
loadToolsEffective,
|
||||
} from "../../lib/agents/tools-effective.ts";
|
||||
import { redactToolDetail } from "../../lib/browser-redact.ts";
|
||||
import {
|
||||
buildAddMcpServerPatch,
|
||||
MCP_SERVER_NAME_PATTERN,
|
||||
@@ -59,10 +61,6 @@ type CapabilityMutationResult =
|
||||
| { ok: true }
|
||||
| { ok: false; error: string; stage: "config" | "session" };
|
||||
|
||||
function errorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
function webSearchBaseEnabled(config: Record<string, unknown> | null): boolean {
|
||||
return asRecord(asRecord(asRecord(config?.tools)?.web)?.search)?.enabled !== false;
|
||||
}
|
||||
@@ -129,7 +127,11 @@ export class ChatComposerCapabilityHost {
|
||||
try {
|
||||
globalResult = await options.patchGlobal(globalConfig);
|
||||
} catch (error) {
|
||||
return { ok: false, error: errorMessage(error), stage: "config" };
|
||||
return {
|
||||
ok: false,
|
||||
error: formatErrorMessage(error, { redact: redactToolDetail }),
|
||||
stage: "config",
|
||||
};
|
||||
}
|
||||
if (!globalResult.ok) {
|
||||
return { ...globalResult, stage: "config" };
|
||||
@@ -141,7 +143,11 @@ export class ChatComposerCapabilityHost {
|
||||
try {
|
||||
loaded = await options.loadSessionOverrides();
|
||||
} catch (error) {
|
||||
return { ok: false, error: errorMessage(error), stage: "session" };
|
||||
return {
|
||||
ok: false,
|
||||
error: formatErrorMessage(error, { redact: redactToolDetail }),
|
||||
stage: "session",
|
||||
};
|
||||
}
|
||||
if (!loaded.ok) {
|
||||
return { ...loaded, stage: "session" };
|
||||
@@ -157,7 +163,11 @@ export class ChatComposerCapabilityHost {
|
||||
try {
|
||||
sessionResult = await options.patchSession(next);
|
||||
} catch (error) {
|
||||
return { ok: false, error: errorMessage(error), stage: "session" };
|
||||
return {
|
||||
ok: false,
|
||||
error: formatErrorMessage(error, { redact: redactToolDetail }),
|
||||
stage: "session",
|
||||
};
|
||||
}
|
||||
return sessionResult.ok ? sessionResult : { ...sessionResult, stage: "session" };
|
||||
}
|
||||
@@ -395,7 +405,7 @@ export class ChatComposerCapabilityHost {
|
||||
} catch (error) {
|
||||
return {
|
||||
ok: false as const,
|
||||
error: errorMessage(error),
|
||||
error: formatErrorMessage(error, { redact: redactToolDetail }),
|
||||
};
|
||||
}
|
||||
if (!identityMatches()) {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { formatErrorMessage } from "@openclaw/normalization-core";
|
||||
import { html, nothing, type PropertyValues } from "lit";
|
||||
import { property, state } from "lit/decorators.js";
|
||||
import type { AgentsWorkspaceGetResult } from "../../../../packages/gateway-protocol/src/index.js";
|
||||
import type { MemorySearchResponse } from "../../../../src/gateway/server-methods/memory-search.ts";
|
||||
import type { GatewayBrowserClient } from "../../api/gateway.ts";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { redactToolDetail } from "../../lib/browser-redact.ts";
|
||||
import { OpenClawLightDomElement } from "../../lit/openclaw-element.ts";
|
||||
import "../../styles/memory-memories.css";
|
||||
|
||||
@@ -18,10 +20,6 @@ type DetailState =
|
||||
| { kind: "ready"; content: string }
|
||||
| { kind: "error"; message: string };
|
||||
|
||||
function errorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
function resultKey(result: SearchResult, index: number): string {
|
||||
return `${index}:${result.path}:${result.startLine}:${result.endLine}`;
|
||||
}
|
||||
@@ -113,7 +111,11 @@ class MemoryMemoriesElement extends OpenClawLightDomElement {
|
||||
if (this.searchRequest !== request || this.agentId !== agentId || this.client !== client) {
|
||||
return;
|
||||
}
|
||||
this.searchState = { kind: "error", query: normalizedQuery, message: errorMessage(error) };
|
||||
this.searchState = {
|
||||
kind: "error",
|
||||
query: normalizedQuery,
|
||||
message: formatErrorMessage(error, { redact: redactToolDetail }),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +159,7 @@ class MemoryMemoriesElement extends OpenClawLightDomElement {
|
||||
}
|
||||
this.details = new Map(this.details).set(key, {
|
||||
kind: "error",
|
||||
message: errorMessage(error),
|
||||
message: formatErrorMessage(error, { redact: redactToolDetail }),
|
||||
});
|
||||
} finally {
|
||||
if (this.detailRequests.get(key) === request) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// this element owns the shared agent selection, Overview status, and global
|
||||
// configuration controllers used by Settings.
|
||||
import { consume } from "@lit/context";
|
||||
import { formatErrorMessage } from "@openclaw/normalization-core";
|
||||
import { asNullableRecord as asConfigRecord } from "@openclaw/normalization-core/record-coerce";
|
||||
import { html, type PropertyValues, type TemplateResult } from "lit";
|
||||
import { property, state } from "lit/decorators.js";
|
||||
@@ -14,6 +15,7 @@ import type { AgentSelectOption } from "../../components/agent-select.ts";
|
||||
import { renderDocsLink } from "../../components/settings-ui.ts";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { listSelectableAgents, normalizeAgentLabel } from "../../lib/agents/display.ts";
|
||||
import { redactToolDetail } from "../../lib/browser-redact.ts";
|
||||
import { currentConfigObject } from "../../lib/config/index.ts";
|
||||
import { isGatewayMethodAdvertised } from "../../lib/gateway-methods.ts";
|
||||
import {
|
||||
@@ -87,10 +89,6 @@ type MemoryPageProps = {
|
||||
buildEditor: (keys: readonly string[]) => TemplateResult;
|
||||
};
|
||||
|
||||
function errorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
class MemorySettingsPage extends OpenClawLightDomElement {
|
||||
@consume({ context: applicationContext, subscribe: true })
|
||||
private context!: ApplicationContext;
|
||||
@@ -383,7 +381,10 @@ class MemorySettingsPage extends OpenClawLightDomElement {
|
||||
if (!this.isConnected || this.overviewRequest !== request) {
|
||||
return;
|
||||
}
|
||||
this.overviewStatus = { kind: "error", message: errorMessage(error) };
|
||||
this.overviewStatus = {
|
||||
kind: "error",
|
||||
message: formatErrorMessage(error, { redact: redactToolDetail }),
|
||||
};
|
||||
} finally {
|
||||
if (this.overviewRequest === request) {
|
||||
this.probingEmbeddings = false;
|
||||
@@ -496,7 +497,10 @@ class MemorySettingsPage extends OpenClawLightDomElement {
|
||||
}
|
||||
} catch (error) {
|
||||
if (this.connection === connection) {
|
||||
this.addonErrors = new Map(this.addonErrors).set(pluginId, errorMessage(error));
|
||||
this.addonErrors = new Map(this.addonErrors).set(
|
||||
pluginId,
|
||||
formatErrorMessage(error, { redact: redactToolDetail }),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
if (this.addonNoticeOperations.get(pluginId) === noticeOperation) {
|
||||
@@ -547,7 +551,10 @@ class MemorySettingsPage extends OpenClawLightDomElement {
|
||||
}
|
||||
} catch (error) {
|
||||
if (this.connection === connection) {
|
||||
this.engineOutcome = { kind: "error", message: errorMessage(error) };
|
||||
this.engineOutcome = {
|
||||
kind: "error",
|
||||
message: formatErrorMessage(error, { redact: redactToolDetail }),
|
||||
};
|
||||
}
|
||||
} finally {
|
||||
if (this.connection === connection) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { formatErrorMessage } from "@openclaw/normalization-core";
|
||||
import { html, nothing } from "lit";
|
||||
import type {
|
||||
EnvironmentsListResult,
|
||||
@@ -6,6 +7,7 @@ import type {
|
||||
import { GatewayRequestError, type GatewayBrowserClient } from "../../api/gateway.ts";
|
||||
import { icons } from "../../components/icons.ts";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { redactToolDetail } from "../../lib/browser-redact.ts";
|
||||
import { generateUUID } from "../../lib/uuid.ts";
|
||||
import type { DraftCloudProfile } from "./discovery.ts";
|
||||
import { readDraftCloudProfiles } from "./discovery.ts";
|
||||
@@ -45,10 +47,6 @@ const PENDING_PLACEMENT_STATES = new Set([
|
||||
"reconciling",
|
||||
]);
|
||||
|
||||
function errorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
function isAmbiguousDispatchError(error: unknown): boolean {
|
||||
if (error instanceof GatewayRequestError) {
|
||||
return error.retryable || error.gatewayCode === "UNAVAILABLE";
|
||||
@@ -70,7 +68,10 @@ async function readPlacement(
|
||||
return { status: "read", placement: described?.session?.placement };
|
||||
} catch (error) {
|
||||
if (!isAmbiguousDispatchError(error)) {
|
||||
return { status: "rejected", error: errorMessage(error) };
|
||||
return {
|
||||
status: "rejected",
|
||||
error: formatErrorMessage(error, { redact: redactToolDetail }),
|
||||
};
|
||||
}
|
||||
return { status: "unavailable" };
|
||||
}
|
||||
@@ -95,7 +96,7 @@ async function cancelActivePlacement(
|
||||
await client.request("environments.destroy", { environmentId });
|
||||
return undefined;
|
||||
} catch (error) {
|
||||
return errorMessage(error);
|
||||
return formatErrorMessage(error, { redact: redactToolDetail });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,7 +232,7 @@ export async function deleteCloudDraftSession(
|
||||
await client.request("sessions.delete", { key, agentId, deleteTranscript: true });
|
||||
return undefined;
|
||||
} catch (error) {
|
||||
return errorMessage(error);
|
||||
return formatErrorMessage(error, { redact: redactToolDetail });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,7 +334,7 @@ export async function startCloudInitialTurn(
|
||||
isCurrent,
|
||||
);
|
||||
} catch (error) {
|
||||
dispatchError = errorMessage(error);
|
||||
dispatchError = formatErrorMessage(error, { redact: redactToolDetail });
|
||||
if (!isAmbiguousDispatchError(error)) {
|
||||
return { status: "dispatch-rejected", error: dispatchError };
|
||||
}
|
||||
@@ -430,9 +431,17 @@ export async function startCloudInitialTurn(
|
||||
});
|
||||
return cleanupError
|
||||
? { status: "cleanup-rejected", error: cleanupError, messageId }
|
||||
: { status: "send-definitive-rejected", error: errorMessage(error), messageId };
|
||||
: {
|
||||
status: "send-definitive-rejected",
|
||||
error: formatErrorMessage(error, { redact: redactToolDetail }),
|
||||
messageId,
|
||||
};
|
||||
}
|
||||
return { status: "send-rejected", error: errorMessage(error), messageId };
|
||||
return {
|
||||
status: "send-rejected",
|
||||
error: formatErrorMessage(error, { redact: redactToolDetail }),
|
||||
messageId,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { consume } from "@lit/context";
|
||||
import { initialState, Task, TaskStatus } from "@lit/task";
|
||||
import { formatErrorMessage } from "@openclaw/normalization-core";
|
||||
import type { RouteLocation } from "@openclaw/uirouter";
|
||||
import { html, type PropertyValues } from "lit";
|
||||
import { property, state } from "lit/decorators.js";
|
||||
@@ -18,6 +19,7 @@ import type { McpServerForm } from "../../components/mcp-server-form.ts";
|
||||
import { renderDocsLink } from "../../components/settings-ui.ts";
|
||||
import { renderSettingsWorkspace } from "../../components/settings-workspace.ts";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { redactToolDetail } from "../../lib/browser-redact.ts";
|
||||
import { resolveEditableSnapshotConfig } from "../../lib/config/index.ts";
|
||||
import {
|
||||
buildAddMcpServerPatch,
|
||||
@@ -69,10 +71,6 @@ export type PluginsRouteData = {
|
||||
location: RouteLocation;
|
||||
};
|
||||
|
||||
function errorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
function committedMutationMessage(success: string, refreshError: string | null): PluginRowMessage {
|
||||
return {
|
||||
kind: "success",
|
||||
@@ -162,7 +160,7 @@ class PluginsPage extends OpenClawLightDomElement {
|
||||
this.replaceResult(result);
|
||||
},
|
||||
onError: (error) => {
|
||||
this.error = errorMessage(error);
|
||||
this.error = formatErrorMessage(error, { redact: redactToolDetail });
|
||||
},
|
||||
});
|
||||
|
||||
@@ -532,14 +530,14 @@ class PluginsPage extends OpenClawLightDomElement {
|
||||
private get searchError(): string | null {
|
||||
return this.searchTask.status === TaskStatus.ERROR &&
|
||||
this.debouncedSearchQuery === this.query.trim()
|
||||
? errorMessage(this.searchTask.error)
|
||||
? formatErrorMessage(this.searchTask.error, { redact: redactToolDetail })
|
||||
: null;
|
||||
}
|
||||
|
||||
private get configRefreshError(): string | null {
|
||||
const failure =
|
||||
this.configTask.status === TaskStatus.ERROR
|
||||
? errorMessage(this.configTask.error)
|
||||
? formatErrorMessage(this.configTask.error, { redact: redactToolDetail })
|
||||
: this.configTask.status === TaskStatus.COMPLETE
|
||||
? this.configTask.value
|
||||
: null;
|
||||
@@ -736,7 +734,10 @@ class PluginsPage extends OpenClawLightDomElement {
|
||||
isCurrent: () => boolean,
|
||||
) => Promise<void>,
|
||||
onError: (error: unknown) => void = (error) => {
|
||||
this.setMessage(rowKey, { kind: "error", text: errorMessage(error) });
|
||||
this.setMessage(rowKey, {
|
||||
kind: "error",
|
||||
text: formatErrorMessage(error, { redact: redactToolDetail }),
|
||||
});
|
||||
},
|
||||
): Promise<void> {
|
||||
const client = this.client;
|
||||
@@ -795,7 +796,10 @@ class PluginsPage extends OpenClawLightDomElement {
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.setMessage(rowKey, { kind: "error", text: errorMessage(error) });
|
||||
this.setMessage(rowKey, {
|
||||
kind: "error",
|
||||
text: formatErrorMessage(error, { redact: redactToolDetail }),
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -889,7 +893,7 @@ class PluginsPage extends OpenClawLightDomElement {
|
||||
this.mcpMessage = { kind: "success", text: params.successText };
|
||||
return true;
|
||||
} catch (error) {
|
||||
return fail(errorMessage(error));
|
||||
return fail(formatErrorMessage(error, { redact: redactToolDetail }));
|
||||
} finally {
|
||||
this.mcpBusy = false;
|
||||
if (params.busyKey) {
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import { formatErrorMessage } from "@openclaw/normalization-core";
|
||||
import { definePage, type RouteLoaderOptions, type RouteLocation } from "@openclaw/uirouter";
|
||||
import { html } from "lit";
|
||||
import { routePageSpec } from "../../app-route-paths.ts";
|
||||
import type { ApplicationContext } from "../../app/context.ts";
|
||||
import { redactToolDetail } from "../../lib/browser-redact.ts";
|
||||
import { loadPluginCatalog } from "../../lib/plugins/index.ts";
|
||||
import type { PluginsRouteData } from "./plugins-page.ts";
|
||||
import { pluginsRouteLocation } from "./route-data.ts";
|
||||
|
||||
function errorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
async function loadPluginsRouteData(
|
||||
context: ApplicationContext,
|
||||
options: RouteLoaderOptions,
|
||||
@@ -25,7 +23,13 @@ async function loadPluginsRouteData(
|
||||
const result = await loadPluginCatalog(client);
|
||||
return { gateway, gatewaySnapshot, result, error: null, location };
|
||||
} catch (error) {
|
||||
return { gateway, gatewaySnapshot, result: null, error: errorMessage(error), location };
|
||||
return {
|
||||
gateway,
|
||||
gatewaySnapshot,
|
||||
result: null,
|
||||
error: formatErrorMessage(error, { redact: redactToolDetail }),
|
||||
location,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import { formatErrorMessage } from "@openclaw/normalization-core";
|
||||
import { html, nothing } from "lit";
|
||||
import type { ApplicationGateway } from "../../app/context.ts";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { redactToolDetail } from "../../lib/browser-redact.ts";
|
||||
import type { SkillWorkshopHistoryScanResult, SkillWorkshopHistoryScanState } from "./state.ts";
|
||||
|
||||
function getErrorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
type SkillWorkshopHistoryStatusLoadParams = {
|
||||
agentId: string;
|
||||
gateway: ApplicationGateway;
|
||||
@@ -70,7 +68,7 @@ export async function loadSkillWorkshopHistoryScanStatus(
|
||||
);
|
||||
current.state.loaded = true;
|
||||
} catch (error) {
|
||||
current.state.error = getErrorMessage(error);
|
||||
current.state.error = formatErrorMessage(error, { redact: redactToolDetail });
|
||||
// Loaded means this scope attempted a read. A scan action can still
|
||||
// force a retry because the result remains absent.
|
||||
current.state.loaded = true;
|
||||
@@ -130,7 +128,7 @@ export async function runSkillWorkshopHistoryScan(params: {
|
||||
params.state.loaded = true;
|
||||
return true;
|
||||
} catch (error) {
|
||||
const scanError = getErrorMessage(error);
|
||||
const scanError = formatErrorMessage(error, { redact: redactToolDetail });
|
||||
try {
|
||||
params.state.result = await client.request<SkillWorkshopHistoryScanResult>(
|
||||
"skills.proposals.historyStatus",
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// Control UI controller manages skill workshop gateway state.
|
||||
import { formatByteSize } from "@openclaw/normalization-core";
|
||||
import { formatByteSize, formatErrorMessage } from "@openclaw/normalization-core";
|
||||
import type { AgentSelectionCapability } from "../../app/agent-selection.ts";
|
||||
import type { ApplicationGateway } from "../../app/context.ts";
|
||||
import { t } from "../../i18n/index.ts";
|
||||
import { redactToolDetail } from "../../lib/browser-redact.ts";
|
||||
import {
|
||||
normalizeAgentId,
|
||||
parseAgentSessionKey,
|
||||
@@ -100,10 +101,6 @@ export type SkillWorkshopContext = {
|
||||
agentSelection: Pick<AgentSelectionCapability, "state">;
|
||||
};
|
||||
|
||||
function getErrorMessage(err: unknown): string {
|
||||
return err instanceof Error ? err.message : String(err);
|
||||
}
|
||||
|
||||
function skillWorkshopAgentParams(context: SkillWorkshopContext): { agentId: string } {
|
||||
const snapshot = context.gateway.snapshot;
|
||||
const sessionAgentId = parseAgentSessionKey(snapshot.sessionKey)?.agentId;
|
||||
@@ -415,7 +412,7 @@ export async function loadSkillWorkshopProposals(
|
||||
await loadSkillWorkshopProposalDetail(state, context, state.skillWorkshopSelectedKey);
|
||||
}
|
||||
} catch (err) {
|
||||
state.skillWorkshopError = getErrorMessage(err);
|
||||
state.skillWorkshopError = formatErrorMessage(err, { redact: redactToolDetail });
|
||||
} finally {
|
||||
state.skillWorkshopLoading = false;
|
||||
if (skillWorkshopAgentParams(context).agentId !== requestAgentId) {
|
||||
@@ -465,7 +462,7 @@ async function loadSkillWorkshopProposalDetail(
|
||||
return true;
|
||||
} catch (err) {
|
||||
if (state.skillWorkshopAgentId === requestAgentId) {
|
||||
state.skillWorkshopError = getErrorMessage(err);
|
||||
state.skillWorkshopError = formatErrorMessage(err, { redact: redactToolDetail });
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
@@ -530,7 +527,7 @@ export async function runSkillWorkshopLifecycleAction(
|
||||
t(action === "apply" ? "skillWorkshop.notices.applied" : "skillWorkshop.notices.rejected"),
|
||||
);
|
||||
} catch (err) {
|
||||
state.skillWorkshopError = getErrorMessage(err);
|
||||
state.skillWorkshopError = formatErrorMessage(err, { redact: redactToolDetail });
|
||||
} finally {
|
||||
if (
|
||||
state.skillWorkshopActionBusy?.key === proposalId &&
|
||||
@@ -594,7 +591,7 @@ export async function runSkillWorkshopEvaluation(
|
||||
return true;
|
||||
} catch (err) {
|
||||
if (state.skillWorkshopAgentId === requestAgentId) {
|
||||
state.skillWorkshopError = getErrorMessage(err);
|
||||
state.skillWorkshopError = formatErrorMessage(err, { redact: redactToolDetail });
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
@@ -645,7 +642,7 @@ export async function requestSkillWorkshopRevision(
|
||||
showActionNotice(state, proposal, t("skillWorkshop.notices.revisionRequested"));
|
||||
return true;
|
||||
} catch (err) {
|
||||
state.skillWorkshopError = getErrorMessage(err);
|
||||
state.skillWorkshopError = formatErrorMessage(err, { redact: redactToolDetail });
|
||||
return false;
|
||||
} finally {
|
||||
if (
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { formatErrorMessage } from "@openclaw/normalization-core";
|
||||
import { definePage } from "@openclaw/uirouter";
|
||||
import { html } from "lit";
|
||||
import { routePageSpec } from "../../app-route-paths.ts";
|
||||
import type { ApplicationContext } from "../../app/context.ts";
|
||||
import { redactToolDetail } from "../../lib/browser-redact.ts";
|
||||
import { loadSkillStatusReport } from "../../lib/skills/index.ts";
|
||||
import type { SkillsRouteData } from "./skills-page.ts";
|
||||
|
||||
function errorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
async function loadSkillsRouteData(context: ApplicationContext): Promise<SkillsRouteData> {
|
||||
const gateway = context.gateway;
|
||||
const gatewaySnapshot = gateway.snapshot;
|
||||
@@ -32,12 +30,12 @@ async function loadSkillsRouteData(context: ApplicationContext): Promise<SkillsR
|
||||
try {
|
||||
agentsList = await agents.ensureList();
|
||||
} catch (err) {
|
||||
error = errorMessage(err);
|
||||
error = formatErrorMessage(err, { redact: redactToolDetail });
|
||||
}
|
||||
try {
|
||||
report = (await loadSkillStatusReport(client, null)) ?? null;
|
||||
} catch (err) {
|
||||
error ??= errorMessage(err);
|
||||
error ??= formatErrorMessage(err, { redact: redactToolDetail });
|
||||
}
|
||||
return {
|
||||
gateway,
|
||||
|
||||
Reference in New Issue
Block a user