mirror of
https://github.com/n8n-io/n8n.git
synced 2026-05-31 16:57:08 +02:00
Merge branch 'ADO-3305' into ADO-3304
This commit is contained in:
commit
8531f9cbe5
1
.github/workflows/e2e-reusable.yml
vendored
1
.github/workflows/e2e-reusable.yml
vendored
|
|
@ -161,7 +161,6 @@ jobs:
|
|||
env:
|
||||
NODE_OPTIONS: --dns-result-order=ipv4first
|
||||
CYPRESS_NODE_VIEW_VERSION: 2
|
||||
N8N_FOLDERS_ENABLED: true
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
E2E_TESTS: true
|
||||
|
|
|
|||
|
|
@ -22,6 +22,31 @@ export function getFolderCards() {
|
|||
export function getFolderCard(name: string) {
|
||||
return cy.getByTestId('folder-card-name').contains(name).closest('[data-test-id="folder-card"]');
|
||||
}
|
||||
|
||||
export function getWorkflowCards() {
|
||||
return cy.getByTestId('resources-list-item-workflow');
|
||||
}
|
||||
|
||||
export function getWorkflowCard(name: string) {
|
||||
return cy
|
||||
.getByTestId('workflow-card-name')
|
||||
.contains(name)
|
||||
.closest('[data-test-id="resources-list-item-workflow"]');
|
||||
}
|
||||
|
||||
export function getWorkflowCardActions(name: string) {
|
||||
return getWorkflowCard(name).find('[data-test-id="workflow-card-actions"]');
|
||||
}
|
||||
|
||||
export function getWorkflowCardActionItem(workflowName: string, actionName: string) {
|
||||
return getWorkflowCardActions(workflowName)
|
||||
.find('span[aria-controls]')
|
||||
.invoke('attr', 'aria-controls')
|
||||
.then((popperId) => {
|
||||
return cy.get(`#${popperId}`).find(`[data-test-id="action-${actionName}"]`);
|
||||
});
|
||||
}
|
||||
|
||||
export function getAddFolderButton() {
|
||||
return cy.getByTestId('add-folder-button');
|
||||
}
|
||||
|
|
@ -34,6 +59,10 @@ export function getHomeProjectBreadcrumb() {
|
|||
return getListBreadcrumbs().findChildByTestId('home-project');
|
||||
}
|
||||
|
||||
export function getListBreadcrumbItem(name: string) {
|
||||
return getListBreadcrumbs().findChildByTestId('breadcrumbs-item').contains(name);
|
||||
}
|
||||
|
||||
export function getVisibleListBreadcrumbs() {
|
||||
return getListBreadcrumbs().findChildByTestId('breadcrumbs-item');
|
||||
}
|
||||
|
|
@ -94,13 +123,14 @@ export function getFolderCardActionToggle(folderName: string) {
|
|||
return getFolderCard(folderName).find('[data-test-id="folder-card-actions"]');
|
||||
}
|
||||
|
||||
export function getFolderCardActionItem(name: string) {
|
||||
return cy
|
||||
.getByTestId('folder-card-actions')
|
||||
export function getFolderCardActionItem(folderName: string, actionName: string) {
|
||||
return getFolderCard(folderName)
|
||||
.findChildByTestId('folder-card-actions')
|
||||
.filter(':visible')
|
||||
.find('span[aria-controls]')
|
||||
.invoke('attr', 'aria-controls')
|
||||
.then((popperId) => {
|
||||
return cy.get(`#${popperId}`).find(`[data-test-id="action-${name}"]`);
|
||||
return cy.get(`#${popperId}`).find(`[data-test-id="action-${actionName}"]`);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -108,10 +138,18 @@ export function getFolderDeleteModal() {
|
|||
return cy.getByTestId('deleteFolder-modal');
|
||||
}
|
||||
|
||||
export function getMoveFolderModal() {
|
||||
return cy.getByTestId('moveFolder-modal');
|
||||
}
|
||||
|
||||
export function getDeleteRadioButton() {
|
||||
return cy.getByTestId('delete-content-radio');
|
||||
}
|
||||
|
||||
export function getTransferContentRadioButton() {
|
||||
return cy.getByTestId('transfer-content-radio');
|
||||
}
|
||||
|
||||
export function getConfirmDeleteInput() {
|
||||
return getFolderDeleteModal().findChildByTestId('delete-data-input').find('input');
|
||||
}
|
||||
|
|
@ -119,6 +157,61 @@ export function getConfirmDeleteInput() {
|
|||
export function getDeleteFolderModalConfirmButton() {
|
||||
return getFolderDeleteModal().findChildByTestId('confirm-delete-folder-button');
|
||||
}
|
||||
|
||||
export function getProjectEmptyState() {
|
||||
return cy.getByTestId('list-empty-state');
|
||||
}
|
||||
|
||||
export function getFolderEmptyState() {
|
||||
return cy.getByTestId('empty-folder-container');
|
||||
}
|
||||
|
||||
export function getProjectMenuItem(name: string) {
|
||||
if (name.toLowerCase() === 'personal') {
|
||||
return getPersonalProjectMenuItem();
|
||||
}
|
||||
return cy.getByTestId('project-menu-item').contains(name);
|
||||
}
|
||||
|
||||
export function getMoveToFolderDropdown() {
|
||||
return cy.getByTestId('move-to-folder-dropdown');
|
||||
}
|
||||
|
||||
export function getMoveToFolderOption(name: string) {
|
||||
return cy.getByTestId('move-to-folder-option').contains(name);
|
||||
}
|
||||
|
||||
export function getMoveToFolderInput() {
|
||||
return getMoveToFolderDropdown().find('input');
|
||||
}
|
||||
|
||||
export function getEmptyFolderDropdownMessage(text: string) {
|
||||
return cy.get('.el-select-dropdown__empty').contains(text);
|
||||
}
|
||||
|
||||
export function getMoveFolderConfirmButton() {
|
||||
return cy.getByTestId('confirm-move-folder-button');
|
||||
}
|
||||
|
||||
export function getMoveWorkflowModal() {
|
||||
return cy.getByTestId('moveFolder-modal');
|
||||
}
|
||||
|
||||
export function getWorkflowCardBreadcrumbs(workflowName: string) {
|
||||
return getWorkflowCard(workflowName).find('[data-test-id="workflow-card-breadcrumbs"]');
|
||||
}
|
||||
|
||||
export function getWorkflowCardBreadcrumbsEllipsis(workflowName: string) {
|
||||
return getWorkflowCardBreadcrumbs(workflowName).find('[data-test-id="ellipsis"]');
|
||||
}
|
||||
|
||||
export function getNewFolderNameInput() {
|
||||
return cy.get('.add-folder-modal').filter(':visible').find('input.el-input__inner');
|
||||
}
|
||||
|
||||
export function getNewFolderModalErrorMessage() {
|
||||
return cy.get('.el-message-box__errormsg').filter(':visible');
|
||||
}
|
||||
/**
|
||||
* Actions
|
||||
*/
|
||||
|
|
@ -136,8 +229,46 @@ export function createFolderFromListHeaderButton(folderName: string) {
|
|||
createNewFolder(folderName);
|
||||
}
|
||||
|
||||
export function createWorkflowFromEmptyState(workflowName?: string) {
|
||||
getFolderEmptyState().find('button').contains('Create Workflow').click();
|
||||
if (workflowName) {
|
||||
cy.getByTestId('workflow-name-input').type(`{selectAll}{backspace}${workflowName}`, {
|
||||
delay: 50,
|
||||
});
|
||||
}
|
||||
cy.getByTestId('workflow-save-button').click();
|
||||
successToast().should('exist');
|
||||
}
|
||||
|
||||
export function createWorkflowFromProjectHeader(folderName?: string, workflowName?: string) {
|
||||
cy.getByTestId('add-resource-workflow').click();
|
||||
if (workflowName) {
|
||||
cy.getByTestId('workflow-name-input').type(`{selectAll}{backspace}${workflowName}`, {
|
||||
delay: 50,
|
||||
});
|
||||
}
|
||||
cy.getByTestId('workflow-save-button').click();
|
||||
if (folderName) {
|
||||
successToast().should(
|
||||
'contain.text',
|
||||
`Workflow successfully created in "Personal", within "${folderName}"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function createWorkflowFromListDropdown(workflowName?: string) {
|
||||
getListActionsToggle().click();
|
||||
getListActionItem('create_workflow').click();
|
||||
if (workflowName) {
|
||||
cy.getByTestId('workflow-name-input').type(`{selectAll}{backspace}${workflowName}`, {
|
||||
delay: 50,
|
||||
});
|
||||
}
|
||||
cy.getByTestId('workflow-save-button').click();
|
||||
successToast().should('exist');
|
||||
}
|
||||
|
||||
export function createFolderFromProjectHeader(folderName: string) {
|
||||
getPersonalProjectMenuItem().click();
|
||||
getAddResourceDropdown().click();
|
||||
cy.getByTestId('action-folder').click();
|
||||
createNewFolder(folderName);
|
||||
|
|
@ -151,7 +282,7 @@ export function createFolderFromListDropdown(folderName: string) {
|
|||
|
||||
export function createFolderFromCardActions(parentName: string, folderName: string) {
|
||||
getFolderCardActionToggle(parentName).click();
|
||||
getFolderCardActionItem('create').click();
|
||||
getFolderCardActionItem(parentName, 'create').click();
|
||||
createNewFolder(folderName);
|
||||
}
|
||||
|
||||
|
|
@ -164,7 +295,7 @@ export function renameFolderFromListActions(folderName: string, newName: string)
|
|||
|
||||
export function renameFolderFromCardActions(folderName: string, newName: string) {
|
||||
getFolderCardActionToggle(folderName).click();
|
||||
getFolderCardActionItem('rename').click();
|
||||
getFolderCardActionItem(folderName, 'rename').click();
|
||||
renameFolder(newName);
|
||||
}
|
||||
|
||||
|
|
@ -194,9 +325,63 @@ export function deleteFolderWithContentsFromListDropdown(folderName: string) {
|
|||
|
||||
export function deleteFolderWithContentsFromCardDropdown(folderName: string) {
|
||||
getFolderCardActionToggle(folderName).click();
|
||||
getFolderCardActionItem('delete').click();
|
||||
getFolderCardActionItem(folderName, 'delete').click();
|
||||
confirmFolderDelete(folderName);
|
||||
}
|
||||
|
||||
export function deleteAndTransferFolderContentsFromCardDropdown(
|
||||
folderName: string,
|
||||
destinationName: string,
|
||||
) {
|
||||
getFolderCardActionToggle(folderName).click();
|
||||
getFolderCardActionItem(folderName, 'delete').click();
|
||||
deleteFolderAndMoveContents(folderName, destinationName);
|
||||
}
|
||||
|
||||
export function deleteAndTransferFolderContentsFromListDropdown(destinationName: string) {
|
||||
getListActionsToggle().click();
|
||||
getListActionItem('delete').click();
|
||||
getCurrentBreadcrumb()
|
||||
.find('span')
|
||||
.invoke('text')
|
||||
.then((currentFolderName) => {
|
||||
deleteFolderAndMoveContents(currentFolderName, destinationName);
|
||||
});
|
||||
}
|
||||
|
||||
export function createNewProject(projectName: string, options: { openAfterCreate?: boolean } = {}) {
|
||||
cy.getByTestId('universal-add').should('exist').click();
|
||||
cy.getByTestId('navigation-menu-item').contains('Project').click();
|
||||
cy.getByTestId('project-settings-name-input').type(projectName, { delay: 50 });
|
||||
cy.getByTestId('project-settings-save-button').click();
|
||||
successToast().should('exist');
|
||||
if (options.openAfterCreate) {
|
||||
getProjectMenuItem(projectName).click();
|
||||
}
|
||||
}
|
||||
|
||||
export function moveFolderFromFolderCardActions(folderName: string, destinationName: string) {
|
||||
getFolderCardActionToggle(folderName).click();
|
||||
getFolderCardActionItem(folderName, 'move').click();
|
||||
moveFolder(folderName, destinationName);
|
||||
}
|
||||
|
||||
export function moveFolderFromListActions(folderName: string, destinationName: string) {
|
||||
getFolderCard(folderName).click();
|
||||
getListActionsToggle().click();
|
||||
getListActionItem('move').click();
|
||||
moveFolder(folderName, destinationName);
|
||||
}
|
||||
|
||||
export function moveWorkflowToFolder(workflowName: string, folderName: string) {
|
||||
getWorkflowCardActions(workflowName).click();
|
||||
getWorkflowCardActionItem(workflowName, 'moveToFolder').click();
|
||||
getMoveFolderModal().should('be.visible');
|
||||
getMoveToFolderDropdown().click();
|
||||
getMoveToFolderInput().type(folderName, { delay: 50 });
|
||||
getMoveToFolderOption(folderName).should('be.visible').click();
|
||||
getMoveFolderConfirmButton().should('be.enabled').click();
|
||||
}
|
||||
/**
|
||||
* Utils
|
||||
*/
|
||||
|
|
@ -240,3 +425,34 @@ function confirmFolderDelete(folderName: string) {
|
|||
cy.wait('@deleteFolder');
|
||||
successToast().contains('Folder deleted').should('exist');
|
||||
}
|
||||
|
||||
function deleteFolderAndMoveContents(folderName: string, destinationName: string) {
|
||||
cy.intercept('DELETE', '/rest/projects/**').as('deleteFolder');
|
||||
getFolderDeleteModal().should('be.visible');
|
||||
getFolderDeleteModal().find('h1').first().contains(`Delete "${folderName}"`);
|
||||
getTransferContentRadioButton().should('be.visible').click();
|
||||
getMoveToFolderDropdown().click();
|
||||
getMoveToFolderInput().type(destinationName);
|
||||
getMoveToFolderOption(destinationName).click();
|
||||
getDeleteFolderModalConfirmButton().should('be.enabled').click();
|
||||
cy.wait('@deleteFolder');
|
||||
successToast().should('contain.text', `Data transferred to "${destinationName}"`);
|
||||
}
|
||||
|
||||
function moveFolder(folderName: string, destinationName: string) {
|
||||
cy.intercept('PATCH', '/rest/projects/**').as('moveFolder');
|
||||
getMoveFolderModal().should('be.visible');
|
||||
getMoveFolderModal().find('h1').first().contains(`Move "${folderName}" to another folder`);
|
||||
getMoveToFolderDropdown().click();
|
||||
// Try to find current folder in the dropdown
|
||||
getMoveToFolderInput().type(folderName, { delay: 50 });
|
||||
// Should not be available
|
||||
getEmptyFolderDropdownMessage('No folders found').should('exist');
|
||||
// Select destination folder
|
||||
getMoveToFolderInput().type(`{selectall}{backspace}${destinationName}`, {
|
||||
delay: 50,
|
||||
});
|
||||
getMoveToFolderOption(destinationName).should('be.visible').click();
|
||||
getMoveFolderConfirmButton().should('be.enabled').click();
|
||||
cy.wait('@moveFolder');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,11 +105,13 @@ export function getNodeOutputHint() {
|
|||
}
|
||||
|
||||
export function getWorkflowCards() {
|
||||
return cy.getByTestId('resources-list-item');
|
||||
return cy.getByTestId('resources-list-item-workflow');
|
||||
}
|
||||
|
||||
export function getWorkflowCard(workflowName: string) {
|
||||
return getWorkflowCards().contains(workflowName).parents('[data-test-id="resources-list-item"]');
|
||||
return getWorkflowCards()
|
||||
.contains(workflowName)
|
||||
.parents('[data-test-id="resources-list-item-workflow"]');
|
||||
}
|
||||
|
||||
export function getWorkflowCardContent(workflowName: string) {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ const switchBetweenEditorAndWorkflowlist = () => {
|
|||
cy.getByTestId('menu-item').first().click();
|
||||
cy.wait(['@getUsers', '@getWorkflows', '@getActiveWorkflows', '@getProjects']);
|
||||
|
||||
cy.getByTestId('resources-list-item').first().click();
|
||||
cy.getByTestId('resources-list-item-workflow').first().click();
|
||||
|
||||
workflowPage.getters.canvasNodes().first().should('be.visible');
|
||||
workflowPage.getters.canvasNodes().last().should('be.visible');
|
||||
|
|
|
|||
|
|
@ -514,7 +514,7 @@ describe('Projects', { disableAutoLogin: true }, () => {
|
|||
workflowsPage.getters.workflowCards().should('have.length', 3);
|
||||
workflowsPage.getters
|
||||
.workflowCards()
|
||||
.filter(':has(.n8n-badge:contains("Project"))')
|
||||
.filter(':has([data-test-id="workflow-card-breadcrumbs"]:contains("Project"))')
|
||||
.should('have.length', 2);
|
||||
workflowsPage.getters.workflowCardActions('Workflow in Home project').click();
|
||||
workflowsPage.getters.workflowMoveButton().click();
|
||||
|
|
|
|||
|
|
@ -4,6 +4,12 @@ import {
|
|||
createFolderFromListHeaderButton,
|
||||
createFolderFromProjectHeader,
|
||||
createFolderInsideFolder,
|
||||
createNewProject,
|
||||
createWorkflowFromEmptyState,
|
||||
createWorkflowFromListDropdown,
|
||||
createWorkflowFromProjectHeader,
|
||||
deleteAndTransferFolderContentsFromCardDropdown,
|
||||
deleteAndTransferFolderContentsFromListDropdown,
|
||||
deleteEmptyFolderFromCardDropdown,
|
||||
deleteEmptyFolderFromListDropdown,
|
||||
deleteFolderWithContentsFromCardDropdown,
|
||||
|
|
@ -14,14 +20,27 @@ import {
|
|||
getFolderCardActionItem,
|
||||
getFolderCardActionToggle,
|
||||
getFolderCards,
|
||||
getFolderEmptyState,
|
||||
getHomeProjectBreadcrumb,
|
||||
getListBreadcrumbItem,
|
||||
getListBreadcrumbs,
|
||||
getMainBreadcrumbsEllipsis,
|
||||
getMainBreadcrumbsEllipsisMenuItems,
|
||||
getNewFolderModalErrorMessage,
|
||||
getNewFolderNameInput,
|
||||
getOverviewMenuItem,
|
||||
getPersonalProjectMenuItem,
|
||||
getProjectEmptyState,
|
||||
getProjectMenuItem,
|
||||
getVisibleListBreadcrumbs,
|
||||
getWorkflowCard,
|
||||
getWorkflowCardBreadcrumbs,
|
||||
getWorkflowCardBreadcrumbsEllipsis,
|
||||
getWorkflowCards,
|
||||
goToPersonalProject,
|
||||
moveFolderFromFolderCardActions,
|
||||
moveFolderFromListActions,
|
||||
moveWorkflowToFolder,
|
||||
renameFolderFromCardActions,
|
||||
renameFolderFromListActions,
|
||||
} from '../composables/folders';
|
||||
|
|
@ -32,6 +51,7 @@ describe('Folders', () => {
|
|||
before(() => {
|
||||
cy.resetDatabase();
|
||||
cy.enableFeature('sharing');
|
||||
cy.enableFeature('folders');
|
||||
cy.enableFeature('advancedPermissions');
|
||||
cy.enableFeature('projectRole:admin');
|
||||
cy.enableFeature('projectRole:editor');
|
||||
|
|
@ -44,6 +64,7 @@ describe('Folders', () => {
|
|||
|
||||
describe('Create and navigate folders', () => {
|
||||
it('should create folder from the project header', () => {
|
||||
getPersonalProjectMenuItem().click();
|
||||
createFolderFromProjectHeader('My Folder');
|
||||
getFolderCards().should('have.length.greaterThan', 0);
|
||||
// Clicking on the success toast should navigate to the folder
|
||||
|
|
@ -51,6 +72,33 @@ describe('Folders', () => {
|
|||
getCurrentBreadcrumb().should('contain.text', 'My Folder');
|
||||
});
|
||||
|
||||
it('should not allow illegal folder names', () => {
|
||||
// Validation logic is thoroughly tested in unit tests
|
||||
// Here we just make sure everything is working in the full UI
|
||||
const ILLEGAL_CHARACTERS_NAME = 'hello[';
|
||||
const ONLY_DOTS_NAME = '...';
|
||||
const REGULAR_NAME = 'My Folder';
|
||||
|
||||
getPersonalProjectMenuItem().click();
|
||||
getAddResourceDropdown().click();
|
||||
cy.getByTestId('action-folder').click();
|
||||
getNewFolderNameInput().type(ILLEGAL_CHARACTERS_NAME, { delay: 50 });
|
||||
getNewFolderModalErrorMessage().should(
|
||||
'contain.text',
|
||||
'Folder name cannot contain the following characters',
|
||||
);
|
||||
getNewFolderNameInput().clear();
|
||||
getNewFolderNameInput().type(ONLY_DOTS_NAME, { delay: 50 });
|
||||
getNewFolderModalErrorMessage().should(
|
||||
'contain.text',
|
||||
'Folder name cannot contain only dots',
|
||||
);
|
||||
getNewFolderNameInput().clear();
|
||||
getNewFolderModalErrorMessage().should('contain.text', 'Folder name cannot be empty');
|
||||
getNewFolderNameInput().type(REGULAR_NAME, { delay: 50 });
|
||||
getNewFolderModalErrorMessage().should('not.exist');
|
||||
});
|
||||
|
||||
it('should create folder from the list header button', () => {
|
||||
goToPersonalProject();
|
||||
// First create a folder so list appears
|
||||
|
|
@ -78,9 +126,9 @@ describe('Folders', () => {
|
|||
getFolderCard('Created from card dropdown').should('exist');
|
||||
createFolderFromCardActions('Created from card dropdown', 'Child Folder');
|
||||
successToast().should('exist');
|
||||
// Open parent folder to see the new child folder
|
||||
getFolderCard('Created from card dropdown').click();
|
||||
// Should be automatically navigated to the new folder
|
||||
getFolderCard('Child Folder').should('exist');
|
||||
getCurrentBreadcrumb().should('contain.text', 'Created from card dropdown');
|
||||
});
|
||||
|
||||
it('should navigate folders using breadcrumbs and dropdown menu', () => {
|
||||
|
|
@ -88,7 +136,7 @@ describe('Folders', () => {
|
|||
createFolderFromProjectHeader('Navigate Test');
|
||||
// Open folder using menu item
|
||||
getFolderCardActionToggle('Navigate Test').click();
|
||||
getFolderCardActionItem('open').click();
|
||||
getFolderCardActionItem('Navigate Test', 'open').click();
|
||||
getCurrentBreadcrumb().should('contain.text', 'Navigate Test');
|
||||
// Create new child folder and navigate to it
|
||||
createFolderFromListHeaderButton('Child Folder');
|
||||
|
|
@ -165,12 +213,72 @@ describe('Folders', () => {
|
|||
|
||||
// In personal, we should see previously created folders
|
||||
getPersonalProjectMenuItem().click();
|
||||
getAddResourceDropdown().click();
|
||||
cy.getByTestId('action-folder').should('exist');
|
||||
createFolderFromProjectHeader('Personal Folder');
|
||||
getFolderCards().should('exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Empty State', () => {
|
||||
it('should show project empty state when no folders exist', () => {
|
||||
createNewProject('Test empty project', { openAfterCreate: true });
|
||||
getProjectEmptyState().should('exist');
|
||||
});
|
||||
|
||||
it('should toggle folder empty state correctly', () => {
|
||||
createNewProject('Test empty folder', { openAfterCreate: true });
|
||||
createFolderFromProjectHeader('My Folder');
|
||||
getProjectEmptyState().should('not.exist');
|
||||
getFolderCard('My Folder').should('exist');
|
||||
getFolderCard('My Folder').click();
|
||||
getFolderEmptyState().should('exist');
|
||||
// Create a new workflow from the empty state
|
||||
createWorkflowFromEmptyState('My Workflow');
|
||||
// Toast should inform that the workflow was created in the folder
|
||||
successToast().should(
|
||||
'contain.text',
|
||||
'Workflow successfully created in "Test empty folder", within "My Folder"',
|
||||
);
|
||||
// Go back to the folder
|
||||
getProjectMenuItem('Test empty folder').click();
|
||||
getFolderCard('My Folder').should('exist');
|
||||
getFolderCard('My Folder').click();
|
||||
// Should not show empty state anymore
|
||||
getFolderEmptyState().should('not.exist');
|
||||
getWorkflowCards().should('have.length.greaterThan', 0);
|
||||
// Also when filtering and there are no results, empty state CTA should not show
|
||||
cy.getByTestId('resources-list-search').type('non-existing', { delay: 20 });
|
||||
getWorkflowCards().should('not.exist');
|
||||
getFolderEmptyState().should('not.exist');
|
||||
// But there should be a message saying that no results were found
|
||||
cy.getByTestId('resources-list-empty').should('exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Create workflows inside folders', () => {
|
||||
it('should create workflows in folders in all supported ways', () => {
|
||||
goToPersonalProject();
|
||||
createFolderFromProjectHeader('Workflows go here');
|
||||
// 1. From empty state
|
||||
getFolderCard('Workflows go here').should('exist').click();
|
||||
createWorkflowFromEmptyState('Created from empty state');
|
||||
goToPersonalProject();
|
||||
getFolderCard('Workflows go here').click();
|
||||
getWorkflowCard('Created from empty state').should('exist');
|
||||
// 2. From the project header
|
||||
createWorkflowFromProjectHeader('Workflows go here', 'Created from project header');
|
||||
goToPersonalProject();
|
||||
getFolderCard('Workflows go here').click();
|
||||
getWorkflowCard('Created from project header').should('exist');
|
||||
// 3. From list breadcrumbs
|
||||
createWorkflowFromListDropdown('Created from list breadcrumbs');
|
||||
goToPersonalProject();
|
||||
getFolderCard('Workflows go here').click();
|
||||
getWorkflowCard('Created from list breadcrumbs').should('exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Rename and delete folders', () => {
|
||||
it('should rename folder from main dropdown', () => {
|
||||
goToPersonalProject();
|
||||
|
|
@ -224,6 +332,175 @@ describe('Folders', () => {
|
|||
deleteFolderWithContentsFromCardDropdown('I also have family');
|
||||
});
|
||||
|
||||
// TODO: Once we have backend endpoint that lists project folders, test transfer when deleting
|
||||
it('should transfer contents when deleting non-empty folder - from card dropdown', () => {
|
||||
goToPersonalProject();
|
||||
createFolderFromProjectHeader('Move my contents');
|
||||
createFolderFromProjectHeader('Destination');
|
||||
createFolderInsideFolder('Child 1', 'Move my contents');
|
||||
getHomeProjectBreadcrumb().click();
|
||||
getFolderCard('Move my contents').should('exist');
|
||||
deleteAndTransferFolderContentsFromCardDropdown('Move my contents', 'Destination');
|
||||
getFolderCard('Destination').click();
|
||||
// Should show the contents of the moved folder
|
||||
getFolderCard('Child 1').should('exist');
|
||||
});
|
||||
|
||||
it('should transfer contents when deleting non-empty folder - from list breadcrumbs', () => {
|
||||
goToPersonalProject();
|
||||
createFolderFromProjectHeader('Move me too');
|
||||
createFolderFromProjectHeader('Destination 2');
|
||||
createFolderInsideFolder('Child 1', 'Move me too');
|
||||
deleteAndTransferFolderContentsFromListDropdown('Destination 2');
|
||||
getFolderCard('Destination').click();
|
||||
// Should show the contents of the moved folder
|
||||
getFolderCard('Child 1').should('exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Move folders and workflows', () => {
|
||||
it('should move empty folder to another folder - from folder card action', () => {
|
||||
goToPersonalProject();
|
||||
createFolderFromProjectHeader('Move me - I am empty');
|
||||
createFolderFromProjectHeader('Destination 3');
|
||||
moveFolderFromFolderCardActions('Move me - I am empty', 'Destination 3');
|
||||
getFolderCard('Destination 3').click();
|
||||
getFolderCard('Move me - I am empty').should('exist');
|
||||
getFolderCard('Move me - I am empty').click();
|
||||
getFolderEmptyState().should('exist');
|
||||
successToast().should('contain.text', 'Move me - I am empty has been moved to Destination 3');
|
||||
// Breadcrumbs should show the destination folder
|
||||
getListBreadcrumbItem('Destination 3').should('exist');
|
||||
});
|
||||
|
||||
it('should move folder with contents to another folder - from folder card action', () => {
|
||||
goToPersonalProject();
|
||||
createFolderFromProjectHeader('Move me - I have family');
|
||||
createFolderFromProjectHeader('Destination 4');
|
||||
// Create a workflow and a folder inside the folder
|
||||
createFolderInsideFolder('Child 1', 'Move me - I have family');
|
||||
createWorkflowFromProjectHeader('Move me - I have family');
|
||||
goToPersonalProject();
|
||||
// Move the folder
|
||||
moveFolderFromFolderCardActions('Move me - I have family', 'Destination 4');
|
||||
successToast().should(
|
||||
'contain.text',
|
||||
'Move me - I have family has been moved to Destination 4',
|
||||
);
|
||||
// Go to destination folder and check if contents are there
|
||||
getFolderCard('Destination 4').click();
|
||||
// Moved folder should be there
|
||||
getFolderCard('Move me - I have family').should('exist').click();
|
||||
// Both the workflow and the folder should be there
|
||||
getFolderCards().should('have.length', 1);
|
||||
getWorkflowCards().should('have.length', 1);
|
||||
// Breadcrumbs should show the destination folder
|
||||
getListBreadcrumbItem('Destination 4').should('exist');
|
||||
});
|
||||
|
||||
it('should move empty folder to another folder - from list breadcrumbs', () => {
|
||||
goToPersonalProject();
|
||||
createFolderFromProjectHeader('Move me too - I am empty');
|
||||
createFolderFromProjectHeader('Destination 5');
|
||||
moveFolderFromListActions('Move me too - I am empty', 'Destination 5');
|
||||
// Since we moved the current folder, we should be in the destination folder
|
||||
getCurrentBreadcrumb().should('contain.text', 'Destination 5');
|
||||
});
|
||||
|
||||
it('should move folder with contents to another folder - from list dropdown', () => {
|
||||
goToPersonalProject();
|
||||
createFolderFromProjectHeader('Move me - I have family 2');
|
||||
createFolderFromProjectHeader('Destination 6');
|
||||
// Create a workflow and a folder inside the folder
|
||||
createFolderInsideFolder('Child 1', 'Move me - I have family 2');
|
||||
createWorkflowFromProjectHeader('Move me - I have family 2');
|
||||
// Navigate back to folder
|
||||
goToPersonalProject();
|
||||
getFolderCard('Move me - I have family 2').should('exist');
|
||||
// Move the folder
|
||||
moveFolderFromListActions('Move me - I have family 2', 'Destination 6');
|
||||
// Since we moved the current folder, we should be in the destination folder
|
||||
getCurrentBreadcrumb().should('contain.text', 'Destination 6');
|
||||
// Moved folder should be there
|
||||
getFolderCard('Move me - I have family 2').should('exist').click();
|
||||
// After navigating to the moved folder, both the workflow and the folder should be there
|
||||
getFolderCards().should('have.length', 1);
|
||||
getWorkflowCards().should('have.length', 1);
|
||||
// Breadcrumbs should show the destination folder
|
||||
getListBreadcrumbItem('Destination 6').should('exist');
|
||||
});
|
||||
|
||||
it('should move folder to project root - from folder card action', () => {
|
||||
goToPersonalProject();
|
||||
createFolderFromProjectHeader('Test parent');
|
||||
createFolderInsideFolder('Move me to root', 'Test parent');
|
||||
moveFolderFromFolderCardActions('Move me to root', 'Personal');
|
||||
// Parent folder should be empty
|
||||
getFolderEmptyState().should('exist');
|
||||
// Child folder should be in the root
|
||||
goToPersonalProject();
|
||||
getFolderCard('Move me to root').should('exist');
|
||||
// Navigate to the moved folder and check breadcrumbs
|
||||
getFolderCard('Move me to root').click();
|
||||
getHomeProjectBreadcrumb().should('contain.text', 'Personal');
|
||||
getListBreadcrumbs().findChildByTestId('breadcrumbs-item').should('not.exist');
|
||||
getCurrentBreadcrumb().should('contain.text', 'Move me to root');
|
||||
});
|
||||
|
||||
it('should move workflow from project root to folder', () => {
|
||||
goToPersonalProject();
|
||||
createWorkflowFromProjectHeader(undefined, 'Move me');
|
||||
goToPersonalProject();
|
||||
createFolderFromProjectHeader('Workflow destination');
|
||||
moveWorkflowToFolder('Move me', 'Workflow destination');
|
||||
successToast().should('contain.text', 'Move me has been moved to Workflow destination');
|
||||
// Navigate to the destination folder
|
||||
getFolderCard('Workflow destination').click();
|
||||
// Moved workflow should be there
|
||||
getWorkflowCards().should('have.length', 1);
|
||||
getWorkflowCard('Move me').should('exist');
|
||||
});
|
||||
|
||||
it('should move workflow to another folder', () => {
|
||||
goToPersonalProject();
|
||||
createFolderFromProjectHeader('Moving workflow from here');
|
||||
createFolderFromProjectHeader('Moving workflow to here');
|
||||
getFolderCard('Moving workflow from here').click();
|
||||
createWorkflowFromProjectHeader(undefined, 'Move me');
|
||||
goToPersonalProject();
|
||||
getFolderCard('Moving workflow from here').click();
|
||||
getWorkflowCard('Move me').should('exist');
|
||||
moveWorkflowToFolder('Move me', 'Moving workflow to here');
|
||||
// Now folder should be empty
|
||||
getFolderEmptyState().should('exist');
|
||||
// Navigate to the destination folder
|
||||
getHomeProjectBreadcrumb().click();
|
||||
getFolderCard('Moving workflow to here').click();
|
||||
// Moved workflow should be there
|
||||
getWorkflowCards().should('have.length', 1);
|
||||
getWorkflowCard('Move me').should('exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Workflow card breadcrumbs', () => {
|
||||
it('should correctly show workflow card breadcrumbs', () => {
|
||||
createNewProject('Test workflow breadcrumbs', { openAfterCreate: true });
|
||||
createFolderFromProjectHeader('Parent Folder');
|
||||
createFolderInsideFolder('Child Folder', 'Parent Folder');
|
||||
getFolderCard('Child Folder').click();
|
||||
createFolderFromListHeaderButton('Child Folder 2');
|
||||
getFolderCard('Child Folder 2').click();
|
||||
createWorkflowFromEmptyState('Breadcrumbs Test');
|
||||
// Go to overview page
|
||||
getOverviewMenuItem().click();
|
||||
getWorkflowCard('Breadcrumbs Test').should('exist');
|
||||
getWorkflowCardBreadcrumbs('Breadcrumbs Test').should('exist');
|
||||
getWorkflowCardBreadcrumbsEllipsis('Breadcrumbs Test').should('exist');
|
||||
getWorkflowCardBreadcrumbsEllipsis('Breadcrumbs Test').realHover({ position: 'topLeft' });
|
||||
cy.get('[role=tooltip]').should('exist');
|
||||
cy.get('[role=tooltip]').should(
|
||||
'contain.text',
|
||||
'est workflow breadcrumbs / Parent Folder / Child Folder / Child Folder 2',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -19,12 +19,12 @@ export class WorkflowsPage extends BasePage {
|
|||
cy.getByTestId('add-resource-workflow').should('be.visible');
|
||||
return cy.getByTestId('add-resource-workflow');
|
||||
},
|
||||
workflowCards: () => cy.getByTestId('resources-list-item'),
|
||||
workflowCards: () => cy.getByTestId('resources-list-item-workflow'),
|
||||
workflowCard: (workflowName: string) =>
|
||||
this.getters
|
||||
.workflowCards()
|
||||
.contains(workflowName)
|
||||
.parents('[data-test-id="resources-list-item"]'),
|
||||
.parents('[data-test-id="resources-list-item-workflow"]'),
|
||||
workflowTags: (workflowName: string) =>
|
||||
this.getters.workflowCard(workflowName).findChildByTestId('workflow-card-tags'),
|
||||
workflowCardContent: (workflowName: string) =>
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ switch (scenario) {
|
|||
testCommand: 'cypress open',
|
||||
customEnv: {
|
||||
CYPRESS_NODE_VIEW_VERSION: 2,
|
||||
N8N_FOLDERS_ENABLED: true,
|
||||
},
|
||||
});
|
||||
break;
|
||||
|
|
@ -59,7 +58,6 @@ switch (scenario) {
|
|||
customEnv: {
|
||||
CYPRESS_NODE_VIEW_VERSION: 1,
|
||||
CYPRESS_BASE_URL: 'http://localhost:8080',
|
||||
N8N_FOLDERS_ENABLED: true,
|
||||
},
|
||||
});
|
||||
break;
|
||||
|
|
@ -71,7 +69,6 @@ switch (scenario) {
|
|||
customEnv: {
|
||||
CYPRESS_NODE_VIEW_VERSION: 2,
|
||||
CYPRESS_BASE_URL: 'http://localhost:8080',
|
||||
N8N_FOLDERS_ENABLED: true,
|
||||
},
|
||||
});
|
||||
break;
|
||||
|
|
@ -85,7 +82,6 @@ switch (scenario) {
|
|||
testCommand: `cypress run --headless ${specParam}`,
|
||||
customEnv: {
|
||||
CYPRESS_NODE_VIEW_VERSION: 2,
|
||||
N8N_FOLDERS_ENABLED: true,
|
||||
},
|
||||
});
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
const FileTypeSchema = z.enum(['credential', 'workflow', 'tags', 'variables', 'file']);
|
||||
const FileTypeSchema = z.enum(['credential', 'workflow', 'tags', 'variables', 'file', 'folders']);
|
||||
export const SOURCE_CONTROL_FILE_TYPE = FileTypeSchema.Values;
|
||||
|
||||
const FileStatusSchema = z.enum([
|
||||
|
|
|
|||
|
|
@ -1,14 +1,6 @@
|
|||
import { ColonSeparatedStringArray } from '../custom-types';
|
||||
import { Config, Env } from '../decorators';
|
||||
|
||||
class ColonSeparatedStringArray<T extends string = string> extends Array<T> {
|
||||
constructor(str: string) {
|
||||
super();
|
||||
const parsed = str.split(':') as this;
|
||||
const filtered = parsed.filter((i) => typeof i === 'string' && i.length);
|
||||
return filtered.length ? filtered : [];
|
||||
}
|
||||
}
|
||||
|
||||
@Config
|
||||
export class ExternalHooksConfig {
|
||||
/** Files containing external hooks. Multiple files can be separated by colon (":") */
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CommaSeperatedStringArray } from '../custom-types';
|
||||
import { Config, Env, Nested } from '../decorators';
|
||||
import { StringArray } from '../utils';
|
||||
|
||||
/** Scopes (areas of functionality) to filter logs by. */
|
||||
export const LOG_SCOPES = [
|
||||
|
|
@ -14,6 +14,7 @@ export const LOG_SCOPES = [
|
|||
'scaling',
|
||||
'waiting-executions',
|
||||
'task-runner',
|
||||
'insights',
|
||||
] as const;
|
||||
|
||||
export type LogScope = (typeof LOG_SCOPES)[number];
|
||||
|
|
@ -57,7 +58,7 @@ export class LoggingConfig {
|
|||
* @example `N8N_LOG_OUTPUT=console,file` will output to both console and file.
|
||||
*/
|
||||
@Env('N8N_LOG_OUTPUT')
|
||||
outputs: StringArray<'console' | 'file'> = ['console'];
|
||||
outputs: CommaSeperatedStringArray<'console' | 'file'> = ['console'];
|
||||
|
||||
@Nested
|
||||
file: FileLoggingConfig;
|
||||
|
|
@ -84,5 +85,5 @@ export class LoggingConfig {
|
|||
* `N8N_LOG_SCOPES=license,waiting-executions`
|
||||
*/
|
||||
@Env('N8N_LOG_SCOPES')
|
||||
scopes: StringArray<LogScope> = [];
|
||||
scopes: CommaSeperatedStringArray<LogScope> = [];
|
||||
}
|
||||
|
|
|
|||
19
packages/@n8n/config/src/custom-types.ts
Normal file
19
packages/@n8n/config/src/custom-types.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
abstract class StringArray<T extends string> extends Array<T> {
|
||||
constructor(str: string, delimiter: string) {
|
||||
super();
|
||||
const parsed = str.split(delimiter) as this;
|
||||
return parsed.filter((i) => typeof i === 'string' && i.length);
|
||||
}
|
||||
}
|
||||
|
||||
export class CommaSeperatedStringArray<T extends string> extends StringArray<T> {
|
||||
constructor(str: string) {
|
||||
super(str, ',');
|
||||
}
|
||||
}
|
||||
|
||||
export class ColonSeparatedStringArray<T extends string = string> extends StringArray<T> {
|
||||
constructor(str: string) {
|
||||
super(str, ':');
|
||||
}
|
||||
}
|
||||
|
|
@ -36,6 +36,7 @@ export { S3Config } from './configs/external-storage.config';
|
|||
export { LOG_SCOPES } from './configs/logging.config';
|
||||
export type { LogScope } from './configs/logging.config';
|
||||
export { WorkflowsConfig } from './configs/workflows.config';
|
||||
export * from './custom-types';
|
||||
|
||||
@Config
|
||||
export class GlobalConfig {
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
export class StringArray<T extends string> extends Array<T> {
|
||||
constructor(str: string) {
|
||||
super();
|
||||
const parsed = str.split(',') as StringArray<T>;
|
||||
return parsed.every((i) => typeof i === 'string') ? parsed : [];
|
||||
}
|
||||
}
|
||||
25
packages/@n8n/config/test/custom-types.test.ts
Normal file
25
packages/@n8n/config/test/custom-types.test.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { CommaSeperatedStringArray, ColonSeparatedStringArray } from '../src/custom-types';
|
||||
|
||||
describe('CommaSeperatedStringArray', () => {
|
||||
it('should parse comma-separated string into array', () => {
|
||||
const result = new CommaSeperatedStringArray('a,b,c');
|
||||
expect(result).toEqual(['a', 'b', 'c']);
|
||||
});
|
||||
|
||||
it('should handle empty strings', () => {
|
||||
const result = new CommaSeperatedStringArray('a,b,,,');
|
||||
expect(result).toEqual(['a', 'b']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ColonSeparatedStringArray', () => {
|
||||
it('should parse colon-separated string into array', () => {
|
||||
const result = new ColonSeparatedStringArray('a:b:c');
|
||||
expect(result).toEqual(['a', 'b', 'c']);
|
||||
});
|
||||
|
||||
it('should handle empty strings', () => {
|
||||
const result = new ColonSeparatedStringArray('a::b:::');
|
||||
expect(result).toEqual(['a', 'b']);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { NodeConnectionType, NodeOperationError } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';
|
||||
import type {
|
||||
INodeInputConfiguration,
|
||||
INodeInputFilter,
|
||||
|
|
@ -7,6 +7,7 @@ import type {
|
|||
INodeType,
|
||||
INodeTypeDescription,
|
||||
INodeProperties,
|
||||
NodeConnectionType,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { promptTypeOptions, textFromPreviousNode, textInput } from '@utils/descriptions';
|
||||
|
|
@ -46,14 +47,14 @@ function getInputs(
|
|||
inputs: SpecialInput[],
|
||||
): Array<NodeConnectionType | INodeInputConfiguration> => {
|
||||
const displayNames: { [key: string]: string } = {
|
||||
[NodeConnectionType.AiLanguageModel]: 'Model',
|
||||
[NodeConnectionType.AiMemory]: 'Memory',
|
||||
[NodeConnectionType.AiTool]: 'Tool',
|
||||
[NodeConnectionType.AiOutputParser]: 'Output Parser',
|
||||
ai_languageModel: 'Model',
|
||||
ai_memory: 'Memory',
|
||||
ai_tool: 'Tool',
|
||||
ai_outputParser: 'Output Parser',
|
||||
};
|
||||
|
||||
return inputs.map(({ type, filter }) => {
|
||||
const isModelType = type === NodeConnectionType.AiLanguageModel;
|
||||
const isModelType = type === ('ai_languageModel' as NodeConnectionType);
|
||||
let displayName = type in displayNames ? displayNames[type] : undefined;
|
||||
if (
|
||||
isModelType &&
|
||||
|
|
@ -65,11 +66,9 @@ function getInputs(
|
|||
type,
|
||||
displayName,
|
||||
required: isModelType,
|
||||
maxConnections: [
|
||||
NodeConnectionType.AiLanguageModel,
|
||||
NodeConnectionType.AiMemory,
|
||||
NodeConnectionType.AiOutputParser,
|
||||
].includes(type as NodeConnectionType)
|
||||
maxConnections: ['ai_languageModel', 'ai_memory', 'ai_outputParser'].includes(
|
||||
type as NodeConnectionType,
|
||||
)
|
||||
? 1
|
||||
: undefined,
|
||||
};
|
||||
|
|
@ -87,7 +86,7 @@ function getInputs(
|
|||
if (agent === 'conversationalAgent') {
|
||||
specialInputs = [
|
||||
{
|
||||
type: NodeConnectionType.AiLanguageModel,
|
||||
type: 'ai_languageModel',
|
||||
filter: {
|
||||
nodes: [
|
||||
'@n8n/n8n-nodes-langchain.lmChatAnthropic',
|
||||
|
|
@ -105,19 +104,19 @@ function getInputs(
|
|||
},
|
||||
},
|
||||
{
|
||||
type: NodeConnectionType.AiMemory,
|
||||
type: 'ai_memory',
|
||||
},
|
||||
{
|
||||
type: NodeConnectionType.AiTool,
|
||||
type: 'ai_tool',
|
||||
},
|
||||
{
|
||||
type: NodeConnectionType.AiOutputParser,
|
||||
type: 'ai_outputParser',
|
||||
},
|
||||
];
|
||||
} else if (agent === 'toolsAgent') {
|
||||
specialInputs = [
|
||||
{
|
||||
type: NodeConnectionType.AiLanguageModel,
|
||||
type: 'ai_languageModel',
|
||||
filter: {
|
||||
nodes: [
|
||||
'@n8n/n8n-nodes-langchain.lmChatAnthropic',
|
||||
|
|
@ -135,20 +134,20 @@ function getInputs(
|
|||
},
|
||||
},
|
||||
{
|
||||
type: NodeConnectionType.AiMemory,
|
||||
type: 'ai_memory',
|
||||
},
|
||||
{
|
||||
type: NodeConnectionType.AiTool,
|
||||
type: 'ai_tool',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
type: NodeConnectionType.AiOutputParser,
|
||||
type: 'ai_outputParser',
|
||||
},
|
||||
];
|
||||
} else if (agent === 'openAiFunctionsAgent') {
|
||||
specialInputs = [
|
||||
{
|
||||
type: NodeConnectionType.AiLanguageModel,
|
||||
type: 'ai_languageModel',
|
||||
filter: {
|
||||
nodes: [
|
||||
'@n8n/n8n-nodes-langchain.lmChatOpenAi',
|
||||
|
|
@ -157,57 +156,55 @@ function getInputs(
|
|||
},
|
||||
},
|
||||
{
|
||||
type: NodeConnectionType.AiMemory,
|
||||
type: 'ai_memory',
|
||||
},
|
||||
{
|
||||
type: NodeConnectionType.AiTool,
|
||||
type: 'ai_tool',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
type: NodeConnectionType.AiOutputParser,
|
||||
type: 'ai_outputParser',
|
||||
},
|
||||
];
|
||||
} else if (agent === 'reActAgent') {
|
||||
specialInputs = [
|
||||
{
|
||||
type: NodeConnectionType.AiLanguageModel,
|
||||
type: 'ai_languageModel',
|
||||
},
|
||||
{
|
||||
type: NodeConnectionType.AiTool,
|
||||
type: 'ai_tool',
|
||||
},
|
||||
{
|
||||
type: NodeConnectionType.AiOutputParser,
|
||||
type: 'ai_outputParser',
|
||||
},
|
||||
];
|
||||
} else if (agent === 'sqlAgent') {
|
||||
specialInputs = [
|
||||
{
|
||||
type: NodeConnectionType.AiLanguageModel,
|
||||
type: 'ai_languageModel',
|
||||
},
|
||||
{
|
||||
type: NodeConnectionType.AiMemory,
|
||||
type: 'ai_memory',
|
||||
},
|
||||
];
|
||||
} else if (agent === 'planAndExecuteAgent') {
|
||||
specialInputs = [
|
||||
{
|
||||
type: NodeConnectionType.AiLanguageModel,
|
||||
type: 'ai_languageModel',
|
||||
},
|
||||
{
|
||||
type: NodeConnectionType.AiTool,
|
||||
type: 'ai_tool',
|
||||
},
|
||||
{
|
||||
type: NodeConnectionType.AiOutputParser,
|
||||
type: 'ai_outputParser',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
if (hasOutputParser === false) {
|
||||
specialInputs = specialInputs.filter(
|
||||
(input) => input.type !== NodeConnectionType.AiOutputParser,
|
||||
);
|
||||
specialInputs = specialInputs.filter((input) => input.type !== 'ai_outputParser');
|
||||
}
|
||||
return [NodeConnectionType.Main, ...getInputData(specialInputs)];
|
||||
return ['main', ...getInputData(specialInputs)];
|
||||
}
|
||||
|
||||
const agentTypeProperty: INodeProperties = {
|
||||
|
|
@ -292,7 +289,7 @@ export class Agent implements INodeType {
|
|||
return getInputs(agent, hasOutputParser)
|
||||
})($parameter.agent, $parameter.hasOutputParser === undefined || $parameter.hasOutputParser === true)
|
||||
}}`,
|
||||
outputs: [NodeConnectionType.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
credentials: [
|
||||
{
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-credentials-name-unsuffixed
|
||||
|
|
@ -432,7 +429,7 @@ export class Agent implements INodeType {
|
|||
},
|
||||
},
|
||||
{
|
||||
displayName: `Connect an <a data-action='openSelectiveNodeCreator' data-action-parameter-connectiontype='${NodeConnectionType.AiOutputParser}'>output parser</a> on the canvas to specify the output format you require`,
|
||||
displayName: `Connect an <a data-action='openSelectiveNodeCreator' data-action-parameter-connectiontype='${NodeConnectionTypes.AiOutputParser}'>output parser</a> on the canvas to specify the output format you require`,
|
||||
name: 'notice',
|
||||
type: 'notice',
|
||||
default: '',
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { BaseChatMemory } from '@langchain/community/memory/chat_memory';
|
|||
import { PromptTemplate } from '@langchain/core/prompts';
|
||||
import { initializeAgentExecutorWithOptions } from 'langchain/agents';
|
||||
import type { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
|
||||
import { NodeConnectionType, NodeOperationError } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';
|
||||
|
||||
import { isChatInstance, getPromptInputByType, getConnectedTools } from '@utils/helpers';
|
||||
import { getOptionalOutputParser } from '@utils/output_parsers/N8nOutputParser';
|
||||
|
|
@ -16,13 +16,13 @@ export async function conversationalAgentExecute(
|
|||
nodeVersion: number,
|
||||
): Promise<INodeExecutionData[][]> {
|
||||
this.logger.debug('Executing Conversational Agent');
|
||||
const model = await this.getInputConnectionData(NodeConnectionType.AiLanguageModel, 0);
|
||||
const model = await this.getInputConnectionData(NodeConnectionTypes.AiLanguageModel, 0);
|
||||
|
||||
if (!isChatInstance(model)) {
|
||||
throw new NodeOperationError(this.getNode(), 'Conversational Agent requires Chat Model');
|
||||
}
|
||||
|
||||
const memory = (await this.getInputConnectionData(NodeConnectionType.AiMemory, 0)) as
|
||||
const memory = (await this.getInputConnectionData(NodeConnectionTypes.AiMemory, 0)) as
|
||||
| BaseChatMemory
|
||||
| undefined;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { BufferMemory, type BaseChatMemory } from 'langchain/memory';
|
|||
import {
|
||||
type IExecuteFunctions,
|
||||
type INodeExecutionData,
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
NodeOperationError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ export async function openAiFunctionsAgentExecute(
|
|||
): Promise<INodeExecutionData[][]> {
|
||||
this.logger.debug('Executing OpenAi Functions Agent');
|
||||
const model = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiLanguageModel,
|
||||
NodeConnectionTypes.AiLanguageModel,
|
||||
0,
|
||||
)) as ChatOpenAI;
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ export async function openAiFunctionsAgentExecute(
|
|||
'OpenAI Functions Agent requires OpenAI Chat Model',
|
||||
);
|
||||
}
|
||||
const memory = (await this.getInputConnectionData(NodeConnectionType.AiMemory, 0)) as
|
||||
const memory = (await this.getInputConnectionData(NodeConnectionTypes.AiMemory, 0)) as
|
||||
| BaseChatMemory
|
||||
| undefined;
|
||||
const tools = await getConnectedTools(this, nodeVersion >= 1.5, false);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { PlanAndExecuteAgentExecutor } from 'langchain/experimental/plan_and_exe
|
|||
import {
|
||||
type IExecuteFunctions,
|
||||
type INodeExecutionData,
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
NodeOperationError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ export async function planAndExecuteAgentExecute(
|
|||
): Promise<INodeExecutionData[][]> {
|
||||
this.logger.debug('Executing PlanAndExecute Agent');
|
||||
const model = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiLanguageModel,
|
||||
NodeConnectionTypes.AiLanguageModel,
|
||||
0,
|
||||
)) as BaseChatModel;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { AgentExecutor, ChatAgent, ZeroShotAgent } from 'langchain/agents';
|
|||
import {
|
||||
type IExecuteFunctions,
|
||||
type INodeExecutionData,
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
NodeOperationError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ export async function reActAgentAgentExecute(
|
|||
): Promise<INodeExecutionData[][]> {
|
||||
this.logger.debug('Executing ReAct Agent');
|
||||
|
||||
const model = (await this.getInputConnectionData(NodeConnectionType.AiLanguageModel, 0)) as
|
||||
const model = (await this.getInputConnectionData(NodeConnectionTypes.AiLanguageModel, 0)) as
|
||||
| BaseLanguageModel
|
||||
| BaseChatModel;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { SqlDatabase } from 'langchain/sql_db';
|
|||
import {
|
||||
type IExecuteFunctions,
|
||||
type INodeExecutionData,
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
NodeOperationError,
|
||||
type IDataObject,
|
||||
} from 'n8n-workflow';
|
||||
|
|
@ -32,7 +32,7 @@ export async function sqlAgentAgentExecute(
|
|||
this.logger.debug('Executing SQL Agent');
|
||||
|
||||
const model = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiLanguageModel,
|
||||
NodeConnectionTypes.AiLanguageModel,
|
||||
0,
|
||||
)) as BaseLanguageModel;
|
||||
const items = this.getInputData();
|
||||
|
|
@ -113,7 +113,7 @@ export async function sqlAgentAgentExecute(
|
|||
const toolkit = new SqlToolkit(dbInstance, model);
|
||||
const agentExecutor = createSqlAgent(model, toolkit, agentOptions);
|
||||
|
||||
const memory = (await this.getInputConnectionData(NodeConnectionType.AiMemory, 0)) as
|
||||
const memory = (await this.getInputConnectionData(NodeConnectionTypes.AiMemory, 0)) as
|
||||
| BaseChatMemory
|
||||
| undefined;
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import type { AgentAction, AgentFinish } from 'langchain/agents';
|
|||
import { AgentExecutor, createToolCallingAgent } from 'langchain/agents';
|
||||
import type { ToolsAgentAction } from 'langchain/dist/agents/tool_calling/output_parser';
|
||||
import { omit } from 'lodash';
|
||||
import { BINARY_ENCODING, jsonParse, NodeConnectionType, NodeOperationError } from 'n8n-workflow';
|
||||
import { BINARY_ENCODING, jsonParse, NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';
|
||||
import type { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
|
||||
import type { ZodObject } from 'zod';
|
||||
import { z } from 'zod';
|
||||
|
|
@ -275,7 +275,7 @@ export const getAgentStepsParser =
|
|||
* @returns The validated chat model
|
||||
*/
|
||||
export async function getChatModel(ctx: IExecuteFunctions): Promise<BaseChatModel> {
|
||||
const model = await ctx.getInputConnectionData(NodeConnectionType.AiLanguageModel, 0);
|
||||
const model = await ctx.getInputConnectionData(NodeConnectionTypes.AiLanguageModel, 0);
|
||||
if (!isChatInstance(model) || !model.bindTools) {
|
||||
throw new NodeOperationError(
|
||||
ctx.getNode(),
|
||||
|
|
@ -294,7 +294,7 @@ export async function getChatModel(ctx: IExecuteFunctions): Promise<BaseChatMode
|
|||
export async function getOptionalMemory(
|
||||
ctx: IExecuteFunctions,
|
||||
): Promise<BaseChatMemory | undefined> {
|
||||
return (await ctx.getInputConnectionData(NodeConnectionType.AiMemory, 0)) as
|
||||
return (await ctx.getInputConnectionData(NodeConnectionTypes.AiMemory, 0)) as
|
||||
| BaseChatMemory
|
||||
| undefined;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { AgentExecutor } from 'langchain/agents';
|
||||
import type { OpenAIToolType } from 'langchain/dist/experimental/openai_assistant/schema';
|
||||
import { OpenAIAssistantRunnable } from 'langchain/experimental/openai_assistant';
|
||||
import { NodeConnectionType, NodeOperationError } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';
|
||||
import type {
|
||||
IExecuteFunctions,
|
||||
INodeExecutionData,
|
||||
|
|
@ -44,10 +44,10 @@ export class OpenAiAssistant implements INodeType {
|
|||
},
|
||||
},
|
||||
inputs: [
|
||||
{ type: NodeConnectionType.Main },
|
||||
{ type: NodeConnectionType.AiTool, displayName: 'Tools' },
|
||||
{ type: NodeConnectionTypes.Main },
|
||||
{ type: NodeConnectionTypes.AiTool, displayName: 'Tools' },
|
||||
],
|
||||
outputs: [NodeConnectionType.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
credentials: [
|
||||
{
|
||||
name: 'openAiApi',
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import type {
|
|||
INodeType,
|
||||
INodeTypeDescription,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeApiError, NodeConnectionType, NodeOperationError } from 'n8n-workflow';
|
||||
import { NodeApiError, NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';
|
||||
|
||||
import { getPromptInputByType } from '@utils/helpers';
|
||||
import { getOptionalOutputParser } from '@utils/output_parsers/N8nOutputParser';
|
||||
|
|
@ -55,7 +55,7 @@ export class ChainLlm implements INodeType {
|
|||
},
|
||||
},
|
||||
inputs: `={{ ((parameter) => { ${getInputs.toString()}; return getInputs(parameter) })($parameter) }}`,
|
||||
outputs: [NodeConnectionType.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
credentials: [],
|
||||
properties: nodeProperties,
|
||||
};
|
||||
|
|
@ -73,7 +73,7 @@ export class ChainLlm implements INodeType {
|
|||
try {
|
||||
// Get the language model
|
||||
const llm = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiLanguageModel,
|
||||
NodeConnectionTypes.AiLanguageModel,
|
||||
0,
|
||||
)) as BaseLanguageModel;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import {
|
|||
HumanMessagePromptTemplate,
|
||||
SystemMessagePromptTemplate,
|
||||
} from '@langchain/core/prompts';
|
||||
import type { IDataObject, INodeProperties } from 'n8n-workflow';
|
||||
import { NodeConnectionType } from 'n8n-workflow';
|
||||
import type { IDataObject, INodeInputConfiguration, INodeProperties } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes } from 'n8n-workflow';
|
||||
|
||||
import { promptTypeOptions, textFromPreviousNode } from '@utils/descriptions';
|
||||
import { getTemplateNoticeField } from '@utils/sharedFields';
|
||||
|
|
@ -13,12 +13,12 @@ import { getTemplateNoticeField } from '@utils/sharedFields';
|
|||
* Dynamic input configuration generation based on node parameters
|
||||
*/
|
||||
export function getInputs(parameters: IDataObject) {
|
||||
const inputs = [
|
||||
{ displayName: '', type: NodeConnectionType.Main },
|
||||
const inputs: INodeInputConfiguration[] = [
|
||||
{ displayName: '', type: 'main' },
|
||||
{
|
||||
displayName: 'Model',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiLanguageModel,
|
||||
type: 'ai_languageModel',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
|
|
@ -29,7 +29,7 @@ export function getInputs(parameters: IDataObject) {
|
|||
if (hasOutputParser === undefined || hasOutputParser === true) {
|
||||
inputs.push({
|
||||
displayName: 'Output Parser',
|
||||
type: NodeConnectionType.AiOutputParser,
|
||||
type: 'ai_outputParser',
|
||||
maxConnections: 1,
|
||||
required: false,
|
||||
});
|
||||
|
|
@ -260,7 +260,7 @@ export const nodeProperties: INodeProperties[] = [
|
|||
],
|
||||
},
|
||||
{
|
||||
displayName: `Connect an <a data-action='openSelectiveNodeCreator' data-action-parameter-connectiontype='${NodeConnectionType.AiOutputParser}'>output parser</a> on the canvas to specify the output format you require`,
|
||||
displayName: `Connect an <a data-action='openSelectiveNodeCreator' data-action-parameter-connectiontype='${NodeConnectionTypes.AiOutputParser}'>output parser</a> on the canvas to specify the output format you require`,
|
||||
name: 'notice',
|
||||
type: 'notice',
|
||||
default: '',
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { HumanMessage } from '@langchain/core/messages';
|
|||
import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
|
||||
import { ChatOllama } from '@langchain/ollama';
|
||||
import type { IExecuteFunctions, IBinaryData } from 'n8n-workflow';
|
||||
import { NodeOperationError, NodeConnectionType, OperationalError } from 'n8n-workflow';
|
||||
import { NodeOperationError, NodeConnectionTypes, OperationalError } from 'n8n-workflow';
|
||||
|
||||
import type { MessageTemplate } from './types';
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ export async function createImageMessage({
|
|||
|
||||
const bufferData = await context.helpers.getBinaryDataBuffer(itemIndex, binaryDataKey);
|
||||
const model = (await context.getInputConnectionData(
|
||||
NodeConnectionType.AiLanguageModel,
|
||||
NodeConnectionTypes.AiLanguageModel,
|
||||
0,
|
||||
)) as BaseLanguageModel;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import { FakeChatModel } from '@langchain/core/utils/testing';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import type { IExecuteFunctions, INode } from 'n8n-workflow';
|
||||
import { NodeConnectionType } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes } from 'n8n-workflow';
|
||||
|
||||
import * as helperModule from '@utils/helpers';
|
||||
import * as outputParserModule from '@utils/output_parsers/N8nOutputParser';
|
||||
|
|
@ -64,7 +64,7 @@ describe('ChainLlm Node', () => {
|
|||
expect(node.description.version).toContain(1.5);
|
||||
expect(node.description.properties).toBeDefined();
|
||||
expect(node.description.inputs).toBeDefined();
|
||||
expect(node.description.outputs).toEqual([NodeConnectionType.Main]);
|
||||
expect(node.description.outputs).toEqual([NodeConnectionTypes.Main]);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { NodeConnectionType } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes } from 'n8n-workflow';
|
||||
|
||||
import { getInputs, nodeProperties } from '../methods/config';
|
||||
|
||||
|
|
@ -8,24 +8,24 @@ describe('config', () => {
|
|||
const inputs = getInputs({});
|
||||
|
||||
expect(inputs).toHaveLength(3);
|
||||
expect(inputs[0].type).toBe(NodeConnectionType.Main);
|
||||
expect(inputs[1].type).toBe(NodeConnectionType.AiLanguageModel);
|
||||
expect(inputs[2].type).toBe(NodeConnectionType.AiOutputParser);
|
||||
expect(inputs[0].type).toBe(NodeConnectionTypes.Main);
|
||||
expect(inputs[1].type).toBe(NodeConnectionTypes.AiLanguageModel);
|
||||
expect(inputs[2].type).toBe(NodeConnectionTypes.AiOutputParser);
|
||||
});
|
||||
|
||||
it('should exclude the OutputParser when hasOutputParser is false', () => {
|
||||
const inputs = getInputs({ hasOutputParser: false });
|
||||
|
||||
expect(inputs).toHaveLength(2);
|
||||
expect(inputs[0].type).toBe(NodeConnectionType.Main);
|
||||
expect(inputs[1].type).toBe(NodeConnectionType.AiLanguageModel);
|
||||
expect(inputs[0].type).toBe(NodeConnectionTypes.Main);
|
||||
expect(inputs[1].type).toBe(NodeConnectionTypes.AiLanguageModel);
|
||||
});
|
||||
|
||||
it('should include the OutputParser when hasOutputParser is true', () => {
|
||||
const inputs = getInputs({ hasOutputParser: true });
|
||||
|
||||
expect(inputs).toHaveLength(3);
|
||||
expect(inputs[2].type).toBe(NodeConnectionType.AiOutputParser);
|
||||
expect(inputs[2].type).toBe(NodeConnectionTypes.AiOutputParser);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
import type { BaseRetriever } from '@langchain/core/retrievers';
|
||||
import { createStuffDocumentsChain } from 'langchain/chains/combine_documents';
|
||||
import { createRetrievalChain } from 'langchain/chains/retrieval';
|
||||
import { NodeConnectionType, NodeOperationError, parseErrorMetadata } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes, NodeOperationError, parseErrorMetadata } from 'n8n-workflow';
|
||||
import {
|
||||
type INodeProperties,
|
||||
type IExecuteFunctions,
|
||||
|
|
@ -70,21 +70,21 @@ export class ChainRetrievalQa implements INodeType {
|
|||
},
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [
|
||||
NodeConnectionType.Main,
|
||||
NodeConnectionTypes.Main,
|
||||
{
|
||||
displayName: 'Model',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiLanguageModel,
|
||||
type: NodeConnectionTypes.AiLanguageModel,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Retriever',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiRetriever,
|
||||
type: NodeConnectionTypes.AiRetriever,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
outputs: [NodeConnectionType.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
credentials: [],
|
||||
properties: [
|
||||
getTemplateNoticeField(1960),
|
||||
|
|
@ -192,12 +192,12 @@ export class ChainRetrievalQa implements INodeType {
|
|||
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
|
||||
try {
|
||||
const model = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiLanguageModel,
|
||||
NodeConnectionTypes.AiLanguageModel,
|
||||
0,
|
||||
)) as BaseLanguageModel;
|
||||
|
||||
const retriever = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiRetriever,
|
||||
NodeConnectionTypes.AiRetriever,
|
||||
0,
|
||||
)) as BaseRetriever;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import type { BaseLanguageModel } from '@langchain/core/language_models/base';
|
|||
import type { BaseRetriever } from '@langchain/core/retrievers';
|
||||
import { FakeChatModel, FakeLLM, FakeRetriever } from '@langchain/core/utils/testing';
|
||||
import get from 'lodash/get';
|
||||
import type { IDataObject, IExecuteFunctions } from 'n8n-workflow';
|
||||
import { NodeConnectionType, NodeOperationError, UnexpectedError } from 'n8n-workflow';
|
||||
import type { IDataObject, IExecuteFunctions, NodeConnectionType } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes, NodeOperationError, UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import { ChainRetrievalQa } from '../ChainRetrievalQa.node';
|
||||
|
||||
|
|
@ -27,10 +27,10 @@ const createExecuteFunctionsMock = (
|
|||
};
|
||||
},
|
||||
getInputConnectionData(type: NodeConnectionType) {
|
||||
if (type === NodeConnectionType.AiLanguageModel) {
|
||||
if (type === NodeConnectionTypes.AiLanguageModel) {
|
||||
return fakeLlm;
|
||||
}
|
||||
if (type === NodeConnectionType.AiRetriever) {
|
||||
if (type === NodeConnectionTypes.AiRetriever) {
|
||||
return fakeRetriever;
|
||||
}
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { PromptTemplate } from '@langchain/core/prompts';
|
|||
import type { SummarizationChainParams } from 'langchain/chains';
|
||||
import { loadSummarizationChain } from 'langchain/chains';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeTypeBaseDescription,
|
||||
type IExecuteFunctions,
|
||||
type INodeExecutionData,
|
||||
|
|
@ -31,21 +31,21 @@ export class ChainSummarizationV1 implements INodeType {
|
|||
},
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [
|
||||
NodeConnectionType.Main,
|
||||
NodeConnectionTypes.Main,
|
||||
{
|
||||
displayName: 'Model',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiLanguageModel,
|
||||
type: NodeConnectionTypes.AiLanguageModel,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Document',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiDocument,
|
||||
type: NodeConnectionTypes.AiDocument,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
outputs: [NodeConnectionType.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
credentials: [],
|
||||
properties: [
|
||||
getTemplateNoticeField(1951),
|
||||
|
|
@ -167,11 +167,11 @@ export class ChainSummarizationV1 implements INodeType {
|
|||
const type = this.getNodeParameter('type', 0) as 'map_reduce' | 'stuff' | 'refine';
|
||||
|
||||
const model = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiLanguageModel,
|
||||
NodeConnectionTypes.AiLanguageModel,
|
||||
0,
|
||||
)) as BaseLanguageModel;
|
||||
|
||||
const documentInput = (await this.getInputConnectionData(NodeConnectionType.AiDocument, 0)) as
|
||||
const documentInput = (await this.getInputConnectionData(NodeConnectionTypes.AiDocument, 0)) as
|
||||
| N8nJsonLoader
|
||||
| Array<Document<Record<string, unknown>>>;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@ import type {
|
|||
INodeType,
|
||||
INodeTypeDescription,
|
||||
IDataObject,
|
||||
INodeInputConfiguration,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeConnectionType } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes } from 'n8n-workflow';
|
||||
|
||||
import { N8nBinaryLoader } from '@utils/N8nBinaryLoader';
|
||||
import { N8nJsonLoader } from '@utils/N8nJsonLoader';
|
||||
|
|
@ -24,12 +25,12 @@ import { REFINE_PROMPT_TEMPLATE, DEFAULT_PROMPT_TEMPLATE } from '../prompt';
|
|||
function getInputs(parameters: IDataObject) {
|
||||
const chunkingMode = parameters?.chunkingMode;
|
||||
const operationMode = parameters?.operationMode;
|
||||
const inputs = [
|
||||
{ displayName: '', type: NodeConnectionType.Main },
|
||||
const inputs: INodeInputConfiguration[] = [
|
||||
{ displayName: '', type: 'main' },
|
||||
{
|
||||
displayName: 'Model',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiLanguageModel,
|
||||
type: 'ai_languageModel',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
|
|
@ -37,7 +38,7 @@ function getInputs(parameters: IDataObject) {
|
|||
if (operationMode === 'documentLoader') {
|
||||
inputs.push({
|
||||
displayName: 'Document',
|
||||
type: NodeConnectionType.AiDocument,
|
||||
type: 'ai_document',
|
||||
required: true,
|
||||
maxConnections: 1,
|
||||
});
|
||||
|
|
@ -47,7 +48,7 @@ function getInputs(parameters: IDataObject) {
|
|||
if (chunkingMode === 'advanced') {
|
||||
inputs.push({
|
||||
displayName: 'Text Splitter',
|
||||
type: NodeConnectionType.AiTextSplitter,
|
||||
type: 'ai_textSplitter',
|
||||
required: false,
|
||||
maxConnections: 1,
|
||||
});
|
||||
|
|
@ -69,7 +70,7 @@ export class ChainSummarizationV2 implements INodeType {
|
|||
},
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: `={{ ((parameter) => { ${getInputs.toString()}; return getInputs(parameter) })($parameter) }}`,
|
||||
outputs: [NodeConnectionType.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
credentials: [],
|
||||
properties: [
|
||||
getTemplateNoticeField(1951),
|
||||
|
|
@ -327,7 +328,7 @@ export class ChainSummarizationV2 implements INodeType {
|
|||
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
|
||||
try {
|
||||
const model = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiLanguageModel,
|
||||
NodeConnectionTypes.AiLanguageModel,
|
||||
0,
|
||||
)) as BaseLanguageModel;
|
||||
|
||||
|
|
@ -356,7 +357,7 @@ export class ChainSummarizationV2 implements INodeType {
|
|||
// Use dedicated document loader input to load documents
|
||||
if (operationMode === 'documentLoader') {
|
||||
const documentInput = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiDocument,
|
||||
NodeConnectionTypes.AiDocument,
|
||||
0,
|
||||
)) as N8nJsonLoader | Array<Document<Record<string, unknown>>>;
|
||||
|
||||
|
|
@ -390,7 +391,7 @@ export class ChainSummarizationV2 implements INodeType {
|
|||
// In advanced mode user can connect text splitter node so we just retrieve it
|
||||
case 'advanced':
|
||||
textSplitter = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiTextSplitter,
|
||||
NodeConnectionTypes.AiTextSplitter,
|
||||
0,
|
||||
)) as TextSplitter | undefined;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { HumanMessage } from '@langchain/core/messages';
|
|||
import { ChatPromptTemplate, SystemMessagePromptTemplate } from '@langchain/core/prompts';
|
||||
import type { JSONSchema7 } from 'json-schema';
|
||||
import { OutputFixingParser, StructuredOutputParser } from 'langchain/output_parsers';
|
||||
import { jsonParse, NodeConnectionType, NodeOperationError } from 'n8n-workflow';
|
||||
import { jsonParse, NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';
|
||||
import type {
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
|
|
@ -51,15 +51,15 @@ export class InformationExtractor implements INodeType {
|
|||
name: 'Information Extractor',
|
||||
},
|
||||
inputs: [
|
||||
{ displayName: '', type: NodeConnectionType.Main },
|
||||
{ displayName: '', type: NodeConnectionTypes.Main },
|
||||
{
|
||||
displayName: 'Model',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiLanguageModel,
|
||||
type: NodeConnectionTypes.AiLanguageModel,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
outputs: [NodeConnectionType.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Text',
|
||||
|
|
@ -222,7 +222,7 @@ export class InformationExtractor implements INodeType {
|
|||
const items = this.getInputData();
|
||||
|
||||
const llm = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiLanguageModel,
|
||||
NodeConnectionTypes.AiLanguageModel,
|
||||
0,
|
||||
)) as BaseLanguageModel;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { BaseLanguageModel } from '@langchain/core/language_models/base';
|
|||
import { HumanMessage } from '@langchain/core/messages';
|
||||
import { SystemMessagePromptTemplate, ChatPromptTemplate } from '@langchain/core/prompts';
|
||||
import { OutputFixingParser, StructuredOutputParser } from 'langchain/output_parsers';
|
||||
import { NodeConnectionType, NodeOperationError } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
|
|
@ -24,7 +24,7 @@ const configuredOutputs = (parameters: INodeParameters, defaultCategories: strin
|
|||
const categories = (options?.categories as string) ?? defaultCategories;
|
||||
const categoriesArray = categories.split(',').map((cat) => cat.trim());
|
||||
|
||||
const ret = categoriesArray.map((cat) => ({ type: NodeConnectionType.Main, displayName: cat }));
|
||||
const ret = categoriesArray.map((cat) => ({ type: NodeConnectionTypes.Main, displayName: cat }));
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
|
@ -54,11 +54,11 @@ export class SentimentAnalysis implements INodeType {
|
|||
name: 'Sentiment Analysis',
|
||||
},
|
||||
inputs: [
|
||||
{ displayName: '', type: NodeConnectionType.Main },
|
||||
{ displayName: '', type: NodeConnectionTypes.Main },
|
||||
{
|
||||
displayName: 'Model',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiLanguageModel,
|
||||
type: NodeConnectionTypes.AiLanguageModel,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
|
|
@ -140,7 +140,7 @@ export class SentimentAnalysis implements INodeType {
|
|||
const items = this.getInputData();
|
||||
|
||||
const llm = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiLanguageModel,
|
||||
NodeConnectionTypes.AiLanguageModel,
|
||||
0,
|
||||
)) as BaseLanguageModel;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { BaseLanguageModel } from '@langchain/core/language_models/base';
|
|||
import { HumanMessage } from '@langchain/core/messages';
|
||||
import { SystemMessagePromptTemplate, ChatPromptTemplate } from '@langchain/core/prompts';
|
||||
import { OutputFixingParser, StructuredOutputParser } from 'langchain/output_parsers';
|
||||
import { NodeOperationError, NodeConnectionType } from 'n8n-workflow';
|
||||
import { NodeOperationError, NodeConnectionTypes } from 'n8n-workflow';
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
|
|
@ -22,9 +22,9 @@ const configuredOutputs = (parameters: INodeParameters) => {
|
|||
const categories = ((parameters.categories as IDataObject)?.categories as IDataObject[]) ?? [];
|
||||
const fallback = (parameters.options as IDataObject)?.fallback as string;
|
||||
const ret = categories.map((cat) => {
|
||||
return { type: NodeConnectionType.Main, displayName: cat.category };
|
||||
return { type: NodeConnectionTypes.Main, displayName: cat.category };
|
||||
});
|
||||
if (fallback === 'other') ret.push({ type: NodeConnectionType.Main, displayName: 'Other' });
|
||||
if (fallback === 'other') ret.push({ type: NodeConnectionTypes.Main, displayName: 'Other' });
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
|
@ -54,11 +54,11 @@ export class TextClassifier implements INodeType {
|
|||
name: 'Text Classifier',
|
||||
},
|
||||
inputs: [
|
||||
{ displayName: '', type: NodeConnectionType.Main },
|
||||
{ displayName: '', type: NodeConnectionTypes.Main },
|
||||
{
|
||||
displayName: 'Model',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiLanguageModel,
|
||||
type: NodeConnectionTypes.AiLanguageModel,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
|
|
@ -167,7 +167,7 @@ export class TextClassifier implements INodeType {
|
|||
const items = this.getInputData();
|
||||
|
||||
const llm = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiLanguageModel,
|
||||
NodeConnectionTypes.AiLanguageModel,
|
||||
0,
|
||||
)) as BaseLanguageModel;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { makeResolverFromLegacyOptions } from '@n8n/vm2';
|
|||
import { JavaScriptSandbox } from 'n8n-nodes-base/dist/nodes/Code/JavaScriptSandbox';
|
||||
import { getSandboxContext } from 'n8n-nodes-base/dist/nodes/Code/Sandbox';
|
||||
import { standardizeOutput } from 'n8n-nodes-base/dist/nodes/Code/utils';
|
||||
import { NodeOperationError, NodeConnectionType } from 'n8n-workflow';
|
||||
import { NodeOperationError, NodeConnectionTypes } from 'n8n-workflow';
|
||||
import type {
|
||||
IExecuteFunctions,
|
||||
INodeExecutionData,
|
||||
|
|
@ -24,16 +24,16 @@ const { NODE_FUNCTION_ALLOW_BUILTIN: builtIn, NODE_FUNCTION_ALLOW_EXTERNAL: exte
|
|||
|
||||
// TODO: Replace
|
||||
const connectorTypes = {
|
||||
[NodeConnectionType.AiChain]: 'Chain',
|
||||
[NodeConnectionType.AiDocument]: 'Document',
|
||||
[NodeConnectionType.AiEmbedding]: 'Embedding',
|
||||
[NodeConnectionType.AiLanguageModel]: 'Language Model',
|
||||
[NodeConnectionType.AiMemory]: 'Memory',
|
||||
[NodeConnectionType.AiOutputParser]: 'Output Parser',
|
||||
[NodeConnectionType.AiTextSplitter]: 'Text Splitter',
|
||||
[NodeConnectionType.AiTool]: 'Tool',
|
||||
[NodeConnectionType.AiVectorStore]: 'Vector Store',
|
||||
[NodeConnectionType.Main]: 'Main',
|
||||
[NodeConnectionTypes.AiChain]: 'Chain',
|
||||
[NodeConnectionTypes.AiDocument]: 'Document',
|
||||
[NodeConnectionTypes.AiEmbedding]: 'Embedding',
|
||||
[NodeConnectionTypes.AiLanguageModel]: 'Language Model',
|
||||
[NodeConnectionTypes.AiMemory]: 'Memory',
|
||||
[NodeConnectionTypes.AiOutputParser]: 'Output Parser',
|
||||
[NodeConnectionTypes.AiTextSplitter]: 'Text Splitter',
|
||||
[NodeConnectionTypes.AiTool]: 'Tool',
|
||||
[NodeConnectionTypes.AiVectorStore]: 'Vector Store',
|
||||
[NodeConnectionTypes.Main]: 'Main',
|
||||
};
|
||||
|
||||
const defaultCodeExecute = `const { PromptTemplate } = require('@langchain/core/prompts');
|
||||
|
|
@ -304,7 +304,7 @@ export class Code implements INodeType {
|
|||
|
||||
const outputs = this.getNodeOutputs();
|
||||
const mainOutputs: INodeOutputConfiguration[] = outputs.filter(
|
||||
(output) => output.type === NodeConnectionType.Main,
|
||||
(output) => output.type === NodeConnectionTypes.Main,
|
||||
);
|
||||
|
||||
const options = { multiOutput: mainOutputs.length !== 1 };
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import type { TextSplitter } from '@langchain/textsplitters';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -51,15 +51,15 @@ export class DocumentBinaryInputLoader implements INodeType {
|
|||
{
|
||||
displayName: 'Text Splitter',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiTextSplitter,
|
||||
type: NodeConnectionTypes.AiTextSplitter,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiDocument],
|
||||
outputs: [NodeConnectionTypes.AiDocument],
|
||||
outputNames: ['Document'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiVectorStore]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiVectorStore]),
|
||||
{
|
||||
displayName: 'Loader Type',
|
||||
name: 'loader',
|
||||
|
|
@ -179,7 +179,7 @@ export class DocumentBinaryInputLoader implements INodeType {
|
|||
async supplyData(this: ISupplyDataFunctions): Promise<SupplyData> {
|
||||
this.logger.debug('Supply Data for Binary Input Loader');
|
||||
const textSplitter = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiTextSplitter,
|
||||
NodeConnectionTypes.AiTextSplitter,
|
||||
0,
|
||||
)) as TextSplitter | undefined;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import type { TextSplitter } from '@langchain/textsplitters';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -49,12 +49,12 @@ export class DocumentDefaultDataLoader implements INodeType {
|
|||
{
|
||||
displayName: 'Text Splitter',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiTextSplitter,
|
||||
type: NodeConnectionTypes.AiTextSplitter,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiDocument],
|
||||
outputs: [NodeConnectionTypes.AiDocument],
|
||||
outputNames: ['Document'],
|
||||
properties: [
|
||||
{
|
||||
|
|
@ -286,7 +286,7 @@ export class DocumentDefaultDataLoader implements INodeType {
|
|||
async supplyData(this: ISupplyDataFunctions, itemIndex: number): Promise<SupplyData> {
|
||||
const dataType = this.getNodeParameter('dataType', itemIndex, 'json') as 'json' | 'binary';
|
||||
const textSplitter = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiTextSplitter,
|
||||
NodeConnectionTypes.AiTextSplitter,
|
||||
0,
|
||||
)) as TextSplitter | undefined;
|
||||
const binaryDataKey = this.getNodeParameter('binaryDataKey', itemIndex, '') as string;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { GithubRepoLoader } from '@langchain/community/document_loaders/web/github';
|
||||
import type { CharacterTextSplitter } from '@langchain/textsplitters';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -47,15 +47,15 @@ export class DocumentGithubLoader implements INodeType {
|
|||
{
|
||||
displayName: 'Text Splitter',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiTextSplitter,
|
||||
type: NodeConnectionTypes.AiTextSplitter,
|
||||
},
|
||||
],
|
||||
inputNames: ['Text Splitter'],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiDocument],
|
||||
outputs: [NodeConnectionTypes.AiDocument],
|
||||
outputNames: ['Document'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiVectorStore]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiVectorStore]),
|
||||
{
|
||||
displayName: 'Repository Link',
|
||||
name: 'repository',
|
||||
|
|
@ -106,11 +106,11 @@ export class DocumentGithubLoader implements INodeType {
|
|||
};
|
||||
|
||||
const textSplitter = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiTextSplitter,
|
||||
NodeConnectionTypes.AiTextSplitter,
|
||||
0,
|
||||
)) as CharacterTextSplitter | undefined;
|
||||
|
||||
const { index } = this.addInputData(NodeConnectionType.AiDocument, [
|
||||
const { index } = this.addInputData(NodeConnectionTypes.AiDocument, [
|
||||
[{ json: { repository, branch, ignorePaths, recursive } }],
|
||||
]);
|
||||
const docs = new GithubRepoLoader(repository, {
|
||||
|
|
@ -125,7 +125,7 @@ export class DocumentGithubLoader implements INodeType {
|
|||
? await textSplitter.splitDocuments(await docs.load())
|
||||
: await docs.load();
|
||||
|
||||
this.addOutputData(NodeConnectionType.AiDocument, index, [[{ json: { loadedDocs } }]]);
|
||||
this.addOutputData(NodeConnectionTypes.AiDocument, index, [[{ json: { loadedDocs } }]]);
|
||||
return {
|
||||
response: logWrapper(loadedDocs, this),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import type { TextSplitter } from '@langchain/textsplitters';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -44,15 +44,15 @@ export class DocumentJsonInputLoader implements INodeType {
|
|||
{
|
||||
displayName: 'Text Splitter',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiTextSplitter,
|
||||
type: NodeConnectionTypes.AiTextSplitter,
|
||||
},
|
||||
],
|
||||
inputNames: ['Text Splitter'],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiDocument],
|
||||
outputs: [NodeConnectionTypes.AiDocument],
|
||||
outputNames: ['Document'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiVectorStore]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiVectorStore]),
|
||||
{
|
||||
displayName: 'Pointers',
|
||||
name: 'pointers',
|
||||
|
|
@ -82,7 +82,7 @@ export class DocumentJsonInputLoader implements INodeType {
|
|||
async supplyData(this: ISupplyDataFunctions): Promise<SupplyData> {
|
||||
this.logger.debug('Supply Data for JSON Input Loader');
|
||||
const textSplitter = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiTextSplitter,
|
||||
NodeConnectionTypes.AiTextSplitter,
|
||||
0,
|
||||
)) as TextSplitter | undefined;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { BedrockEmbeddings } from '@langchain/aws';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -45,14 +45,14 @@ export class EmbeddingsAwsBedrock implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiEmbedding],
|
||||
outputs: [NodeConnectionTypes.AiEmbedding],
|
||||
outputNames: ['Embeddings'],
|
||||
requestDefaults: {
|
||||
ignoreHttpStatusErrors: true,
|
||||
baseURL: '=https://bedrock.{{$credentials?.region ?? "eu-central-1"}}.amazonaws.com',
|
||||
},
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiVectorStore]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiVectorStore]),
|
||||
{
|
||||
displayName: 'Model',
|
||||
name: 'model',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { OpenAIEmbeddings } from '@langchain/openai';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -45,10 +45,10 @@ export class EmbeddingsAzureOpenAi implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiEmbedding],
|
||||
outputs: [NodeConnectionTypes.AiEmbedding],
|
||||
outputNames: ['Embeddings'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiVectorStore]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiVectorStore]),
|
||||
{
|
||||
displayName: 'Model (Deployment) Name',
|
||||
name: 'model',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { CohereEmbeddings } from '@langchain/cohere';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -48,10 +48,10 @@ export class EmbeddingsCohere implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiEmbedding],
|
||||
outputs: [NodeConnectionTypes.AiEmbedding],
|
||||
outputNames: ['Embeddings'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiVectorStore]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiVectorStore]),
|
||||
{
|
||||
displayName:
|
||||
'Each model is using different dimensional density for embeddings. Please make sure to use the same dimensionality for your vector store. The default model is using 768-dimensional embeddings.',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { GoogleGenerativeAIEmbeddings } from '@langchain/google-genai';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -48,10 +48,10 @@ export class EmbeddingsGoogleGemini implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiEmbedding],
|
||||
outputs: [NodeConnectionTypes.AiEmbedding],
|
||||
outputNames: ['Embeddings'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiVectorStore]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiVectorStore]),
|
||||
{
|
||||
displayName:
|
||||
'Each model is using different dimensional density for embeddings. Please make sure to use the same dimensionality for your vector store. The default model is using 768-dimensional embeddings.',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { HuggingFaceInferenceEmbeddings } from '@langchain/community/embeddings/hf';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -44,10 +44,10 @@ export class EmbeddingsHuggingFaceInference implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiEmbedding],
|
||||
outputs: [NodeConnectionTypes.AiEmbedding],
|
||||
outputNames: ['Embeddings'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiVectorStore]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiVectorStore]),
|
||||
{
|
||||
displayName:
|
||||
'Each model is using different dimensional density for embeddings. Please make sure to use the same dimensionality for your vector store. The default model is using 768-dimensional embeddings.',
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import type { MistralAIEmbeddingsParams } from '@langchain/mistralai';
|
||||
import { MistralAIEmbeddings } from '@langchain/mistralai';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -46,14 +46,14 @@ export class EmbeddingsMistralCloud implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiEmbedding],
|
||||
outputs: [NodeConnectionTypes.AiEmbedding],
|
||||
outputNames: ['Embeddings'],
|
||||
requestDefaults: {
|
||||
ignoreHttpStatusErrors: true,
|
||||
baseURL: 'https://api.mistral.ai/v1',
|
||||
},
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiVectorStore]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiVectorStore]),
|
||||
{
|
||||
displayName: 'Model',
|
||||
name: 'model',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { OllamaEmbeddings } from '@langchain/ollama';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -41,9 +41,9 @@ export class EmbeddingsOllama implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiEmbedding],
|
||||
outputs: [NodeConnectionTypes.AiEmbedding],
|
||||
outputNames: ['Embeddings'],
|
||||
properties: [getConnectionHintNoticeField([NodeConnectionType.AiVectorStore]), ollamaModel],
|
||||
properties: [getConnectionHintNoticeField([NodeConnectionTypes.AiVectorStore]), ollamaModel],
|
||||
};
|
||||
|
||||
async supplyData(this: ISupplyDataFunctions, itemIndex: number): Promise<SupplyData> {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { OpenAIEmbeddings } from '@langchain/openai';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type SupplyData,
|
||||
|
|
@ -101,7 +101,7 @@ export class EmbeddingsOpenAi implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiEmbedding],
|
||||
outputs: [NodeConnectionTypes.AiEmbedding],
|
||||
outputNames: ['Embeddings'],
|
||||
requestDefaults: {
|
||||
ignoreHttpStatusErrors: true,
|
||||
|
|
@ -109,7 +109,7 @@ export class EmbeddingsOpenAi implements INodeType {
|
|||
'={{ $parameter.options?.baseURL?.split("/").slice(0,-1).join("/") || $credentials.url?.split("/").slice(0,-1).join("/") || "https://api.openai.com" }}',
|
||||
},
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiVectorStore]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiVectorStore]),
|
||||
{
|
||||
...modelParameter,
|
||||
default: 'text-embedding-ada-002',
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import { ChatAnthropic } from '@langchain/anthropic';
|
||||
import type { LLMResult } from '@langchain/core/outputs';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodePropertyOptions,
|
||||
type INodeProperties,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -109,7 +109,7 @@ export class LmChatAnthropic implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiLanguageModel],
|
||||
outputs: [NodeConnectionTypes.AiLanguageModel],
|
||||
outputNames: ['Model'],
|
||||
credentials: [
|
||||
{
|
||||
|
|
@ -118,7 +118,7 @@ export class LmChatAnthropic implements INodeType {
|
|||
},
|
||||
],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiChain, NodeConnectionType.AiChain]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiChain, NodeConnectionTypes.AiChain]),
|
||||
{
|
||||
...modelField,
|
||||
displayOptions: {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import type { ChatOllamaInput } from '@langchain/ollama';
|
||||
import { ChatOllama } from '@langchain/ollama';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -45,11 +45,11 @@ export class LmChatOllama implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiLanguageModel],
|
||||
outputs: [NodeConnectionTypes.AiLanguageModel],
|
||||
outputNames: ['Model'],
|
||||
...ollamaDescription,
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiChain, NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiChain, NodeConnectionTypes.AiAgent]),
|
||||
ollamaModel,
|
||||
ollamaOptions,
|
||||
],
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { ChatOpenAI, type ClientOptions } from '@langchain/openai';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -51,7 +51,7 @@ export class LmChatOpenAi implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiLanguageModel],
|
||||
outputs: [NodeConnectionTypes.AiLanguageModel],
|
||||
outputNames: ['Model'],
|
||||
credentials: [
|
||||
{
|
||||
|
|
@ -65,7 +65,7 @@ export class LmChatOpenAi implements INodeType {
|
|||
'={{ $parameter.options?.baseURL?.split("/").slice(0,-1).join("/") || $credentials?.url?.split("/").slice(0,-1).join("/") || "https://api.openai.com" }}',
|
||||
},
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiChain, NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiChain, NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName:
|
||||
'If using JSON response format, you must include word "json" in the prompt in your chain or agent. Also, make sure to select latest models released post November 2023.',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { Cohere } from '@langchain/cohere';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -42,7 +42,7 @@ export class LmCohere implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiLanguageModel],
|
||||
outputs: [NodeConnectionTypes.AiLanguageModel],
|
||||
outputNames: ['Model'],
|
||||
credentials: [
|
||||
{
|
||||
|
|
@ -51,7 +51,7 @@ export class LmCohere implements INodeType {
|
|||
},
|
||||
],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiChain, NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiChain, NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { Ollama } from '@langchain/community/llms/ollama';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -44,11 +44,11 @@ export class LmOllama implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiLanguageModel],
|
||||
outputs: [NodeConnectionTypes.AiLanguageModel],
|
||||
outputNames: ['Model'],
|
||||
...ollamaDescription,
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiChain, NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiChain, NodeConnectionTypes.AiAgent]),
|
||||
ollamaModel,
|
||||
ollamaOptions,
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { OpenAI, type ClientOptions } from '@langchain/openai';
|
||||
import { NodeConnectionType } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes } from 'n8n-workflow';
|
||||
import type {
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
|
|
@ -53,7 +53,7 @@ export class LmOpenAi implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiLanguageModel],
|
||||
outputs: [NodeConnectionTypes.AiLanguageModel],
|
||||
outputNames: ['Model'],
|
||||
credentials: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { HuggingFaceInference } from '@langchain/community/llms/hf';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -42,7 +42,7 @@ export class LmOpenHuggingFaceInference implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiLanguageModel],
|
||||
outputs: [NodeConnectionTypes.AiLanguageModel],
|
||||
outputNames: ['Model'],
|
||||
credentials: [
|
||||
{
|
||||
|
|
@ -51,7 +51,7 @@ export class LmOpenHuggingFaceInference implements INodeType {
|
|||
},
|
||||
],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiChain, NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiChain, NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName: 'Model',
|
||||
name: 'model',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { ChatBedrockConverse } from '@langchain/aws';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -42,7 +42,7 @@ export class LmChatAwsBedrock implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiLanguageModel],
|
||||
outputs: [NodeConnectionTypes.AiLanguageModel],
|
||||
outputNames: ['Model'],
|
||||
credentials: [
|
||||
{
|
||||
|
|
@ -56,7 +56,7 @@ export class LmChatAwsBedrock implements INodeType {
|
|||
baseURL: '=https://bedrock.{{$credentials?.region ?? "eu-central-1"}}.amazonaws.com',
|
||||
},
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiChain, NodeConnectionType.AiChain]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiChain, NodeConnectionTypes.AiChain]),
|
||||
{
|
||||
displayName: 'Model',
|
||||
name: 'model',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { AzureChatOpenAI } from '@langchain/openai';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -42,7 +42,7 @@ export class LmChatAzureOpenAi implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiLanguageModel],
|
||||
outputs: [NodeConnectionTypes.AiLanguageModel],
|
||||
outputNames: ['Model'],
|
||||
credentials: [
|
||||
{
|
||||
|
|
@ -51,7 +51,7 @@ export class LmChatAzureOpenAi implements INodeType {
|
|||
},
|
||||
],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiChain, NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiChain, NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName:
|
||||
'If using JSON response format, you must include word "json" in the prompt in your chain or agent. Also, make sure to select latest models released post November 2023.',
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { ChatOpenAI, type ClientOptions } from '@langchain/openai';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -44,7 +44,7 @@ export class LmChatDeepSeek implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiLanguageModel],
|
||||
outputs: [NodeConnectionTypes.AiLanguageModel],
|
||||
outputNames: ['Model'],
|
||||
credentials: [
|
||||
{
|
||||
|
|
@ -57,7 +57,7 @@ export class LmChatDeepSeek implements INodeType {
|
|||
baseURL: '={{ $credentials?.url }}',
|
||||
},
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiChain, NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiChain, NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName:
|
||||
'If using JSON response format, you must include word "json" in the prompt in your chain or agent. Also, make sure to select latest models released post November 2023.',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import type { SafetySetting } from '@google/generative-ai';
|
||||
import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
|
||||
import { NodeConnectionType } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes } from 'n8n-workflow';
|
||||
import type {
|
||||
NodeError,
|
||||
INodeType,
|
||||
|
|
@ -52,7 +52,7 @@ export class LmChatGoogleGemini implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiLanguageModel],
|
||||
outputs: [NodeConnectionTypes.AiLanguageModel],
|
||||
outputNames: ['Model'],
|
||||
credentials: [
|
||||
{
|
||||
|
|
@ -65,7 +65,7 @@ export class LmChatGoogleGemini implements INodeType {
|
|||
baseURL: '={{ $credentials.host }}',
|
||||
},
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiChain, NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiChain, NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName: 'Model',
|
||||
name: 'modelName',
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { ProjectsClient } from '@google-cloud/resource-manager';
|
|||
import { ChatVertexAI } from '@langchain/google-vertexai';
|
||||
import { formatPrivateKey } from 'n8n-nodes-base/dist/utils/utilities';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -50,7 +50,7 @@ export class LmChatGoogleVertex implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiLanguageModel],
|
||||
outputs: [NodeConnectionTypes.AiLanguageModel],
|
||||
outputNames: ['Model'],
|
||||
credentials: [
|
||||
{
|
||||
|
|
@ -59,7 +59,7 @@ export class LmChatGoogleVertex implements INodeType {
|
|||
},
|
||||
],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiChain, NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiChain, NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName: 'Project ID',
|
||||
name: 'projectId',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { ChatGroq } from '@langchain/groq';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -42,7 +42,7 @@ export class LmChatGroq implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiLanguageModel],
|
||||
outputs: [NodeConnectionTypes.AiLanguageModel],
|
||||
outputNames: ['Model'],
|
||||
credentials: [
|
||||
{
|
||||
|
|
@ -54,7 +54,7 @@ export class LmChatGroq implements INodeType {
|
|||
baseURL: 'https://api.groq.com/openai/v1',
|
||||
},
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiChain, NodeConnectionType.AiChain]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiChain, NodeConnectionTypes.AiChain]),
|
||||
{
|
||||
displayName: 'Model',
|
||||
name: 'model',
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import type { ChatMistralAIInput } from '@langchain/mistralai';
|
||||
import { ChatMistralAI } from '@langchain/mistralai';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -44,7 +44,7 @@ export class LmChatMistralCloud implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiLanguageModel],
|
||||
outputs: [NodeConnectionTypes.AiLanguageModel],
|
||||
outputNames: ['Model'],
|
||||
credentials: [
|
||||
{
|
||||
|
|
@ -57,7 +57,7 @@ export class LmChatMistralCloud implements INodeType {
|
|||
baseURL: 'https://api.mistral.ai/v1',
|
||||
},
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiChain, NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiChain, NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName: 'Model',
|
||||
name: 'model',
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { ChatOpenAI, type ClientOptions } from '@langchain/openai';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -43,7 +43,7 @@ export class LmChatOpenRouter implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiLanguageModel],
|
||||
outputs: [NodeConnectionTypes.AiLanguageModel],
|
||||
outputNames: ['Model'],
|
||||
credentials: [
|
||||
{
|
||||
|
|
@ -56,7 +56,7 @@ export class LmChatOpenRouter implements INodeType {
|
|||
baseURL: '={{ $credentials?.url }}',
|
||||
},
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiChain, NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiChain, NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName:
|
||||
'If using JSON response format, you must include word "json" in the prompt in your chain or agent. Also, make sure to select latest models released post November 2023.',
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import type { LLMResult } from '@langchain/core/outputs';
|
|||
import { encodingForModel } from '@langchain/core/utils/tiktoken';
|
||||
import { pick } from 'lodash';
|
||||
import type { IDataObject, ISupplyDataFunctions, JsonObject } from 'n8n-workflow';
|
||||
import { NodeConnectionType, NodeError, NodeOperationError } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes, NodeError, NodeOperationError } from 'n8n-workflow';
|
||||
|
||||
import { logAiEvent } from '@utils/helpers';
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ export class N8nLlmTracing extends BaseCallbackHandler {
|
|||
// This is crucial for the handleLLMError handler to work correctly (it should be called before the error is propagated to the root node)
|
||||
awaitHandlers = true;
|
||||
|
||||
connectionType = NodeConnectionType.AiLanguageModel;
|
||||
connectionType = NodeConnectionTypes.AiLanguageModel;
|
||||
|
||||
promptTokensEstimate = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import type { BufferWindowMemoryInput } from 'langchain/memory';
|
||||
import { BufferWindowMemory } from 'langchain/memory';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -101,10 +101,10 @@ export class MemoryBufferWindow implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiMemory],
|
||||
outputs: [NodeConnectionTypes.AiMemory],
|
||||
outputNames: ['Memory'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName: 'Session Key',
|
||||
name: 'sessionKey',
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import type { BaseChatMemory } from '@langchain/community/memory/chat_memory';
|
||||
import type { BaseMessage } from '@langchain/core/messages';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type IDataObject,
|
||||
type IExecuteFunctions,
|
||||
type INodeExecutionData,
|
||||
|
|
@ -61,16 +61,16 @@ export class MemoryChatRetriever implements INodeType {
|
|||
},
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [
|
||||
NodeConnectionType.Main,
|
||||
NodeConnectionTypes.Main,
|
||||
{
|
||||
displayName: 'Memory',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiMemory,
|
||||
type: NodeConnectionTypes.AiMemory,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
properties: [
|
||||
{
|
||||
displayName: "This node is deprecated. Use 'Chat Memory Manager' node instead.",
|
||||
|
|
@ -91,7 +91,7 @@ export class MemoryChatRetriever implements INodeType {
|
|||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
this.logger.debug('Executing Chat Memory Retriever');
|
||||
|
||||
const memory = (await this.getInputConnectionData(NodeConnectionType.AiMemory, 0)) as
|
||||
const memory = (await this.getInputConnectionData(NodeConnectionTypes.AiMemory, 0)) as
|
||||
| BaseChatMemory
|
||||
| undefined;
|
||||
const simplifyOutput = this.getNodeParameter('simplifyOutput', 0) as boolean;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import type { BaseChatMemory } from '@langchain/community/memory/chat_memory';
|
||||
import { AIMessage, SystemMessage, HumanMessage, type BaseMessage } from '@langchain/core/messages';
|
||||
import { NodeConnectionType } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes } from 'n8n-workflow';
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
|
|
@ -92,11 +92,11 @@ export class MemoryManager implements INodeType {
|
|||
inputs: [
|
||||
{
|
||||
displayName: '',
|
||||
type: NodeConnectionType.Main,
|
||||
type: NodeConnectionTypes.Main,
|
||||
},
|
||||
{
|
||||
displayName: 'Memory',
|
||||
type: NodeConnectionType.AiMemory,
|
||||
type: NodeConnectionTypes.AiMemory,
|
||||
required: true,
|
||||
maxConnections: 1,
|
||||
},
|
||||
|
|
@ -105,7 +105,7 @@ export class MemoryManager implements INodeType {
|
|||
outputs: [
|
||||
{
|
||||
displayName: '',
|
||||
type: NodeConnectionType.Main,
|
||||
type: NodeConnectionTypes.Main,
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
|
|
@ -297,7 +297,7 @@ export class MemoryManager implements INodeType {
|
|||
const items = this.getInputData();
|
||||
const mode = this.getNodeParameter('mode', 0, 'load') as 'load' | 'insert' | 'delete';
|
||||
const memory = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiMemory,
|
||||
NodeConnectionTypes.AiMemory,
|
||||
0,
|
||||
)) as BaseChatMemory;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { MotorheadMemory } from '@langchain/community/memory/motorhead_memory';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -42,7 +42,7 @@ export class MemoryMotorhead implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiMemory],
|
||||
outputs: [NodeConnectionTypes.AiMemory],
|
||||
outputNames: ['Memory'],
|
||||
credentials: [
|
||||
{
|
||||
|
|
@ -51,7 +51,7 @@ export class MemoryMotorhead implements INodeType {
|
|||
},
|
||||
],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName: 'Session ID',
|
||||
name: 'sessionId',
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import type {
|
|||
INodeTypeDescription,
|
||||
SupplyData,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeConnectionType } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes } from 'n8n-workflow';
|
||||
import type pg from 'pg';
|
||||
|
||||
import { getSessionId } from '@utils/helpers';
|
||||
|
|
@ -58,10 +58,10 @@ export class MemoryPostgresChat implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiMemory],
|
||||
outputs: [NodeConnectionTypes.AiMemory],
|
||||
outputNames: ['Memory'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiAgent]),
|
||||
sessionIdOption,
|
||||
expressionSessionKeyProperty(1.2),
|
||||
sessionKeyProperty,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
type SupplyData,
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
} from 'n8n-workflow';
|
||||
import type { RedisClientOptions } from 'redis';
|
||||
import { createClient } from 'redis';
|
||||
|
|
@ -57,10 +57,10 @@ export class MemoryRedisChat implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiMemory],
|
||||
outputs: [NodeConnectionTypes.AiMemory],
|
||||
outputNames: ['Memory'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName: 'Session Key',
|
||||
name: 'sessionKey',
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { XataChatMessageHistory } from '@langchain/community/stores/message/xata';
|
||||
import { BaseClient } from '@xata.io/client';
|
||||
import { BufferMemory, BufferWindowMemory } from 'langchain/memory';
|
||||
import { NodeConnectionType, NodeOperationError } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';
|
||||
import type {
|
||||
ISupplyDataFunctions,
|
||||
INodeType,
|
||||
|
|
@ -50,7 +50,7 @@ export class MemoryXata implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiMemory],
|
||||
outputs: [NodeConnectionTypes.AiMemory],
|
||||
outputNames: ['Memory'],
|
||||
credentials: [
|
||||
{
|
||||
|
|
@ -59,7 +59,7 @@ export class MemoryXata implements INodeType {
|
|||
},
|
||||
],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName: 'Session ID',
|
||||
name: 'sessionId',
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { ZepCloudMemory } from '@langchain/community/memory/zep_cloud';
|
|||
import type { InputValues, MemoryVariables } from '@langchain/core/memory';
|
||||
import type { BaseMessage } from '@langchain/core/messages';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type ISupplyDataFunctions,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
|
|
@ -58,7 +58,7 @@ export class MemoryZep implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiMemory],
|
||||
outputs: [NodeConnectionTypes.AiMemory],
|
||||
outputNames: ['Memory'],
|
||||
credentials: [
|
||||
{
|
||||
|
|
@ -67,7 +67,7 @@ export class MemoryZep implements INodeType {
|
|||
},
|
||||
],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName: 'Only works with Zep Cloud and Community edition <= v0.27.2',
|
||||
name: 'supportedVersions',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { BaseLanguageModel } from '@langchain/core/language_models/base';
|
||||
import { PromptTemplate } from '@langchain/core/prompts';
|
||||
import { NodeConnectionType, NodeOperationError } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';
|
||||
import type {
|
||||
ISupplyDataFunctions,
|
||||
INodeType,
|
||||
|
|
@ -47,18 +47,18 @@ export class OutputParserAutofixing implements INodeType {
|
|||
{
|
||||
displayName: 'Model',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiLanguageModel,
|
||||
type: NodeConnectionTypes.AiLanguageModel,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Output Parser',
|
||||
maxConnections: 1,
|
||||
required: true,
|
||||
type: NodeConnectionType.AiOutputParser,
|
||||
type: NodeConnectionTypes.AiOutputParser,
|
||||
},
|
||||
],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiOutputParser],
|
||||
outputs: [NodeConnectionTypes.AiOutputParser],
|
||||
outputNames: ['Output Parser'],
|
||||
properties: [
|
||||
{
|
||||
|
|
@ -68,7 +68,7 @@ export class OutputParserAutofixing implements INodeType {
|
|||
type: 'notice',
|
||||
default: '',
|
||||
},
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiChain, NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiChain, NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
|
|
@ -95,11 +95,11 @@ export class OutputParserAutofixing implements INodeType {
|
|||
|
||||
async supplyData(this: ISupplyDataFunctions, itemIndex: number): Promise<SupplyData> {
|
||||
const model = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiLanguageModel,
|
||||
NodeConnectionTypes.AiLanguageModel,
|
||||
itemIndex,
|
||||
)) as BaseLanguageModel;
|
||||
const outputParser = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiOutputParser,
|
||||
NodeConnectionTypes.AiOutputParser,
|
||||
itemIndex,
|
||||
)) as N8nStructuredOutputParser;
|
||||
const prompt = this.getNodeParameter('options.prompt', itemIndex, NAIVE_FIX_PROMPT) as string;
|
||||
|
|
|
|||
|
|
@ -5,8 +5,12 @@ import { OutputParserException } from '@langchain/core/output_parsers';
|
|||
import type { MockProxy } from 'jest-mock-extended';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import { normalizeItems } from 'n8n-core';
|
||||
import type { ISupplyDataFunctions, IWorkflowDataProxyData } from 'n8n-workflow';
|
||||
import { ApplicationError, NodeConnectionType, NodeOperationError } from 'n8n-workflow';
|
||||
import type {
|
||||
ISupplyDataFunctions,
|
||||
IWorkflowDataProxyData,
|
||||
NodeConnectionType,
|
||||
} from 'n8n-workflow';
|
||||
import { ApplicationError, NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';
|
||||
|
||||
import type {
|
||||
N8nOutputFixingParser,
|
||||
|
|
@ -34,8 +38,8 @@ describe('OutputParserAutofixing', () => {
|
|||
thisArg.addInputData.mockReturnValue({ index: 0 });
|
||||
thisArg.addOutputData.mockReturnValue();
|
||||
thisArg.getInputConnectionData.mockImplementation(async (type: NodeConnectionType) => {
|
||||
if (type === NodeConnectionType.AiLanguageModel) return mockModel;
|
||||
if (type === NodeConnectionType.AiOutputParser) return mockStructuredOutputParser;
|
||||
if (type === NodeConnectionTypes.AiLanguageModel) return mockModel;
|
||||
if (type === NodeConnectionTypes.AiOutputParser) return mockStructuredOutputParser;
|
||||
|
||||
throw new ApplicationError('Unexpected connection type');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -39,10 +39,10 @@ export class OutputParserItemList implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiOutputParser],
|
||||
outputs: [NodeConnectionTypes.AiOutputParser],
|
||||
outputNames: ['Output Parser'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiChain, NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiChain, NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import {
|
|||
type ISupplyDataFunctions,
|
||||
type SupplyData,
|
||||
NodeOperationError,
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
} from 'n8n-workflow';
|
||||
import type { z } from 'zod';
|
||||
|
||||
|
|
@ -46,10 +46,10 @@ export class OutputParserStructured implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiOutputParser],
|
||||
outputs: [NodeConnectionTypes.AiOutputParser],
|
||||
outputNames: ['Output Parser'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiChain, NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiChain, NodeConnectionTypes.AiAgent]),
|
||||
{ ...schemaTypeField, displayOptions: { show: { '@version': [{ _cnd: { gte: 1.2 } }] } } },
|
||||
{
|
||||
...jsonSchemaExampleField,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import type { BaseRetriever } from '@langchain/core/retrievers';
|
|||
import { ContextualCompressionRetriever } from 'langchain/retrievers/contextual_compression';
|
||||
import { LLMChainExtractor } from 'langchain/retrievers/document_compressors/chain_extract';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -44,13 +44,13 @@ export class RetrieverContextualCompression implements INodeType {
|
|||
{
|
||||
displayName: 'Model',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiLanguageModel,
|
||||
type: NodeConnectionTypes.AiLanguageModel,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Retriever',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiRetriever,
|
||||
type: NodeConnectionTypes.AiRetriever,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
|
|
@ -58,7 +58,7 @@ export class RetrieverContextualCompression implements INodeType {
|
|||
{
|
||||
displayName: 'Retriever',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiRetriever,
|
||||
type: NodeConnectionTypes.AiRetriever,
|
||||
},
|
||||
],
|
||||
properties: [],
|
||||
|
|
@ -68,12 +68,12 @@ export class RetrieverContextualCompression implements INodeType {
|
|||
this.logger.debug('Supplying data for Contextual Compression Retriever');
|
||||
|
||||
const model = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiLanguageModel,
|
||||
NodeConnectionTypes.AiLanguageModel,
|
||||
itemIndex,
|
||||
)) as BaseLanguageModel;
|
||||
|
||||
const baseRetriever = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiRetriever,
|
||||
NodeConnectionTypes.AiRetriever,
|
||||
itemIndex,
|
||||
)) as BaseRetriever;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import type { BaseLanguageModel } from '@langchain/core/language_models/base';
|
|||
import type { BaseRetriever } from '@langchain/core/retrievers';
|
||||
import { MultiQueryRetriever } from 'langchain/retrievers/multi_query';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -44,13 +44,13 @@ export class RetrieverMultiQuery implements INodeType {
|
|||
{
|
||||
displayName: 'Model',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiLanguageModel,
|
||||
type: NodeConnectionTypes.AiLanguageModel,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Retriever',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiRetriever,
|
||||
type: NodeConnectionTypes.AiRetriever,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
|
|
@ -58,7 +58,7 @@ export class RetrieverMultiQuery implements INodeType {
|
|||
{
|
||||
displayName: 'Retriever',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiRetriever,
|
||||
type: NodeConnectionTypes.AiRetriever,
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
|
|
@ -89,12 +89,12 @@ export class RetrieverMultiQuery implements INodeType {
|
|||
const options = this.getNodeParameter('options', itemIndex, {}) as { queryCount?: number };
|
||||
|
||||
const model = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiLanguageModel,
|
||||
NodeConnectionTypes.AiLanguageModel,
|
||||
itemIndex,
|
||||
)) as BaseLanguageModel;
|
||||
|
||||
const baseRetriever = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiRetriever,
|
||||
NodeConnectionTypes.AiRetriever,
|
||||
itemIndex,
|
||||
)) as BaseRetriever;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import type { VectorStore } from '@langchain/core/vectorstores';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -40,12 +40,12 @@ export class RetrieverVectorStore implements INodeType {
|
|||
{
|
||||
displayName: 'Vector Store',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiVectorStore,
|
||||
type: NodeConnectionTypes.AiVectorStore,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiRetriever],
|
||||
outputs: [NodeConnectionTypes.AiRetriever],
|
||||
outputNames: ['Retriever'],
|
||||
properties: [
|
||||
{
|
||||
|
|
@ -63,7 +63,7 @@ export class RetrieverVectorStore implements INodeType {
|
|||
|
||||
const topK = this.getNodeParameter('topK', itemIndex, 4) as number;
|
||||
const vectorStore = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiVectorStore,
|
||||
NodeConnectionTypes.AiVectorStore,
|
||||
itemIndex,
|
||||
)) as VectorStore;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { Document } from '@langchain/core/documents';
|
|||
import { BaseRetriever, type BaseRetrieverInput } from '@langchain/core/retrievers';
|
||||
import type { SetField, SetNodeOptions } from 'n8n-nodes-base/dist/nodes/Set/v2/helpers/interfaces';
|
||||
import * as manual from 'n8n-nodes-base/dist/nodes/Set/v2/manual.mode';
|
||||
import { NodeConnectionType, NodeOperationError } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteWorkflowInfo,
|
||||
|
|
@ -66,7 +66,7 @@ export class RetrieverWorkflow implements INodeType {
|
|||
{
|
||||
displayName: 'Retriever',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiRetriever,
|
||||
type: NodeConnectionTypes.AiRetriever,
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import type { CharacterTextSplitterParams } from '@langchain/textsplitters';
|
||||
import { CharacterTextSplitter } from '@langchain/textsplitters';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -40,10 +40,10 @@ export class TextSplitterCharacterTextSplitter implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiTextSplitter],
|
||||
outputs: [NodeConnectionTypes.AiTextSplitter],
|
||||
outputNames: ['Text Splitter'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiDocument]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiDocument]),
|
||||
{
|
||||
displayName: 'Separator',
|
||||
name: 'separator',
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import type {
|
|||
} from '@langchain/textsplitters';
|
||||
import { RecursiveCharacterTextSplitter } from '@langchain/textsplitters';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -60,10 +60,10 @@ export class TextSplitterRecursiveCharacterTextSplitter implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiTextSplitter],
|
||||
outputs: [NodeConnectionTypes.AiTextSplitter],
|
||||
outputNames: ['Text Splitter'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiDocument]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiDocument]),
|
||||
{
|
||||
displayName: 'Chunk Size',
|
||||
name: 'chunkSize',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { TokenTextSplitter } from '@langchain/textsplitters';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -39,10 +39,10 @@ export class TextSplitterTokenSplitter implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiTextSplitter],
|
||||
outputs: [NodeConnectionTypes.AiTextSplitter],
|
||||
outputNames: ['Text Splitter'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiDocument]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiDocument]),
|
||||
{
|
||||
displayName: 'Chunk Size',
|
||||
name: 'chunkSize',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { Calculator } from '@langchain/community/tools/calculator';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -40,9 +40,9 @@ export class ToolCalculator implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiTool],
|
||||
outputs: [NodeConnectionTypes.AiTool],
|
||||
outputNames: ['Tool'],
|
||||
properties: [getConnectionHintNoticeField([NodeConnectionType.AiAgent])],
|
||||
properties: [getConnectionHintNoticeField([NodeConnectionTypes.AiAgent])],
|
||||
};
|
||||
|
||||
async supplyData(this: ISupplyDataFunctions): Promise<SupplyData> {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import type {
|
|||
ExecutionError,
|
||||
IDataObject,
|
||||
} from 'n8n-workflow';
|
||||
import { jsonParse, NodeConnectionType, NodeOperationError } from 'n8n-workflow';
|
||||
import { jsonParse, NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
buildInputSchemaField,
|
||||
|
|
@ -54,10 +54,10 @@ export class ToolCode implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiTool],
|
||||
outputs: [NodeConnectionTypes.AiTool],
|
||||
outputNames: ['Tool'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName:
|
||||
'See an example of a conversational agent with custom tool written in JavaScript <a href="/templates/1963" target="_blank">here</a>.',
|
||||
|
|
@ -221,7 +221,7 @@ export class ToolCode implements INodeType {
|
|||
};
|
||||
|
||||
const toolHandler = async (query: string | IDataObject): Promise<string> => {
|
||||
const { index } = this.addInputData(NodeConnectionType.AiTool, [[{ json: { query } }]]);
|
||||
const { index } = this.addInputData(NodeConnectionTypes.AiTool, [[{ json: { query } }]]);
|
||||
|
||||
let response: string = '';
|
||||
let executionError: ExecutionError | undefined;
|
||||
|
|
@ -245,9 +245,9 @@ export class ToolCode implements INodeType {
|
|||
}
|
||||
|
||||
if (executionError) {
|
||||
void this.addOutputData(NodeConnectionType.AiTool, index, executionError);
|
||||
void this.addOutputData(NodeConnectionTypes.AiTool, index, executionError);
|
||||
} else {
|
||||
void this.addOutputData(NodeConnectionType.AiTool, index, [[{ json: { response } }]]);
|
||||
void this.addOutputData(NodeConnectionTypes.AiTool, index, [[{ json: { response } }]]);
|
||||
}
|
||||
|
||||
return response;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,11 @@ import type {
|
|||
IHttpRequestMethods,
|
||||
IHttpRequestOptions,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeConnectionType, NodeOperationError, tryToParseAlphanumericString } from 'n8n-workflow';
|
||||
import {
|
||||
NodeConnectionTypes,
|
||||
NodeOperationError,
|
||||
tryToParseAlphanumericString,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { N8nTool } from '@utils/N8nTool';
|
||||
import { getConnectionHintNoticeField } from '@utils/sharedFields';
|
||||
|
|
@ -62,10 +66,10 @@ export class ToolHttpRequest implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiTool],
|
||||
outputs: [NodeConnectionTypes.AiTool],
|
||||
outputNames: ['Tool'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName: 'Description',
|
||||
name: 'toolDescription',
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import type {
|
|||
NodeApiError,
|
||||
ISupplyDataFunctions,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeConnectionType, NodeOperationError, jsonParse } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes, NodeOperationError, jsonParse } from 'n8n-workflow';
|
||||
import { z } from 'zod';
|
||||
|
||||
import type {
|
||||
|
|
@ -585,7 +585,7 @@ export const configureToolFunction = (
|
|||
optimizeResponse: (response: string) => string,
|
||||
) => {
|
||||
return async (query: string | IDataObject): Promise<string> => {
|
||||
const { index } = ctx.addInputData(NodeConnectionType.AiTool, [[{ json: { query } }]]);
|
||||
const { index } = ctx.addInputData(NodeConnectionTypes.AiTool, [[{ json: { query } }]]);
|
||||
|
||||
// Clone options and rawRequestOptions to avoid mutating the original objects
|
||||
const options: IHttpRequestOptions | null = structuredClone(requestOptions);
|
||||
|
|
@ -792,9 +792,9 @@ export const configureToolFunction = (
|
|||
}
|
||||
|
||||
if (executionError) {
|
||||
void ctx.addOutputData(NodeConnectionType.AiTool, index, executionError as ExecutionError);
|
||||
void ctx.addOutputData(NodeConnectionTypes.AiTool, index, executionError as ExecutionError);
|
||||
} else {
|
||||
void ctx.addOutputData(NodeConnectionType.AiTool, index, [[{ json: { response } }]]);
|
||||
void ctx.addOutputData(NodeConnectionTypes.AiTool, index, [[{ json: { response } }]]);
|
||||
}
|
||||
|
||||
return response;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { SerpAPI } from '@langchain/community/tools/serpapi';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -39,7 +39,7 @@ export class ToolSerpApi implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiTool],
|
||||
outputs: [NodeConnectionTypes.AiTool],
|
||||
outputNames: ['Tool'],
|
||||
credentials: [
|
||||
{
|
||||
|
|
@ -48,7 +48,7 @@ export class ToolSerpApi implements INodeType {
|
|||
},
|
||||
],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import type {
|
|||
ISupplyDataFunctions,
|
||||
SupplyData,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeConnectionType } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes } from 'n8n-workflow';
|
||||
|
||||
import { logWrapper } from '@utils/logWrapper';
|
||||
import { getConnectionHintNoticeField } from '@utils/sharedFields';
|
||||
|
|
@ -44,21 +44,21 @@ export class ToolVectorStore implements INodeType {
|
|||
{
|
||||
displayName: 'Vector Store',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiVectorStore,
|
||||
type: NodeConnectionTypes.AiVectorStore,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Model',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiLanguageModel,
|
||||
type: NodeConnectionTypes.AiLanguageModel,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiTool],
|
||||
outputs: [NodeConnectionTypes.AiTool],
|
||||
outputNames: ['Tool'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName: 'Data Name',
|
||||
name: 'name',
|
||||
|
|
@ -97,12 +97,12 @@ export class ToolVectorStore implements INodeType {
|
|||
const topK = this.getNodeParameter('topK', itemIndex, 4) as number;
|
||||
|
||||
const vectorStore = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiVectorStore,
|
||||
NodeConnectionTypes.AiVectorStore,
|
||||
itemIndex,
|
||||
)) as VectorStore;
|
||||
|
||||
const llm = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiLanguageModel,
|
||||
NodeConnectionTypes.AiLanguageModel,
|
||||
0,
|
||||
)) as BaseLanguageModel;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { WikipediaQueryRun } from '@langchain/community/tools/wikipedia_query_run';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -39,9 +39,9 @@ export class ToolWikipedia implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiTool],
|
||||
outputs: [NodeConnectionTypes.AiTool],
|
||||
outputNames: ['Tool'],
|
||||
properties: [getConnectionHintNoticeField([NodeConnectionType.AiAgent])],
|
||||
properties: [getConnectionHintNoticeField([NodeConnectionTypes.AiAgent])],
|
||||
};
|
||||
|
||||
async supplyData(this: ISupplyDataFunctions): Promise<SupplyData> {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { WolframAlphaTool } from '@langchain/community/tools/wolframalpha';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -45,9 +45,9 @@ export class ToolWolframAlpha implements INodeType {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiTool],
|
||||
outputs: [NodeConnectionTypes.AiTool],
|
||||
outputNames: ['Tool'],
|
||||
properties: [getConnectionHintNoticeField([NodeConnectionType.AiAgent])],
|
||||
properties: [getConnectionHintNoticeField([NodeConnectionTypes.AiAgent])],
|
||||
};
|
||||
|
||||
async supplyData(this: ISupplyDataFunctions): Promise<SupplyData> {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import type {
|
|||
ITaskMetadata,
|
||||
INodeTypeBaseDescription,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeConnectionType, NodeOperationError, jsonParse } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes, NodeOperationError, jsonParse } from 'n8n-workflow';
|
||||
|
||||
import { versionDescription } from './versionDescription';
|
||||
import type { DynamicZodObject } from '../../../../types/zod.types';
|
||||
|
|
@ -148,7 +148,7 @@ export class ToolWorkflowV1 implements INodeType {
|
|||
query: string | IDataObject,
|
||||
runManager?: CallbackManagerForToolRun,
|
||||
): Promise<string> => {
|
||||
const { index } = this.addInputData(NodeConnectionType.AiTool, [[{ json: { query } }]]);
|
||||
const { index } = this.addInputData(NodeConnectionTypes.AiTool, [[{ json: { query } }]]);
|
||||
|
||||
let response: string = '';
|
||||
let executionError: ExecutionError | undefined;
|
||||
|
|
@ -189,12 +189,12 @@ export class ToolWorkflowV1 implements INodeType {
|
|||
}
|
||||
|
||||
if (executionError) {
|
||||
void this.addOutputData(NodeConnectionType.AiTool, index, executionError, metadata);
|
||||
void this.addOutputData(NodeConnectionTypes.AiTool, index, executionError, metadata);
|
||||
} else {
|
||||
// Output always needs to be an object
|
||||
// so we try to parse the response as JSON and if it fails we just return the string wrapped in an object
|
||||
const json = jsonParse<IDataObject>(response, { fallbackValue: { response } });
|
||||
void this.addOutputData(NodeConnectionType.AiTool, index, [[{ json }]], metadata);
|
||||
void this.addOutputData(NodeConnectionTypes.AiTool, index, [[{ json }]], metadata);
|
||||
}
|
||||
return response;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-filename-against-convention */
|
||||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import type { INodeTypeDescription } from 'n8n-workflow';
|
||||
import { NodeConnectionType } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes } from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
inputSchemaField,
|
||||
|
|
@ -36,10 +36,10 @@ export const versionDescription: INodeTypeDescription = {
|
|||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [],
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
||||
outputs: [NodeConnectionType.AiTool],
|
||||
outputs: [NodeConnectionTypes.AiTool],
|
||||
outputNames: ['Tool'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName:
|
||||
'See an example of a workflow to suggest meeting slots using AI <a href="/templates/1953" target="_blank">here</a>.',
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import type {
|
|||
import {
|
||||
generateZodSchema,
|
||||
jsonParse,
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
NodeOperationError,
|
||||
parseErrorMetadata,
|
||||
traverseNodeParameters,
|
||||
|
|
@ -113,7 +113,7 @@ export class WorkflowToolService {
|
|||
}
|
||||
|
||||
void context.addOutputData(
|
||||
NodeConnectionType.AiTool,
|
||||
NodeConnectionTypes.AiTool,
|
||||
localRunIndex,
|
||||
[responseData],
|
||||
metadata,
|
||||
|
|
@ -126,7 +126,7 @@ export class WorkflowToolService {
|
|||
|
||||
const metadata = parseErrorMetadata(error);
|
||||
void context.addOutputData(
|
||||
NodeConnectionType.AiTool,
|
||||
NodeConnectionTypes.AiTool,
|
||||
localRunIndex,
|
||||
executionError,
|
||||
metadata,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* eslint-disable n8n-nodes-base/node-filename-against-convention */
|
||||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import { NodeConnectionType, type INodeTypeDescription } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes, type INodeTypeDescription } from 'n8n-workflow';
|
||||
|
||||
import { getConnectionHintNoticeField } from '../../../../utils/sharedFields';
|
||||
|
||||
|
|
@ -14,10 +14,10 @@ export const versionDescription: INodeTypeDescription = {
|
|||
},
|
||||
version: [2, 2.1],
|
||||
inputs: [],
|
||||
outputs: [NodeConnectionType.AiTool],
|
||||
outputs: [NodeConnectionTypes.AiTool],
|
||||
outputNames: ['Tool'],
|
||||
properties: [
|
||||
getConnectionHintNoticeField([NodeConnectionType.AiAgent]),
|
||||
getConnectionHintNoticeField([NodeConnectionTypes.AiAgent]),
|
||||
{
|
||||
displayName:
|
||||
'See an example of a workflow to suggest meeting slots using AI <a href="/templates/1953" target="_blank">here</a>.',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { BaseChatMemory } from '@langchain/community/memory/chat_memory';
|
||||
import { pick } from 'lodash';
|
||||
import { Node, NodeConnectionType } from 'n8n-workflow';
|
||||
import { Node, NodeConnectionTypes } from 'n8n-workflow';
|
||||
import type {
|
||||
IDataObject,
|
||||
IWebhookFunctions,
|
||||
|
|
@ -70,12 +70,12 @@ export class ChatTrigger extends Node {
|
|||
{
|
||||
displayName: 'Memory',
|
||||
maxConnections: 1,
|
||||
type: '${NodeConnectionType.AiMemory}',
|
||||
type: '${NodeConnectionTypes.AiMemory}',
|
||||
required: true,
|
||||
}
|
||||
];
|
||||
})() }}`,
|
||||
outputs: [NodeConnectionType.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
credentials: [
|
||||
{
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-credentials-name-unsuffixed
|
||||
|
|
@ -554,7 +554,7 @@ ${cssVariables}
|
|||
|
||||
if (bodyData.action === 'loadPreviousSession') {
|
||||
if (options?.loadPreviousSession === 'memory') {
|
||||
const memory = (await ctx.getInputConnectionData(NodeConnectionType.AiMemory, 0)) as
|
||||
const memory = (await ctx.getInputConnectionData(NodeConnectionTypes.AiMemory, 0)) as
|
||||
| BaseChatMemory
|
||||
| undefined;
|
||||
const messages = ((await memory?.chatHistory.getMessages()) ?? [])
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import {
|
|||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ITriggerResponse,
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class ManualChatTrigger implements INodeType {
|
||||
|
|
@ -35,7 +35,7 @@ export class ManualChatTrigger implements INodeType {
|
|||
},
|
||||
},
|
||||
inputs: [],
|
||||
outputs: [NodeConnectionType.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
properties: [
|
||||
{
|
||||
displayName:
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ import type { MemoryVectorStore } from 'langchain/vectorstores/memory';
|
|||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
import { createVectorStoreNode } from '../shared/createVectorStoreNode/createVectorStoreNode';
|
||||
import { MemoryVectorStoreManager } from '../shared/MemoryVectorStoreManager';
|
||||
import { MemoryVectorStoreManager } from '../shared/MemoryManager/MemoryVectorStoreManager';
|
||||
|
||||
const insertFields: INodeProperties[] = [
|
||||
{
|
||||
displayName:
|
||||
'The embedded data are stored in the server memory, so they will be lost when the server is restarted. Additionally, if the amount of data is too large, it may cause the server to crash due to insufficient memory.',
|
||||
'<strong>For experimental use only</strong>: Data is stored in memory and will be lost if n8n restarts. Data may also be cleared if available memory gets low. <a href="https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.vectorstoreinmemory/">More info</a>',
|
||||
name: 'notice',
|
||||
type: 'notice',
|
||||
default: '',
|
||||
|
|
@ -48,7 +48,7 @@ export class VectorStoreInMemory extends createVectorStoreNode<MemoryVectorStore
|
|||
async getVectorStoreClient(context, _filter, embeddings, itemIndex) {
|
||||
const workflowId = context.getWorkflow().id;
|
||||
const memoryKey = context.getNodeParameter('memoryKey', itemIndex) as string;
|
||||
const vectorStoreSingleton = MemoryVectorStoreManager.getInstance(embeddings);
|
||||
const vectorStoreSingleton = MemoryVectorStoreManager.getInstance(embeddings, context.logger);
|
||||
|
||||
return await vectorStoreSingleton.getVectorStore(`${workflowId}__${memoryKey}`);
|
||||
},
|
||||
|
|
@ -56,7 +56,7 @@ export class VectorStoreInMemory extends createVectorStoreNode<MemoryVectorStore
|
|||
const memoryKey = context.getNodeParameter('memoryKey', itemIndex) as string;
|
||||
const clearStore = context.getNodeParameter('clearStore', itemIndex) as boolean;
|
||||
const workflowId = context.getWorkflow().id;
|
||||
const vectorStoreInstance = MemoryVectorStoreManager.getInstance(embeddings);
|
||||
const vectorStoreInstance = MemoryVectorStoreManager.getInstance(embeddings, context.logger);
|
||||
|
||||
await vectorStoreInstance.addDocuments(`${workflowId}__${memoryKey}`, documents, clearStore);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import type { Embeddings } from '@langchain/core/embeddings';
|
||||
import type { Document } from 'langchain/document';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeExecutionData,
|
||||
type IExecuteFunctions,
|
||||
type INodeType,
|
||||
|
|
@ -11,7 +11,7 @@ import {
|
|||
|
||||
import type { N8nJsonLoader } from '@utils/N8nJsonLoader';
|
||||
|
||||
import { MemoryVectorStoreManager } from '../shared/MemoryVectorStoreManager';
|
||||
import { MemoryVectorStoreManager } from '../shared/MemoryManager/MemoryVectorStoreManager';
|
||||
import { processDocuments } from '../shared/processDocuments';
|
||||
|
||||
// This node is deprecated. Use VectorStoreInMemory instead.
|
||||
|
|
@ -42,21 +42,21 @@ export class VectorStoreInMemoryInsert implements INodeType {
|
|||
},
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: [
|
||||
NodeConnectionType.Main,
|
||||
NodeConnectionTypes.Main,
|
||||
{
|
||||
displayName: 'Document',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiDocument,
|
||||
type: NodeConnectionTypes.AiDocument,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Embedding',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiEmbedding,
|
||||
type: NodeConnectionTypes.AiEmbedding,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
outputs: [NodeConnectionType.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
properties: [
|
||||
{
|
||||
displayName:
|
||||
|
|
@ -86,13 +86,13 @@ export class VectorStoreInMemoryInsert implements INodeType {
|
|||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData(0);
|
||||
const embeddings = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiEmbedding,
|
||||
NodeConnectionTypes.AiEmbedding,
|
||||
0,
|
||||
)) as Embeddings;
|
||||
|
||||
const memoryKey = this.getNodeParameter('memoryKey', 0) as string;
|
||||
const clearStore = this.getNodeParameter('clearStore', 0) as boolean;
|
||||
const documentInput = (await this.getInputConnectionData(NodeConnectionType.AiDocument, 0)) as
|
||||
const documentInput = (await this.getInputConnectionData(NodeConnectionTypes.AiDocument, 0)) as
|
||||
| N8nJsonLoader
|
||||
| Array<Document<Record<string, unknown>>>;
|
||||
|
||||
|
|
@ -103,7 +103,7 @@ export class VectorStoreInMemoryInsert implements INodeType {
|
|||
|
||||
const workflowId = this.getWorkflow().id;
|
||||
|
||||
const vectorStoreInstance = MemoryVectorStoreManager.getInstance(embeddings);
|
||||
const vectorStoreInstance = MemoryVectorStoreManager.getInstance(embeddings, this.logger);
|
||||
await vectorStoreInstance.addDocuments(
|
||||
`${workflowId}__${memoryKey}`,
|
||||
processedDocuments,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import type { Embeddings } from '@langchain/core/embeddings';
|
||||
import {
|
||||
NodeConnectionType,
|
||||
NodeConnectionTypes,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
type ISupplyDataFunctions,
|
||||
|
|
@ -10,7 +10,7 @@ import {
|
|||
|
||||
import { logWrapper } from '@utils/logWrapper';
|
||||
|
||||
import { MemoryVectorStoreManager } from '../shared/MemoryVectorStoreManager';
|
||||
import { MemoryVectorStoreManager } from '../shared/MemoryManager/MemoryVectorStoreManager';
|
||||
|
||||
// This node is deprecated. Use VectorStoreInMemory instead.
|
||||
export class VectorStoreInMemoryLoad implements INodeType {
|
||||
|
|
@ -43,11 +43,11 @@ export class VectorStoreInMemoryLoad implements INodeType {
|
|||
{
|
||||
displayName: 'Embedding',
|
||||
maxConnections: 1,
|
||||
type: NodeConnectionType.AiEmbedding,
|
||||
type: NodeConnectionTypes.AiEmbedding,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
outputs: [NodeConnectionType.AiVectorStore],
|
||||
outputs: [NodeConnectionTypes.AiVectorStore],
|
||||
outputNames: ['Vector Store'],
|
||||
properties: [
|
||||
{
|
||||
|
|
@ -63,14 +63,14 @@ export class VectorStoreInMemoryLoad implements INodeType {
|
|||
|
||||
async supplyData(this: ISupplyDataFunctions, itemIndex: number): Promise<SupplyData> {
|
||||
const embeddings = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiEmbedding,
|
||||
NodeConnectionTypes.AiEmbedding,
|
||||
itemIndex,
|
||||
)) as Embeddings;
|
||||
|
||||
const workflowId = this.getWorkflow().id;
|
||||
const memoryKey = this.getNodeParameter('memoryKey', 0) as string;
|
||||
|
||||
const vectorStoreSingleton = MemoryVectorStoreManager.getInstance(embeddings);
|
||||
const vectorStoreSingleton = MemoryVectorStoreManager.getInstance(embeddings, this.logger);
|
||||
const vectorStoreInstance = await vectorStoreSingleton.getVectorStore(
|
||||
`${workflowId}__${memoryKey}`,
|
||||
);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user