UNPKG

n8n

Version:

n8n Workflow Automation Tool

109 lines 5.49 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createRichInteractionTool = createRichInteractionTool; const agents_1 = require("@n8n/agents"); const di_1 = require("@n8n/di"); const zod_1 = require("zod"); const agent_chat_integration_1 = require("./agent-chat-integration"); const DEFAULT_SUPPORTED_COMPONENTS = ['section', 'button', 'divider', 'fields']; const RICH_INTERACTION_INSTRUCTION_FRAGMENT = 'When you have an image URL, gif, or content that benefits from visual ' + 'structure (key-value summaries, info cards, choice options), call the ' + 'rich_interaction tool to render it as a card instead of pasting URLs or ' + 'text directly. With no buttons or selects, the card simply displays and ' + 'you continue immediately — no need to wait for a user response.'; function buildDescription(supportedComponents) { const componentList = supportedComponents.join(', '); return [ 'Render a card to the user in chat. Use this whenever you want the user to ', 'SEE rich content rather than read plain text — images and gifs, formatted ', 'info cards, key-value summaries, or sets of choices.', '\n\n', `Available components: ${componentList}.`, '\n\n', 'Behavior depends on which components you include:', '\n', ' • Display-only (no button, select, or radio_select): the card renders in chat ', 'and you continue immediately. Use this for posting gifs, screenshots, summary cards.', '\n', ' • Interactive (any button, select, or radio_select): the card renders and the ', "run pauses; the user's click/selection is returned as your tool result.", '\n\n', 'Prefer this tool over plain text whenever you have an image URL, a gif, or ', 'content that benefits from visual structure.', ].join(''); } const selectOptionSchema = zod_1.z.object({ label: zod_1.z.string().describe('Display text'), value: zod_1.z.string().describe('Value returned on selection'), description: zod_1.z.string().optional().describe('Help text'), }); const fieldPairSchema = zod_1.z.object({ label: zod_1.z.string().describe('Field label'), value: zod_1.z.string().describe('Field value'), }); const resumeSchema = zod_1.z.discriminatedUnion('type', [ zod_1.z.object({ type: zod_1.z.literal('button'), value: zod_1.z.string().describe('The clicked button value'), }), zod_1.z.object({ type: zod_1.z.literal('select'), id: zod_1.z.string().describe('The select component ID'), value: zod_1.z.string().describe('The selected option value'), }), ]); function buildComponentSchema(supportedComponents) { const types = supportedComponents; const hasSelects = supportedComponents.includes('select') || supportedComponents.includes('radio_select'); const hasImage = supportedComponents.includes('image'); const shape = { type: zod_1.z.enum(types).describe('Component type'), text: zod_1.z.string().optional().describe('Text content (supports markdown)'), label: zod_1.z.string().optional().describe('Display label'), value: zod_1.z.string().optional().describe('Value returned on interaction'), style: zod_1.z.enum(['primary', 'danger']).optional().describe('Button style'), fields: zod_1.z.array(fieldPairSchema).optional().describe('Key-value pairs for fields component'), }; if (hasSelects) { shape.id = zod_1.z.string().optional().describe('Unique ID for select/radio_select'); shape.placeholder = zod_1.z.string().optional().describe('Placeholder text'); shape.options = zod_1.z .array(selectOptionSchema) .optional() .describe('Options for select/radio_select'); } if (hasImage) { shape.url = zod_1.z.string().optional().describe('Image URL'); shape.alt = zod_1.z.string().optional().describe('Image alt text'); } return zod_1.z.object(shape); } function createRichInteractionTool(platform) { const integration = platform ? di_1.Container.get(agent_chat_integration_1.ChatIntegrationRegistry).get(platform) : undefined; const supportedComponents = integration?.supportedComponents ?? DEFAULT_SUPPORTED_COMPONENTS; const description = buildDescription(supportedComponents); const componentSchema = buildComponentSchema(supportedComponents); const inputSchema = zod_1.z.object({ title: zod_1.z.string().optional().describe('Card title / header text'), message: zod_1.z.string().optional().describe('Subtitle or description text'), components: zod_1.z.array(componentSchema).describe('Card components to render'), }); const suspendSchema = inputSchema; return new agents_1.Tool('rich_interaction') .description(description) .systemInstruction(RICH_INTERACTION_INSTRUCTION_FRAGMENT) .input(inputSchema) .suspend(suspendSchema) .resume(resumeSchema) .handler(async (input, ctx) => { if (ctx.resumeData) { return ctx.resumeData; } const hasActionable = input.components.some((c) => c.type === 'button' || c.type === 'select' || c.type === 'radio_select'); if (!hasActionable) { return { displayOnly: true }; } return await ctx.suspend(input); }); } //# sourceMappingURL=rich-interaction-tool.js.map