refactor(cron): share diagnostic summary normalization (#113595)

This commit is contained in:
Vincent Koc
2026-07-25 17:41:47 +08:00
committed by GitHub
parent 87b424aca8
commit f0ce854be2
3 changed files with 22 additions and 17 deletions
+2 -2
View File
@@ -113,7 +113,7 @@ function normalizeDiagnosticMessage(
return { message: `${truncateUtf16Safe(redacted, MAX_ENTRY_CHARS - 1)}`, truncated: true };
}
function trimSummary(value: string | undefined): string | undefined {
export function normalizeCronRunDiagnosticSummary(value: string | undefined): string | undefined {
const normalized = normalizeOptionalString(value);
if (!normalized) {
return undefined;
@@ -167,7 +167,7 @@ export function normalizeCronRunDiagnostics(
entries.shift();
}
}
const summary = trimSummary(
const summary = normalizeCronRunDiagnosticSummary(
typeof record.summary === "string" ? redactText(record.summary) : undefined,
);
if (entries.length === 0 && !summary) {
+15
View File
@@ -90,6 +90,21 @@ describe("cron run diagnostics", () => {
expect(summarizeCronRunDiagnostics(undefined)).toBeUndefined();
});
it("bounds fallback summaries at valid UTF-16 boundaries", () => {
expect(
summarizeCronRunDiagnostics({
entries: [
{
ts: 1,
source: "exec",
severity: "error",
message: `${"s".repeat(1_998)}😀tail`,
},
],
}),
).toBe(`${"s".repeat(1_998)}`);
});
it("creates diagnostics from errors and prefers the latest error summary", () => {
const first = createCronRunDiagnosticsFromError("cron-preflight", "first failure", {
nowMs: () => 100,
+5 -15
View File
@@ -1,6 +1,5 @@
/** Builds bounded, redacted diagnostics for cron run logs and UI surfaces. */
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
import { truncateUtf16Safe } from "@openclaw/normalization-core/utf16-slice";
import { isToolAllowedByPolicyName } from "../agents/tool-policy-match.js";
import { normalizeToolName as normalizePolicyToolName } from "../agents/tool-policy.js";
import { getReplyPayloadMetadata } from "../auto-reply/reply-payload.js";
@@ -8,6 +7,7 @@ import { redactSensitiveText } from "../logging/redact.js";
import {
formatUnknownError,
isRecord,
normalizeCronRunDiagnosticSummary,
normalizeCronRunDiagnostics as normalizeCronRunDiagnosticsValue,
normalizeExitCode,
normalizeToolName,
@@ -20,7 +20,6 @@ import type {
CronRunDiagnosticSource,
} from "./types.js";
const MAX_SUMMARY_CHARS = 2_000;
const EXEC_DIAGNOSTIC_TAIL_CHARS = 2_000;
const WEB_SEARCH_TOOL_NAME = "web_search";
@@ -37,17 +36,6 @@ export function toolsAllowRequestsWebSearch(toolsAllow?: string[]): boolean {
);
}
function trimSummary(value: string | undefined): string | undefined {
const normalized = normalizeOptionalString(value);
if (!normalized) {
return undefined;
}
if (normalized.length <= MAX_SUMMARY_CHARS) {
return normalized;
}
return `${truncateUtf16Safe(normalized, MAX_SUMMARY_CHARS - 1)}`;
}
/** Returns the operator-facing summary for persisted cron diagnostics. */
export function summarizeCronRunDiagnostics(
diagnostics: CronRunDiagnostics | undefined,
@@ -55,7 +43,7 @@ export function summarizeCronRunDiagnostics(
if (!diagnostics) {
return undefined;
}
return trimSummary(diagnostics.summary ?? diagnostics.entries[0]?.message);
return normalizeCronRunDiagnosticSummary(diagnostics.summary ?? diagnostics.entries[0]?.message);
}
/** Normalizes untrusted cron diagnostic payloads into bounded, redacted entries. */
@@ -84,7 +72,9 @@ export function mergeCronRunDiagnostics(
normalized.entries.findLast((entry) => entry.severity === "error") ??
normalized.entries.findLast((entry) => entry.severity === "warn") ??
normalized.entries.findLast((entry) => entry.severity === "info");
const summary = trimSummary(normalized.summary ?? entryCandidate?.message);
const summary = normalizeCronRunDiagnosticSummary(
normalized.summary ?? entryCandidate?.message,
);
if (summary) {
const severity =
entryCandidate?.severity === "error" ? 2 : entryCandidate?.severity === "warn" ? 1 : 0;