perf(channels): split hot-path message channel normalization

This commit is contained in:
Vincent Koc
2026-04-13 18:21:59 +01:00
parent 527895f036
commit b6abd68a29
5 changed files with 79 additions and 25 deletions

View File

@@ -0,0 +1,35 @@
import type { ActivePluginChannelRegistration } from "../plugins/channel-registry-state.types.js";
import { getActivePluginChannelRegistryFromState } from "../plugins/runtime-channel-state.js";
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
import { normalizeChatChannelId, type ChatChannelId } from "./ids.js";
import type { ChannelId } from "./plugins/channel-id.types.js";
function listRegisteredChannelPluginEntries(): ActivePluginChannelRegistration[] {
const channelRegistry = getActivePluginChannelRegistryFromState();
if (channelRegistry?.channels && channelRegistry.channels.length > 0) {
return channelRegistry.channels;
}
return [];
}
export function normalizeChannelId(raw?: string | null): ChatChannelId | null {
return normalizeChatChannelId(raw);
}
export function normalizeAnyChannelId(raw?: string | null): ChannelId | null {
const key = normalizeOptionalLowercaseString(raw);
if (!key) {
return null;
}
return (
listRegisteredChannelPluginEntries().find((entry) => {
const id = normalizeOptionalLowercaseString(entry.plugin.id ?? "") ?? "";
if (id && id === key) {
return true;
}
return (entry.plugin.meta?.aliases ?? []).some(
(alias) => normalizeOptionalLowercaseString(alias) === key,
);
})?.plugin.id ?? null
);
}

View File

@@ -6,13 +6,13 @@ import {
import type { ChannelOutboundTargetMode } from "../../channels/plugins/types.public.js";
import type { SessionEntry } from "../../config/sessions.js";
import { deliveryContextFromSession } from "../../utils/delivery-context.shared.js";
import type {
DeliverableMessageChannel,
GatewayMessageChannel,
} from "../../utils/message-channel-normalize.js";
import {
isDeliverableMessageChannel,
normalizeMessageChannel,
} from "../../utils/message-channel-core.js";
import type {
DeliverableMessageChannel,
GatewayMessageChannel,
} from "../../utils/message-channel-normalize.js";
export type SessionDeliveryTarget = {

View File

@@ -1,7 +1,7 @@
import { normalizeOptionalString } from "../shared/string-coerce.js";
import { normalizeAccountId } from "./account-id.js";
import type { DeliveryContext, DeliveryContextSessionSource } from "./delivery-context.types.js";
import { normalizeMessageChannel } from "./message-channel-normalize.js";
import { normalizeMessageChannel } from "./message-channel-core.js";
export type { DeliveryContext, DeliveryContextSessionSource } from "./delivery-context.types.js";
export function normalizeDeliveryContext(context?: DeliveryContext): DeliveryContext | undefined {

View File

@@ -0,0 +1,33 @@
import { normalizeChatChannelId } from "../channels/ids.js";
import { normalizeAnyChannelId } from "../channels/registry-normalize.js";
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
import { INTERNAL_MESSAGE_CHANNEL } from "./message-channel-constants.js";
export function normalizeMessageChannel(raw?: string | null): string | undefined {
const normalized = normalizeOptionalLowercaseString(raw);
if (!normalized) {
return undefined;
}
if (normalized === INTERNAL_MESSAGE_CHANNEL) {
return INTERNAL_MESSAGE_CHANNEL;
}
const builtIn = normalizeChatChannelId(normalized);
if (builtIn) {
return builtIn;
}
return normalizeAnyChannelId(normalized) ?? normalized;
}
export function isDeliverableMessageChannel(value: string): boolean {
const normalized = normalizeMessageChannel(value);
return (
normalized !== undefined && normalized !== INTERNAL_MESSAGE_CHANNEL && normalized === value
);
}
export function resolveMessageChannel(
primary?: string | null,
fallback?: string | null,
): string | undefined {
return normalizeMessageChannel(primary) ?? normalizeMessageChannel(fallback);
}

View File

@@ -1,16 +1,13 @@
import { CHANNEL_IDS, listChatChannelAliases } from "../channels/ids.js";
import {
CHANNEL_IDS,
listChatChannelAliases,
listRegisteredChannelPluginAliases,
listRegisteredChannelPluginIds,
normalizeAnyChannelId,
normalizeChatChannelId,
} from "../channels/registry.js";
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
import {
INTERNAL_MESSAGE_CHANNEL,
type InternalMessageChannel,
} from "./message-channel-constants.js";
import { normalizeMessageChannel as normalizeMessageChannelCore } from "./message-channel-core.js";
type ChannelId = string & { readonly __openclawChannelIdBrand?: never };
@@ -20,6 +17,10 @@ export type GatewayMessageChannel = DeliverableMessageChannel;
export type GatewayAgentChannelHint = GatewayMessageChannel;
export function normalizeMessageChannel(raw?: string | null): string | undefined {
return normalizeMessageChannelCore(raw);
}
const listPluginChannelIds = (): string[] => {
return listRegisteredChannelPluginIds();
};
@@ -28,21 +29,6 @@ const listPluginChannelAliases = (): string[] => {
return listRegisteredChannelPluginAliases();
};
export function normalizeMessageChannel(raw?: string | null): string | undefined {
const normalized = normalizeOptionalLowercaseString(raw);
if (!normalized) {
return undefined;
}
if (normalized === INTERNAL_MESSAGE_CHANNEL) {
return INTERNAL_MESSAGE_CHANNEL;
}
const builtIn = normalizeChatChannelId(normalized);
if (builtIn) {
return builtIn;
}
return normalizeAnyChannelId(normalized) ?? normalized;
}
export const listDeliverableMessageChannels = (): ChannelId[] =>
Array.from(new Set([...CHANNEL_IDS, ...listPluginChannelIds()]));