UNPKG

n8n

Version:

n8n Workflow Automation Tool

250 lines 8.96 kB
"use strict"; 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 isV2Content(content) { return content !== null && typeof content === 'object' && !Array.isArray(content); } function extractTextFromContent(content) { if (typeof content === 'string') return content; if (!isV2Content(content)) return ''; if (content.content) return content.content; if (content.parts) { return content.parts .filter((p) => p.type === 'text' && p.text) .map((p) => p.text) .join(''); } return ''; } function extractReasoningFromContent(content) { if (typeof content === 'string') return ''; if (!isV2Content(content)) return ''; if (content.reasoning?.length) { return content.reasoning.map((r) => r.text).join(''); } if (content.parts) { return content.parts .filter((p) => p.type === 'reasoning' && p.text) .map((p) => p.text) .join(''); } return ''; } function extractParts(content) { if (!isV2Content(content)) return undefined; return content.parts; } function extractToolInvocations(content) { if (typeof content === 'string') return []; if (!isV2Content(content)) return []; if (content.toolInvocations?.length) return content.toolInvocations; if (content.parts) { return content.parts .filter((p) => p.type === 'tool-invocation' && p.toolInvocation) .map((p) => p.toolInvocation); } 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-invocation' && part.toolInvocation) { timeline.push({ type: 'tool-call', toolCallId: part.toolInvocation.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(mastraMessages, snapshots) { const messages = []; const snapshotList = snapshots ?? []; const assistantCount = mastraMessages.filter((m) => m.role === 'assistant').length; const hasSnapshotTimestamps = snapshotList.some((snapshot) => snapshot.createdAt !== undefined); const snapshotCount = snapshotList.length; const snapshotOffset = !hasSnapshotTimestamps && snapshotCount <= assistantCount ? assistantCount - snapshotCount : 0; let assistantIdx = 0; let nextSnapshotIdx = 0; const consumedSnapshots = new Set(); let lastUserMessageId; function appendChronologicalOrphansBefore(message) { if (!hasSnapshotTimestamps) return; 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) { if (!hasSnapshotTimestamps) { const snapshotIdx = assistantIdx - snapshotOffset; const snapshot = snapshotIdx >= 0 && snapshotIdx < snapshotList.length ? snapshotList[snapshotIdx] : undefined; if (snapshot) consumedSnapshots.add(snapshot); return snapshot; } appendChronologicalOrphansBefore(message); const snapshot = snapshotList[nextSnapshotIdx]; if (!snapshot) return undefined; const nextMessageTimestamp = getNextConversationMessageTimestamp(mastraMessages, 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 mastraMessages.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); assistantIdx++; 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