Skip to content

Commit

Permalink
feat(editor): Support node-creator actions for vector store nodes (#1…
Browse files Browse the repository at this point in the history
  • Loading branch information
OlegIvaniv authored Oct 1, 2024
1 parent 3a9c65e commit 72b70d9
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 8 deletions.
6 changes: 6 additions & 0 deletions cypress/composables/workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ export function addToolNodeToParent(nodeName: string, parentNodeName: string) {
export function addOutputParserNodeToParent(nodeName: string, parentNodeName: string) {
addSupplementalNodeToParent(nodeName, 'ai_outputParser', parentNodeName);
}
export function addVectorStoreNodeToParent(nodeName: string, parentNodeName: string) {
addSupplementalNodeToParent(nodeName, 'ai_vectorStore', parentNodeName);
}
export function addRetrieverNodeToParent(nodeName: string, parentNodeName: string) {
addSupplementalNodeToParent(nodeName, 'ai_retriever', parentNodeName);
}

export function clickExecuteWorkflowButton() {
getExecuteWorkflowButton().click();
Expand Down
40 changes: 40 additions & 0 deletions cypress/e2e/4-node-creator.cy.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import {
addNodeToCanvas,
addRetrieverNodeToParent,
addVectorStoreNodeToParent,
getNodeCreatorItems,
} from '../composables/workflow';
import { IF_NODE_NAME } from '../constants';
import { NodeCreator } from '../pages/features/node-creator';
import { NDV } from '../pages/ndv';
Expand Down Expand Up @@ -504,4 +510,38 @@ describe('Node Creator', () => {
nodeCreatorFeature.getters.searchBar().find('input').clear().type('gith');
nodeCreatorFeature.getters.nodeItemName().first().should('have.text', 'GitHub');
});

it('should show vector stores actions', () => {
const actions = [
'Get ranked documents from vector store',
'Add documents to vector store',
'Retrieve documents for AI processing',
];

nodeCreatorFeature.actions.openNodeCreator();

nodeCreatorFeature.getters.searchBar().find('input').clear().type('Vector Store');

getNodeCreatorItems().then((items) => {
const vectorStores = items.map((_i, el) => el.innerText);

// Loop over all vector stores and check if they have the three actions
vectorStores.each((_i, vectorStore) => {
nodeCreatorFeature.getters.getCreatorItem(vectorStore).click();
actions.forEach((action) => {
nodeCreatorFeature.getters.getCreatorItem(action).should('be.visible');
});
cy.realPress('ArrowLeft');
});
});
});

it('should add node directly for sub-connection', () => {
addNodeToCanvas('Question and Answer Chain', true);
addRetrieverNodeToParent('Vector Store Retriever', 'Question and Answer Chain');
cy.realPress('Escape');
addVectorStoreNodeToParent('In-Memory Vector Store', 'Vector Store Retriever');
cy.realPress('Escape');
WorkflowPage.getters.canvasNodes().should('have.length', 4);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -88,25 +88,25 @@ function getOperationModeOptions(args: VectorStoreNodeConstructorArgs): INodePro
name: 'Get Many',
value: 'load',
description: 'Get many ranked documents from vector store for query',
action: 'Get many ranked documents from vector store for query',
action: 'Get ranked documents from vector store',
},
{
name: 'Insert Documents',
value: 'insert',
description: 'Insert documents into vector store',
action: 'Insert documents into vector store',
action: 'Add documents to vector store',
},
{
name: 'Retrieve Documents (For Agent/Chain)',
value: 'retrieve',
description: 'Retrieve documents from vector store to be used with AI nodes',
action: 'Retrieve documents from vector store to be used with AI nodes',
action: 'Retrieve documents for AI processing',
},
{
name: 'Update Documents',
value: 'update',
description: 'Update documents in vector store by ID',
action: 'Update documents in vector store by ID',
action: 'Update vector store documents',
},
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useNodeCreatorStore } from '@/stores/nodeCreator.store';
import NodeIcon from '@/components/NodeIcon.vue';
import { useActions } from '../composables/useActions';
import { useViewStacks } from '../composables/useViewStacks';
import { useI18n } from '@/composables/useI18n';
import { useTelemetry } from '@/composables/useTelemetry';
import { useNodeType } from '@/composables/useNodeType';
Expand All @@ -34,6 +35,7 @@ const telemetry = useTelemetry();
const { actions } = useNodeCreatorStore();
const { getAddedNodesAndConnections } = useActions();
const { activeViewStack } = useViewStacks();
const { isSubNodeType } = useNodeType({
nodeType: props.nodeType,
});
Expand Down Expand Up @@ -61,7 +63,7 @@ const dataTestId = computed(() =>
);
const hasActions = computed(() => {
return nodeActions.value.length > 1;
return nodeActions.value.length > 1 && !activeViewStack.hideActions;
});
const nodeActions = computed(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ function onSelected(item: INodeCreateElement) {
if (item.type === 'node') {
const nodeActions = actions?.[item.key] || [];
if (nodeActions.length <= 1) {
// Only show actions if there are more than one or if the view is not an AI subcategory
if (nodeActions.length <= 1 || activeViewStack.value.hideActions) {
selectNodeType([item.key]);
return;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { ActionTypeDescription, ActionsRecord, SimplifiedNodeType } from '@/Interface';
import { CUSTOM_API_CALL_KEY, HTTP_REQUEST_NODE_TYPE } from '@/constants';
import { AI_SUBCATEGORY, CUSTOM_API_CALL_KEY, HTTP_REQUEST_NODE_TYPE } from '@/constants';
import { memoize, startCase } from 'lodash-es';
import type {
ICredentialType,
Expand Down Expand Up @@ -97,6 +97,36 @@ function operationsCategory(nodeTypeDescription: INodeTypeDescription): ActionTy
return items;
}

function modeCategory(nodeTypeDescription: INodeTypeDescription): ActionTypeDescription[] {
// Mode actions should only be available for AI nodes
const isAINode = nodeTypeDescription.codex?.categories?.includes(AI_SUBCATEGORY);
if (!isAINode) return [];

const matchedProperty = nodeTypeDescription.properties.find(
(property) => property.name?.toLowerCase() === 'mode',
);

if (!matchedProperty?.options) return [];

const modeOptions = matchedProperty.options as INodePropertyOptions[];

const items = modeOptions.map((item: INodePropertyOptions) => ({
...getNodeTypeBase(nodeTypeDescription),
actionKey: item.value as string,
displayName: item.action ?? startCase(item.name),
description: item.description ?? '',
displayOptions: matchedProperty.displayOptions,
values: {
[matchedProperty.name]: item.value,
},
}));

// Do not return empty category
if (items.length === 0) return [];

return items;
}

function triggersCategory(nodeTypeDescription: INodeTypeDescription): ActionTypeDescription[] {
const matchingKeys = ['event', 'events', 'trigger on'];
const isTrigger = nodeTypeDescription.displayName?.toLowerCase().includes('trigger');
Expand Down Expand Up @@ -231,7 +261,12 @@ export function useActionsGenerator() {
function generateNodeActions(node: INodeTypeDescription | undefined) {
if (!node) return [];
if (node.codex?.subcategories?.AI?.includes('Tools')) return [];
return [...triggersCategory(node), ...operationsCategory(node), ...resourceCategories(node)];
return [
...triggersCategory(node),
...operationsCategory(node),
...resourceCategories(node),
...modeCategory(node),
];
}
function filterActions(actions: ActionTypeDescription[]) {
// Do not show single action nodes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ interface ViewStack {
searchItems?: SimplifiedNodeType[];
forceIncludeNodes?: string[];
mode?: 'actions' | 'nodes';
hideActions?: boolean;
baseFilter?: (item: INodeCreateElement) => boolean;
itemsMapper?: (item: INodeCreateElement) => INodeCreateElement;
panelClass?: string;
Expand Down Expand Up @@ -344,6 +345,7 @@ export const useViewStacks = defineStore('nodeCreatorViewStacks', () => {
subcategory: connectionType,
};
},
hideActions: true,
preventBack: true,
});
}
Expand Down

0 comments on commit 72b70d9

Please sign in to comment.