diff --git a/src/agents/pi-embedded-runner/compact.ts b/src/agents/pi-embedded-runner/compact.ts index 9bb06f43578f..b7be44f96f58 100644 --- a/src/agents/pi-embedded-runner/compact.ts +++ b/src/agents/pi-embedded-runner/compact.ts @@ -143,7 +143,7 @@ import { } from "./tool-schema-runtime.js"; import { splitSdkTools } from "./tool-split.js"; import type { EmbeddedPiCompactResult } from "./types.js"; -import { describeUnknownError, mapThinkingLevel } from "./utils.js"; +import { mapThinkingLevel } from "./utils.js"; import { flushPendingToolResultsAfterIdle } from "./wait-for-idle-before-flush.js"; export type CompactEmbeddedPiSessionParams = { @@ -395,7 +395,7 @@ export async function compactEmbeddedPiSessionDirect( authStorage.setRuntimeApiKey(runtimeModel.provider, runtimeApiKey); } } catch (err) { - const reason = describeUnknownError(err); + const reason = formatErrorMessage(err); return fail(reason); } @@ -1103,7 +1103,7 @@ export async function compactEmbeddedPiSessionDirect( }; } catch (err) { const fallbackThinking = pickFallbackThinkingLevel({ - message: describeUnknownError(err), + message: formatErrorMessage(err), attempted: attemptedThinking, }); if (fallbackThinking) { @@ -1149,7 +1149,7 @@ export async function compactEmbeddedPiSessionDirect( } } catch (err) { const reason = resolveCompactionFailureReason({ - reason: describeUnknownError(err), + reason: formatErrorMessage(err), safeguardCancelReason: consumeCompactionSafeguardCancelReason(compactionSessionManager), }); return fail(reason); diff --git a/src/agents/pi-embedded-runner/run.ts b/src/agents/pi-embedded-runner/run.ts index b60cb1a00822..39a9dc790f12 100644 --- a/src/agents/pi-embedded-runner/run.ts +++ b/src/agents/pi-embedded-runner/run.ts @@ -7,6 +7,7 @@ import { } from "../../context-engine/index.js"; import { emitAgentPlanEvent } from "../../infra/agent-events.js"; import { sleepWithAbort } from "../../infra/backoff.js"; +import { formatErrorMessage } from "../../infra/errors.js"; import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js"; import { enqueueCommandInLane } from "../../process/command-queue.js"; import { sanitizeForLog } from "../../terminal/ansi.js"; @@ -101,7 +102,6 @@ import { } from "./tool-result-truncation.js"; import type { EmbeddedPiAgentMeta, EmbeddedPiRunResult } from "./types.js"; import { createUsageAccumulator, mergeUsageIntoAccumulator } from "./usage-accumulator.js"; -import { describeUnknownError } from "./utils.js"; type ApiKeyInfo = ResolvedProviderAuth; @@ -139,7 +139,7 @@ function backfillSessionKey(params: { return resolved.sessionKey?.trim() || undefined; } catch (err) { log.warn( - `[backfillSessionKey] Failed to resolve sessionKey for sessionId=${redactRunIdentifier(sanitizeForLog(params.sessionId))}: ${describeUnknownError(err)}`, + `[backfillSessionKey] Failed to resolve sessionKey for sessionId=${redactRunIdentifier(sanitizeForLog(params.sessionId))}: ${formatErrorMessage(err)}`, ); return undefined; } @@ -850,7 +850,7 @@ export async function runEmbeddedPiAgent( const contextOverflowError = !aborted ? (() => { if (promptError) { - const errorText = describeUnknownError(promptError); + const errorText = formatErrorMessage(promptError); if (isLikelyContextOverflowError(errorText)) { return { text: errorText, source: "promptError" as const }; } @@ -1092,7 +1092,7 @@ export async function runEmbeddedPiAgent( const promptErrorDetails = normalizedPromptFailover ? describeFailoverError(normalizedPromptFailover) : describeFailoverError(promptError); - const errorText = promptErrorDetails.message || describeUnknownError(promptError); + const errorText = promptErrorDetails.message || formatErrorMessage(promptError); if (await maybeRefreshRuntimeAuthForAuthError(errorText, runtimeAuthRetry)) { authRetryPending = true; continue; @@ -1584,7 +1584,7 @@ export async function runEmbeddedPiAgent( if (params.cleanupBundleMcpOnRunEnd === true) { await disposeSessionMcpRuntime(params.sessionId).catch((error) => { log.warn( - `bundle-mcp cleanup failed after run for ${params.sessionId}: ${describeUnknownError(error)}`, + `bundle-mcp cleanup failed after run for ${params.sessionId}: ${formatErrorMessage(error)}`, ); }); } diff --git a/src/agents/pi-embedded-runner/run/attempt.ts b/src/agents/pi-embedded-runner/run/attempt.ts index 43c9cd1770e9..83ba25e4b4d0 100644 --- a/src/agents/pi-embedded-runner/run/attempt.ts +++ b/src/agents/pi-embedded-runner/run/attempt.ts @@ -9,6 +9,7 @@ import { import { filterHeartbeatPairs } from "../../../auto-reply/heartbeat-filter.js"; import { resolveHeartbeatPrompt } from "../../../auto-reply/heartbeat.js"; import { resolveChannelCapabilities } from "../../../config/channel-capabilities.js"; +import { formatErrorMessage } from "../../../infra/errors.js"; import { resolveHeartbeatSummaryForAgent } from "../../../infra/heartbeat-summary.js"; import { getMachineDisplayName } from "../../../infra/machine-name.js"; import { @@ -151,7 +152,7 @@ import { normalizeProviderToolSchemas, } from "../tool-schema-runtime.js"; import { splitSdkTools } from "../tool-split.js"; -import { describeUnknownError, mapThinkingLevel } from "../utils.js"; +import { mapThinkingLevel } from "../utils.js"; import { flushPendingToolResultsAfterIdle } from "../wait-for-idle-before-flush.js"; import { assembleAttemptContextEngine, @@ -1992,7 +1993,7 @@ export async function runEmbeddedAttempt( provider: params.provider, model: params.modelId, api: params.model.api, - error: describeUnknownError(promptError), + error: formatErrorMessage(promptError), }); } catch (entryErr) { log.warn(`failed to persist prompt error entry: ${String(entryErr)}`); @@ -2071,7 +2072,7 @@ export async function runEmbeddedAttempt( { messages: messagesSnapshot, success: !aborted && !promptError, - error: promptError ? describeUnknownError(promptError) : undefined, + error: promptError ? formatErrorMessage(promptError) : undefined, durationMs: Date.now() - promptStartedAt, }, { diff --git a/src/agents/pi-embedded-runner/run/auth-controller.ts b/src/agents/pi-embedded-runner/run/auth-controller.ts index 154269d5ca24..b354f658953f 100644 --- a/src/agents/pi-embedded-runner/run/auth-controller.ts +++ b/src/agents/pi-embedded-runner/run/auth-controller.ts @@ -1,5 +1,6 @@ import type { Api, Model } from "@mariozechner/pi-ai"; import type { ThinkLevel } from "../../../auto-reply/thinking.js"; +import { formatErrorMessage } from "../../../infra/errors.js"; import { prepareProviderRuntimeAuth } from "../../../plugins/provider-runtime.js"; import { type AuthProfileStore, @@ -19,7 +20,6 @@ import { sanitizeRuntimeProviderRequestOverrides, } from "../../provider-request-config.js"; import { clampRuntimeAuthRefreshDelayMs } from "../../runtime-auth-refresh.js"; -import { describeUnknownError } from "../utils.js"; import { RUNTIME_AUTH_REFRESH_MARGIN_MS, RUNTIME_AUTH_REFRESH_MIN_DELAY_MS, @@ -186,7 +186,7 @@ export function createEmbeddedRunAuthController(params: { .catch((err) => { const runtimeModel = params.getRuntimeModel(); params.log.warn( - `Runtime auth refresh failed for ${runtimeModel.provider}: ${describeUnknownError(err)}`, + `Runtime auth refresh failed for ${runtimeModel.provider}: ${formatErrorMessage(err)}`, ); throw err; }) @@ -289,7 +289,7 @@ export function createEmbeddedRunAuthController(params: { const fallbackMessage = `No available auth profile for ${provider} (all in cooldown or unavailable).`; const message = failoverParams.message?.trim() || - (failoverParams.error ? describeUnknownError(failoverParams.error).trim() : "") || + (failoverParams.error ? formatErrorMessage(failoverParams.error).trim() : "") || fallbackMessage; const reason = resolveAuthProfileFailoverReason({ allInCooldown: failoverParams.allInCooldown, diff --git a/src/agents/pi-embedded-runner/utils.ts b/src/agents/pi-embedded-runner/utils.ts index 991e767139b8..f6ac79ecd470 100644 --- a/src/agents/pi-embedded-runner/utils.ts +++ b/src/agents/pi-embedded-runner/utils.ts @@ -1,6 +1,5 @@ import type { ThinkingLevel } from "@mariozechner/pi-agent-core"; import type { ReasoningLevel, ThinkLevel } from "../../auto-reply/thinking.js"; -import { formatErrorMessage } from "../../infra/errors.js"; export function mapThinkingLevel(level?: ThinkLevel): ThinkingLevel { // pi-agent-core supports "xhigh"; OpenClaw enables it for specific models. @@ -17,8 +16,4 @@ export function mapThinkingLevel(level?: ThinkLevel): ThinkingLevel { return level; } -export function describeUnknownError(error: unknown): string { - return formatErrorMessage(error); -} - export type { ReasoningLevel, ThinkLevel }; diff --git a/src/cli/command-secret-gateway.ts b/src/cli/command-secret-gateway.ts index 6186e335068a..d79ba70369ec 100644 --- a/src/cli/command-secret-gateway.ts +++ b/src/cli/command-secret-gateway.ts @@ -2,6 +2,7 @@ import type { OpenClawConfig } from "../config/config.js"; import { resolveSecretInputRef } from "../config/types.secrets.js"; import { callGateway } from "../gateway/call.js"; import { validateSecretsResolveResult } from "../gateway/protocol/index.js"; +import { formatErrorMessage } from "../infra/errors.js"; import { resolveManifestContractOwnerPluginId } from "../plugins/manifest-registry.js"; import { analyzeCommandSecretAssignmentsFromSnapshot, @@ -13,7 +14,6 @@ import { collectConfigAssignments } from "../secrets/runtime-config-collectors.j import { createResolverContext } from "../secrets/runtime-shared.js"; import { resolveRuntimeWebTools } from "../secrets/runtime-web-tools.js"; import { assertExpectedResolvedSecretValue } from "../secrets/secret-value.js"; -import { describeUnknownError } from "../secrets/shared.js"; import { discoverConfigSecretTargetsByIds, type DiscoveredConfigSecretTarget, @@ -398,7 +398,7 @@ function collectInactiveSurfacePathsFromDiagnostics(diagnostics: string[]): Set< } function isUnsupportedSecretsResolveError(err: unknown): boolean { - const message = describeUnknownError(err).toLowerCase(); + const message = formatErrorMessage(err).toLowerCase(); if (!message.includes("secrets.resolve")) { return false; } @@ -460,7 +460,7 @@ async function resolveCommandSecretRefsLocally(params: { throw error; } localResolutionDiagnostics.push( - `${params.commandName}: failed to resolve web tool secrets locally (${describeUnknownError(error)}).`, + `${params.commandName}: failed to resolve web tool secrets locally (${formatErrorMessage(error)}).`, ); } } @@ -650,7 +650,7 @@ async function resolveTargetSecretLocally(params: { } catch (error) { if (!enforcesResolvedSecrets(params.mode)) { params.localResolutionDiagnostics.push( - `${params.commandName}: failed to resolve ${params.target.path} locally (${describeUnknownError(error)}).`, + `${params.commandName}: failed to resolve ${params.target.path} locally (${formatErrorMessage(error)}).`, ); } } @@ -725,7 +725,7 @@ export async function resolveCommandSecretRefsViaGateway(params: { resolvedConfig: fallback.resolvedConfig, diagnostics: dedupeDiagnostics([ ...fallback.diagnostics, - `${params.commandName}: gateway secrets.resolve unavailable (${describeUnknownError(err)}); ${fallbackMessage}`, + `${params.commandName}: gateway secrets.resolve unavailable (${formatErrorMessage(err)}); ${fallbackMessage}`, ]), targetStatesByPath: fallback.targetStatesByPath, hadUnresolvedTargets: fallback.hadUnresolvedTargets, @@ -735,12 +735,12 @@ export async function resolveCommandSecretRefsViaGateway(params: { } if (isUnsupportedSecretsResolveError(err)) { throw new Error( - `${params.commandName}: active gateway does not support secrets.resolve (${describeUnknownError(err)}). Update the gateway or run without SecretRefs.`, + `${params.commandName}: active gateway does not support secrets.resolve (${formatErrorMessage(err)}). Update the gateway or run without SecretRefs.`, { cause: err }, ); } throw new Error( - `${params.commandName}: failed to resolve secrets from the active gateway snapshot (${describeUnknownError(err)}). Start the gateway and retry.`, + `${params.commandName}: failed to resolve secrets from the active gateway snapshot (${formatErrorMessage(err)}). Start the gateway and retry.`, { cause: err }, ); } @@ -757,7 +757,7 @@ export async function resolveCommandSecretRefsViaGateway(params: { } catch (err) { const path = pathSegments.join("."); throw new Error( - `${params.commandName}: failed to apply resolved secret assignment at ${path} (${describeUnknownError(err)}).`, + `${params.commandName}: failed to apply resolved secret assignment at ${path} (${formatErrorMessage(err)}).`, { cause: err }, ); } @@ -837,7 +837,7 @@ export async function resolveCommandSecretRefsViaGateway(params: { scrubUnresolvedAssignments(resolvedConfig, analyzed.unresolved); diagnostics = dedupeDiagnostics([ ...diagnostics, - `${params.commandName}: local fallback after incomplete gateway snapshot failed (${describeUnknownError(error)}).`, + `${params.commandName}: local fallback after incomplete gateway snapshot failed (${formatErrorMessage(error)}).`, ...buildUnresolvedDiagnostics(params.commandName, analyzed.unresolved, mode), ]); } diff --git a/src/cli/exec-approvals-cli.ts b/src/cli/exec-approvals-cli.ts index 61cccf068e77..d681e14150fd 100644 --- a/src/cli/exec-approvals-cli.ts +++ b/src/cli/exec-approvals-cli.ts @@ -2,6 +2,7 @@ import fs from "node:fs/promises"; import type { Command } from "commander"; import JSON5 from "json5"; import { readBestEffortConfig, type OpenClawConfig } from "../config/config.js"; +import { formatErrorMessage } from "../infra/errors.js"; import { collectExecPolicyScopeSnapshots, type ExecPolicyScopeSnapshot, @@ -17,7 +18,6 @@ import { defaultRuntime } from "../runtime.js"; import { formatDocsLink } from "../terminal/links.js"; import { getTerminalTableWidth, renderTable } from "../terminal/table.js"; import { isRich, theme } from "../terminal/theme.js"; -import { describeUnknownError } from "./gateway-cli/shared.js"; import { callGatewayFromCli } from "./gateway-rpc.js"; import { nodesCallOpts, resolveNodeId } from "./nodes-cli/rpc.js"; import type { NodesRpcOpts } from "./nodes-cli/types.js"; @@ -157,7 +157,7 @@ async function saveSnapshotTargeted(params: { } function formatCliError(err: unknown): string { - const msg = describeUnknownError(err); + const msg = formatErrorMessage(err); return msg.includes("\n") ? msg.split("\n")[0] : msg; } diff --git a/src/cli/gateway-cli/run.ts b/src/cli/gateway-cli/run.ts index 6e3245003542..9f4826f41bde 100644 --- a/src/cli/gateway-cli/run.ts +++ b/src/cli/gateway-cli/run.ts @@ -36,7 +36,6 @@ import { withProgress } from "../progress.js"; import { ensureDevGatewayConfig } from "./dev.js"; import { runGatewayLoop } from "./run-loop.js"; import { - describeUnknownError, extractGatewayMiskeys, maybeExplainGatewayServiceStop, parsePort, @@ -559,7 +558,7 @@ async function runGatewayCommand(opts: GatewayRunOpts) { } } catch (err) { if (isGatewayLockError(err)) { - const errMessage = describeUnknownError(err); + const errMessage = formatErrorMessage(err); defaultRuntime.error( `Gateway failed to start: ${errMessage}\nIf the gateway is supervised, stop it with: ${formatCliCommand("openclaw gateway stop")}`, ); diff --git a/src/cli/gateway-cli/shared.ts b/src/cli/gateway-cli/shared.ts index a7cce082c28c..848279e9b639 100644 --- a/src/cli/gateway-cli/shared.ts +++ b/src/cli/gateway-cli/shared.ts @@ -4,7 +4,6 @@ import { resolveGatewayWindowsTaskName, } from "../../daemon/constants.js"; import { resolveGatewayService } from "../../daemon/service.js"; -import { formatErrorMessage } from "../../infra/errors.js"; import { defaultRuntime } from "../../runtime.js"; import { formatCliCommand } from "../command-format.js"; import { parsePort } from "../shared/parse-port.js"; @@ -21,10 +20,6 @@ export const toOptionString = (value: unknown): string | undefined => { return undefined; }; -export function describeUnknownError(err: unknown): string { - return formatErrorMessage(err); -} - export function extractGatewayMiskeys(parsed: unknown): { hasGatewayToken: boolean; hasRemoteToken: boolean; diff --git a/src/secrets/audit.ts b/src/secrets/audit.ts index 701a0cdd30e2..0c93c43187ab 100644 --- a/src/secrets/audit.ts +++ b/src/secrets/audit.ts @@ -9,6 +9,7 @@ import { normalizeProviderId } from "../agents/model-selection.js"; import { resolveStateDir, type OpenClawConfig } from "../config/config.js"; import { coerceSecretRef } from "../config/types.secrets.js"; import { resolveSecretInputRef, type SecretRef } from "../config/types.secrets.js"; +import { formatErrorMessage } from "../infra/errors.js"; import { resolveConfigDir, resolveUserPath } from "../utils.js"; import { runTasksWithConcurrency } from "../utils/run-with-concurrency.js"; import { iterateAuthProfileCredentials } from "./auth-profiles-scan.js"; @@ -27,7 +28,6 @@ import { isExpectedResolvedSecretValue, } from "./secret-value.js"; import { isNonEmptyString, isRecord } from "./shared.js"; -import { describeUnknownError } from "./shared.js"; import { listAgentModelsJsonPaths, listAuthProfileStorePaths, @@ -568,7 +568,7 @@ async function collectUnresolvedRefFindings(params: { severity: "error", file: assignment.file, jsonPath: assignment.path, - message: `Failed to resolve ${assignment.ref.source}:${assignment.ref.provider}:${assignment.ref.id} (${describeUnknownError(resolveErr)}).`, + message: `Failed to resolve ${assignment.ref.source}:${assignment.ref.provider}:${assignment.ref.id} (${formatErrorMessage(resolveErr)}).`, provider: assignment.provider, }); continue; diff --git a/src/secrets/resolve.ts b/src/secrets/resolve.ts index 103075b8cd96..49503618e7f8 100644 --- a/src/secrets/resolve.ts +++ b/src/secrets/resolve.ts @@ -9,6 +9,7 @@ import type { SecretRef, SecretRefSource, } from "../config/types.secrets.js"; +import { formatErrorMessage } from "../infra/errors.js"; import { inspectPathPermissions, safeStat } from "../security/audit-fs.js"; import { isPathInside } from "../security/scan-paths.js"; import { resolveUserPath } from "../utils.js"; @@ -21,12 +22,7 @@ import { resolveDefaultSecretProviderAlias, secretRefKey, } from "./ref-contract.js"; -import { - describeUnknownError, - isNonEmptyString, - isRecord, - normalizePositiveInt, -} from "./shared.js"; +import { isNonEmptyString, isRecord, normalizePositiveInt } from "./shared.js"; const DEFAULT_PROVIDER_CONCURRENCY = 4; const DEFAULT_MAX_REFS_PER_PROVIDER = 512; @@ -140,7 +136,7 @@ function throwUnknownProviderResolutionError(params: { throw providerResolutionError({ source: params.source, provider: params.provider, - message: describeUnknownError(params.err), + message: formatErrorMessage(params.err), cause: params.err, }); } @@ -419,7 +415,7 @@ async function resolveFileRefs(params: { source: "file", provider: params.providerName, refId: ref.id, - message: describeUnknownError(err), + message: formatErrorMessage(err), cause: err, }); } diff --git a/src/secrets/shared.ts b/src/secrets/shared.ts index 751cf6709923..98635ac25f9d 100644 --- a/src/secrets/shared.ts +++ b/src/secrets/shared.ts @@ -1,6 +1,5 @@ import fs from "node:fs"; import path from "node:path"; -import { formatErrorMessage } from "../infra/errors.js"; export { isRecord } from "../utils.js"; export function isNonEmptyString(value: unknown): value is string { @@ -60,7 +59,3 @@ export function writeTextFileAtomic(pathname: string, value: string, mode = 0o60 fs.chmodSync(tempPath, mode); fs.renameSync(tempPath, pathname); } - -export function describeUnknownError(err: unknown): string { - return formatErrorMessage(err); -}