@n8n-plus/n8n-plus
Version:
n8n Workflow Automation Tool (plus edition)
254 lines • 8.88 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseStoredMessages = parseStoredMessages;
const api_types_1 = require("@n8n/api-types");
const internal_messages_1 = require("./internal-messages");
function extractTextFromContent(content) {
if (typeof content === 'string')
return content;
if (Array.isArray(content))
return extractTextFromParts(content);
return '';
}
function extractReasoningFromContent(content) {
if (typeof content === 'string')
return '';
if (Array.isArray(content))
return extractReasoningFromParts(content);
return '';
}
function extractTextFromParts(parts) {
return parts
.filter((p) => typeof p === 'object' &&
p !== null &&
'type' in p &&
p.type === 'text' &&
'text' in p &&
typeof p.text === 'string')
.map((p) => p.text)
.join('');
}
function extractReasoningFromParts(parts) {
return parts
.filter((p) => typeof p === 'object' &&
p !== null &&
'type' in p &&
p.type === 'reasoning' &&
'text' in p &&
typeof p.text === 'string')
.map((p) => p.text)
.join('');
}
function extractParts(content) {
if (Array.isArray(content))
return content.filter(isStoredContentPart);
return undefined;
}
function isStoredContentPart(value) {
return typeof value === 'object' && value !== null && 'type' in value;
}
function nativeToolPartToInvocation(part) {
if (part.type === 'tool-call' && part.toolCallId && part.toolName) {
return {
state: 'call',
toolCallId: part.toolCallId,
toolName: part.toolName,
args: part.input ?? {},
};
}
if (part.type === 'tool-result' && part.toolCallId && part.toolName) {
return {
state: 'result',
toolCallId: part.toolCallId,
toolName: part.toolName,
args: part.input ?? {},
result: part.result,
};
}
return undefined;
}
function extractToolInvocations(content) {
if (typeof content === 'string')
return [];
if (Array.isArray(content))
return content.filter(isStoredContentPart).flatMap((part) => {
const invocation = nativeToolPartToInvocation(part);
return invocation ? [invocation] : [];
});
return [];
}
function buildToolCallState(invocation) {
const isCompleted = invocation.state === 'result';
return {
toolCallId: invocation.toolCallId,
toolName: invocation.toolName,
args: invocation.args,
result: isCompleted ? invocation.result : undefined,
isLoading: !isCompleted,
renderHint: (0, api_types_1.getRenderHint)(invocation.toolName),
};
}
function buildTimeline(textContent, toolCalls, parts) {
if (parts?.length) {
const timeline = [];
for (const part of parts) {
if (part.type === 'text' && part.text) {
timeline.push({ type: 'text', content: part.text });
}
else if ((part.type === 'tool-call' || part.type === 'tool-result') && part.toolCallId) {
timeline.push({ type: 'tool-call', toolCallId: part.toolCallId });
}
}
return timeline;
}
const timeline = [];
for (const tc of toolCalls) {
timeline.push({ type: 'tool-call', toolCallId: tc.toolCallId });
}
if (textContent) {
timeline.push({ type: 'text', content: textContent });
}
return timeline;
}
function buildFlatAgentTree(textContent, reasoning, toolCalls, parts) {
return {
agentId: 'agent-001',
role: 'orchestrator',
status: 'completed',
textContent,
reasoning,
toolCalls,
children: [],
timeline: buildTimeline(textContent, toolCalls, parts),
};
}
function snapshotTimestamp(snapshot) {
return (snapshot.updatedAt ?? snapshot.createdAt ?? new Date(0)).toISOString();
}
function snapshotCreatedAtMs(snapshot) {
return snapshot.createdAt?.getTime();
}
function messageCreatedAtMs(message) {
return message.createdAt.getTime();
}
function getNextConversationMessageTimestamp(messages, currentIndex) {
for (let i = currentIndex + 1; i < messages.length; i++) {
const role = messages[i].role;
if (role === 'user' || role === 'assistant')
return messageCreatedAtMs(messages[i]);
}
return undefined;
}
function buildSnapshotMessage(snapshot) {
const groupId = snapshot.messageGroupId ?? snapshot.runId;
return {
id: groupId,
runId: snapshot.runId,
messageGroupId: snapshot.messageGroupId,
runIds: snapshot.runIds,
role: 'assistant',
createdAt: snapshotTimestamp(snapshot),
content: snapshot.tree.textContent,
reasoning: snapshot.tree.reasoning,
isStreaming: false,
agentTree: snapshot.tree,
};
}
function parseStoredMessages(storedMessages, snapshots) {
const messages = [];
const snapshotList = snapshots ?? [];
const conversationMessages = storedMessages.filter((message) => 'role' in message);
let nextSnapshotIdx = 0;
const consumedSnapshots = new Set();
let lastUserMessageId;
function appendChronologicalOrphansBefore(message) {
const messageTimestamp = messageCreatedAtMs(message);
while (nextSnapshotIdx < snapshotList.length) {
const snapshot = snapshotList[nextSnapshotIdx];
const snapshotTimestamp = snapshotCreatedAtMs(snapshot);
if (snapshotTimestamp === undefined || snapshotTimestamp >= messageTimestamp)
return;
consumedSnapshots.add(snapshot);
messages.push(buildSnapshotMessage(snapshot));
nextSnapshotIdx++;
}
}
function takeSnapshotForAssistant(message, messageIndex) {
appendChronologicalOrphansBefore(message);
const snapshot = snapshotList[nextSnapshotIdx];
if (!snapshot)
return undefined;
const nextMessageTimestamp = getNextConversationMessageTimestamp(conversationMessages, messageIndex);
const snapshotTimestamp = snapshotCreatedAtMs(snapshot);
if (snapshotTimestamp === undefined ||
(nextMessageTimestamp !== undefined && snapshotTimestamp > nextMessageTimestamp)) {
return undefined;
}
consumedSnapshots.add(snapshot);
nextSnapshotIdx++;
return snapshot;
}
for (const [messageIndex, msg] of conversationMessages.entries()) {
appendChronologicalOrphansBefore(msg);
const text = extractTextFromContent(msg.content);
if (msg.role === 'user') {
lastUserMessageId = msg.id;
const content = (0, internal_messages_1.cleanStoredUserMessage)(text);
if (content === null)
continue;
messages.push({
id: msg.id,
role: 'user',
createdAt: msg.createdAt.toISOString(),
content,
reasoning: '',
isStreaming: false,
});
continue;
}
if (msg.role === 'assistant') {
const reasoning = extractReasoningFromContent(msg.content);
const invocations = extractToolInvocations(msg.content);
const toolCalls = invocations.map(buildToolCallState);
const parts = extractParts(msg.content);
const snapshot = takeSnapshotForAssistant(msg, messageIndex);
const runId = snapshot?.runId ?? lastUserMessageId ?? msg.id;
const agentTree = snapshot?.tree ??
(toolCalls.length > 0 || text
? buildFlatAgentTree(text, reasoning, toolCalls, parts)
: undefined);
messages.push({
id: msg.id,
runId,
messageGroupId: snapshot?.messageGroupId,
runIds: snapshot?.runIds,
role: 'assistant',
createdAt: msg.createdAt.toISOString(),
content: text,
reasoning,
isStreaming: false,
agentTree,
});
continue;
}
}
for (const snapshot of snapshots ?? []) {
if (consumedSnapshots.has(snapshot))
continue;
messages.push(buildSnapshotMessage(snapshot));
}
const seen = new Set();
for (let i = messages.length - 1; i >= 0; i--) {
const gid = messages[i].messageGroupId;
if (!gid)
continue;
if (seen.has(gid)) {
messages.splice(i, 1);
}
else {
seen.add(gid);
}
}
return messages;
}
//# sourceMappingURL=message-parser.js.map