@mastra/core
Version:
270 lines (269 loc) • 10.8 kB
JavaScript
import { n as createSignal, s as mastraDBMessageToSignal } from "./signals-DTzJ08gd.js";
//#region src/agent/state-signals.ts
function isPlainObject$1(value) {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function getStateSignalsMetadata(threadMetadata) {
if (!threadMetadata) return {};
const mastra = threadMetadata.mastra;
if (!isPlainObject$1(mastra)) return {};
const stateSignals = mastra.stateSignals;
return isPlainObject$1(stateSignals) ? stateSignals : {};
}
function setStateSignalMetadata(threadMetadata, stateId, tracking) {
const existing = threadMetadata ?? {};
const existingMastra = isPlainObject$1(existing.mastra) ? existing.mastra : {};
const existingStateSignals = isPlainObject$1(existingMastra.stateSignals) ? existingMastra.stateSignals : {};
return {
...existing,
mastra: {
...existingMastra,
stateSignals: {
...existingStateSignals,
[stateId]: tracking
}
}
};
}
function signalCreatedAt(signal) {
const timestamp = (signal.createdAt instanceof Date ? signal.createdAt : new Date(signal.createdAt)).getTime();
return Number.isNaN(timestamp) ? 0 : timestamp;
}
function sortStateSignals(signals) {
return signals.map((signal, index) => ({
signal,
index
})).sort((left, right) => signalCreatedAt(left.signal) - signalCreatedAt(right.signal) || left.index - right.index).map(({ signal }) => signal);
}
function dbMessagesToStateSignals(messages, stateId, threadId) {
return sortStateSignals(messages.filter((message) => message.role === "signal").map((message) => {
try {
return mastraDBMessageToSignal(message);
} catch {
return;
}
}).filter((signal) => signal?.type === "state" && isPlainObject$1(signal.metadata?.state) && (!stateId || signal.metadata.state.id === stateId) && signal.metadata.state.threadId === threadId));
}
function getActiveStateSignals(messageList, stateId, threadId) {
return dbMessagesToStateSignals(messageList.get.all.db(), stateId, threadId);
}
function mergeStateSignals(...signalGroups) {
const signalsById = /* @__PURE__ */ new Map();
for (const signal of signalGroups.flat()) signalsById.set(signal.id, signal);
return sortStateSignals([...signalsById.values()]);
}
function deriveStateSignalHistory(activeStateSignals) {
const sortedStateSignals = sortStateSignals(activeStateSignals);
const lastSnapshotIndex = sortedStateSignals.findLastIndex((signal) => signal.metadata?.state?.mode === "snapshot");
const lastSnapshot = lastSnapshotIndex >= 0 ? sortedStateSignals[lastSnapshotIndex] : void 0;
const deltasSinceSnapshot = sortedStateSignals.slice(lastSnapshotIndex + 1).filter((signal) => signal.metadata?.state?.mode === "delta");
return {
activeStateSignals: sortedStateSignals,
contextWindow: { hasSnapshot: Boolean(lastSnapshot) },
lastSnapshot,
deltasSinceSnapshot
};
}
async function resolveStateSignalHistory({ messageList, memory, threadId, stateId, tracking }) {
const localStateSignals = getActiveStateSignals(messageList, stateId, threadId);
const localHistory = deriveStateSignalHistory(localStateSignals);
const contextWindow = localHistory.contextWindow;
if (localHistory.contextWindow.hasSnapshot || !tracking?.lastSnapshotSignalId) return {
...localHistory,
contextWindow
};
const memoryStore = await memory.storage.getStore("memory");
if (!memoryStore) return {
...localHistory,
contextWindow
};
const trackedSignalIds = /* @__PURE__ */ new Set();
for (const activeCopy of tracking.activeCopies ?? []) trackedSignalIds.add(activeCopy.id);
trackedSignalIds.add(tracking.lastSnapshotSignalId);
if (trackedSignalIds.size === 0 || typeof memoryStore.listMessagesById !== "function") return {
...localHistory,
contextWindow
};
const resolvedStateSignals = mergeStateSignals(dbMessagesToStateSignals((await memoryStore.listMessagesById({ messageIds: [...trackedSignalIds] })).messages, stateId, threadId), localStateSignals);
return {
...deriveStateSignalHistory(resolvedStateSignals.length > 0 ? resolvedStateSignals : localStateSignals),
contextWindow
};
}
function createStateSignalInput(input, options) {
const stateId = input.id ?? options?.defaultId;
if (!stateId) throw new Error("state signal id is required");
if (!input.cacheKey) throw new Error("state signal cacheKey is required");
const mode = input.mode ?? "snapshot";
const { id: _stateId, cacheKey, mode: _mode, value, delta, metadata, ...signalInput } = input;
return {
stateId,
signal: createSignal({
...signalInput,
type: "state",
tagName: signalInput.tagName ?? "state",
acceptedAt: options?.acceptedAt,
metadata: {
...metadata,
state: {
...isPlainObject$1(metadata?.state) ? metadata.state : {},
id: stateId,
cacheKey,
mode
},
...value !== void 0 ? { value } : {},
...delta !== void 0 ? { delta } : {}
}
}),
mode,
cacheKey
};
}
async function applyStateSignal({ input, memory, thread, resourceId, threadId, memoryConfig, messageList, activeStateSignals, defaultId, acceptedAt, beforeAddSignal, writeSignal }) {
const { stateId, signal, cacheKey, mode } = createStateSignalInput(input, {
defaultId,
acceptedAt
});
const activeSignals = activeStateSignals ?? (messageList ? getActiveStateSignals(messageList, stateId, threadId) : []);
const tracking = getStateSignalsMetadata(thread.metadata)[stateId];
const usesActiveWindow = Boolean(messageList || activeStateSignals);
const hasActiveCopy = activeSignals.some((signal) => signal.metadata?.state?.cacheKey === cacheKey && signal.metadata?.state?.mode === mode);
const matchesCurrentState = tracking?.currentCacheKey === cacheKey && (tracking.currentMode === mode || !tracking.currentMode && hasActiveCopy);
if (matchesCurrentState && (!usesActiveWindow || hasActiveCopy)) return {
skipped: true,
reason: "unchanged",
stateId,
tracking
};
const previousVersion = typeof tracking?.version === "number" ? tracking.version : 0;
const version = matchesCurrentState ? previousVersion || 1 : previousVersion + 1;
const updatedSignal = createSignal({
...signal,
metadata: {
...signal.metadata,
state: {
...isPlainObject$1(signal.metadata?.state) ? signal.metadata.state : {},
id: stateId,
threadId,
cacheKey,
version,
mode
}
}
});
beforeAddSignal?.();
if (messageList) messageList.addSignal(updatedSignal);
await writeSignal?.(updatedSignal);
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
const updatedActiveSignals = [...activeSignals, updatedSignal];
const nextTracking = {
currentCacheKey: cacheKey,
currentMode: mode,
version,
lastSignalId: updatedSignal.id,
lastSnapshotSignalId: mode === "snapshot" ? updatedSignal.id : tracking?.lastSnapshotSignalId,
updatedAt,
activeCopies: updatedActiveSignals.map((activeSignal) => {
const activeStateMetadata = isPlainObject$1(activeSignal.metadata?.state) ? activeSignal.metadata.state : {};
return {
id: activeSignal.id,
...typeof activeStateMetadata.cacheKey === "string" ? { cacheKey: activeStateMetadata.cacheKey } : {},
...activeStateMetadata.mode === "snapshot" || activeStateMetadata.mode === "delta" ? { mode: activeStateMetadata.mode } : {},
...typeof activeStateMetadata.version === "number" ? { version: activeStateMetadata.version } : {}
};
})
};
await memory.saveThread({
thread: {
...thread,
id: threadId,
resourceId: thread.resourceId ?? resourceId,
createdAt: thread.createdAt ?? /* @__PURE__ */ new Date(),
updatedAt: new Date(updatedAt),
metadata: setStateSignalMetadata(thread.metadata, stateId, nextTracking)
},
memoryConfig
});
return {
skipped: false,
signal: updatedSignal,
stateId,
version,
tracking: nextTracking
};
}
//#endregion
//#region src/memory/types.ts
function isPlainObject(value) {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
/**
* Helper to get OM metadata from a thread's metadata object.
* Returns undefined if not present or if the structure is invalid.
*/
function getThreadOMMetadata(threadMetadata) {
if (!threadMetadata) return void 0;
const mastra = threadMetadata.mastra;
if (!isPlainObject(mastra)) return void 0;
const om = mastra.om;
if (!isPlainObject(om)) return void 0;
return om;
}
/**
* Helper to set OM metadata on a thread's metadata object.
* Creates the nested structure if it doesn't exist.
* Returns a new metadata object (does not mutate the original).
* Safely handles cases where existing mastra/om values are not objects.
*/
function setThreadOMMetadata(threadMetadata, omMetadata) {
const existing = threadMetadata ?? {};
const existingMastra = isPlainObject(existing.mastra) ? existing.mastra : {};
const existingOM = isPlainObject(existingMastra.om) ? existingMastra.om : {};
return {
...existing,
mastra: {
...existingMastra,
om: {
...existingOM,
...omMetadata
}
}
};
}
/**
* Parse and validate memory runtime context from RequestContext
* @param requestContext - The RequestContext to extract memory context from
* @returns The validated MemoryRequestContext or null if not available
* @throws Error if the context exists but is malformed
*/
function parseMemoryRequestContext(requestContext) {
if (!requestContext) return null;
const memoryContext = requestContext.get("MastraMemory");
if (!memoryContext) return null;
if (typeof memoryContext !== "object" || memoryContext === null) throw new Error(`Invalid MemoryRequestContext: expected object, got ${typeof memoryContext}`);
const ctx = memoryContext;
if (ctx.thread !== void 0) {
if (typeof ctx.thread !== "object" || ctx.thread === null) throw new Error(`Invalid MemoryRequestContext.thread: expected object, got ${typeof ctx.thread}`);
const thread = ctx.thread;
if (typeof thread.id !== "string") throw new Error(`Invalid MemoryRequestContext.thread.id: expected string, got ${typeof thread.id}`);
}
if (ctx.resourceId !== void 0 && typeof ctx.resourceId !== "string") throw new Error(`Invalid MemoryRequestContext.resourceId: expected string, got ${typeof ctx.resourceId}`);
return memoryContext;
}
/**
* Check if observational memory is enabled from a `boolean | ObservationalMemoryOptions` value.
*
* - `true` → enabled
* - `false` → disabled
* - `{ enabled: false }` → disabled
* - `{ ... }` (without `enabled: false`) → enabled
* - `undefined` → disabled
*/
function isObservationalMemoryEnabled(config) {
if (config === true) return true;
if (config === false || config === void 0) return false;
return config.enabled !== false;
}
//#endregion
export { applyStateSignal as a, setThreadOMMetadata as i, isObservationalMemoryEnabled as n, getStateSignalsMetadata as o, parseMemoryRequestContext as r, resolveStateSignalHistory as s, getThreadOMMetadata as t };
//# sourceMappingURL=types-LyOfO-TK.js.map