UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

217 lines (216 loc) • 9.54 kB
import { a as asOptionalRecord } from "./record-coerce-TIsquoVR.mjs"; import { s as resolveSessionTranscriptActiveLeafEntryId } from "./transcript-tree-CaYJo8Xs.mjs"; import { n as readLegacyCompactionMetrics } from "./legacy-compaction-history-DS8GebGO.mjs"; import { r as augmentChatHistoryWithCanvasBlocks } from "./chat-display-projection.canvas-DwEc-tyR.mjs"; import { o as isHeartbeatHistoryTurnBoundaryMessage, r as dropPreSessionStartAnnouncePairs } from "./chat-display-projection.history-C7mOEuaq.mjs"; import { s as projectChatDisplayMessagesWithState, t as createChatHistoryRecoveryProjection } from "./chat-display-projection.core-BRO3Pr6M.mjs"; import { a as readChatHistoryRecoveryContext, i as readChatHistoryPaginationKey, n as readChatHistoryMessageId, o as readIncrementalChatHistoryTail, r as readChatHistoryMessageSeq, t as dropChatHistoryOverreadContextMessage } from "./session-history-tail-fjrDpLEk.mjs"; //#region src/gateway/server-methods/chat-history-page-kernel.ts function resolveChatHistoryNextOffset(params) { const sequence = (message) => params.messageSequences?.[readChatHistoryPaginationKey(message) ?? ""] ?? readChatHistoryMessageSeq(message); let oldestSeq; let boundedSiblings = 0; for (const message of params.messages) { const seq = sequence(message); oldestSeq ??= seq; if (seq !== void 0 && seq === oldestSeq) boundedSiblings += 1; } if (oldestSeq === void 0) return params.offset + params.rawPageMessages; const recordOffset = params.totalMessages - oldestSeq + 1; const replayOffset = recordOffset - 1; if (replayOffset > params.offset) { let projectedSiblings = 0; for (const message of params.projected) if (sequence(message) === oldestSeq) { projectedSiblings += 1; if (projectedSiblings > boundedSiblings) return replayOffset; } } return Math.max(params.offset + 1, recordOffset); } function resolveChatHistoryActiveLeafEntryId(readPage) { if (readPage.transcriptSource !== "active") return null; if (Object.hasOwn(readPage, "activeLeafEntryId")) return readPage.activeLeafEntryId ?? null; return resolveSessionTranscriptActiveLeafEntryId(readPage.transcriptEvents ?? []) ?? null; } /** Preserve token metrics saved by pre-removal builds; new markers own their metrics. */ function enrichChatHistoryCompactionMarkers(messages, entry, metrics = readLegacyCompactionMetrics(entry)) { if (metrics.length === 0) return messages; const checkpointByEntryId = new Map(metrics.map((metric) => [metric.entryId, metric])); let changed = false; const enriched = messages.map((message) => { const record = asOptionalRecord(message); const metadata = asOptionalRecord(record?.["__openclaw"]); if (metadata?.kind !== "compaction" || typeof metadata.id !== "string") return message; const checkpoint = checkpointByEntryId.get(metadata.id); if (!checkpoint) return message; const tokensBefore = checkpoint.tokensBefore; const tokensAfter = checkpoint.tokensAfter; if (tokensBefore === void 0 && tokensAfter === void 0) return message; changed = true; return { ...record, __openclaw: { ...metadata, ...tokensBefore !== void 0 ? { tokensBefore } : {}, ...tokensAfter !== void 0 ? { tokensAfter } : {} } }; }); return changed ? enriched : messages; } function resolveChatHistoryMessageGroup(messages, index, messageCost) { const seq = readChatHistoryMessageSeq(messages[index]); let start = index; let end = index + 1; let cost = messageCost(messages[index]); if (seq === void 0) return { start, end, cost }; while (start > 0 && readChatHistoryMessageSeq(messages[start - 1]) === seq) { start -= 1; cost += messageCost(messages[start]); } while (end < messages.length && readChatHistoryMessageSeq(messages[end]) === seq) { cost += messageCost(messages[end]); end += 1; } return { start, end, cost }; } function capChatHistoryAroundMessage(params) { const anchorIndex = params.messages.findIndex((message) => readChatHistoryMessageId(message) === params.messageId); if (anchorIndex === -1) return []; const messageCost = params.messageCost ?? (() => 1); const anchorGroup = resolveChatHistoryMessageGroup(params.messages, anchorIndex, messageCost); if (!(anchorGroup.cost <= params.maxCost)) return [params.messages[anchorIndex]]; let { start, end, cost } = anchorGroup; let canGrowOlder = start > 0; let canGrowNewer = end < params.messages.length; while (canGrowOlder || canGrowNewer) { if (canGrowOlder) { const olderGroup = resolveChatHistoryMessageGroup(params.messages, start - 1, messageCost); if (cost + olderGroup.cost <= params.maxCost) { start = olderGroup.start; cost += olderGroup.cost; } else canGrowOlder = false; } canGrowOlder &&= start > 0; if (canGrowNewer) { const newerGroup = resolveChatHistoryMessageGroup(params.messages, end, messageCost); if (cost + newerGroup.cost <= params.maxCost) { end = newerGroup.end; cost += newerGroup.cost; } else canGrowNewer = false; } canGrowNewer &&= end < params.messages.length; } return params.messages.slice(start, end); } /** Assemble one page from admitted readers; host imports and profile discovery stay outside. */ async function readChatHistoryPageKernel(params, options) { const { entry, sessionId, storePath, sessionAgentId, canonicalKey, max, maxHistoryBytes, effectiveMaxChars, offset, messageId } = params; if (!sessionId || !storePath) { if (messageId) return { messages: [] }; return { ...(offset ?? 0) === 0 ? { activeLeafEntryId: null } : {}, messages: [], ...offset !== void 0 ? { responseOffset: offset } : {}, pagination: { offset: offset ?? 0, totalMessages: 0, rawPageMessages: 0 } }; } const readScope = { agentId: sessionAgentId, sessionEntry: entry, sessionId, sessionKey: canonicalKey, storePath }; const readSequence = options.readMessageSequence ?? readChatHistoryMessageSeq; if (messageId) { const readPage = await options.readers.readSessionMessagesAroundIdWithStatsAsync(readScope, { messageId, maxMessages: max, allowResetArchiveFallback: true, readOnly: options.readOnly }); if (!readPage.found) return { messages: [] }; const overreadContextMessage = readPage.hasOverreadContext || readPage.messages.length > max ? readPage.messages[0] : void 0; const localMessages = dropChatHistoryOverreadContextMessage(dropPreSessionStartAnnouncePairs(readPage.messages, typeof entry?.sessionStartedAt === "number" ? entry.sessionStartedAt : void 0), overreadContextMessage); const project = (messages) => projectChatDisplayMessagesWithState(messages, { subagentCoordination: options.readers.subagentCoordination, includeCommentaryFallbacks: true, maxChars: effectiveMaxChars, resolveCronJobName: options.resolveCronJobName, ...options.deferProfileDisplay ? {} : { resolveCurrentUserProfileDisplay: options.resolveCurrentUserProfileDisplay }, turnBoundaryPending: isHeartbeatHistoryTurnBoundaryMessage(overreadContextMessage) }); const projection = project(localMessages); let projected = projection.messages; const newestPageSeq = readSequence(localMessages.at(-1)); if (readPage.offset > 0 && newestPageSeq !== void 0 && projection.assistantErrorPending) { const recoveryContext = await readChatHistoryRecoveryContext({ messages: localMessages, createRecovery: (messages) => { const recovery = createChatHistoryRecoveryProjection({ maxChars: effectiveMaxChars, subagentCoordination: options.readers.subagentCoordination }); recovery.append(messages); return recovery; }, readScope, readers: options.readers, displaySource: readPage.displaySource, maxBytes: maxHistoryBytes, readOnly: options.readOnly }); if (recoveryContext.length > 0) projected = project([...localMessages, ...recoveryContext]).messages.filter((message) => (readSequence(message) ?? Infinity) <= newestPageSeq); } return { messages: augmentChatHistoryWithCanvasBlocks(capChatHistoryAroundMessage({ messages: projected, messageId, maxCost: max })), ...projection.activity.length ? { activity: projection.activity } : {} }; } const incrementalTail = await readIncrementalChatHistoryTail({ entry, readScope, effectiveMaxChars, max, maxBytes: maxHistoryBytes, offset, ...options }); const { readPage } = incrementalTail; const currentOffset = incrementalTail.windowReset ? 0 : offset; const isOffsetPage = currentOffset !== void 0; const includeActiveLeaf = !isOffsetPage || currentOffset === 0; const activeLeafEntryId = includeActiveLeaf ? resolveChatHistoryActiveLeafEntryId(readPage) : null; return { ...incrementalTail.windowReset ? { windowReset: true } : {}, ...includeActiveLeaf ? { activeLeafEntryId } : {}, ...includeActiveLeaf && readPage.transcriptSource === "active" && readPage.deltaCursor && !incrementalTail.projection.assistantErrorPending ? { deltaCursor: readPage.deltaCursor } : {}, messages: augmentChatHistoryWithCanvasBlocks(incrementalTail.projected), ...incrementalTail.projection.activity.length ? { activity: incrementalTail.projection.activity } : {}, ...isOffsetPage ? { responseOffset: currentOffset } : {}, pagination: { offset: currentOffset ?? 0, totalMessages: readPage.totalMessages, rawPageMessages: incrementalTail.rawPageMessages } }; } //#endregion export { resolveChatHistoryNextOffset as i, enrichChatHistoryCompactionMarkers as n, readChatHistoryPageKernel as r, capChatHistoryAroundMessage as t };