fix(editor): Show previous nodes autocomplete in AI tool nodes (#11111)

This commit is contained in:
Elias Meire 2024-10-08 09:51:59 +02:00 committed by GitHub
parent 05d267954c
commit 8566b3a999
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 100 additions and 7 deletions

View file

@ -1,5 +1,16 @@
import { expressionWithFirstItem } from '../utils';
import { createTestNode, createTestWorkflowObject } from '@/__tests__/mocks';
import * as workflowHelpers from '@/composables/useWorkflowHelpers';
import { javascriptLanguage } from '@codemirror/lang-javascript';
import { autocompletableNodeNames, expressionWithFirstItem } from '../utils';
import type { MockInstance } from 'vitest';
import * as ndvStore from '@/stores/ndv.store';
import { NodeConnectionType, type IConnections } from 'n8n-workflow';
vi.mock('@/composables/useWorkflowHelpers', () => ({
useWorkflowHelpers: vi.fn().mockReturnValue({
getCurrentWorkflow: vi.fn(),
}),
}));
describe('completion utils', () => {
describe('expressionWithFirstItem', () => {
@ -43,4 +54,72 @@ describe('completion utils', () => {
expect(result).toBe(expected);
});
});
describe('autocompletableNodeNames', () => {
it('should work for normal nodes', () => {
const nodes = [
createTestNode({ name: 'Node 1' }),
createTestNode({ name: 'Node 2' }),
createTestNode({ name: 'Node 3' }),
];
const connections = {
[nodes[0].name]: {
[NodeConnectionType.Main]: [
[{ node: nodes[1].name, type: NodeConnectionType.Main, index: 0 }],
],
},
[nodes[1].name]: {
[NodeConnectionType.Main]: [
[{ node: nodes[2].name, type: NodeConnectionType.Main, index: 0 }],
],
},
};
const workflowObject = createTestWorkflowObject({
nodes,
connections,
});
const workflowHelpersMock: MockInstance = vi.spyOn(workflowHelpers, 'useWorkflowHelpers');
workflowHelpersMock.mockReturnValue({
getCurrentWorkflow: vi.fn(() => workflowObject),
});
const ndvStoreMock: MockInstance = vi.spyOn(ndvStore, 'useNDVStore');
ndvStoreMock.mockReturnValue({ activeNode: nodes[2] });
expect(autocompletableNodeNames()).toEqual(['Node 2', 'Node 1']);
});
it('should work for AI tool nodes', () => {
const nodes = [
createTestNode({ name: 'Normal Node' }),
createTestNode({ name: 'Agent' }),
createTestNode({ name: 'Tool' }),
];
const connections: IConnections = {
[nodes[0].name]: {
[NodeConnectionType.Main]: [
[{ node: nodes[1].name, type: NodeConnectionType.Main, index: 0 }],
],
},
[nodes[2].name]: {
[NodeConnectionType.AiMemory]: [
[{ node: nodes[1].name, type: NodeConnectionType.AiMemory, index: 0 }],
],
},
};
const workflowObject = createTestWorkflowObject({
nodes,
connections,
});
const workflowHelpersMock: MockInstance = vi.spyOn(workflowHelpers, 'useWorkflowHelpers');
workflowHelpersMock.mockReturnValue({
getCurrentWorkflow: vi.fn(() => workflowObject),
});
const ndvStoreMock: MockInstance = vi.spyOn(ndvStore, 'useNDVStore');
ndvStoreMock.mockReturnValue({ activeNode: nodes[2] });
expect(autocompletableNodeNames()).toEqual(['Normal Node']);
});
});
});

View file

@ -208,15 +208,29 @@ export const isSplitInBatchesAbsent = () =>
!useWorkflowsStore().workflow.nodes.some((node) => node.type === SPLIT_IN_BATCHES_NODE_TYPE);
export function autocompletableNodeNames() {
const activeNodeName = useNDVStore().activeNode?.name;
const activeNode = useNDVStore().activeNode;
if (!activeNodeName) return [];
if (!activeNode) return [];
return useWorkflowHelpers({ router: useRouter() })
.getCurrentWorkflow()
.getParentNodesByDepth(activeNodeName)
const activeNodeName = activeNode.name;
const workflow = useWorkflowHelpers({ router: useRouter() }).getCurrentWorkflow();
const nonMainChildren = workflow.getChildNodes(activeNodeName, 'ALL_NON_MAIN');
// This is a tool node, look for the nearest node with main connections
if (nonMainChildren.length > 0) {
return nonMainChildren.map(getPreviousNodes).flat();
}
return getPreviousNodes(activeNodeName);
}
export function getPreviousNodes(nodeName: string) {
const workflow = useWorkflowHelpers({ router: useRouter() }).getCurrentWorkflow();
return workflow
.getParentNodesByDepth(nodeName)
.map((node) => node.name)
.filter((name) => name !== activeNodeName);
.filter((name) => name !== nodeName);
}
/**