mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-26 05:04:05 -08:00
170 lines
4 KiB
TypeScript
170 lines
4 KiB
TypeScript
import { N8nTool } from './N8nTool';
|
|
import { createMockExecuteFunction } from 'n8n-nodes-base/test/nodes/Helpers';
|
|
import { z } from 'zod';
|
|
import type { INode } from 'n8n-workflow';
|
|
import { DynamicStructuredTool, DynamicTool } from '@langchain/core/tools';
|
|
|
|
const mockNode: INode = {
|
|
id: '1',
|
|
name: 'Mock node',
|
|
typeVersion: 2,
|
|
type: 'n8n-nodes-base.mock',
|
|
position: [60, 760],
|
|
parameters: {
|
|
operation: 'test',
|
|
},
|
|
};
|
|
|
|
describe('Test N8nTool wrapper as DynamicStructuredTool', () => {
|
|
it('should wrap a tool', () => {
|
|
const func = jest.fn();
|
|
|
|
const ctx = createMockExecuteFunction({}, mockNode);
|
|
|
|
const tool = new N8nTool(ctx, {
|
|
name: 'Dummy Tool',
|
|
description: 'A dummy tool for testing',
|
|
func,
|
|
schema: z.object({
|
|
foo: z.string(),
|
|
}),
|
|
});
|
|
|
|
expect(tool).toBeInstanceOf(DynamicStructuredTool);
|
|
});
|
|
});
|
|
|
|
describe('Test N8nTool wrapper - DynamicTool fallback', () => {
|
|
it('should convert the tool to a dynamic tool', () => {
|
|
const func = jest.fn();
|
|
|
|
const ctx = createMockExecuteFunction({}, mockNode);
|
|
|
|
const tool = new N8nTool(ctx, {
|
|
name: 'Dummy Tool',
|
|
description: 'A dummy tool for testing',
|
|
func,
|
|
schema: z.object({
|
|
foo: z.string(),
|
|
}),
|
|
});
|
|
|
|
const dynamicTool = tool.asDynamicTool();
|
|
|
|
expect(dynamicTool).toBeInstanceOf(DynamicTool);
|
|
});
|
|
|
|
it('should format fallback description correctly', () => {
|
|
const func = jest.fn();
|
|
|
|
const ctx = createMockExecuteFunction({}, mockNode);
|
|
|
|
const tool = new N8nTool(ctx, {
|
|
name: 'Dummy Tool',
|
|
description: 'A dummy tool for testing',
|
|
func,
|
|
schema: z.object({
|
|
foo: z.string(),
|
|
bar: z.number().optional(),
|
|
qwe: z.boolean().describe('Boolean description'),
|
|
}),
|
|
});
|
|
|
|
const dynamicTool = tool.asDynamicTool();
|
|
|
|
expect(dynamicTool.description).toContain('foo: (description: , type: string, required: true)');
|
|
expect(dynamicTool.description).toContain(
|
|
'bar: (description: , type: number, required: false)',
|
|
);
|
|
|
|
expect(dynamicTool.description).toContain(
|
|
'qwe: (description: Boolean description, type: boolean, required: true)',
|
|
);
|
|
});
|
|
|
|
it('should handle empty parameter list correctly', () => {
|
|
const func = jest.fn();
|
|
|
|
const ctx = createMockExecuteFunction({}, mockNode);
|
|
|
|
const tool = new N8nTool(ctx, {
|
|
name: 'Dummy Tool',
|
|
description: 'A dummy tool for testing',
|
|
func,
|
|
schema: z.object({}),
|
|
});
|
|
|
|
const dynamicTool = tool.asDynamicTool();
|
|
|
|
expect(dynamicTool.description).toEqual('A dummy tool for testing');
|
|
});
|
|
|
|
it('should parse correct parameters', async () => {
|
|
const func = jest.fn();
|
|
|
|
const ctx = createMockExecuteFunction({}, mockNode);
|
|
|
|
const tool = new N8nTool(ctx, {
|
|
name: 'Dummy Tool',
|
|
description: 'A dummy tool for testing',
|
|
func,
|
|
schema: z.object({
|
|
foo: z.string().describe('Foo description'),
|
|
bar: z.number().optional(),
|
|
}),
|
|
});
|
|
|
|
const dynamicTool = tool.asDynamicTool();
|
|
|
|
const testParameters = { foo: 'some value' };
|
|
|
|
await dynamicTool.func(JSON.stringify(testParameters));
|
|
|
|
expect(func).toHaveBeenCalledWith(testParameters);
|
|
});
|
|
|
|
it('should recover when 1 parameter is passed directly', async () => {
|
|
const func = jest.fn();
|
|
|
|
const ctx = createMockExecuteFunction({}, mockNode);
|
|
|
|
const tool = new N8nTool(ctx, {
|
|
name: 'Dummy Tool',
|
|
description: 'A dummy tool for testing',
|
|
func,
|
|
schema: z.object({
|
|
foo: z.string().describe('Foo description'),
|
|
}),
|
|
});
|
|
|
|
const dynamicTool = tool.asDynamicTool();
|
|
|
|
const testParameter = 'some value';
|
|
|
|
await dynamicTool.func(testParameter);
|
|
|
|
expect(func).toHaveBeenCalledWith({ foo: testParameter });
|
|
});
|
|
|
|
it('should recover when JS object is passed instead of JSON', async () => {
|
|
const func = jest.fn();
|
|
|
|
const ctx = createMockExecuteFunction({}, mockNode);
|
|
|
|
const tool = new N8nTool(ctx, {
|
|
name: 'Dummy Tool',
|
|
description: 'A dummy tool for testing',
|
|
func,
|
|
schema: z.object({
|
|
foo: z.string().describe('Foo description'),
|
|
}),
|
|
});
|
|
|
|
const dynamicTool = tool.asDynamicTool();
|
|
|
|
await dynamicTool.func('{ foo: "some value" }');
|
|
|
|
expect(func).toHaveBeenCalledWith({ foo: 'some value' });
|
|
});
|
|
});
|