fix(editor): Simplify workflow payload to AI Assistant (no-changelog) (#11975)

This commit is contained in:
Milorad FIlipović 2024-12-02 11:53:21 +01:00 committed by GitHub
parent 8d71307da0
commit 0ffc8591a0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 176 additions and 5 deletions

View file

@ -2,6 +2,7 @@
import type { N8nLocale } from 'n8n-design-system/types';
export default {
'generic.retry': 'Retry',
'nds.auth.roles.owner': 'Owner',
'nds.userInfo.you': '(you)',
'nds.userSelect.selectUser': 'Select User',

View file

@ -1,8 +1,9 @@
import { describe, it, expect } from 'vitest';
import type { INode } from 'n8n-workflow';
import type { INode, IRunExecutionData, NodeConnectionType } from 'n8n-workflow';
import { useAIAssistantHelpers } from './useAIAssistantHelpers';
import { createTestingPinia } from '@pinia/testing';
import { setActivePinia } from 'pinia';
import type { IWorkflowDb } from '@/Interface';
const referencedNodesTestCases: Array<{ caseName: string; node: INode; expected: string[] }> = [
{
@ -76,6 +77,15 @@ const referencedNodesTestCases: Array<{ caseName: string; node: INode; expected:
name: 'document',
value: "={{ $('Edit Fields 2').item.json.document}}",
type: 'string',
typeVersion: 1,
},
{
parameters: {},
id: 'b5942df6-0160-4ef7-965d-57583acdc8aa',
name: 'Replace me with your logic',
type: 'n8n-nodes-base.noOp',
position: [520, 340],
typeVersion: 1,
},
],
},
@ -377,6 +387,121 @@ const referencedNodesTestCases: Array<{ caseName: string; node: INode; expected:
},
];
const testWorkflow: IWorkflowDb = {
id: 'MokOcBHON6KkPq6Y',
name: 'My Sub-Workflow 3',
active: false,
createdAt: -1,
updatedAt: -1,
connections: {
'Execute Workflow Trigger': {
main: [
[
{
node: 'Replace me with your logic',
type: 'main' as NodeConnectionType,
index: 0,
},
],
],
},
},
nodes: [
{
parameters: {
notice: '',
events: 'worklfow_call',
},
id: 'c055762a-8fe7-4141-a639-df2372f30060',
name: 'Execute Workflow Trigger',
type: 'n8n-nodes-base.executeWorkflowTrigger',
position: [260, 340],
typeVersion: 0,
},
{
parameters: {},
id: 'b5942df6-0160-4ef7-965d-57583acdc8aa',
name: 'Replace me with your logic',
type: 'n8n-nodes-base.noOp',
position: [520, 340],
typeVersion: 1,
},
],
settings: {
executionOrder: 'v1',
},
tags: [],
pinData: {},
versionId: '9f3263e3-d23d-4cc8-bff0-0fdecfbd82bf',
usedCredentials: [],
scopes: [
'workflow:create',
'workflow:delete',
'workflow:execute',
'workflow:list',
'workflow:move',
'workflow:read',
'workflow:share',
'workflow:update',
],
sharedWithProjects: [],
};
const testExecutionData: IRunExecutionData['resultData'] = {
runData: {
'When clicking Test workflow': [
{
hints: [],
startTime: 1732882780588,
executionTime: 4,
source: [],
executionStatus: 'success',
data: {
main: [
[
{
json: {},
pairedItem: {
item: 0,
},
},
],
],
},
},
],
'Edit Fields': [
{
hints: [],
startTime: 1732882780593,
executionTime: 0,
source: [
{
previousNode: 'When clicking Test workflow',
},
],
executionStatus: 'success',
data: {
main: [
[
{
json: {
something: 'here',
},
pairedItem: {
item: 0,
},
},
],
],
},
},
],
},
pinData: {},
lastNodeExecuted: 'Edit Fields',
};
describe.each(referencedNodesTestCases)('getReferencedNodes', (testCase) => {
let aiAssistantHelpers: ReturnType<typeof useAIAssistantHelpers>;
@ -390,3 +515,37 @@ describe.each(referencedNodesTestCases)('getReferencedNodes', (testCase) => {
expect(aiAssistantHelpers.getReferencedNodes(testCase.node)).toEqual(testCase.expected);
});
});
describe('Simplify assistant payloads', () => {
let aiAssistantHelpers: ReturnType<typeof useAIAssistantHelpers>;
beforeEach(() => {
setActivePinia(createTestingPinia());
aiAssistantHelpers = useAIAssistantHelpers();
});
it('simplifyWorkflowForAssistant: Should remove unnecessary properties from workflow object', () => {
const simplifiedWorkflow = aiAssistantHelpers.simplifyWorkflowForAssistant(testWorkflow);
const removedProperties = [
'createdAt',
'updatedAt',
'settings',
'versionId',
'usedCredentials',
'sharedWithProjects',
'pinData',
'scopes',
'tags',
];
removedProperties.forEach((property) => {
expect(simplifiedWorkflow).not.toHaveProperty(property);
});
});
it('simplifyResultData: Should remove data from nodes', () => {
const simplifiedResultData = aiAssistantHelpers.simplifyResultData(testExecutionData);
for (const nodeName of Object.keys(simplifiedResultData.runData)) {
expect(simplifiedResultData.runData[nodeName][0]).not.toHaveProperty('data');
}
});
});

View file

@ -16,6 +16,7 @@ import { useWorkflowsStore } from '@/stores/workflows.store';
import { useDataSchema } from './useDataSchema';
import { VIEWS } from '@/constants';
import { useI18n } from './useI18n';
import type { IWorkflowDb } from '@/Interface';
const CANVAS_VIEWS = [VIEWS.NEW_WORKFLOW, VIEWS.WORKFLOW, VIEWS.EXECUTION_DEBUG];
const EXECUTION_VIEWS = [VIEWS.EXECUTION_PREVIEW];
@ -225,13 +226,13 @@ export const useAIAssistantHelpers = () => {
simplifiedResultData.error = data.error;
}
// Map runData, excluding the `data` field from ITaskData
Object.keys(data.runData).forEach((key) => {
for (const key of Object.keys(data.runData)) {
const taskDataArray = data.runData[key];
simplifiedResultData.runData[key] = taskDataArray.map((taskData) => {
const { data: taskDataContent, ...taskDataWithoutData } = taskData;
return taskDataWithoutData;
});
});
}
// Handle lastNodeExecuted if it exists
if (data.lastNodeExecuted) {
simplifiedResultData.lastNodeExecuted = data.lastNodeExecuted;
@ -243,6 +244,13 @@ export const useAIAssistantHelpers = () => {
return simplifiedResultData;
}
const simplifyWorkflowForAssistant = (workflow: IWorkflowDb): Partial<IWorkflowDb> => ({
name: workflow.name,
active: workflow.active,
connections: workflow.connections,
nodes: workflow.nodes,
});
return {
processNodeForAssistant,
getNodeInfoForAssistant,
@ -252,5 +260,6 @@ export const useAIAssistantHelpers = () => {
getCurrentViewDescription,
getReferencedNodes,
simplifyResultData,
simplifyWorkflowForAssistant,
};
};

View file

@ -399,7 +399,9 @@ export const useAssistantStore = defineStore(STORES.ASSISTANT, () => {
authType: nodeInfo?.authType?.name,
}
: undefined,
currentWorkflow: workflowDataStale.value ? workflowsStore.workflow : undefined,
currentWorkflow: workflowDataStale.value
? assistantHelpers.simplifyWorkflowForAssistant(workflowsStore.workflow)
: undefined,
executionData:
workflowExecutionDataStale.value && executionResult
? assistantHelpers.simplifyResultData(executionResult)

View file

@ -19,7 +19,7 @@ export namespace ChatRequest {
export interface WorkflowContext {
executionSchema?: NodeExecutionSchema[];
currentWorkflow?: IWorkflowDb;
currentWorkflow?: Partial<IWorkflowDb>;
executionData?: IRunExecutionData['resultData'];
}