mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-26 16:06:16 +00:00
refactor: dedupe qa and diff error formatting
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { constants as fsConstants } from "node:fs";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { chromium } from "playwright-core";
|
||||
import type { OpenClawConfig } from "../api.js";
|
||||
import type { DiffRenderOptions, DiffTheme } from "./types.js";
|
||||
@@ -255,7 +256,7 @@ export class PlaywrightDiffScreenshotter implements DiffScreenshotter {
|
||||
if (error instanceof Error && error.message === IMAGE_SIZE_LIMIT_ERROR) {
|
||||
throw error;
|
||||
}
|
||||
const reason = error instanceof Error ? error.message : String(error);
|
||||
const reason = formatErrorMessage(error);
|
||||
throw new Error(
|
||||
`Diff PNG/PDF rendering requires a Chromium-compatible browser. Set browser.executablePath or install Chrome/Chromium. ${reason}`,
|
||||
{ cause: error },
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import fs from "node:fs/promises";
|
||||
import { Static, Type } from "@sinclair/typebox";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import type { AnyAgentTool, OpenClawPluginApi, OpenClawPluginToolContext } from "../api.js";
|
||||
import { PlaywrightDiffScreenshotter, type DiffScreenshotter } from "./browser.js";
|
||||
import { resolveDiffImageRenderOptions } from "./config.js";
|
||||
@@ -295,19 +296,19 @@ export function createDiffsTool(params: {
|
||||
};
|
||||
} catch (error) {
|
||||
if (mode === "both") {
|
||||
const errorMessage = formatErrorMessage(error);
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text:
|
||||
`Diff viewer ready.\n${viewerUrl}\n` +
|
||||
`File rendering failed: ${error instanceof Error ? error.message : String(error)}`,
|
||||
`Diff viewer ready.\n${viewerUrl}\n` + `File rendering failed: ${errorMessage}`,
|
||||
},
|
||||
],
|
||||
details: {
|
||||
...baseDetails,
|
||||
fileError: error instanceof Error ? error.message : String(error),
|
||||
imageError: error instanceof Error ? error.message : String(error),
|
||||
fileError: errorMessage,
|
||||
imageError: errorMessage,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ function resolveGatewayInfoWithFallback(params: { runtime?: RuntimeEnv; error: u
|
||||
if (!isTransientGatewayMetadataError(params.error)) {
|
||||
throw params.error;
|
||||
}
|
||||
const message = params.error instanceof Error ? params.error.message : String(params.error);
|
||||
const message = formatErrorMessage(params.error);
|
||||
params.runtime?.log?.(
|
||||
`discord: gateway metadata lookup failed transiently; using default gateway url (${message})`,
|
||||
);
|
||||
|
||||
@@ -532,7 +532,7 @@ export class QmdMemoryManager implements MemorySearchManager {
|
||||
await this.removeCollection(conflictName);
|
||||
existing.delete(conflictName);
|
||||
} catch (removeErr) {
|
||||
const removeMessage = removeErr instanceof Error ? removeErr.message : String(removeErr);
|
||||
const removeMessage = formatErrorMessage(removeErr);
|
||||
if (!this.isCollectionMissingError(removeMessage)) {
|
||||
log.warn(`qmd collection remove failed for ${conflictName}: ${removeMessage}`);
|
||||
}
|
||||
@@ -547,7 +547,7 @@ export class QmdMemoryManager implements MemorySearchManager {
|
||||
});
|
||||
return true;
|
||||
} catch (retryErr) {
|
||||
const retryMessage = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
||||
const retryMessage = formatErrorMessage(retryErr);
|
||||
log.warn(
|
||||
`qmd collection add failed for ${collection.name} after rebinding ${conflictName}: ${retryMessage} (initial: ${addErrorMessage})`,
|
||||
);
|
||||
@@ -821,7 +821,7 @@ export class QmdMemoryManager implements MemorySearchManager {
|
||||
try {
|
||||
await this.removeCollection(collection.name);
|
||||
} catch (removeErr) {
|
||||
const removeMessage = removeErr instanceof Error ? removeErr.message : String(removeErr);
|
||||
const removeMessage = formatErrorMessage(removeErr);
|
||||
if (!this.isCollectionMissingError(removeMessage)) {
|
||||
log.warn(`qmd collection remove failed for ${collection.name}: ${removeMessage}`);
|
||||
}
|
||||
@@ -829,7 +829,7 @@ export class QmdMemoryManager implements MemorySearchManager {
|
||||
try {
|
||||
await this.addCollection(collection.path, collection.name, collection.pattern);
|
||||
} catch (addErr) {
|
||||
const addMessage = addErr instanceof Error ? addErr.message : String(addErr);
|
||||
const addMessage = formatErrorMessage(addErr);
|
||||
if (!this.isCollectionAlreadyExistsError(addMessage)) {
|
||||
log.warn(`qmd collection add failed for ${collection.name}: ${addMessage}`);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createServer, type IncomingMessage, type Server, type ServerResponse } from "node:http";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import type { QaBusState } from "./bus-state.js";
|
||||
import type {
|
||||
QaBusCreateThreadInput,
|
||||
@@ -33,7 +34,7 @@ export function writeJson(res: ServerResponse, statusCode: number, body: unknown
|
||||
|
||||
export function writeError(res: ServerResponse, statusCode: number, error: unknown) {
|
||||
writeJson(res, statusCode, {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: formatErrorMessage(error),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import net from "node:net";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { setTimeout as sleep } from "node:timers/promises";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { seedQaAgentWorkspace } from "./qa-agent-workspace.js";
|
||||
import { buildQaGatewayConfig } from "./qa-gateway-config.js";
|
||||
|
||||
@@ -242,7 +243,7 @@ export async function startQaGatewayChild(params: {
|
||||
JSON.stringify(rpcParams ?? {}),
|
||||
],
|
||||
}).catch((error) => {
|
||||
const details = error instanceof Error ? error.message : String(error);
|
||||
const details = formatErrorMessage(error);
|
||||
throw new Error(`${details}\nGateway logs:\n${logs()}`);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -11,6 +11,7 @@ import path from "node:path";
|
||||
import type { Duplex } from "node:stream";
|
||||
import tls from "node:tls";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { handleQaBusRequest, writeError, writeJson } from "./bus-server.js";
|
||||
import { createQaBusState, type QaBusState } from "./bus-state.js";
|
||||
import { createQaRunnerRuntime } from "./harness-runtime.js";
|
||||
@@ -670,7 +671,7 @@ export async function startQaLabServer(params?: {
|
||||
startedAt,
|
||||
finishedAt: new Date().toISOString(),
|
||||
artifacts: null,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: formatErrorMessage(error),
|
||||
};
|
||||
} finally {
|
||||
activeSuiteRun = null;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import type { QaBusState } from "./bus-state.js";
|
||||
|
||||
export type QaScenarioStepContext = {
|
||||
@@ -42,7 +43,7 @@ export async function runQaScenario(
|
||||
...(details ? { details } : {}),
|
||||
});
|
||||
} catch (error) {
|
||||
const details = error instanceof Error ? error.message : String(error);
|
||||
const details = formatErrorMessage(error);
|
||||
steps.push({
|
||||
name: step.name,
|
||||
status: "fail",
|
||||
|
||||
@@ -6,6 +6,7 @@ import { setTimeout as sleep } from "node:timers/promises";
|
||||
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
||||
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/core";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { buildAgentSessionKey } from "openclaw/plugin-sdk/routing";
|
||||
import type { QaBusState } from "./bus-state.js";
|
||||
import { extractQaToolPayload } from "./extract-tool-payload.js";
|
||||
@@ -179,7 +180,7 @@ async function runScenario(name: string, steps: QaSuiteStep[]): Promise<QaSuiteS
|
||||
...(details ? { details } : {}),
|
||||
});
|
||||
} catch (error) {
|
||||
const details = error instanceof Error ? error.message : String(error);
|
||||
const details = formatErrorMessage(error);
|
||||
if (process.env.OPENCLAW_QA_DEBUG === "1") {
|
||||
console.error(`[qa-suite] fail scenario="${name}" step="${step.name}" details=${details}`);
|
||||
}
|
||||
@@ -271,7 +272,7 @@ async function waitForConfigRestartSettle(
|
||||
}
|
||||
|
||||
function isGatewayRestartRace(error: unknown) {
|
||||
const text = error instanceof Error ? error.message : String(error);
|
||||
const text = formatErrorMessage(error);
|
||||
return (
|
||||
text.includes("gateway closed (1012)") ||
|
||||
text.includes("gateway closed (1006") ||
|
||||
@@ -1484,7 +1485,7 @@ When the user asks for the hot install marker exactly, reply with exactly: HOT-I
|
||||
250,
|
||||
).catch((error) => {
|
||||
throw new Error(
|
||||
`image provider was never invoked: ${error instanceof Error ? error.message : String(error)}; toolOutput=${String(imageRequest.toolOutput ?? "")}`,
|
||||
`image provider was never invoked: ${formatErrorMessage(error)}; toolOutput=${String(imageRequest.toolOutput ?? "")}`,
|
||||
);
|
||||
});
|
||||
return `${outbound.text}\nIMAGE_PROMPT:${generated.prompt ?? ""}`;
|
||||
@@ -1568,7 +1569,7 @@ When the user asks for the hot disable marker exactly, reply with exactly: HOT-P
|
||||
200,
|
||||
).catch((error) => {
|
||||
throw new Error(
|
||||
`hot-disable skill never became eligible: ${error instanceof Error ? error.message : String(error)}`,
|
||||
`hot-disable skill never became eligible: ${formatErrorMessage(error)}`,
|
||||
);
|
||||
});
|
||||
const beforeSkills = await readSkillStatus(env);
|
||||
@@ -1595,9 +1596,9 @@ When the user asks for the hot disable marker exactly, reply with exactly: HOT-P
|
||||
};
|
||||
await waitForQaChannelReady(env, 60_000).catch((error) => {
|
||||
throw new Error(
|
||||
`qa-channel never returned ready after config.patch: ${
|
||||
error instanceof Error ? error.message : String(error)
|
||||
}`,
|
||||
`qa-channel never returned ready after config.patch: ${formatErrorMessage(
|
||||
error,
|
||||
)}`,
|
||||
);
|
||||
});
|
||||
await waitForCondition(
|
||||
@@ -1609,9 +1610,7 @@ When the user asks for the hot disable marker exactly, reply with exactly: HOT-P
|
||||
200,
|
||||
).catch((error) => {
|
||||
throw new Error(
|
||||
`hot-disable skill never flipped to disabled: ${
|
||||
error instanceof Error ? error.message : String(error)
|
||||
}`,
|
||||
`hot-disable skill never flipped to disabled: ${formatErrorMessage(error)}`,
|
||||
);
|
||||
});
|
||||
const afterSkills = await readSkillStatus(env);
|
||||
@@ -1667,16 +1666,14 @@ When the user asks for the hot disable marker exactly, reply with exactly: HOT-P
|
||||
});
|
||||
await waitForGatewayHealthy(env, 60_000).catch((error) => {
|
||||
throw new Error(
|
||||
`gateway never returned healthy after config.apply: ${
|
||||
error instanceof Error ? error.message : String(error)
|
||||
}`,
|
||||
`gateway never returned healthy after config.apply: ${formatErrorMessage(error)}`,
|
||||
);
|
||||
});
|
||||
await waitForQaChannelReady(env, 60_000).catch((error) => {
|
||||
throw new Error(
|
||||
`qa-channel never returned ready after config.apply: ${
|
||||
error instanceof Error ? error.message : String(error)
|
||||
}`,
|
||||
`qa-channel never returned ready after config.apply: ${formatErrorMessage(
|
||||
error,
|
||||
)}`,
|
||||
);
|
||||
});
|
||||
const outbound = await waitForOutboundMessage(
|
||||
@@ -1685,9 +1682,9 @@ When the user asks for the hot disable marker exactly, reply with exactly: HOT-P
|
||||
60_000,
|
||||
).catch((error) => {
|
||||
throw new Error(
|
||||
`restart sentinel never appeared: ${
|
||||
error instanceof Error ? error.message : String(error)
|
||||
}; outbound=${recentOutboundSummary(state)}`,
|
||||
`restart sentinel never appeared: ${formatErrorMessage(
|
||||
error,
|
||||
)}; outbound=${recentOutboundSummary(state)}`,
|
||||
);
|
||||
});
|
||||
return `${outbound.conversation.id}: ${outbound.text}`;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
|
||||
/** Structured reminder payload emitted by the model. */
|
||||
export interface CronReminderPayload {
|
||||
type: "cron_reminder";
|
||||
@@ -83,7 +85,7 @@ export function parseQQBotPayload(text: string): ParseResult {
|
||||
} catch (e) {
|
||||
return {
|
||||
isPayload: true,
|
||||
error: `Failed to parse JSON: ${e instanceof Error ? e.message : String(e)}`,
|
||||
error: `Failed to parse JSON: ${formatErrorMessage(e)}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -143,7 +145,7 @@ export function decodeCronPayload(message: string): {
|
||||
} catch (e) {
|
||||
return {
|
||||
isCronPayload: true,
|
||||
error: `Failed to decode cron payload: ${e instanceof Error ? e.message : String(e)}`,
|
||||
error: `Failed to decode cron payload: ${formatErrorMessage(e)}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user