From a71306e2d0856cc3f66ed2ddc1712f60e5db2deb Mon Sep 17 00:00:00 2001 From: oleg Date: Mon, 29 Sep 2025 13:35:20 +0200 Subject: [PATCH] feat(editor): Add workflow execution to AI Workflow Builder (no-changelog) (#20037) Co-authored-by: Giulio Andreini --- .../src/tools/prompts/main-agent.prompt.ts | 42 ++- .../AskAssistantChat/AskAssistantChat.vue | 1 + .../AskAssistantChat.test.ts.snap | 10 + .../frontend/@n8n/i18n/src/locales/en.json | 10 + .../AskAssistant/Agent/AskAssistantBuild.vue | 70 ++++- .../AskAssistant/Agent/ExecuteMessage.test.ts | 245 +++++++++++++++++ .../AskAssistant/Agent/ExecuteMessage.vue | 260 ++++++++++++++++++ .../AskAssistant/Agent/NodeIssueItem.test.ts | 63 +++++ .../AskAssistant/Agent/NodeIssueItem.vue | 104 +++++++ .../buttons/CanvasRunWorkflowButton.vue | 16 +- .../src/stores/builder.store.test.ts | 205 ++++++++++---- .../editor-ui/src/stores/builder.store.ts | 79 +++++- .../src/stores/workflows.store.test.ts | 87 ++++++ .../editor-ui/src/stores/workflows.store.ts | 62 +++++ .../frontend/editor-ui/src/views/NodeView.vue | 8 +- 15 files changed, 1191 insertions(+), 71 deletions(-) create mode 100644 packages/frontend/editor-ui/src/components/AskAssistant/Agent/ExecuteMessage.test.ts create mode 100644 packages/frontend/editor-ui/src/components/AskAssistant/Agent/ExecuteMessage.vue create mode 100644 packages/frontend/editor-ui/src/components/AskAssistant/Agent/NodeIssueItem.test.ts create mode 100644 packages/frontend/editor-ui/src/components/AskAssistant/Agent/NodeIssueItem.vue diff --git a/packages/@n8n/ai-workflow-builder.ee/src/tools/prompts/main-agent.prompt.ts b/packages/@n8n/ai-workflow-builder.ee/src/tools/prompts/main-agent.prompt.ts index 4ec5a59248d..0f4c2d18c1b 100644 --- a/packages/@n8n/ai-workflow-builder.ee/src/tools/prompts/main-agent.prompt.ts +++ b/packages/@n8n/ai-workflow-builder.ee/src/tools/prompts/main-agent.prompt.ts @@ -362,24 +362,42 @@ update_node_parameters({{ const responsePatterns = ` -IMPORTANT: Only provide ONE response AFTER all tool execution is complete. +IMPORTANT: Only provide ONE response AFTER all tool executions are complete. -Response format: +EXCEPTION - Error handling: +When tool execution fails, provide a brief acknowledgment before attempting fixes: +- "The workflow hit an error. Let me debug this." +- "Execution failed. Let me trace the issue." +- "Got a workflow error. Investigating now." +- Or similar brief phrases +Then proceed with debugging/fixing without additional commentary. + +Response format conditions: +- Include "**âš™ī¸ How to Setup**" section ONLY if this is the initial workflow creation +- Include "**📝 What's changed**" section ONLY for non-initial modifications (skip for first workflow creation) +- Skip setup section for minor tweaks, bug fixes, or cosmetic changes + +When changes section is included: +**📝 What's changed** +- Brief bullets highlighting key modifications made +- Focus on functional changes, not technical implementation details + +When setup section is included: **âš™ī¸ How to Setup** (numbered format) -- List credentials and parameters that need to configured -- Only list incomplete tasks that need user action (skip what's already configured) +- List only parameter placeholders requiring user configuration +- Include only incomplete tasks needing user action (skip pre-configured items) +- IMPORTANT: NEVER instruct user to set-up authentication or credentials for nodes - this will be handled in the UI +- IMPORTANT: Focus on workflow-specific parameters/placeholders only -**â„šī¸ How to Use** -- Only essential user actions (what to click, where to go) - -End with: "Let me know if you'd like to adjust anything." +Always end with: "Let me know if you'd like to adjust anything." ABSOLUTELY FORBIDDEN IN BUILDING MODE: -- Any text between tool calls +- Any text between tool calls (except error acknowledgments) - Progress updates during execution -- "Perfect!", "Now let me...", "Excellent!" -- Describing what was built -- Explaining workflow functionality +- Celebratory phrases ("Perfect!", "Now let me...", "Excellent!", "Great!") +- Describing what was built or explaining functionality +- Workflow narration or step-by-step commentary +- Status updates while tools are running `; diff --git a/packages/frontend/@n8n/design-system/src/components/AskAssistantChat/AskAssistantChat.vue b/packages/frontend/@n8n/design-system/src/components/AskAssistantChat/AskAssistantChat.vue index dc2ccbb8546..4e31f79049b 100644 --- a/packages/frontend/@n8n/design-system/src/components/AskAssistantChat/AskAssistantChat.vue +++ b/packages/frontend/@n8n/design-system/src/components/AskAssistantChat/AskAssistantChat.vue @@ -377,6 +377,7 @@ defineExpose({ +
renders chat with messages correctly 1`] = `
+ + @@ -445,6 +447,8 @@ exports[`AskAssistantChat > renders end of session chat correctly 1`] = ` + + @@ -530,6 +534,8 @@ exports[`AskAssistantChat > renders error message correctly with retry button 1` + + @@ -615,6 +621,8 @@ exports[`AskAssistantChat > renders message with code snippet 1`] = ` + + @@ -700,6 +708,8 @@ exports[`AskAssistantChat > renders streaming chat correctly 1`] = ` + + diff --git a/packages/frontend/@n8n/i18n/src/locales/en.json b/packages/frontend/@n8n/i18n/src/locales/en.json index 71fc0b9d462..859b9b09cc4 100644 --- a/packages/frontend/@n8n/i18n/src/locales/en.json +++ b/packages/frontend/@n8n/i18n/src/locales/en.json @@ -217,6 +217,16 @@ "aiAssistant.builder.canvasPrompt.startManually.title": "Start manually", "aiAssistant.builder.canvasPrompt.startManually.subTitle": "Add the first node", "aiAssistant.builder.streamAbortedMessage": "[Task aborted]", + "aiAssistant.builder.executeMessage.description": "Complete these steps before executing your workflow:", + "aiAssistant.builder.executeMessage.noIssues": "Your workflow is ready to be executed", + "aiAssistant.builder.executeMessage.validationTooltip": "Complete the steps above before executing", + "aiAssistant.builder.executeMessage.execute": "Execute and refine", + "aiAssistant.builder.executeMessage.noExecutionData": "Workflow execution could not be started. Please try again.", + "aiAssistant.builder.executeMessage.executionSuccess": "Workflow executed successfully.", + "aiAssistant.builder.executeMessage.executionFailedOnNode": "Workflow execution failed on node \"{nodeName}\": {errorMessage}", + "aiAssistant.builder.executeMessage.executionFailed": "Workflow execution failed: {errorMessage}", + "aiAssistant.builder.toast.title": "Send chat message to start the execution", + "aiAssistant.builder.toast.description": "Please send a message in the chat panel to start the execution of your workflow", "aiAssistant.assistant": "AI Assistant", "aiAssistant.newSessionModal.title.part1": "Start new", "aiAssistant.newSessionModal.title.part2": "session", diff --git a/packages/frontend/editor-ui/src/components/AskAssistant/Agent/AskAssistantBuild.vue b/packages/frontend/editor-ui/src/components/AskAssistant/Agent/AskAssistantBuild.vue index f3c0108cd80..42fec552b78 100644 --- a/packages/frontend/editor-ui/src/components/AskAssistant/Agent/AskAssistantBuild.vue +++ b/packages/frontend/editor-ui/src/components/AskAssistant/Agent/AskAssistantBuild.vue @@ -11,6 +11,7 @@ import { useWorkflowSaving } from '@/composables/useWorkflowSaving'; import type { RatingFeedback } from '@n8n/design-system/types/assistant'; import { isWorkflowUpdatedMessage } from '@n8n/design-system/types/assistant'; import { nodeViewEventBus } from '@/event-bus'; +import ExecuteMessage from './ExecuteMessage.vue'; import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper'; const emit = defineEmits<{ @@ -30,7 +31,6 @@ const { goToUpgrade } = usePageRedirectionHelper(); // Track processed workflow updates const processedWorkflowUpdates = ref(new Set()); const trackedTools = ref(new Set()); -const assistantChatRef = ref | null>(null); const workflowUpdated = ref<{ start: string; end: string } | undefined>(); const user = computed(() => ({ @@ -40,9 +40,19 @@ const user = computed(() => ({ const loadingMessage = computed(() => builderStore.assistantThinkingMessage); const currentRoute = computed(() => route.name); +const showExecuteMessage = computed(() => { + const builderUpdatedWorkflowMessageIndex = builderStore.chatMessages.findLastIndex( + (msg) => msg.type === 'workflow-updated', + ); + return ( + !builderStore.streaming && + workflowsStore.workflow.nodes.length > 0 && + builderUpdatedWorkflowMessageIndex > -1 + ); +}); const creditsQuota = computed(() => builderStore.creditsQuota); const creditsRemaining = computed(() => builderStore.creditsRemaining); -const showAskOwnerTooltip = computed(() => usersStore.isInstanceOwner !== false); +const showAskOwnerTooltip = computed(() => usersStore.isInstanceOwner); async function onUserMessage(content: string) { const isNewWorkflow = workflowsStore.isNewWorkflow; @@ -109,6 +119,56 @@ function trackWorkflowModifications() { } } +function onWorkflowExecuted() { + const executionData = workflowsStore.workflowExecutionData; + const executionStatus = executionData?.status ?? 'unknown'; + const errorNodeName = executionData?.data?.resultData.lastNodeExecuted; + const errorNodeType = errorNodeName + ? workflowsStore.workflow.nodes.find((node) => node.name === errorNodeName)?.type + : undefined; + + if (!executionData) { + builderStore.sendChatMessage({ + text: i18n.baseText('aiAssistant.builder.executeMessage.noExecutionData'), + type: 'execution', + executionStatus: 'error', + errorMessage: 'Workflow execution data missing after run attempt.', + }); + return; + } + + if (executionStatus === 'success') { + builderStore.sendChatMessage({ + text: i18n.baseText('aiAssistant.builder.executeMessage.executionSuccess'), + type: 'execution', + executionStatus, + }); + return; + } + + const executionError = executionData.data?.resultData.error?.message ?? 'Unknown error'; + const scopedErrorMessage = errorNodeName + ? i18n.baseText('aiAssistant.builder.executeMessage.executionFailedOnNode', { + interpolate: { + nodeName: errorNodeName, + errorMessage: executionError, + }, + }) + : i18n.baseText('aiAssistant.builder.executeMessage.executionFailed', { + interpolate: { errorMessage: executionError }, + }); + + const failureStatus = executionStatus === 'unknown' ? 'error' : executionStatus; + + builderStore.sendChatMessage({ + text: scopedErrorMessage, + type: 'execution', + errorMessage: executionError, + errorNodeType, + executionStatus: failureStatus, + }); +} + // Watch for workflow updates and apply them watch( () => builderStore.workflowMessages, @@ -186,7 +246,6 @@ watch(currentRoute, () => {