UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

140 lines (139 loc) 6.48 kB
import { o as resolveSessionStorePathCore } from "./paths-CXdaYWF_.js"; import { o as getOwnedSessionTranscriptWriterFence } from "./transcript-write-context-mhuh2Sos.js"; import { F as persistSessionTranscriptTurn, Pt as readActiveTranscriptEntryAnchor, V as sessionMatchesExpectedTranscriptTurn } from "./session-accessor-YsytfDtG.js"; import { D as readTranscriptEventMessage, E as readTranscriptEventId, m as findTranscriptEvent } from "./session-accessor.sqlite-transcript-store-B0zw3fAU.js"; import { x as loadExactSessionEntry } from "./session-accessor.sqlite-entry-CWk3jL7s.js"; import { a as isOpenClawDeliveryMirrorAssistantMessage } from "./transcript-only-openclaw-assistant-CVgy4bjA.js"; import { s as resolveSessionEntrySelection } from "./session-accessor.entry-CQ2WPpfn.js"; import "./sessions-9nxpeTwt.js"; import { i as retainAssistantModelContent, r as readAssistantDisplayContent } from "./assistant-display-content-BZljc_tT.js"; import { t as appendAssistantMessageToSessionTranscript } from "./transcript-Dv8-hmIo.js"; import { r as getAgentScopedMediaLocalRootsForSources } from "./local-roots-BphuGw-a.js"; import { t as createKeyedFifoLeaseRegistry } from "./keyed-fifo-lease-hVhofezd.js"; import { d as removeManagedOutgoingMediaBlocks, i as attachManagedOutgoingMediaToMessage, s as createManagedOutgoingMediaBlocks, u as prepareOutgoingMediaFromReplyPayload } from "./managed-image-attachments-CwIi4Xb-.js"; //#region src/gateway/internal-source-reply-persistence.ts const internalSourceReplyPersistenceLeases = createKeyedFifoLeaseRegistry(Symbol.for("openclaw.internalSourceReplyPersistenceLeases")); async function completePersistedInternalSourceReply(params) { if (!params.expectedSessionId || !params.idempotencyKey) return false; const storePath = resolveSessionStorePathCore(params.cfg.session?.store, { agentId: params.agentId }); const scope = { agentId: params.agentId, sessionId: params.expectedSessionId, sessionKey: params.sessionKey, storePath }; scope.sessionKey = resolveSessionEntrySelection(scope).normalizedKey; const expected = { expectedSessionId: params.expectedSessionId, ...getOwnedSessionTranscriptWriterFence({ sessionKey: scope.sessionKey }) }; const found = await findTranscriptEvent(scope, (event) => { const message = readTranscriptEventMessage(event); return message?.idempotencyKey === params.idempotencyKey && isOpenClawDeliveryMirrorAssistantMessage(message); }); if (!found) return false; const messageId = readTranscriptEventId(found.event); const message = readTranscriptEventMessage(found.event); if (!messageId || !message) throw new Error("Internal source reply transcript identity is unavailable"); const assertCurrentReplay = (entryId) => { if (!sessionMatchesExpectedTranscriptTurn(loadExactSessionEntry(scope), expected) || !readActiveTranscriptEntryAnchor({ ...scope, entryId })) throw new Error("Internal source reply no longer owns the active transcript"); }; const replay = await persistSessionTranscriptTurn(scope, { config: params.cfg, ...expected, messages: [{ eventId: messageId, message, idempotencyLookup: "scan", shouldAppendInTransaction: () => { assertCurrentReplay(messageId); return true; } }], touchSessionEntry: false, updateMode: "file-only", publishWhen: "always", onMessageCommitted: (result) => { assertCurrentReplay(result.messageId); attachSourceReplyMedia(result); } }); if (replay.rejectedReason || replay.messages.length === 0) throw new Error("Internal source reply no longer owns the active transcript"); return true; } function attachSourceReplyMedia(result) { const message = result.message; const blocks = readAssistantDisplayContent(message).filter((block) => block.type !== "text"); if (blocks.length > 0 && !attachManagedOutgoingMediaToMessage({ messageId: result.messageId, blocks })) throw new Error("Internal source reply media ownership could not be persisted"); } /** Persist the private WebChat source reply before its successful tool result becomes visible. */ async function persistInternalSourceReply(params) { const leaseKey = params.idempotencyKey ? JSON.stringify([ params.agentId ?? "", params.sessionKey, params.expectedSessionId ?? "", params.idempotencyKey ]) : void 0; const lease = leaseKey ? internalSourceReplyPersistenceLeases.reserve([leaseKey]) : void 0; await lease?.wait(); try { if (await completePersistedInternalSourceReply(params)) return; const media = prepareOutgoingMediaFromReplyPayload(params.payload); const mediaBlocks = await createManagedOutgoingMediaBlocks({ sessionKey: params.sessionKey, agentId: params.agentId, items: media, localRoots: getAgentScopedMediaLocalRootsForSources({ cfg: params.cfg, agentId: params.agentId, mediaSources: media.map((item) => item.url) }) }); let committed = false; try { const content = [...params.payload.text ? [{ type: "text", text: params.payload.text }] : [], ...mediaBlocks]; const writerFence = getOwnedSessionTranscriptWriterFence({ sessionKey: params.sessionKey }); const appended = await appendAssistantMessageToSessionTranscript({ agentId: params.agentId, sessionKey: params.sessionKey, ...params.expectedSessionId ? { expectedSessionId: params.expectedSessionId } : {}, ...writerFence?.expectedLifecycleRevision !== void 0 ? { expectedLifecycleRevision: writerFence.expectedLifecycleRevision } : {}, ...writerFence ? { expectedWriterRunId: writerFence.expectedWriterRunId } : {}, content: retainAssistantModelContent(content), displayContent: content, idempotencyKey: params.idempotencyKey, runId: params.runId, ...params.sourceReplyFinal !== void 0 ? { deliveryMirror: { kind: "message-tool-source-reply", final: params.sourceReplyFinal, ...params.toolCallId ? { toolCallId: params.toolCallId } : {}, ...params.sourceTurnId ? { sourceTurnId: params.sourceTurnId } : {} } } : {}, config: params.cfg, onMessageCommitted: (result) => { committed = result.appended; attachSourceReplyMedia(result); } }); if (!appended.ok) throw new Error(`Internal source reply persistence failed: ${appended.reason}`); } finally { if (!committed) await removeManagedOutgoingMediaBlocks({ blocks: mediaBlocks, messageId: null }); } } finally { lease?.release(); } } //#endregion export { persistInternalSourceReply };