mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(cron): preserve canonical failure alert routes (#116933)
This commit is contained in:
committed by
GitHub
parent
00194139ba
commit
2433fa213c
@@ -9,25 +9,64 @@ import { resolveFailureAlert } from "./failure-alerts.js";
|
||||
import { createCronServiceState, type DeferredCronNotifications } from "./state.js";
|
||||
import { applyJobResult } from "./timer.js";
|
||||
|
||||
function stripTestTargetPrefix(raw: string, prefixes: readonly string[]): string | undefined {
|
||||
const target = raw
|
||||
.trim()
|
||||
.replace(new RegExp(`^(?:${prefixes.join("|")}):`, "i"), "")
|
||||
.trim();
|
||||
return target || undefined;
|
||||
}
|
||||
|
||||
function normalizeDiscordTestTarget(raw: string): string | undefined {
|
||||
const target = raw.trim().toLowerCase();
|
||||
if (!target) {
|
||||
return undefined;
|
||||
}
|
||||
if (target.startsWith("discord:channel:")) {
|
||||
return target.slice("discord:".length);
|
||||
}
|
||||
if (target.startsWith("discord:")) {
|
||||
return `user:${target.slice("discord:".length)}`;
|
||||
}
|
||||
return /^(channel|user):/.test(target) ? target : `channel:${target}`;
|
||||
}
|
||||
|
||||
describe("cron failure alert account routing", () => {
|
||||
beforeEach(() => {
|
||||
const pluginSpecs = [
|
||||
{
|
||||
id: "telegram",
|
||||
aliases: [],
|
||||
targetPrefixes: ["telegram", "tg"],
|
||||
normalizeTarget: (raw: string) => {
|
||||
const target = stripTestTargetPrefix(raw, ["telegram", "tg"]);
|
||||
return target ? `telegram:${target}` : undefined;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "googlechat",
|
||||
aliases: ["gchat", "google-chat"],
|
||||
targetPrefixes: ["googlechat", "google-chat", "gchat"],
|
||||
normalizeTarget: (raw: string) =>
|
||||
stripTestTargetPrefix(raw, ["googlechat", "google-chat", "gchat"]),
|
||||
},
|
||||
{
|
||||
id: "discord",
|
||||
aliases: [],
|
||||
targetPrefixes: ["discord"],
|
||||
normalizeTarget: normalizeDiscordTestTarget,
|
||||
},
|
||||
];
|
||||
setActivePluginRegistry(
|
||||
createTestRegistry(
|
||||
[
|
||||
{ id: "telegram", aliases: [], targetPrefixes: ["telegram", "tg"] },
|
||||
{
|
||||
id: "googlechat",
|
||||
aliases: ["gchat", "google-chat"],
|
||||
targetPrefixes: ["googlechat", "google-chat", "gchat"],
|
||||
},
|
||||
].map(({ id, aliases, targetPrefixes }) => {
|
||||
pluginSpecs.map(({ id, aliases, targetPrefixes, normalizeTarget }) => {
|
||||
const plugin = createChannelTestPluginBase({ id });
|
||||
return {
|
||||
pluginId: id,
|
||||
plugin: {
|
||||
...plugin,
|
||||
meta: { ...plugin.meta, aliases },
|
||||
messaging: { targetPrefixes },
|
||||
messaging: { targetPrefixes, normalizeTarget },
|
||||
},
|
||||
source: `test:${id}`,
|
||||
};
|
||||
@@ -199,6 +238,19 @@ describe("cron failure alert account routing", () => {
|
||||
jobAlert: undefined,
|
||||
expected: { channel: "slack", to: undefined, accountId: undefined },
|
||||
},
|
||||
{
|
||||
name: "does not equate Discord user and channel targets with the same id",
|
||||
globalAlert: { enabled: true, after: 1 },
|
||||
deliveryChannel: "discord",
|
||||
deliveryTo: "1234567890",
|
||||
jobAlert: { channel: "discord", to: "discord:1234567890" },
|
||||
expected: {
|
||||
channel: "discord",
|
||||
to: "discord:1234567890",
|
||||
accountId: undefined,
|
||||
threadId: undefined,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "does not inherit the primary account for a webhook",
|
||||
globalAlert: {
|
||||
@@ -309,6 +361,13 @@ describe("cron failure alert account routing", () => {
|
||||
failureAlert: { channel: "googlechat", to: "googlechat:RoomA" },
|
||||
expectedChannel: "googlechat",
|
||||
},
|
||||
{
|
||||
name: "plugin-normalized equivalent",
|
||||
deliveryChannel: "discord",
|
||||
deliveryTo: "1234567890",
|
||||
failureAlert: { channel: "discord", to: "discord:channel:1234567890" },
|
||||
expectedChannel: "discord",
|
||||
},
|
||||
])("keeps the primary account and topic on $name failure alerts", (testCase) => {
|
||||
const { failureAlert } = testCase;
|
||||
const sendCronFailureAlert = vi.fn(async () => undefined);
|
||||
|
||||
@@ -3,10 +3,8 @@ import { normalizeOptionalLowercaseString } from "@openclaw/normalization-core/s
|
||||
import { truncateUtf16Safe } from "@openclaw/normalization-core/utf16-slice";
|
||||
import type { FailoverReason } from "../../agents/embedded-agent-helpers/types.js";
|
||||
import { normalizeAnyChannelId } from "../../channels/registry-normalize.js";
|
||||
import {
|
||||
resolveTargetPrefixedChannel,
|
||||
stripTargetProviderPrefix,
|
||||
} from "../../infra/outbound/channel-target-prefix.js";
|
||||
import { resolveTargetPrefixedChannel } from "../../infra/outbound/channel-target-prefix.js";
|
||||
import { normalizeTargetForProvider } from "../../infra/outbound/target-normalization.js";
|
||||
import type { CronFailureNotificationDelivery, CronJob, CronMessageChannel } from "../types.js";
|
||||
import type { CronServiceState, DeferredCronNotifications } from "./state.js";
|
||||
|
||||
@@ -53,11 +51,12 @@ function resolveFailureAlertChannel(channel: unknown, to?: string): CronMessageC
|
||||
}
|
||||
|
||||
function normalizeFailureAlertRecipient(channel: CronMessageChannel, to: string): string {
|
||||
if (resolveTargetPrefixedChannel(to) !== channel) {
|
||||
try {
|
||||
return normalizeTargetForProvider(channel, to) ?? to;
|
||||
} catch {
|
||||
// Invalid loaded targets are distinct routes; they must not block run finalization.
|
||||
return to;
|
||||
}
|
||||
// Canonicalize loaded-provider aliases only; recipient/topic ids can be case-sensitive.
|
||||
return stripTargetProviderPrefix(to, to.slice(0, to.indexOf(":")));
|
||||
}
|
||||
|
||||
function normalizeTo(input: unknown): string | undefined {
|
||||
|
||||
Reference in New Issue
Block a user