openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
156 lines (155 loc) • 7.26 kB
JavaScript
import { c as normalizeOptionalLowercaseString, o as normalizeLowercaseStringOrEmpty } from "./string-coerce-1VuiLaaR.mjs";
import { a as asOptionalRecord, c as isRecord } from "./record-coerce-TIsquoVR.mjs";
import { n as normalizeAgentId } from "./agent-id-D1-Q6vR4.mjs";
import { n as buildAgentMainSessionKey } from "./session-key-CmZ4o9-l.mjs";
import { M as parseAgentSessionKey, O as parseThreadSessionSuffix, h as scopedHeartbeatWakeOptions, u as resolveEventSessionKey } from "./session-key-C09ow4h0.mjs";
import { t as deriveSessionChatTypeFromKey } from "./session-chat-type-shared-BzwKnB1m.mjs";
import { r as resolveChannelAccountEntry } from "./account-lookup-D_rRUHd5.mjs";
import { i as resolvePinnedMainDmOwnerFromAllowlist } from "./dm-policy-shared-BRGB1_No.mjs";
import { o as resolveAgentRoute } from "./resolve-route-DYoHvZlS.mjs";
//#region src/infra/event-session-routing.ts
function readAllowFrom(value) {
const allowFrom = asOptionalRecord(value)?.allowFrom;
return Array.isArray(allowFrom) ? allowFrom : void 0;
}
function readDmAllowFrom(value) {
return readAllowFrom(asOptionalRecord(value)?.dm);
}
/** Parse an agent direct-session key into channel/account/peer routing parts. */
function parseDirectAgentSessionTarget(sessionKey) {
const { baseSessionKey } = parseThreadSessionSuffix(sessionKey);
const directSessionKey = baseSessionKey ?? sessionKey;
const parsed = parseAgentSessionKey(directSessionKey);
if (!parsed || deriveSessionChatTypeFromKey(directSessionKey) !== "direct") return null;
const parts = parsed.rest.split(":");
const directIndex = parts.findIndex((part) => part === "direct" || part === "dm");
if (directIndex < 0 || directIndex > 2 || directIndex >= parts.length - 1) return null;
const peerId = normalizeLowercaseStringOrEmpty(parts.slice(directIndex + 1).join(":"));
if (!peerId) return null;
return {
agentId: parsed.agentId,
...directIndex >= 1 ? { channel: normalizeLowercaseStringOrEmpty(parts[0]) } : {},
...directIndex >= 2 ? { accountId: normalizeLowercaseStringOrEmpty(parts[1]) } : {},
peerId
};
}
/** Resolve the configured DM allowlist that applies to an event session. */
function resolveEventSessionAllowFrom(params) {
const cfg = params.cfg;
if (!cfg?.channels) return;
const channelKey = normalizeLowercaseStringOrEmpty(params.channel ?? params.target?.channel);
if (!channelKey) return;
const channelConfig = isRecord(cfg.channels) ? cfg.channels[channelKey] : void 0;
if (!isRecord(channelConfig)) return;
const accountId = normalizeLowercaseStringOrEmpty(params.accountId ?? params.target?.accountId);
const accountConfig = accountId && isRecord(channelConfig.accounts) ? resolveChannelAccountEntry(channelConfig.accounts, accountId, channelKey, (id) => id) : void 0;
const accountNestedConfig = asOptionalRecord(asOptionalRecord(accountConfig)?.config);
return readDmAllowFrom(accountConfig) ?? readDmAllowFrom(accountNestedConfig) ?? readAllowFrom(accountConfig) ?? readAllowFrom(accountNestedConfig) ?? readDmAllowFrom(channelConfig) ?? readAllowFrom(channelConfig);
}
function shouldPreserveDirectSessionKeyFromRoute(params) {
if (!params.cfg || !params.target?.channel) return false;
try {
const route = resolveAgentRoute({
cfg: params.cfg,
channel: params.target.channel,
accountId: params.target.accountId,
peer: {
kind: "direct",
id: params.target.peerId
}
});
const { baseSessionKey } = parseThreadSessionSuffix(params.sessionKey);
const normalizedRouteSessionKey = normalizeLowercaseStringOrEmpty(route.sessionKey);
return route.lastRoutePolicy === "session" && (normalizedRouteSessionKey === normalizeLowercaseStringOrEmpty(params.sessionKey) || baseSessionKey !== void 0 && normalizedRouteSessionKey === normalizeLowercaseStringOrEmpty(baseSessionKey));
} catch {
return false;
}
}
/** Build the routing policy used by event wakeups and scoped heartbeat options. */
function resolveEventSessionRoutingPolicy(params) {
const target = parseDirectAgentSessionTarget(params.sessionKey);
const channel = normalizeOptionalLowercaseString(params.channel ?? target?.channel);
const accountId = normalizeOptionalLowercaseString(params.accountId ?? target?.accountId);
const allowFrom = params.allowFrom ?? resolveEventSessionAllowFrom({
cfg: params.cfg,
target,
channel,
accountId
});
return {
mainKey: params.cfg?.session?.mainKey,
sessionScope: params.cfg?.session?.scope,
dmScope: params.dmScope ?? params.cfg?.session?.dmScope,
allowFrom,
channel,
accountId,
preserveSessionKey: params.sessionKey ? shouldPreserveDirectSessionKeyFromRoute({
cfg: params.cfg,
sessionKey: params.sessionKey,
target
}) : false
};
}
/** Resolve a direct DM event session to the configured main session when allowed. */
function resolveMainScopedEventSessionKey(params) {
const sessionKey = params.sessionKey.trim();
if (!sessionKey || params.policy?.preserveSessionKey === true) return null;
const target = parseDirectAgentSessionTarget(sessionKey);
if (!target) return null;
const resolvedAgentId = normalizeAgentId(params.agentId ?? target.agentId);
if (normalizeAgentId(target.agentId) !== resolvedAgentId) return null;
const policy = params.policy ?? resolveEventSessionRoutingPolicy({
cfg: params.cfg,
sessionKey
});
const allowFrom = Array.from(policy.allowFrom ?? []);
const pinnedOwner = resolvePinnedMainDmOwnerFromAllowlist({
dmScope: policy.dmScope ?? params.cfg?.session?.dmScope,
allowFrom,
normalizeEntry: normalizeOptionalLowercaseString
});
if (!pinnedOwner || normalizeOptionalLowercaseString(target.peerId) !== pinnedOwner) return null;
if (shouldPreserveDirectSessionKeyFromRoute({
cfg: params.cfg,
sessionKey,
target
})) return null;
if (policy.sessionScope === "global") return "global";
return buildAgentMainSessionKey({
agentId: resolvedAgentId,
mainKey: policy.mainKey ?? params.cfg?.session?.mainKey
});
}
/** Apply event routing policy to a raw session key. */
function resolveEventSessionKeyForPolicy(sessionKey, policy) {
const cronScoped = resolveEventSessionKey(sessionKey, policy?.mainKey, policy?.sessionScope);
if (cronScoped !== sessionKey) return cronScoped;
return resolveMainScopedEventSessionKey({
sessionKey,
policy
}) ?? sessionKey;
}
/** Apply event routing policy while preserving wake option typing. */
function scopedHeartbeatWakeOptionsForPolicy(sessionKey, wakeOptions, policy) {
if (resolveEventSessionKey(sessionKey, policy?.mainKey, policy?.sessionScope) !== sessionKey) return scopedHeartbeatWakeOptions(sessionKey, wakeOptions, policy?.mainKey, policy?.sessionScope);
const mainScoped = resolveMainScopedEventSessionKey({
sessionKey,
policy
});
if (mainScoped) {
if (mainScoped === "global") {
const agentId = parseAgentSessionKey(sessionKey)?.agentId;
return agentId ? {
...wakeOptions,
agentId
} : wakeOptions;
}
return {
...wakeOptions,
sessionKey: mainScoped
};
}
return scopedHeartbeatWakeOptions(sessionKey, wakeOptions, policy?.mainKey, policy?.sessionScope);
}
//#endregion
export { scopedHeartbeatWakeOptionsForPolicy as i, resolveEventSessionRoutingPolicy as n, resolveMainScopedEventSessionKey as r, resolveEventSessionKeyForPolicy as t };