n8n
Version:
n8n Workflow Automation Tool
159 lines • 5.49 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.executionToMessagesDto = executionToMessagesDto;
exports.executionsToMessagesDto = executionsToMessagesDto;
const is_record_1 = require("@n8n/utils/is-record");
function textPart(text) {
if (!text.trim())
return null;
return { type: 'text', text };
}
function textMessageDto(id, role, text, executionId) {
if (!text)
return null;
const contentPart = textPart(text);
if (!contentPart)
return null;
return {
id,
role,
content: [contentPart],
executionId,
};
}
function toolCallState(event) {
if (typeof event.endTime !== 'number' || event.endTime <= 0)
return undefined;
return event.success ? 'resolved' : 'rejected';
}
function isToolCallWithId(part) {
return part.type === 'tool-call' && typeof part.toolCallId === 'string' && part.toolCallId !== '';
}
function isTerminalToolCallPart(part) {
return (part.state === 'resolved' ||
part.state === 'rejected' ||
part.canceled === true ||
part.output !== undefined ||
part.error !== undefined);
}
function mergeTerminalToolCallPart(previous, terminal) {
return {
...previous,
...terminal,
input: previous.input ?? terminal.input,
startTime: previous.startTime ?? terminal.startTime,
endTime: terminal.endTime ?? previous.endTime,
canceled: terminal.canceled ?? previous.canceled,
};
}
function toolErrorMessage(output) {
if (typeof output === 'string' && output.trim())
return output;
if ((0, is_record_1.isRecord)(output)) {
const message = output.message;
if (typeof message === 'string' && message.trim())
return message;
const error = output.error;
if (typeof error === 'string' && error.trim())
return error;
}
if (output === undefined || output === null)
return undefined;
try {
return JSON.stringify(output);
}
catch {
return String(output);
}
}
function timelineToolCallToPart(event) {
const state = toolCallState(event);
const base = {
type: 'tool-call',
toolName: event.name,
toolCallId: event.toolCallId,
input: event.input,
...(event.startTime > 0 ? { startTime: event.startTime } : {}),
...(event.endTime > 0 ? { endTime: event.endTime } : {}),
};
if (state === undefined)
return base;
if (state === 'resolved') {
return {
...base,
state,
output: event.output,
};
}
return {
...base,
state,
error: toolErrorMessage(event.output) ?? `Tool "${event.name}" failed`,
};
}
function assistantContentFromExecution(execution) {
const content = [];
for (const event of execution.timeline ?? []) {
if (event.type === 'text') {
const part = textPart(event.content);
if (!part)
continue;
content.push(part);
}
else if (event.type === 'tool-call') {
content.push(timelineToolCallToPart(event));
}
}
return content;
}
function executionToMessagesDto(execution) {
const messages = [];
const userMessage = textMessageDto(`${execution.id}:user`, 'user', execution.userMessage, execution.id);
if (userMessage)
messages.push(userMessage);
const assistantContent = assistantContentFromExecution(execution);
if (assistantContent.length > 0) {
messages.push({
id: `${execution.id}:assistant`,
role: 'assistant',
content: assistantContent,
executionId: execution.id,
});
}
return messages;
}
function executionsToMessagesDto(executions) {
const messages = executions.flatMap(executionToMessagesDto);
const firstToolCallById = new Map();
const duplicatePartIndexesByMessage = new Map();
for (const message of messages) {
for (const [partIndex, part] of message.content.entries()) {
if (!isToolCallWithId(part))
continue;
const first = firstToolCallById.get(part.toolCallId);
if (!first) {
firstToolCallById.set(part.toolCallId, { message, partIndex });
continue;
}
const firstPart = first.message.content[first.partIndex];
if (!isToolCallWithId(firstPart))
continue;
if (isTerminalToolCallPart(part)) {
first.message.content[first.partIndex] = mergeTerminalToolCallPart(firstPart, part);
const indexes = duplicatePartIndexesByMessage.get(message) ?? new Set();
indexes.add(partIndex);
duplicatePartIndexesByMessage.set(message, indexes);
}
else if (isTerminalToolCallPart(firstPart)) {
const indexes = duplicatePartIndexesByMessage.get(message) ?? new Set();
indexes.add(partIndex);
duplicatePartIndexesByMessage.set(message, indexes);
}
}
}
for (const [message, duplicateIndexes] of duplicatePartIndexesByMessage) {
message.content = message.content.filter((_, index) => !duplicateIndexes.has(index));
}
return messages.filter((message) => message.content.length > 0);
}
//# sourceMappingURL=execution-to-message-mapper.js.map