n8n
Version:
n8n Workflow Automation Tool
223 lines • 8.19 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ComponentMapper = void 0;
const di_1 = require("@n8n/di");
const agent_chat_integration_1 = require("./agent-chat-integration");
const esm_loader_1 = require("./esm-loader");
class ComponentMapper {
async toCard(payload, runId, toolCallId, resumeSchema, shortenCallback, platform) {
const sdk = await (0, esm_loader_1.loadChatSdk)();
const integration = platform ? di_1.Container.get(agent_chat_integration_1.ChatIntegrationRegistry).get(platform) : undefined;
const components = integration?.normalizeComponents?.(payload.components) ?? payload.components;
const children = [];
const buttons = [];
const buttonIndex = { value: 0 };
const makeButton = async (label, rawValue, style) => {
let id = `resume:${runId}:${toolCallId}:${buttonIndex.value++}`;
let value = JSON.stringify(this.wrapValueForSchema(rawValue, resumeSchema));
if (shortenCallback) {
const shortened = await shortenCallback(id, value);
id = shortened.id;
value = shortened.value;
}
return sdk.Button({
id,
label,
style: style === 'danger' ? 'danger' : 'primary',
value,
});
};
for (const component of components) {
await this.appendComponent({
component,
sdk,
runId,
toolCallId,
children,
buttons,
makeButton,
});
}
if (buttons.length > 0) {
children.push(sdk.Actions(buttons));
}
const title = payload.title ?? payload.message;
return sdk.Card({ title, children: children });
}
async appendComponent(ctx) {
const { component, children, buttons, makeButton } = ctx;
switch (component.type) {
case 'button':
buttons.push(await makeButton(component.label ?? 'Action', component.value ?? '', component.style));
return;
case 'section':
await this.appendSection(ctx);
return;
case 'divider':
children.push(ctx.sdk.Divider());
return;
case 'image':
this.appendImage(ctx);
return;
case 'context':
this.appendContext(ctx);
return;
case 'select':
this.appendSelect(ctx);
return;
case 'radio_select':
this.appendRadioSelect(ctx);
return;
case 'fields':
this.appendFields(ctx);
return;
default:
return;
}
}
async appendSection({ component, sdk, children, makeButton, }) {
if (component.text) {
children.push(sdk.Section([sdk.CardText(component.text)]));
}
if (component.button) {
children.push(sdk.Actions([
await makeButton(component.button.label, component.button.value, component.button.style),
]));
}
}
appendImage({ component, sdk, children }) {
children.push(sdk.Image({
url: component.url,
alt: component.altText ?? 'image',
}));
}
appendContext({ component, sdk, children }) {
if (component.elements && Array.isArray(component.elements)) {
for (const el of component.elements) {
if (el.type === 'text' && el.text) {
children.push(sdk.CardText(el.text));
}
else if (el.type === 'image' && el.url) {
children.push(sdk.Image({ url: el.url, alt: el.altText ?? '' }));
}
}
}
else if (component.text) {
children.push(sdk.CardText(component.text));
}
}
appendSelect({ component, sdk, runId, toolCallId, children, }) {
children.push(sdk.Actions([
sdk.Select({
id: `ri-sel:${component.id ?? 'select'}:${runId}:${toolCallId}`,
label: component.label ?? 'Select',
placeholder: component.placeholder,
options: this.toSelectOptions(component),
}),
]));
}
appendRadioSelect({ component, sdk, runId, toolCallId, children, }) {
children.push(sdk.Actions([
sdk.RadioSelect({
id: `ri-sel:${component.id ?? 'radio'}:${runId}:${toolCallId}`,
label: component.label ?? 'Select',
options: this.toSelectOptions(component),
}),
]));
}
appendFields({ component, sdk, children }) {
const fieldElements = (component.fields ?? []).map((f) => sdk.Field({ label: f.label, value: f.value }));
children.push(sdk.Fields(fieldElements));
}
toSelectOptions(component) {
return (component.options ?? []).map((o) => ({
label: o.label,
value: o.value,
description: o.description,
}));
}
wrapValueForSchema(rawValue, resumeSchema) {
if (!resumeSchema || typeof resumeSchema !== 'object') {
try {
const parsed = JSON.parse(rawValue);
if (typeof parsed === 'object' && parsed !== null)
return parsed;
}
catch {
}
return { value: rawValue };
}
const schema = resumeSchema;
const props = schema.properties ?? {};
if ('approved' in props) {
return { approved: rawValue === 'true' };
}
if ('type' in props && 'value' in props) {
return { type: 'button', value: rawValue };
}
if ('values' in props) {
return { values: { action: rawValue } };
}
try {
const parsed = JSON.parse(rawValue);
if (typeof parsed === 'object' && parsed !== null)
return parsed;
}
catch {
}
return { value: rawValue };
}
async toCardOrMarkdown(message) {
if (typeof message === 'string')
return message;
if (message && typeof message === 'object' && 'components' in message) {
const sdk = await (0, esm_loader_1.loadChatSdk)();
const { components } = message;
const children = [];
for (const c of components) {
this.appendMarkdownChild(c, sdk, children);
}
return sdk.Card({ children: children });
}
return String(message);
}
appendMarkdownChild(c, sdk, children) {
switch (c.type) {
case 'section':
if (c.text)
children.push(sdk.Section([sdk.CardText(c.text)]));
return;
case 'divider':
children.push(sdk.Divider());
return;
case 'image':
if (c.url)
children.push(sdk.Image({ url: c.url, alt: c.altText ?? '' }));
return;
case 'context':
this.appendMarkdownContext(c, sdk, children);
return;
default:
if (c.text)
children.push(sdk.CardText(c.text));
return;
}
}
appendMarkdownContext(c, sdk, children) {
if (c.elements) {
for (const el of c.elements) {
if (el.type === 'text' && el.text) {
children.push(sdk.CardText(el.text));
}
else if (el.type === 'image' && el.url) {
children.push(sdk.Image({ url: el.url, alt: el.altText ?? '' }));
}
}
}
else if (c.text) {
children.push(sdk.CardText(c.text));
}
}
}
exports.ComponentMapper = ComponentMapper;
//# sourceMappingURL=component-mapper.js.map