feat(editor): Split Tools and Models into sub-sections (#10159)

This commit is contained in:
oleg 2024-07-23 16:40:28 +02:00 committed by GitHub
parent 95b85dd5c1
commit 3846eb967a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 71 additions and 17 deletions

View file

@ -53,7 +53,7 @@ export const AGENT_NODE_NAME = 'AI Agent';
export const BASIC_LLM_CHAIN_NODE_NAME = 'Basic LLM Chain'; export const BASIC_LLM_CHAIN_NODE_NAME = 'Basic LLM Chain';
export const AI_MEMORY_WINDOW_BUFFER_MEMORY_NODE_NAME = 'Window Buffer Memory'; export const AI_MEMORY_WINDOW_BUFFER_MEMORY_NODE_NAME = 'Window Buffer Memory';
export const AI_TOOL_CALCULATOR_NODE_NAME = 'Calculator'; export const AI_TOOL_CALCULATOR_NODE_NAME = 'Calculator';
export const AI_TOOL_CODE_NODE_NAME = 'Custom Code Tool'; export const AI_TOOL_CODE_NODE_NAME = 'Code Tool';
export const AI_TOOL_WIKIPEDIA_NODE_NAME = 'Wikipedia'; export const AI_TOOL_WIKIPEDIA_NODE_NAME = 'Wikipedia';
export const AI_LANGUAGE_MODEL_OPENAI_CHAT_MODEL_NODE_NAME = 'OpenAI Chat Model'; export const AI_LANGUAGE_MODEL_OPENAI_CHAT_MODEL_NODE_NAME = 'OpenAI Chat Model';
export const AI_OUTPUT_PARSER_AUTO_FIXING_NODE_NAME = 'Auto-fixing Output Parser'; export const AI_OUTPUT_PARSER_AUTO_FIXING_NODE_NAME = 'Auto-fixing Output Parser';

View file

@ -47,10 +47,18 @@ function getInputs(
}; };
return inputs.map(({ type, filter }) => { return inputs.map(({ type, filter }) => {
const isModelType = type === NodeConnectionType.AiLanguageModel;
let displayName = type in displayNames ? displayNames[type] : undefined;
if (
isModelType &&
['openAiFunctionsAgent', 'toolsAgent', 'conversationalAgent'].includes(agent)
) {
displayName = 'Chat Model';
}
const input: INodeInputConfiguration = { const input: INodeInputConfiguration = {
type, type,
displayName: type in displayNames ? displayNames[type] : undefined, displayName,
required: type === NodeConnectionType.AiLanguageModel, required: isModelType,
maxConnections: [NodeConnectionType.AiLanguageModel, NodeConnectionType.AiMemory].includes( maxConnections: [NodeConnectionType.AiLanguageModel, NodeConnectionType.AiMemory].includes(
type as NodeConnectionType, type as NodeConnectionType,
) )

View file

@ -75,6 +75,7 @@ export class LmChatAnthropic implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Language Models'], AI: ['Language Models'],
'Language Models': ['Chat Models (Recommended)'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -29,6 +29,7 @@ export class LmChatOllama implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Language Models'], AI: ['Language Models'],
'Language Models': ['Chat Models (Recommended)'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -27,6 +27,7 @@ export class LmChatOpenAi implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Language Models'], AI: ['Language Models'],
'Language Models': ['Chat Models (Recommended)'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -27,6 +27,7 @@ export class LmCohere implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Language Models'], AI: ['Language Models'],
'Language Models': ['Text Completion Models'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -28,6 +28,7 @@ export class LmOllama implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Language Models'], AI: ['Language Models'],
'Language Models': ['Text Completion Models'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -39,6 +39,7 @@ export class LmOpenAi implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Language Models'], AI: ['Language Models'],
'Language Models': ['Text Completion Models'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -27,6 +27,7 @@ export class LmOpenHuggingFaceInference implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Language Models'], AI: ['Language Models'],
'Language Models': ['Text Completion Models'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -30,6 +30,7 @@ export class LmChatAwsBedrock implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Language Models'], AI: ['Language Models'],
'Language Models': ['Chat Models (Recommended)'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -28,6 +28,7 @@ export class LmChatAzureOpenAi implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Language Models'], AI: ['Language Models'],
'Language Models': ['Chat Models (Recommended)'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -28,6 +28,7 @@ export class LmChatGoogleGemini implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Language Models'], AI: ['Language Models'],
'Language Models': ['Chat Models (Recommended)'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -26,6 +26,7 @@ export class LmChatGooglePalm implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Language Models'], AI: ['Language Models'],
'Language Models': ['Chat Models (Recommended)'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -33,6 +33,7 @@ export class LmChatGoogleVertex implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Language Models'], AI: ['Language Models'],
'Language Models': ['Chat Models (Recommended)'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -27,6 +27,7 @@ export class LmChatGroq implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Language Models'], AI: ['Language Models'],
'Language Models': ['Chat Models (Recommended)'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -28,6 +28,7 @@ export class LmChatMistralCloud implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Language Models'], AI: ['Language Models'],
'Language Models': ['Chat Models (Recommended)'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -26,6 +26,7 @@ export class LmGooglePalm implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Language Models'], AI: ['Language Models'],
'Language Models': ['Text Completion Models'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -25,6 +25,7 @@ export class ToolCalculator implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Tools'], AI: ['Tools'],
Tools: ['Other Tools'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -17,19 +17,20 @@ import { getConnectionHintNoticeField } from '../../../utils/sharedFields';
export class ToolCode implements INodeType { export class ToolCode implements INodeType {
description: INodeTypeDescription = { description: INodeTypeDescription = {
displayName: 'Custom Code Tool', displayName: 'Code Tool',
name: 'toolCode', name: 'toolCode',
icon: 'fa:code', icon: 'fa:code',
group: ['transform'], group: ['transform'],
version: [1, 1.1], version: [1, 1.1],
description: 'Write a tool in JS or Python', description: 'Write a tool in JS or Python',
defaults: { defaults: {
name: 'Custom Code Tool', name: 'Code Tool',
}, },
codex: { codex: {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Tools'], AI: ['Tools'],
Tools: ['Recommended Tools'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -49,6 +49,7 @@ export class ToolHttpRequest implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Tools'], AI: ['Tools'],
Tools: ['Recommended Tools'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -25,6 +25,7 @@ export class ToolSerpApi implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Tools'], AI: ['Tools'],
Tools: ['Other Tools'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -23,6 +23,7 @@ export class ToolVectorStore implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Tools'], AI: ['Tools'],
Tools: ['Other Tools'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -25,6 +25,7 @@ export class ToolWikipedia implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Tools'], AI: ['Tools'],
Tools: ['Other Tools'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -31,6 +31,7 @@ export class ToolWolframAlpha implements INodeType {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Tools'], AI: ['Tools'],
Tools: ['Other Tools'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -28,19 +28,20 @@ import {
} from '../../../utils/descriptions'; } from '../../../utils/descriptions';
export class ToolWorkflow implements INodeType { export class ToolWorkflow implements INodeType {
description: INodeTypeDescription = { description: INodeTypeDescription = {
displayName: 'Custom n8n Workflow Tool', displayName: 'Call n8n Workflow Tool',
name: 'toolWorkflow', name: 'toolWorkflow',
icon: 'fa:network-wired', icon: 'fa:network-wired',
group: ['transform'], group: ['transform'],
version: [1, 1.1], version: [1, 1.1],
description: 'Uses another n8n workflow as a tool. Allows packaging any n8n node(s) as a tool.', description: 'Uses another n8n workflow as a tool. Allows packaging any n8n node(s) as a tool.',
defaults: { defaults: {
name: 'Custom n8n Workflow Tool', name: 'Call n8n Workflow Tool',
}, },
codex: { codex: {
categories: ['AI'], categories: ['AI'],
subcategories: { subcategories: {
AI: ['Tools'], AI: ['Tools'],
Tools: ['Recommended Tools'],
}, },
resources: { resources: {
primaryDocumentation: [ primaryDocumentation: [

View file

@ -9,7 +9,10 @@
<div :class="$style.title"> <div :class="$style.title">
<slot name="title" /> <slot name="title" />
<p v-text="$locale.baseText('nodeCreator.noResults.weDidntMakeThatYet')" /> <p v-text="$locale.baseText('nodeCreator.noResults.weDidntMakeThatYet')" />
<div :class="$style.action"> <div
v-if="rootView === REGULAR_NODE_CREATOR_VIEW || rootView === TRIGGER_NODE_CREATOR_VIEW"
:class="$style.action"
>
{{ $locale.baseText('nodeCreator.noResults.dontWorryYouCanProbablyDoItWithThe') }} {{ $locale.baseText('nodeCreator.noResults.dontWorryYouCanProbablyDoItWithThe') }}
<n8n-link v-if="rootView === REGULAR_NODE_CREATOR_VIEW" @click="$emit('addHttpNode')"> <n8n-link v-if="rootView === REGULAR_NODE_CREATOR_VIEW" @click="$emit('addHttpNode')">
{{ $locale.baseText('nodeCreator.noResults.httpRequest') }} {{ $locale.baseText('nodeCreator.noResults.httpRequest') }}

View file

@ -93,8 +93,9 @@ export const useViewStacks = defineStore('nodeCreatorViewStacks', () => {
if ( if (
// Filter-out AI sub-nodes if canvas has no AI nodes and the root view is not AI // Filter-out AI sub-nodes if canvas has no AI nodes and the root view is not AI
!(isAiRootView(stack) || canvasHasAINodes) || !(isAiRootView(stack) || canvasHasAINodes) ||
// or if the source is a plus endpoint or a node connection drop // or if the source is a plus endpoint or a node connection drop and the root view is not AI subcategory
['plus_endpoint', 'node_connection_drop'].includes(nodeCreatorStore.openSource) (['plus_endpoint', 'node_connection_drop'].includes(nodeCreatorStore.openSource) &&
!isAiSubcategoryView(stack))
) { ) {
searchBase = filterOutAiNodes(searchBase); searchBase = filterOutAiNodes(searchBase);
} }
@ -135,6 +136,10 @@ export const useViewStacks = defineStore('nodeCreatorViewStacks', () => {
return stack.searchItems.map((item) => transformNodeType(item, stack.subcategory)); return stack.searchItems.map((item) => transformNodeType(item, stack.subcategory));
}); });
function isAiSubcategoryView(stack: ViewStack) {
return stack.rootView === AI_OTHERS_NODE_CREATOR_VIEW;
}
function getLastActiveStack() { function getLastActiveStack() {
return viewStacks.value[viewStacks.value.length - 1]; return viewStacks.value[viewStacks.value.length - 1];
} }
@ -142,7 +147,7 @@ export const useViewStacks = defineStore('nodeCreatorViewStacks', () => {
// Generate a delta between the global search results(all nodes) and the stack search results // Generate a delta between the global search results(all nodes) and the stack search results
const globalSearchItemsDiff = computed<INodeCreateElement[]>(() => { const globalSearchItemsDiff = computed<INodeCreateElement[]>(() => {
const stack = getLastActiveStack(); const stack = getLastActiveStack();
if (!stack?.search) return []; if (!stack?.search || isAiSubcategoryView(stack)) return [];
const allNodes = nodeCreatorStore.mergedNodes.map((item) => transformNodeType(item)); const allNodes = nodeCreatorStore.mergedNodes.map((item) => transformNodeType(item));
// Apply filtering for AI nodes if the current view is not the AI root view // Apply filtering for AI nodes if the current view is not the AI root view
@ -213,17 +218,25 @@ export const useViewStacks = defineStore('nodeCreatorViewStacks', () => {
const section = node.properties.codex?.subcategories?.[AI_SUBCATEGORY]?.[0]; const section = node.properties.codex?.subcategories?.[AI_SUBCATEGORY]?.[0];
if (section) { if (section) {
const currentItems = sectionsMap.get(section)?.items ?? []; const subSection = node.properties.codex?.subcategories?.[section]?.[0];
const sectionKey = subSection ?? section;
const currentItems = sectionsMap.get(sectionKey)?.items ?? [];
const isSubnodesSection = const isSubnodesSection =
!node.properties.codex?.subcategories?.[AI_SUBCATEGORY].includes( !node.properties.codex?.subcategories?.[AI_SUBCATEGORY].includes(
AI_CATEGORY_ROOT_NODES, AI_CATEGORY_ROOT_NODES,
); );
sectionsMap.set(section, { let title = section;
key: section, if (isSubnodesSection) {
title: isSubnodesSection title = `${section} (${i18n.baseText('nodeCreator.subnodes')})`;
? `${section} (${i18n.baseText('nodeCreator.subnodes')})` }
: section, if (subSection) {
title = subSection;
}
sectionsMap.set(sectionKey, {
key: sectionKey,
title,
items: [...currentItems, node.key], items: [...currentItems, node.key],
}); });
} }
@ -419,6 +432,7 @@ export const useViewStacks = defineStore('nodeCreatorViewStacks', () => {
activeViewStack, activeViewStack,
activeViewStackMode, activeViewStackMode,
globalSearchItemsDiff, globalSearchItemsDiff,
isAiSubcategoryView,
gotoCompatibleConnectionView, gotoCompatibleConnectionView,
resetViewStacks, resetViewStacks,
updateCurrentViewStack, updateCurrentViewStack,

View file

@ -157,6 +157,12 @@ export function groupItemsInSections(
}) })
.filter((section) => section.type !== 'section' || section.children.length > 0); .filter((section) => section.type !== 'section' || section.children.length > 0);
result.sort((a, b) => {
if (a.key.toLowerCase().includes('recommended')) return -1;
if (b.key.toLowerCase().includes('recommended')) return 1;
return 0;
});
if (result.length <= 1) { if (result.length <= 1) {
return items; return items;
} }