openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
140 lines (139 loc) • 6.48 kB
JavaScript
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 };