import type { ChannelId } from "../channels/plugins/types.js"; import { CHANNEL_IDS, getChatChannelMeta, getRegisteredChannelPluginMeta, listRegisteredChannelPluginAliases, listRegisteredChannelPluginIds, listChatChannelAliases, normalizeChatChannelId, normalizeAnyChannelId, } from "../channels/registry.js"; import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES, type GatewayClientMode, type GatewayClientName, normalizeGatewayClientMode, normalizeGatewayClientName, } from "../gateway/protocol/client-info.js"; export const INTERNAL_MESSAGE_CHANNEL = "webchat" as const; export type InternalMessageChannel = typeof INTERNAL_MESSAGE_CHANNEL; export { GATEWAY_CLIENT_NAMES, GATEWAY_CLIENT_MODES }; export type { GatewayClientName, GatewayClientMode }; export { normalizeGatewayClientName, normalizeGatewayClientMode }; type GatewayClientInfoLike = { mode?: string | null; id?: string | null; }; export function isGatewayCliClient(client?: GatewayClientInfoLike | null): boolean { return normalizeGatewayClientMode(client?.mode) === GATEWAY_CLIENT_MODES.CLI; } export function isOperatorUiClient(client?: GatewayClientInfoLike | null): boolean { const clientId = normalizeGatewayClientName(client?.id); return clientId === GATEWAY_CLIENT_NAMES.CONTROL_UI || clientId === GATEWAY_CLIENT_NAMES.TUI; } export function isBrowserOperatorUiClient(client?: GatewayClientInfoLike | null): boolean { const clientId = normalizeGatewayClientName(client?.id); return clientId === GATEWAY_CLIENT_NAMES.CONTROL_UI; } export function isInternalMessageChannel(raw?: string | null): raw is InternalMessageChannel { return normalizeMessageChannel(raw) === INTERNAL_MESSAGE_CHANNEL; } export function isWebchatClient(client?: GatewayClientInfoLike | null): boolean { const mode = normalizeGatewayClientMode(client?.mode); if (mode === GATEWAY_CLIENT_MODES.WEBCHAT) { return true; } return normalizeGatewayClientName(client?.id) === GATEWAY_CLIENT_NAMES.WEBCHAT_UI; } export function normalizeMessageChannel(raw?: string | null): string | undefined { const normalized = raw?.trim().toLowerCase(); 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; } const listPluginChannelIds = (): string[] => { return listRegisteredChannelPluginIds(); }; const listPluginChannelAliases = (): string[] => { return listRegisteredChannelPluginAliases(); }; export const listDeliverableMessageChannels = (): ChannelId[] => Array.from(new Set([...CHANNEL_IDS, ...listPluginChannelIds()])); export type DeliverableMessageChannel = ChannelId; export type GatewayMessageChannel = DeliverableMessageChannel; export const listGatewayMessageChannels = (): GatewayMessageChannel[] => [ ...listDeliverableMessageChannels(), INTERNAL_MESSAGE_CHANNEL, ]; export const listGatewayAgentChannelAliases = (): string[] => Array.from(new Set([...listChatChannelAliases(), ...listPluginChannelAliases()])); export type GatewayAgentChannelHint = GatewayMessageChannel; export const listGatewayAgentChannelValues = (): string[] => Array.from( new Set([...listGatewayMessageChannels(), "last", ...listGatewayAgentChannelAliases()]), ); export function isGatewayMessageChannel(value: string): value is GatewayMessageChannel { return listGatewayMessageChannels().includes(value as GatewayMessageChannel); } export function isDeliverableMessageChannel(value: string): value is DeliverableMessageChannel { return listDeliverableMessageChannels().includes(value as DeliverableMessageChannel); } export function resolveGatewayMessageChannel( raw?: string | null, ): GatewayMessageChannel | undefined { const normalized = normalizeMessageChannel(raw); if (!normalized) { return undefined; } return isGatewayMessageChannel(normalized) ? normalized : undefined; } export function resolveMessageChannel( primary?: string | null, fallback?: string | null, ): string | undefined { return normalizeMessageChannel(primary) ?? normalizeMessageChannel(fallback); } export function isMarkdownCapableMessageChannel(raw?: string | null): boolean { const channel = normalizeMessageChannel(raw); if (!channel) { return false; } if (channel === INTERNAL_MESSAGE_CHANNEL || channel === "tui") { return true; } const builtInChannel = normalizeChatChannelId(channel); if (builtInChannel) { return getChatChannelMeta(builtInChannel).markdownCapable === true; } return getRegisteredChannelPluginMeta(channel)?.markdownCapable === true; }