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 AI_MEMORY_WINDOW_BUFFER_MEMORY_NODE_NAME = 'Window Buffer Memory';
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_LANGUAGE_MODEL_OPENAI_CHAT_MODEL_NODE_NAME = 'OpenAI Chat Model';
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 }) => {
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 = {
type,
displayName: type in displayNames ? displayNames[type] : undefined,
required: type === NodeConnectionType.AiLanguageModel,
displayName,
required: isModelType,
maxConnections: [NodeConnectionType.AiLanguageModel, NodeConnectionType.AiMemory].includes(
type as NodeConnectionType,
)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -157,6 +157,12 @@ export function groupItemsInSections(
})
.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) {
return items;
}