openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
184 lines (183 loc) • 7.45 kB
JavaScript
import { o as normalizeLowercaseStringOrEmpty } from "./string-coerce-CIXf7egm.js";
import { n as normalizeAgentId } from "./agent-id-CeT3w4ap.js";
import { T as isSubagentSessionKey, b as toAgentStoreSessionKey, f as resolveAgentIdFromSessionKey } from "./session-key-BnWWjqNc.js";
import { o as resolveSessionStorePathCore } from "./paths-CXdaYWF_.js";
import "./session-accessor-YsytfDtG.js";
import { d as patchSessionEntryCore, l as loadSessionEntry } from "./session-accessor.sqlite-entry-CWk3jL7s.js";
import { n as canonicalizeMainSessionAlias, r as resolveAgentMainSessionKey } from "./main-session-Br0F9dzh.js";
import { r as resolveMainScopedEventSessionKey } from "./event-session-routing-CJOO5dMS.js";
//#region src/infra/heartbeat-runner-session.ts
function resolveHeartbeatSessionKey(cfg, agentId, heartbeat, forcedSessionKey, env = process.env) {
const sessionCfg = cfg.session;
const scope = sessionCfg?.scope ?? "per-sender";
const resolvedAgentId = normalizeAgentId(agentId);
const mainSessionKey = scope === "global" ? "global" : resolveAgentMainSessionKey({
cfg,
agentId: resolvedAgentId
});
const storePath = resolveSessionStorePathCore(sessionCfg?.store, {
agentId: resolvedAgentId,
env
});
const mainSession = (suppressOriginatingContext = false) => ({
sessionKey: mainSessionKey,
storePath,
suppressOriginatingContext
});
if (scope === "global") return mainSession();
const forced = forcedSessionKey?.trim();
if (forced && isSubagentSessionKey(forced)) return mainSession(true);
if (forced && !isSubagentSessionKey(forced)) {
const forcedCandidate = toAgentStoreSessionKey({
agentId: resolvedAgentId,
requestKey: forced,
mainKey: cfg.session?.mainKey
});
if (!isSubagentSessionKey(forcedCandidate)) {
const forcedCanonical = canonicalizeMainSessionAlias({
cfg,
agentId: resolvedAgentId,
sessionKey: forcedCandidate
});
if (forcedCanonical !== "global" && !isSubagentSessionKey(forcedCanonical)) {
if (resolveAgentIdFromSessionKey(forcedCanonical) === normalizeAgentId(resolvedAgentId)) return {
sessionKey: resolveMainScopedEventSessionKey({
cfg,
sessionKey: forcedCanonical,
agentId: resolvedAgentId
}) ?? forcedCanonical,
storePath,
suppressOriginatingContext: false
};
}
}
}
const trimmed = heartbeat?.session?.trim() ?? "";
if (!trimmed || isSubagentSessionKey(trimmed)) return mainSession();
const normalized = normalizeLowercaseStringOrEmpty(trimmed);
if (normalized === "main" || normalized === "global") return mainSession();
const candidate = toAgentStoreSessionKey({
agentId: resolvedAgentId,
requestKey: trimmed,
mainKey: cfg.session?.mainKey
});
if (isSubagentSessionKey(candidate)) return mainSession();
const canonical = canonicalizeMainSessionAlias({
cfg,
agentId: resolvedAgentId,
sessionKey: candidate
});
if (canonical !== "global" && !isSubagentSessionKey(canonical)) {
if (resolveAgentIdFromSessionKey(canonical) === normalizeAgentId(resolvedAgentId)) return {
sessionKey: canonical,
storePath,
suppressOriginatingContext: false
};
}
return mainSession();
}
function resolveHeartbeatSession(cfg, agentId, heartbeat, forcedSessionKey, env = process.env) {
const resolved = resolveHeartbeatSessionKey(cfg, agentId, heartbeat, forcedSessionKey, env);
return {
...resolved,
entry: loadSessionEntry({
storePath: resolved.storePath,
sessionKey: resolved.sessionKey,
env
})
};
}
function resolveIsolatedHeartbeatSessionKey(params) {
const storedBaseSessionKey = params.sessionEntry?.heartbeatIsolatedBaseSessionKey?.trim();
if (params.configuredSessionKey === "global") {
const isolatedSessionKey = toAgentStoreSessionKey({
agentId: params.agentId,
requestKey: "global:heartbeat"
});
const suffix = params.sessionKey.slice(isolatedSessionKey.length);
if (params.sessionKey === "global" || storedBaseSessionKey === "global" && (params.sessionKey === isolatedSessionKey || params.sessionKey.startsWith(isolatedSessionKey) && /^(:heartbeat)+$/.test(suffix))) return {
isolatedSessionKey,
isolatedBaseSessionKey: "global"
};
}
if (storedBaseSessionKey) {
const suffix = params.sessionKey.slice(storedBaseSessionKey.length);
if (params.sessionKey.startsWith(storedBaseSessionKey) && suffix.length > 0 && /^(:heartbeat)+$/.test(suffix)) return {
isolatedSessionKey: `${storedBaseSessionKey}:heartbeat`,
isolatedBaseSessionKey: storedBaseSessionKey
};
}
const configuredSuffix = params.sessionKey.slice(params.configuredSessionKey.length);
if (params.sessionKey.startsWith(params.configuredSessionKey) && /^(:heartbeat)+$/.test(configuredSuffix) && !params.configuredSessionKey.endsWith(":heartbeat")) return {
isolatedSessionKey: `${params.configuredSessionKey}:heartbeat`,
isolatedBaseSessionKey: params.configuredSessionKey
};
return {
isolatedSessionKey: `${params.sessionKey}:heartbeat`,
isolatedBaseSessionKey: params.sessionKey
};
}
/** Selects the event queue, execution key and descriptive conversation before delivery. */
function resolveHeartbeatSessionSelection(cfg, agentId, heartbeat, forcedSessionKey, env = process.env) {
const session = resolveHeartbeatSession(cfg, agentId, heartbeat, forcedSessionKey, env);
if (heartbeat?.isolatedSession !== true) return {
...session,
run: {
kind: "shared",
sessionKey: session.sessionKey
},
conversationEntry: session.entry,
inspectsRunQueue: true
};
const configured = resolveHeartbeatSessionKey(cfg, agentId, heartbeat, void 0, env);
const { isolatedSessionKey, isolatedBaseSessionKey } = resolveIsolatedHeartbeatSessionKey({
agentId,
sessionKey: session.sessionKey,
configuredSessionKey: configured.sessionKey,
sessionEntry: session.entry
});
return {
...session,
run: {
kind: "isolated",
sessionKey: isolatedSessionKey,
baseSessionKey: isolatedBaseSessionKey
},
conversationEntry: isolatedBaseSessionKey === session.sessionKey ? session.entry : loadSessionEntry({
storePath: session.storePath,
sessionKey: isolatedBaseSessionKey,
env
}),
inspectsRunQueue: session.sessionKey !== isolatedBaseSessionKey
};
}
function resolveStaleHeartbeatIsolatedSessionKey(params) {
if (params.sessionKey === params.isolatedSessionKey) return;
const suffix = params.sessionKey.slice(params.isolatedBaseSessionKey.length);
if (params.sessionKey.startsWith(params.isolatedBaseSessionKey) && suffix.length > 0 && /^(:heartbeat)+$/.test(suffix)) return params.sessionKey;
}
async function restoreHeartbeatUpdatedAt(params) {
const { storePath, sessionKey, updatedAt } = params;
if (typeof updatedAt !== "number") return;
const entry = loadSessionEntry({
storePath,
sessionKey
});
if (!entry) return;
const nextUpdatedAt = Math.max(entry.updatedAt ?? 0, updatedAt);
if (entry.updatedAt === nextUpdatedAt) return;
await patchSessionEntryCore({
storePath,
sessionKey
}, (nextEntry, context) => {
if (!context.existingEntry) return null;
const resolvedUpdatedAt = Math.max(nextEntry.updatedAt ?? 0, updatedAt);
if (nextEntry.updatedAt === resolvedUpdatedAt) return null;
return {
...nextEntry,
updatedAt: resolvedUpdatedAt
};
}, { replaceEntry: true });
}
//#endregion
export { restoreHeartbeatUpdatedAt as a, resolveStaleHeartbeatIsolatedSessionKey as i, resolveHeartbeatSessionKey as n, resolveHeartbeatSessionSelection as r, resolveHeartbeatSession as t };