openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
127 lines (126 loc) • 5.45 kB
JavaScript
import { O as parseAgentSessionKey } from "./session-key-BnWWjqNc.js";
import { o as loadGatewaySessionRow } from "./session-utils-list-B0k8KJn5.js";
import { r as resolveSessionEventAgentScope, t as resolvePrivateSessionEventBroadcastScope } from "./session-request-agent-CCRSEGCB.js";
import "./session-utils-Cai0_C6U.js";
import { D as invalidateSessionSharingSnapshot } from "./session-sharing-B7MI8hNo.js";
import { n as buildGatewaySessionSnapshot } from "./session-event-payload-COi33-eM.js";
import { i as resolveVisibleActiveSessionRunState } from "./session-active-runs-CCNuJW7B.js";
import { t as hasSessionChangeReceivers } from "./session-change-receivers-BH6Ki2zl.js";
//#region src/gateway/server-methods/session-change-event.ts
const SESSIONS_CHANGED_DEBOUNCE_MS = 100;
const SESSIONS_CHANGED_MAX_WAIT_MS = 500;
const sessionsMutationVersions = /* @__PURE__ */ new WeakMap();
const pendingChangesByContext = /* @__PURE__ */ new WeakMap();
const pendingSessionChanges = /* @__PURE__ */ new Set();
function readSessionsMutationVersion(context) {
return sessionsMutationVersions.get(context) ?? 0;
}
function sessionChangeKey(payload, scope) {
return `${scope?.[1] ?? payload.agentId ?? ""}\0${payload.sessionKey ?? ""}`;
}
function broadcastSessionsChanged(context, payload, scope) {
const connIds = context.getSessionEventSubscriberConnIds();
if (!hasSessionChangeReceivers(connIds)) return;
if (scope === null) return;
const [eventAgentId, routingAgentId, compatibilityOwnerAgentId] = scope;
const privateBroadcastScope = resolvePrivateSessionEventBroadcastScope(payload.sessionKey, scope);
const broadcastAgentId = routingAgentId;
const broadcastOptions = {
...broadcastAgentId ? { agentId: broadcastAgentId } : {},
...privateBroadcastScope,
dropIfSlow: true
};
const eventPayload = {
...payload,
...eventAgentId ? { agentId: eventAgentId } : {},
ts: Date.now()
};
if (payload.reason === "delete" || !payload.sessionKey || !routingAgentId || !eventAgentId && !compatibilityOwnerAgentId && !parseAgentSessionKey(payload.sessionKey)) {
context.broadcastToConnIds("sessions.changed", eventPayload, connIds, broadcastOptions);
return;
}
const sessionRow = loadGatewaySessionRow(payload.sessionKey, { agentId: routingAgentId });
const activeRunState = sessionRow && (sessionRow.key !== "global" || routingAgentId !== void 0) ? resolveVisibleActiveSessionRunState({
context,
requestedKey: payload.sessionKey ?? sessionRow.key,
canonicalKey: sessionRow.key,
sessionId: sessionRow.sessionId,
agentId: routingAgentId,
defaultAgentId: compatibilityOwnerAgentId
}) : null;
context.broadcastToConnIds("sessions.changed", {
...eventPayload,
...sessionRow ? { ...buildGatewaySessionSnapshot({
sessionRow,
agentId: eventAgentId,
activeRunState
}) } : {}
}, connIds, {
...broadcastOptions,
...sessionRow?.key ? { sessionKeys: [sessionRow.key] } : {}
});
}
function finishPendingSessionChange(pending) {
if (pending.timer) {
clearTimeout(pending.timer);
pending.timer = null;
}
pendingSessionChanges.delete(pending);
const byKey = pendingChangesByContext.get(pending.context);
if (byKey?.get(pending.key) === pending) byKey.delete(pending.key);
if (pending.dirty) broadcastSessionsChanged(pending.context, pending.payload, pending.scope);
}
/** Flush trailing notifications and release every debounce timer before gateway shutdown. */
function flushPendingSessionsChangedEvents(context) {
for (const pending of pendingSessionChanges) if (!context || pending.context === context) finishPendingSessionChange(pending);
}
function emitSessionsChanged(context, payload) {
sessionsMutationVersions.set(context, readSessionsMutationVersion(context) + 1);
invalidateSessionSharingSnapshot(payload.sessionKey);
context.mentionInbox?.invalidate();
const connIds = context.getSessionEventSubscriberConnIds();
if (!hasSessionChangeReceivers(connIds)) return;
const scope = payload.sessionKey ? resolveSessionEventAgentScope(context.getRuntimeConfig(), payload.sessionKey, payload.agentId) : [
payload.agentId,
payload.agentId,
void 0
];
const key = sessionChangeKey(payload, scope);
const byKey = pendingChangesByContext.get(context) ?? /* @__PURE__ */ new Map();
pendingChangesByContext.set(context, byKey);
const pending = byKey.get(key);
if (pending) {
pending.payload = payload;
pending.scope = scope;
pending.dirty = true;
pending.firstDeferredAt ??= Date.now();
if (pending.timer) clearTimeout(pending.timer);
const maxWaitRemaining = pending.firstDeferredAt + SESSIONS_CHANGED_MAX_WAIT_MS - Date.now();
pending.timer = setTimeout(() => finishPendingSessionChange(pending), Math.max(0, Math.min(SESSIONS_CHANGED_DEBOUNCE_MS, maxWaitRemaining)));
pending.timer.unref?.();
return;
}
const next = {
context,
dirty: false,
key,
payload,
scope,
timer: null
};
next.timer = setTimeout(() => finishPendingSessionChange(next), SESSIONS_CHANGED_DEBOUNCE_MS);
next.timer.unref?.();
byKey.set(key, next);
pendingSessionChanges.add(next);
broadcastSessionsChanged(context, payload, scope);
}
function emitSessionArchived(context, sessionKey, agentId) {
if (!sessionKey) return;
emitSessionsChanged(context, {
sessionKey,
...agentId ? { agentId } : {},
reason: "archive"
});
}
//#endregion
export { readSessionsMutationVersion as i, emitSessionsChanged as n, flushPendingSessionsChangedEvents as r, emitSessionArchived as t };