UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

282 lines (281 loc) • 11.4 kB
import { o as normalizeLowercaseStringOrEmpty } from "./string-coerce-1VuiLaaR.mjs"; import { r as isIncognitoSessionKey } from "./session-key-CmZ4o9-l.mjs"; import { N as requiresFoldedSessionKeyAliasProof } from "./session-key-C09ow4h0.mjs"; import { l as resolveSessionStorePathCore } from "./paths-dpReqUI8.mjs"; import { r as getRuntimeConfig } from "./io.runtime-BsUXSsD4.mjs"; import "./io-BYWYXJXl.mjs"; import { r as hasDeliveryTargetFields } from "./delivery-context.shared-PF5njaoI.mjs"; import { t as deliveryContextFromSession } from "./delivery-context.read-CR06zOJ4.mjs"; import { a as normalizeStoreSessionKey, i as isConfirmedLowercasedLegacyAlias, n as foldedSessionKeyAliasCandidates, r as hasMismatchedCaseSensitiveDeliveryProof } from "./store-entry-Bb_svqyv.mjs"; import { i as loadExactSessionEntryCandidatesReadOnlyBatch, o as loadExactSessionEntryReadOnly } from "./session-accessor.sqlite-exact-read-JW6IveXD.mjs"; import { a as resolveAllAgentSessionStoreTargetsSync } from "./targets-BbcRkdUC.mjs"; import { n as openSessionEntryReadView } from "./session-accessor.entry-BpOUC9jw.mjs"; import "./session-accessor-BDmTPdtx.mjs"; import { a as resolveSessionStoreKey, i as resolveSessionStoreIdentity } from "./session-store-key-Ci099tm9.mjs"; import { i as resolveSessionThreadInfo } from "./session-conversation-BZFiAP5-.mjs"; //#region src/config/sessions/delivery-info.ts /** Reads only the current session; missing delivery must not widen into alias discovery. */ function readExactSessionDeliveryContext(params) { const sessionKey = params.sessionKey?.trim(); if (!sessionKey) return; try { const { agentId, canonicalKey } = resolveSessionStoreIdentity({ cfg: params.cfg, sessionKey }); const entry = loadExactSessionEntryReadOnly({ storePath: resolveSessionStorePathCore(params.cfg.session?.store, { agentId }), sessionKey: canonicalKey, projection: "list" })?.entry; if (params.sessionId && entry?.sessionId !== params.sessionId) return; return deliveryContextFromSession(entry); } catch { return; } } /** * Extracts the routable delivery context and thread id for a persisted session key. * * Thread/topic keys first try their exact store entry, then fall back to the base session when * the thread entry has no delivery route of its own. */ function extractDeliveryInfo(sessionKey, options) { return extractDeliveryInfoBatch([sessionKey], options)[0]; } /** Resolves one synchronous batch; only detached delivery facts leave the read scope. */ function extractDeliveryInfoBatch(sessionKeys, options) { const parsed = sessionKeys.map((sessionKey) => ({ sessionKey, ...resolveSessionThreadInfo(sessionKey) })); const results = parsed.map(({ threadId }) => ({ deliveryContext: void 0, threadId })); if (!parsed.some(({ sessionKey, baseSessionKey }) => sessionKey && baseSessionKey)) return results; let cfg; try { cfg = options?.cfg ?? getRuntimeConfig(); } catch { return results; } let storeTargets; function prepareDeliveryLookup(sessionKey, baseSessionKey) { const { agentId, canonicalKey: canonicalBaseKey } = resolveSessionStoreIdentity({ cfg, sessionKey: baseSessionKey }); const canonicalKey = resolveSessionStoreKey({ cfg, sessionKey, storeAgentId: agentId }); const storePaths = /* @__PURE__ */ new Set([resolveSessionStorePathCore(cfg.session?.store, { agentId })]); for (const target of storeTargets ??= resolveAllAgentSessionStoreTargetsSync(cfg)) if (target.agentId === agentId) storePaths.add(target.storePath); return { sessionKeys: [sessionKey, canonicalKey], baseKeys: [baseSessionKey, canonicalBaseKey], storePaths: [...storePaths] }; } const reads = []; const lookups = parsed.flatMap(({ sessionKey, baseSessionKey }, index) => { if (!sessionKey || !baseSessionKey) return []; try { const lookup = prepareDeliveryLookup(sessionKey, baseSessionKey); return [{ index, sessionKey, baseSessionKey, lookup, readIndexes: isIncognitoSessionKey(sessionKey) ? void 0 : lookup.storePaths.map((storePath) => { reads.push({ storePath, sessionKeys: deliveryLookupExactKeys([...lookup.sessionKeys, ...lookup.baseKeys]) }); return reads.length - 1; }) }]; } catch { return []; } }); const readGroups = /* @__PURE__ */ new Map(); for (const [index, read] of reads.entries()) { const group = readGroups.get(read.storePath) ?? []; group.push(index); readGroups.set(read.storePath, group); } const exactResults = /* @__PURE__ */ new Map(); const readExact = (index) => { const cached = exactResults.get(index); if (cached) return cached; const group = readGroups.get(reads[index].storePath); const loaded = loadExactSessionEntryCandidatesReadOnlyBatch(group.map((readIndex) => { const read = reads[readIndex]; return { storePath: read.storePath, sessionKeys: read.sessionKeys, projection: "delivery", onReadSource: (source) => { read.source = source; } }; })); for (const [offset, readIndex] of group.entries()) exactResults.set(readIndex, loaded[offset]); return exactResults.get(index); }; const indexes = /* @__PURE__ */ new Map(); for (const { index, sessionKey, baseSessionKey, lookup, readIndexes } of lookups) try { const selected = loadDeliverySessionEntry(lookup, (storePath, storeIndex) => { const readIndex = readIndexes?.[storeIndex]; const read = readIndex === void 0 ? void 0 : reads[readIndex]; const exact = readIndex === void 0 ? void 0 : readExact(readIndex); if (exact && !exact.ok) throw exact.error; const source = read?.source; const indexKey = source ? `${source.agentId}\u0000${source.path}` : storePath; let normalizedIndex = indexes.get(indexKey); if (!normalizedIndex) { normalizedIndex = lazyDeliveryIndex(source ? { storePath: source.path, agentId: source.agentId } : { storePath }); indexes.set(indexKey, normalizedIndex); } const entries = exact?.ok ? new Map(exact.value.map(({ sessionKey: key, entry }) => [key, entry])) : void 0; return { get: (entries ? { get: (key) => entries.get(key) } : openSessionEntryReadView({ storePath, projection: "list" })).get, normalizedIndex }; }); let context = deliveryContextFromSession(selected.entry); if (!hasDeliveryTargetFields(context) && baseSessionKey !== sessionKey) context = deliveryContextFromSession(selected.baseEntry); if (hasDeliveryTargetFields(context)) results[index].deliveryContext = { channel: context.channel, to: context.to, accountId: context.accountId, threadId: context.threadId }; } catch {} return results; } function deliveryLookupExactKeys(keys) { return [...new Set(keys.flatMap((key) => { const normalized = normalizeStoreSessionKey(key); return [ normalized, ...foldedSessionKeyAliasCandidates(normalized), key.trim() ]; }))]; } function lazyDeliveryIndex(scope) { let result; return () => { if (!result) try { result = { index: buildFreshestSessionEntryIndex(openSessionEntryReadView({ ...scope, projection: "list" })) }; } catch (error) { result = { error }; } if ("error" in result) throw result.error; return result.index; }; } function findSessionEntryInStore(store, keys) { let bestEntry; let bestUpdatedAt = 0; let bestRoutable = false; let bestExact = false; const acceptCandidate = (entry, isExact = false) => { if (!entry) return; const candidateRoutable = hasDeliveryTargetFields(deliveryContextFromSession(entry)); const candidateUpdatedAt = entry.updatedAt ?? 0; if (!bestEntry || candidateRoutable && !bestRoutable || candidateRoutable === bestRoutable && isExact && !bestExact || candidateRoutable === bestRoutable && isExact === bestExact && candidateUpdatedAt > bestUpdatedAt) { bestEntry = entry; bestUpdatedAt = candidateUpdatedAt; bestRoutable = candidateRoutable; bestExact = isExact; } }; for (const key of keys) { const trimmed = key.trim(); const normalized = normalizeStoreSessionKey(key); const foldedLegacyKeys = foldedSessionKeyAliasCandidates(normalized); const exactKeyWins = requiresFoldedSessionKeyAliasProof(normalized); let foundRoutableCandidate = false; const exactEntry = store.get(normalized); if (exactEntry && !hasMismatchedCaseSensitiveDeliveryProof(exactEntry, normalized)) { foundRoutableCandidate ||= hasDeliveryTargetFields(deliveryContextFromSession(exactEntry)); acceptCandidate(exactEntry, exactKeyWins); } for (const foldedLegacyKey of foldedLegacyKeys) { const foldedLegacyEntry = store.get(foldedLegacyKey); if (!foldedLegacyEntry || !isConfirmedLowercasedLegacyAlias(foldedLegacyEntry, normalized)) continue; foundRoutableCandidate ||= hasDeliveryTargetFields(deliveryContextFromSession(foldedLegacyEntry)); acceptCandidate(foldedLegacyEntry); } const trimmedEntry = trimmed !== normalized ? store.get(trimmed) : void 0; if (trimmedEntry && !hasMismatchedCaseSensitiveDeliveryProof(trimmedEntry, normalized)) { foundRoutableCandidate ||= hasDeliveryTargetFields(deliveryContextFromSession(trimmedEntry)); acceptCandidate(trimmedEntry); } if (trimmed !== normalized || !foundRoutableCandidate) { const normalizedIndex = store.normalizedIndex(); const freshest = normalizedIndex.get(normalized); if (!hasMismatchedCaseSensitiveDeliveryProof(freshest, normalized)) acceptCandidate(freshest); for (const foldedLegacyKey of foldedLegacyKeys) { const foldedFreshest = normalizedIndex.get(foldedLegacyKey); if (isConfirmedLowercasedLegacyAlias(foldedFreshest, normalized)) acceptCandidate(foldedFreshest); } } } return bestEntry; } function buildFreshestSessionEntryIndex(store) { const index = /* @__PURE__ */ new Map(); const indexEntry = (key, entry) => { const existing = index.get(key); const entryRoutable = hasDeliveryTargetFields(deliveryContextFromSession(entry)); const existingRoutable = hasDeliveryTargetFields(deliveryContextFromSession(existing)); if (!existing || entryRoutable && !existingRoutable || entryRoutable === existingRoutable && (entry.updatedAt ?? 0) > (existing.updatedAt ?? 0)) index.set(key, entry); }; for (const { sessionKey: key, entry } of store.entries()) { if (!entry) continue; const normalized = normalizeStoreSessionKey(key); indexEntry(normalized, entry); const foldedLegacyKey = normalizeLowercaseStringOrEmpty(normalized); if (foldedLegacyKey === normalized || requiresFoldedSessionKeyAliasProof(normalized)) continue; indexEntry(foldedLegacyKey, entry); } return index; } function loadDeliverySessionEntry(lookup, readStore) { let fallback; for (const [storeIndex, storePath] of lookup.storePaths.entries()) { const store = readStore(storePath, storeIndex); const entry = findSessionEntryInStore(store, lookup.sessionKeys); const baseEntry = findSessionEntryInStore(store, lookup.baseKeys); if (!entry && !baseEntry) continue; fallback ??= { entry, baseEntry }; if (hasDeliveryTargetFields(deliveryContextFromSession(entry)) || hasDeliveryTargetFields(deliveryContextFromSession(baseEntry))) return { entry, baseEntry }; } return fallback ?? { entry: void 0, baseEntry: void 0 }; } //#endregion export { extractDeliveryInfoBatch as n, readExactSessionDeliveryContext as r, extractDeliveryInfo as t };