mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-20 11:22:15 +00:00
feat(editor): Align DynamicStructuredTool and DynamicTool name fields (#14604)
feat(Code Tool Node): Use node's name instead of separate name field as tool name feat(Vector Store Tool Node): Use node's name instead of separate name field as tool name feat(Custom n8n Workflow Tool Node): Use node's name instead of separate name field as tool name
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import { VectorStoreQATool } from 'langchain/tools';
|
||||
import { NodeConnectionTypes, type INode, type ISupplyDataFunctions } from 'n8n-workflow';
|
||||
|
||||
import { ToolVectorStore } from './ToolVectorStore.node';
|
||||
|
||||
describe('ToolVectorStore', () => {
|
||||
describe('supplyData', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('should read name from node name on version >=1.1', async () => {
|
||||
const node = new ToolVectorStore();
|
||||
|
||||
const supplyDataResult = await node.supplyData.call(
|
||||
mock<ISupplyDataFunctions>({
|
||||
getNode: jest.fn(() => mock<INode>({ typeVersion: 1.2, name: 'test tool' })),
|
||||
getNodeParameter: jest.fn().mockImplementation((paramName, _itemIndex) => {
|
||||
switch (paramName) {
|
||||
case 'name':
|
||||
return 'wrong_field';
|
||||
case 'topK':
|
||||
return 4;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}),
|
||||
getInputConnectionData: jest.fn().mockImplementation(async (inputName, _itemIndex) => {
|
||||
switch (inputName) {
|
||||
case NodeConnectionTypes.AiVectorStore:
|
||||
return jest.fn();
|
||||
case NodeConnectionTypes.AiLanguageModel:
|
||||
return {
|
||||
_modelType: jest.fn(),
|
||||
};
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}),
|
||||
}),
|
||||
0,
|
||||
);
|
||||
|
||||
expect(supplyDataResult.response).toBeInstanceOf(VectorStoreQATool);
|
||||
|
||||
const tool = supplyDataResult.response as VectorStoreQATool;
|
||||
expect(tool.name).toBe('test_tool');
|
||||
expect(tool.description).toContain('test_tool');
|
||||
});
|
||||
|
||||
it('should read name from name parameter on version <1.2', async () => {
|
||||
const node = new ToolVectorStore();
|
||||
|
||||
const supplyDataResult = await node.supplyData.call(
|
||||
mock<ISupplyDataFunctions>({
|
||||
getNode: jest.fn(() => mock<INode>({ typeVersion: 1, name: 'wrong name' })),
|
||||
getNodeParameter: jest.fn().mockImplementation((paramName, _itemIndex) => {
|
||||
switch (paramName) {
|
||||
case 'name':
|
||||
return 'test_tool';
|
||||
case 'topK':
|
||||
return 4;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}),
|
||||
getInputConnectionData: jest.fn().mockImplementation(async (inputName, _itemIndex) => {
|
||||
switch (inputName) {
|
||||
case NodeConnectionTypes.AiVectorStore:
|
||||
return jest.fn();
|
||||
case NodeConnectionTypes.AiLanguageModel:
|
||||
return {
|
||||
_modelType: jest.fn(),
|
||||
};
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}),
|
||||
}),
|
||||
0,
|
||||
);
|
||||
|
||||
expect(supplyDataResult.response).toBeInstanceOf(VectorStoreQATool);
|
||||
|
||||
const tool = supplyDataResult.response as VectorStoreQATool;
|
||||
expect(tool.name).toBe('test_tool');
|
||||
expect(tool.description).toContain('test_tool');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -10,6 +10,7 @@ import type {
|
||||
} from 'n8n-workflow';
|
||||
import { NodeConnectionTypes } from 'n8n-workflow';
|
||||
|
||||
import { nodeNameToToolName } from '@utils/helpers';
|
||||
import { logWrapper } from '@utils/logWrapper';
|
||||
import { getConnectionHintNoticeField } from '@utils/sharedFields';
|
||||
|
||||
@@ -20,7 +21,7 @@ export class ToolVectorStore implements INodeType {
|
||||
icon: 'fa:database',
|
||||
iconColor: 'black',
|
||||
group: ['transform'],
|
||||
version: [1],
|
||||
version: [1, 1.1],
|
||||
description: 'Answer questions with a vector store',
|
||||
defaults: {
|
||||
name: 'Answer questions with a vector store',
|
||||
@@ -68,6 +69,11 @@ export class ToolVectorStore implements INodeType {
|
||||
validateType: 'string-alphanumeric',
|
||||
description:
|
||||
'Name of the data in vector store. This will be used to fill this tool description: Useful for when you need to answer questions about [name]. Whenever you need information about [data description], you should ALWAYS use this. Input should be a fully formed question.',
|
||||
displayOptions: {
|
||||
show: {
|
||||
'@version': [1],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Description of Data',
|
||||
@@ -92,7 +98,12 @@ export class ToolVectorStore implements INodeType {
|
||||
};
|
||||
|
||||
async supplyData(this: ISupplyDataFunctions, itemIndex: number): Promise<SupplyData> {
|
||||
const name = this.getNodeParameter('name', itemIndex) as string;
|
||||
const node = this.getNode();
|
||||
const { typeVersion } = node;
|
||||
const name =
|
||||
typeVersion <= 1
|
||||
? (this.getNodeParameter('name', itemIndex) as string)
|
||||
: nodeNameToToolName(node);
|
||||
const toolDescription = this.getNodeParameter('description', itemIndex) as string;
|
||||
const topK = this.getNodeParameter('topK', itemIndex, 4) as number;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user