refactor(outbound): share thread id normalization

This commit is contained in:
Peter Steinberger
2026-03-17 03:56:17 +00:00
parent 233ef31190
commit 6a27db0cd7
6 changed files with 38 additions and 57 deletions

View File

@@ -26,6 +26,7 @@ import {
type OpenClawConfig,
} from "openclaw/plugin-sdk/discord";
import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js";
import { normalizeOutboundThreadId } from "../../../src/infra/outbound/thread-id.js";
import { normalizeMessageChannel } from "../../../src/utils/message-channel.js";
import {
listDiscordAccountIds,
@@ -196,20 +197,6 @@ function parseDiscordExplicitTarget(raw: string) {
}
}
function normalizeOutboundThreadId(value?: string | number | null): string | undefined {
if (value == null) {
return undefined;
}
if (typeof value === "number") {
if (!Number.isFinite(value)) {
return undefined;
}
return String(Math.trunc(value));
}
const trimmed = value.trim();
return trimmed ? trimmed : undefined;
}
function buildDiscordBaseSessionKey(params: {
cfg: OpenClawConfig;
agentId: string;

View File

@@ -25,6 +25,7 @@ import {
type OpenClawConfig,
} from "openclaw/plugin-sdk/slack";
import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js";
import { normalizeOutboundThreadId } from "../../../src/infra/outbound/thread-id.js";
import { buildPassiveProbedChannelStatusSummary } from "../../shared/channel-status-summary.js";
import {
listEnabledSlackAccounts,
@@ -136,20 +137,6 @@ function parseSlackExplicitTarget(raw: string) {
};
}
function normalizeOutboundThreadId(value?: string | number | null): string | undefined {
if (value == null) {
return undefined;
}
if (typeof value === "number") {
if (!Number.isFinite(value)) {
return undefined;
}
return String(Math.trunc(value));
}
const trimmed = value.trim();
return trimmed ? trimmed : undefined;
}
function buildSlackBaseSessionKey(params: {
cfg: OpenClawConfig;
agentId: string;

View File

@@ -31,6 +31,7 @@ import {
type OutboundSendDeps,
resolveOutboundSendDep,
} from "../../../src/infra/outbound/send-deps.js";
import { normalizeOutboundThreadId } from "../../../src/infra/outbound/thread-id.js";
import { normalizeMessageChannel } from "../../../src/utils/message-channel.js";
import { inspectTelegramAccount } from "./account-inspect.js";
import {
@@ -185,20 +186,6 @@ function parseTelegramExplicitTarget(raw: string) {
};
}
function normalizeOutboundThreadId(value?: string | number | null): string | undefined {
if (value == null) {
return undefined;
}
if (typeof value === "number") {
if (!Number.isFinite(value)) {
return undefined;
}
return String(Math.trunc(value));
}
const trimmed = value.trim();
return trimmed ? trimmed : undefined;
}
function buildTelegramBaseSessionKey(params: {
cfg: OpenClawConfig;
agentId: string;

View File

@@ -8,6 +8,7 @@ import { buildAgentSessionKey, type RoutePeer } from "../../routing/resolve-rout
import { resolveThreadSessionKeys } from "../../routing/session-key.js";
import { isWhatsAppGroupJid, normalizeWhatsAppTarget } from "../../whatsapp/normalize.js";
import type { ResolvedMessagingTarget } from "./target-resolver.js";
import { normalizeOutboundThreadId } from "./thread-id.js";
export type OutboundSessionRoute = {
sessionKey: string;
@@ -30,20 +31,6 @@ export type ResolveOutboundSessionRouteParams = {
threadId?: string | number | null;
};
function normalizeThreadId(value?: string | number | null): string | undefined {
if (value == null) {
return undefined;
}
if (typeof value === "number") {
if (!Number.isFinite(value)) {
return undefined;
}
return String(Math.trunc(value));
}
const trimmed = value.trim();
return trimmed ? trimmed : undefined;
}
function stripProviderPrefix(raw: string, channel: string): string {
const trimmed = raw.trim();
const lower = trimmed.toLowerCase();
@@ -240,7 +227,7 @@ function resolveMattermostSession(
channel: "mattermost",
peer: { kind: isUser ? "direct" : "channel", id: rawId },
});
const threadId = normalizeThreadId(params.replyToId ?? params.threadId);
const threadId = normalizeOutboundThreadId(params.replyToId ?? params.threadId);
const threadKeys = resolveThreadSessionKeys({
baseSessionKey,
threadId,

View File

@@ -0,0 +1,20 @@
import { describe, expect, it } from "vitest";
import { normalizeOutboundThreadId } from "./thread-id.js";
describe("normalizeOutboundThreadId", () => {
it("returns undefined for missing values", () => {
expect(normalizeOutboundThreadId()).toBeUndefined();
expect(normalizeOutboundThreadId(null)).toBeUndefined();
expect(normalizeOutboundThreadId(" ")).toBeUndefined();
});
it("normalizes numbers and trims strings", () => {
expect(normalizeOutboundThreadId(123.9)).toBe("123");
expect(normalizeOutboundThreadId(" 456 ")).toBe("456");
});
it("drops non-finite numeric values", () => {
expect(normalizeOutboundThreadId(Number.NaN)).toBeUndefined();
expect(normalizeOutboundThreadId(Number.POSITIVE_INFINITY)).toBeUndefined();
});
});

View File

@@ -0,0 +1,13 @@
export function normalizeOutboundThreadId(value?: string | number | null): string | undefined {
if (value == null) {
return undefined;
}
if (typeof value === "number") {
if (!Number.isFinite(value)) {
return undefined;
}
return String(Math.trunc(value));
}
const trimmed = value.trim();
return trimmed ? trimmed : undefined;
}