UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

199 lines (198 loc) 8.33 kB
import { l as asPositiveSafeInteger } from "./number-coercion-CJQ8TR--.js"; import { a as readRecentSessionMessagesWithStatsAsync, d as readSessionMessagesAsync, t as attachOpenClawTranscriptMeta } from "./session-utils.fs-D_8-X4jl.js"; import "./session-utils-CHNCuY8a.js"; import { a as projectChatDisplayMessages } from "./chat-display-projection-Bv2HD4Rr.js"; //#region src/gateway/session-history-state.ts /** Computes an oversized raw transcript tail window for projected chat history. */ function resolveSessionHistoryTailReadOptions(limit) { const rawWindow = Math.max(1, Math.floor(limit)) * 20 + 20; return { maxMessages: rawWindow, maxLines: rawWindow }; } function resolveCursorSeq(cursor) { if (!cursor) return; const normalized = cursor.startsWith("seq:") ? cursor.slice(4) : cursor; if (!/^\d+$/.test(normalized)) return; const value = Number(normalized); return Number.isSafeInteger(value) && value > 0 ? value : void 0; } function toSessionHistoryMessages(messages) { return messages.filter((message) => Boolean(message) && typeof message === "object" && !Array.isArray(message)); } function buildPaginatedSessionHistory(params) { return { items: params.messages, messages: params.messages, hasMore: params.hasMore, ...params.nextCursor ? { nextCursor: params.nextCursor } : {} }; } function resolveMessageSeq(message) { return asPositiveSafeInteger(message?.["__openclaw"]?.seq); } function isMessageToolMirrorMessage(message) { return message.openclawMessageToolMirror !== void 0; } function paginateSessionMessages(messages, limit, cursor) { const cursorSeq = resolveCursorSeq(cursor); let endExclusive = messages.length; if (typeof cursorSeq === "number") { endExclusive = messages.findIndex((message, index) => { const seq = resolveMessageSeq(message); if (typeof seq === "number") return seq >= cursorSeq; return index + 1 >= cursorSeq; }); if (endExclusive < 0) endExclusive = messages.length; } const start = typeof limit === "number" && limit > 0 ? Math.max(0, endExclusive - limit) : 0; const paginatedMessages = messages.slice(start, endExclusive); const firstSeq = resolveMessageSeq(paginatedMessages[0]); return buildPaginatedSessionHistory({ messages: paginatedMessages, hasMore: start > 0, ...start > 0 && typeof firstSeq === "number" ? { nextCursor: String(firstSeq) } : {} }); } /** Builds the display history snapshot and raw transcript sequence watermark. */ function buildSessionHistorySnapshot(params) { const history = paginateSessionMessages(toSessionHistoryMessages(projectChatDisplayMessages(params.rawMessages, { maxChars: params.maxChars ?? 8e3 })), params.limit, params.cursor); if (!params.cursor && typeof params.totalRawMessages === "number" && params.totalRawMessages > params.rawMessages.length && history.messages.length > 0) { const firstSeq = resolveMessageSeq(history.messages[0]); history.hasMore = true; if (typeof firstSeq === "number") history.nextCursor = String(firstSeq); } const rawHistoryMessages = toSessionHistoryMessages(params.rawMessages); return { history, rawTranscriptSeq: params.rawTranscriptSeq ?? resolveMessageSeq(rawHistoryMessages.at(-1)) ?? rawHistoryMessages.length }; } /** Tracks session-history SSE state and decides when inline appends are still valid. */ var SessionHistorySseState = class SessionHistorySseState { static fromRawSnapshot(params) { return new SessionHistorySseState({ target: params.target, maxChars: params.maxChars, limit: params.limit, cursor: params.cursor, initialRawMessages: params.rawMessages, rawTranscriptSeq: params.rawTranscriptSeq, totalRawMessages: params.totalRawMessages }); } constructor(params) { this.target = params.target; this.maxChars = params.maxChars ?? 8e3; this.limit = params.limit; this.cursor = params.cursor; const snapshot = this.buildSnapshot({ rawMessages: params.initialRawMessages, ...typeof params.rawTranscriptSeq === "number" ? { rawTranscriptSeq: params.rawTranscriptSeq } : {}, ...typeof params.totalRawMessages === "number" ? { totalRawMessages: params.totalRawMessages } : {} }); this.sentHistory = snapshot.history; this.rawTranscriptSeq = snapshot.rawTranscriptSeq; } snapshot() { return this.sentHistory; } appendInlineMessage(update) { if (this.limit !== void 0 || this.cursor !== void 0) return null; const carriedSeq = asPositiveSafeInteger(update.messageSeq); if (carriedSeq !== void 0) { if (carriedSeq <= this.rawTranscriptSeq) return { shouldRefresh: true }; this.rawTranscriptSeq = carriedSeq; } else this.rawTranscriptSeq += 1; const nextMessage = attachOpenClawTranscriptMeta(update.message, { ...typeof update.messageId === "string" ? { id: update.messageId } : {}, seq: this.rawTranscriptSeq }); const projectedMessages = toSessionHistoryMessages(projectChatDisplayMessages([...this.sentHistory.messages, nextMessage], { maxChars: this.maxChars })); if (projectedMessages.length > this.sentHistory.messages.length) { const addedMessages = projectedMessages.slice(this.sentHistory.messages.length); if (addedMessages.length > 1) { this.sentHistory = buildPaginatedSessionHistory({ messages: projectedMessages, hasMore: false }); return { shouldRefresh: true }; } const projectedMessage = addedMessages[0]; if (projectedMessage !== void 0) { const emittedMessage = isMessageToolMirrorMessage(projectedMessage) || resolveMessageSeq(projectedMessage) === void 0 ? attachOpenClawTranscriptMeta(projectedMessage, { seq: this.rawTranscriptSeq }) : projectedMessage; const nextMessages = [...this.sentHistory.messages, emittedMessage]; this.sentHistory = buildPaginatedSessionHistory({ messages: nextMessages, hasMore: false }); return { message: emittedMessage, messageSeq: resolveMessageSeq(emittedMessage) }; } } const [sanitizedMessage] = toSessionHistoryMessages(projectChatDisplayMessages([nextMessage], { maxChars: this.maxChars })); if (!sanitizedMessage) { if (projectedMessages.length < this.sentHistory.messages.length) { this.sentHistory = buildPaginatedSessionHistory({ messages: projectedMessages, hasMore: false }); return { shouldRefresh: true }; } return null; } if (projectedMessages.length <= this.sentHistory.messages.length) { this.sentHistory = buildPaginatedSessionHistory({ messages: projectedMessages, hasMore: false }); return { shouldRefresh: true }; } const projectedMessage = projectedMessages.at(-1) ?? sanitizedMessage; const nextMessages = [...this.sentHistory.messages, projectedMessage]; this.sentHistory = buildPaginatedSessionHistory({ messages: nextMessages, hasMore: false }); return { message: projectedMessage, messageSeq: resolveMessageSeq(projectedMessage) }; } async refreshAsync() { const rawSnapshot = await this.readRawSnapshotAsync(); const snapshot = this.buildSnapshot(rawSnapshot); this.rawTranscriptSeq = snapshot.rawTranscriptSeq; this.sentHistory = snapshot.history; return snapshot.history; } buildSnapshot(rawSnapshot) { return buildSessionHistorySnapshot({ rawMessages: rawSnapshot.rawMessages, maxChars: this.maxChars, limit: this.limit, cursor: this.cursor, ...typeof rawSnapshot.rawTranscriptSeq === "number" ? { rawTranscriptSeq: rawSnapshot.rawTranscriptSeq } : {}, ...typeof rawSnapshot.totalRawMessages === "number" ? { totalRawMessages: rawSnapshot.totalRawMessages } : {} }); } async readRawSnapshotAsync() { if (this.cursor === void 0 && typeof this.limit === "number") { const snapshot = await readRecentSessionMessagesWithStatsAsync(this.target.sessionId, this.target.storePath, this.target.sessionFile, { ...resolveSessionHistoryTailReadOptions(this.limit) }); return { rawMessages: snapshot.messages, rawTranscriptSeq: snapshot.totalMessages, totalRawMessages: snapshot.totalMessages }; } return { rawMessages: await readSessionMessagesAsync(this.target.sessionId, this.target.storePath, this.target.sessionFile, { mode: "full", reason: "session history cursor pagination" }) }; } }; //#endregion export { buildSessionHistorySnapshot as n, resolveSessionHistoryTailReadOptions as r, SessionHistorySseState as t };