UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

162 lines (161 loc) • 7.96 kB
import { r as normalizeOptionalAccountId } from "./account-id-CW6dlabA.mjs"; import { r as isInternalNonDeliveryChannel } from "./message-channel-constants-Dq-VU_KZ.mjs"; import { n as normalizeMessageChannel, t as isNormalizedMessageChannel } from "./message-channel-core-JDeu-bNU.mjs"; import { l as normalizeChannelRouteRef, o as channelRouteThreadId, r as channelRouteTarget, t as channelRouteCompactKey, u as normalizeChannelRouteTarget } from "./channel-route-BIXHeyAA.mjs"; //#region src/utils/delivery-context.shared.ts /** * Delivery-context normalization and projection helpers. * * Persisted sessions expose one closed delivery state. Compatibility * projections are derived from that state at public boundaries. */ /** Normalizes a delivery context into canonical channel route fields, dropping invalid routes. */ function normalizeDeliveryContext(context) { if (!context) return; const route = normalizeChannelRouteTarget({ channel: typeof context.channel === "string" ? normalizeMessageChannel(context.channel) ?? context.channel.trim() : void 0, to: context.to, accountId: context.accountId, threadId: context.threadId }); if (!route) return; const normalized = { channel: route.channel, to: channelRouteTarget(route), accountId: normalizeOptionalAccountId(route.accountId) }; const threadId = channelRouteThreadId(route); if (threadId != null) normalized.threadId = threadId; return normalized; } /** Checks raw channel/to presence only; does not normalize or validate deliverability. */ function hasDeliveryTargetFields(context) { return Boolean(context?.channel && context?.to); } /** Normalizes an unknown channel route payload from persisted session/plugin metadata. */ function normalizeDeliveryChannelRoute(route) { if (!route || typeof route !== "object" || Array.isArray(route)) return; const candidate = route; return normalizeChannelRouteRef({ channel: candidate.channel, to: candidate.target?.to, rawTo: candidate.target?.rawTo, chatType: candidate.target?.chatType, accountId: candidate.accountId, threadId: candidate.thread?.id, threadKind: candidate.thread?.kind, threadSource: candidate.thread?.source }); } /** Converts a normalized channel route reference into a delivery context. */ function deliveryContextFromChannelRoute(route) { const normalized = normalizeDeliveryChannelRoute(route); return normalizeDeliveryContext({ channel: normalized?.channel, to: channelRouteTarget(normalized), accountId: normalized?.accountId, threadId: channelRouteThreadId(normalized) }); } function mergeRouteMetadataWithDeliveryContext(route, context) { if (!route) return normalizeChannelRouteTarget(normalizeDeliveryContext(context)); return normalizeChannelRouteRef({ channel: route.channel ?? context.channel, to: route.target?.to ?? context.to, rawTo: route.target?.rawTo, chatType: route.target?.chatType, accountId: route.accountId ?? context.accountId, threadId: route.thread?.id ?? context.threadId, threadKind: route.thread?.kind, threadSource: route.thread?.source }); } function isInternalRouteContext(context) { const channel = context?.channel; return Boolean(channel && (channel === "webchat" || isInternalNonDeliveryChannel(channel))); } function hasExternalDeliveryTarget(context) { const channel = context?.channel; return Boolean(channel && isNormalizedMessageChannel(channel) && !isInternalNonDeliveryChannel(channel) && context?.to); } function mergeExternalDeliveryContextOverInternalRoute(deliveryContext, internalContext) { return normalizeDeliveryContext({ channel: deliveryContext?.channel, to: deliveryContext?.to, accountId: deliveryContext?.accountId ?? internalContext?.accountId, threadId: deliveryContext?.threadId ?? internalContext?.threadId }); } function isCanonicalSessionDeliveryState(value) { if (!value || typeof value !== "object" || Array.isArray(value)) return false; const candidate = value; if (candidate.kind === "none" || candidate.kind === "internal") return true; return candidate.kind === "external" && Boolean(candidate.route && typeof candidate.route === "object") && Boolean(candidate.context && typeof candidate.context === "object") && Boolean(candidate.origin && typeof candidate.origin === "object"); } /** Builds one canonical delivery state from current turn routing facts. */ function normalizeSessionDeliveryState(params) { if (!params) return { kind: "none" }; const normalizedRoute = normalizeDeliveryChannelRoute(params.route); const routeContext = deliveryContextFromChannelRoute(normalizedRoute); const originContext = normalizeDeliveryContext({ channel: params.origin?.provider, to: params.origin?.to, accountId: params.origin?.accountId, threadId: params.origin?.threadId }); const context = normalizeDeliveryContext(params.context); const fallbackContext = mergeDeliveryContext(context, originContext); const routeIsInternalFallback = isInternalRouteContext(routeContext) && hasExternalDeliveryTarget(context); const merged = routeIsInternalFallback ? mergeExternalDeliveryContextOverInternalRoute(context, mergeDeliveryContext(routeContext, originContext)) : mergeDeliveryContext(routeContext, fallbackContext); if (!merged) return { kind: "none" }; if (isInternalRouteContext(merged)) return { kind: "internal" }; const route = mergeRouteMetadataWithDeliveryContext(routeIsInternalFallback ? void 0 : normalizedRoute, merged); if (!route) return { kind: "none" }; const origin = { ...params.origin }; origin.provider ??= merged.channel; origin.to ??= merged.to; origin.accountId ??= merged.accountId; origin.threadId ??= merged.threadId; origin.chatType ??= route.target?.chatType; return { kind: "external", route, context: merged, origin }; } /** Projects compatibility fields without persisting duplicate delivery state. */ function projectSessionDeliveryFields(delivery) { if (delivery?.kind !== "external") return {}; return { route: delivery.route, deliveryContext: delivery.context, origin: delivery.origin, channel: delivery.context.channel ?? delivery.origin.provider, lastChannel: delivery.context.channel, lastTo: delivery.context.to, lastAccountId: delivery.context.accountId, lastThreadId: delivery.context.threadId }; } /** Merges delivery contexts without mixing target/account/thread fields across route owners. */ function mergeDeliveryContext(primary, fallback) { const normalizedPrimary = normalizeDeliveryContext(primary); const normalizedFallback = normalizeDeliveryContext(fallback); if (!normalizedPrimary && !normalizedFallback) return; const channelsConflict = normalizedPrimary?.channel && normalizedFallback?.channel && normalizedPrimary.channel !== normalizedFallback.channel; const accountsConflict = normalizedPrimary?.accountId && normalizedFallback?.accountId && normalizedPrimary.accountId !== normalizedFallback.accountId; const routesConflict = channelsConflict || accountsConflict; return normalizeDeliveryContext({ channel: accountsConflict ? normalizedPrimary?.channel : normalizedPrimary?.channel ?? normalizedFallback?.channel, to: routesConflict ? normalizedPrimary?.to : normalizedPrimary?.to ?? normalizedFallback?.to, accountId: routesConflict ? normalizedPrimary?.accountId : normalizedPrimary?.accountId ?? normalizedFallback?.accountId, threadId: routesConflict ? normalizedPrimary?.threadId : normalizedPrimary?.threadId ?? normalizedFallback?.threadId }); } /** Builds a compact stable key for a routable delivery context. */ function deliveryContextKey(context) { return channelRouteCompactKey(normalizeDeliveryContext(context)); } //#endregion export { mergeDeliveryContext as a, normalizeSessionDeliveryState as c, isCanonicalSessionDeliveryState as i, projectSessionDeliveryFields as l, deliveryContextKey as n, normalizeDeliveryChannelRoute as o, hasDeliveryTargetFields as r, normalizeDeliveryContext as s, deliveryContextFromChannelRoute as t };