mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 17:46:45 +00:00
feat(editor): Add AI Starter pack experiment (no-changelog) (#17497)
This commit is contained in:
committed by
GitHub
parent
79306b040e
commit
5ddf290795
@@ -76,6 +76,7 @@
|
||||
"generic.service": "the service",
|
||||
"generic.star": "Star",
|
||||
"generic.tryNow": "Try now",
|
||||
"generic.startNow": "Start now",
|
||||
"generic.dismiss": "Dismiss",
|
||||
"generic.unsavedWork.confirmMessage.headline": "Save changes before leaving?",
|
||||
"generic.unsavedWork.confirmMessage.message": "If you don't save, you will lose your changes.",
|
||||
@@ -2679,6 +2680,10 @@
|
||||
"workflows.create.folder.toast.title": "Workflow successfully created in \"{projectName}\", within \"{folderName}\"",
|
||||
"workflows.create.project.toast.text": "All members from {projectName} will have access to this workflow.",
|
||||
"workflows.deactivated": "Workflow deactivated",
|
||||
"workflows.ai.starter.collection.callout": "Learn how to build AI Agents in n8n",
|
||||
"workflows.ai.starter.collection.card": "Learn how to build AI Agents",
|
||||
"workflows.ai.starter.collection.folder.name": "🎁 n8n basics: Learn how to build Agents in n8n",
|
||||
"workflows.ai.starter.collection.error": "Error loading AI Agent starter collection. Please try again later.",
|
||||
"workflowSelectorParameterInput.createNewSubworkflow.name": "My Sub-Workflow",
|
||||
"importCurlModal.title": "Import cURL command",
|
||||
"importCurlModal.input.label": "cURL Command",
|
||||
|
||||
@@ -31,4 +31,5 @@ export const STORES = {
|
||||
FOLDERS: 'folders',
|
||||
MODULES: 'modules',
|
||||
FOCUS_PANEL: 'focusPanel',
|
||||
AI_TEMPLATES_STARTER_COLLECTION: 'aiTemplatesStarterCollection',
|
||||
} as const;
|
||||
|
||||
@@ -27,6 +27,7 @@ import { useNodeHelpers } from '@/composables/useNodeHelpers';
|
||||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||
import { useRunWorkflow } from '@/composables/useRunWorkflow';
|
||||
import { useWorkflowSaving } from '@/composables/useWorkflowSaving';
|
||||
import { useAITemplatesStarterCollectionStore } from '@/experiments/aiTemplatesStarterCollection/stores/aiTemplatesStarterCollection.store';
|
||||
|
||||
export type SimplifiedExecution = Pick<
|
||||
IExecutionResponse,
|
||||
@@ -42,6 +43,7 @@ export async function executionFinished(
|
||||
) {
|
||||
const workflowsStore = useWorkflowsStore();
|
||||
const uiStore = useUIStore();
|
||||
const aiTemplatesStarterCollectionStore = useAITemplatesStarterCollectionStore();
|
||||
|
||||
workflowsStore.lastAddedExecutingNode = null;
|
||||
|
||||
@@ -63,6 +65,12 @@ export async function executionFinished(
|
||||
status: data.status,
|
||||
});
|
||||
}
|
||||
if (workflow.meta.templateId.startsWith('035_template_onboarding')) {
|
||||
aiTemplatesStarterCollectionStore.trackUserExecutedWorkflow(
|
||||
workflow.meta.templateId.split('-').pop() ?? '',
|
||||
data.status,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
uiStore.setProcessingExecutionResults(true);
|
||||
|
||||
@@ -761,10 +761,18 @@ export const FOCUS_PANEL_EXPERIMENT = {
|
||||
variant: 'variant',
|
||||
};
|
||||
|
||||
export const TEMPLATE_ONBOARDING_EXPERIMENT = {
|
||||
name: '035_template_onboarding',
|
||||
control: 'control',
|
||||
variantStarterPack: 'variant-starter-pack',
|
||||
variantSuggestedTemplates: 'variant-suggested-templates',
|
||||
};
|
||||
|
||||
export const EXPERIMENTS_TO_TRACK = [
|
||||
WORKFLOW_BUILDER_EXPERIMENT.name,
|
||||
RAG_STARTER_WORKFLOW_EXPERIMENT.name,
|
||||
EXTRA_TEMPLATE_LINKS_EXPERIMENT.name,
|
||||
TEMPLATE_ONBOARDING_EXPERIMENT.name,
|
||||
];
|
||||
|
||||
export const MFA_FORM = {
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import { useFoldersStore } from '@/stores/folders.store';
|
||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||
import type { WorkflowDataCreate } from '@n8n/rest-api-client';
|
||||
import { STORES } from '@n8n/stores';
|
||||
import { defineStore } from 'pinia';
|
||||
import { computed } from 'vue';
|
||||
import { AGENT_WITH_MEMORY } from '../workflows/1_agent_with_memory';
|
||||
import { AGENT_WITH_TOOLS } from '../workflows/2_agent_with_tools';
|
||||
import { AGENT_WITH_KNOWLEDGE } from '../workflows/3_agent_with_knowledge';
|
||||
import { useTelemetry } from '@/composables/useTelemetry';
|
||||
import { usePostHog } from '@/stores/posthog.store';
|
||||
import { TEMPLATE_ONBOARDING_EXPERIMENT } from '@/constants';
|
||||
import { useLocalStorage } from '@vueuse/core';
|
||||
import { useI18n } from '@n8n/i18n';
|
||||
|
||||
const LOCAL_STORAGE_SETTING_KEY = 'N8N_AI_TEMPLATES_STARTER_COLLECTION_CALL_OUT_DISMISSED';
|
||||
|
||||
export const useAITemplatesStarterCollectionStore = defineStore(
|
||||
STORES.AI_TEMPLATES_STARTER_COLLECTION,
|
||||
() => {
|
||||
const telemetry = useTelemetry();
|
||||
const i18n = useI18n();
|
||||
|
||||
const foldersStore = useFoldersStore();
|
||||
const workflowsStore = useWorkflowsStore();
|
||||
const posthogStore = usePostHog();
|
||||
|
||||
const calloutDismissedRef = useLocalStorage(LOCAL_STORAGE_SETTING_KEY, false);
|
||||
const calloutDismissed = computed(() => calloutDismissedRef.value);
|
||||
|
||||
const isFeatureEnabled = computed(() => {
|
||||
return (
|
||||
posthogStore.getVariant(TEMPLATE_ONBOARDING_EXPERIMENT.name) ===
|
||||
TEMPLATE_ONBOARDING_EXPERIMENT.variantStarterPack
|
||||
);
|
||||
});
|
||||
|
||||
const dismissCallout = () => {
|
||||
calloutDismissedRef.value = true;
|
||||
};
|
||||
|
||||
const createStarterWorkflows = async (projectId: string, parentFolderId?: string) => {
|
||||
const collectionFolder = await foldersStore.createFolder(
|
||||
i18n.baseText('workflows.ai.starter.collection.folder.name'),
|
||||
projectId,
|
||||
parentFolderId,
|
||||
);
|
||||
const agentWitheMemory: WorkflowDataCreate = {
|
||||
...AGENT_WITH_MEMORY,
|
||||
parentFolderId: collectionFolder.id,
|
||||
};
|
||||
const agentWithTools: WorkflowDataCreate = {
|
||||
...AGENT_WITH_TOOLS,
|
||||
parentFolderId: collectionFolder.id,
|
||||
};
|
||||
const agentWithKnowledge: WorkflowDataCreate = {
|
||||
...AGENT_WITH_KNOWLEDGE,
|
||||
parentFolderId: collectionFolder.id,
|
||||
};
|
||||
await workflowsStore.createNewWorkflow(agentWithKnowledge);
|
||||
await workflowsStore.createNewWorkflow(agentWithTools);
|
||||
await workflowsStore.createNewWorkflow(agentWitheMemory);
|
||||
dismissCallout();
|
||||
return collectionFolder;
|
||||
};
|
||||
|
||||
const trackUserCreatedStarterCollection = (source: 'card' | 'callout') => {
|
||||
telemetry.track('User created AI templates starter collection', {
|
||||
source,
|
||||
});
|
||||
};
|
||||
|
||||
const trackUserDismissedCallout = () => {
|
||||
telemetry.track('User dismissed AI templates starter collection callout');
|
||||
};
|
||||
|
||||
const trackUserOpenedWorkflow = (template: string) => {
|
||||
telemetry.track('User opened AI template workflow', {
|
||||
template,
|
||||
});
|
||||
};
|
||||
|
||||
const trackUserExecutedWorkflow = (template: string, status: string) => {
|
||||
telemetry.track('User executed AI template', {
|
||||
template,
|
||||
status,
|
||||
});
|
||||
};
|
||||
return {
|
||||
isFeatureEnabled,
|
||||
calloutDismissed,
|
||||
dismissCallout,
|
||||
createStarterWorkflows,
|
||||
trackUserCreatedStarterCollection,
|
||||
trackUserDismissedCallout,
|
||||
trackUserOpenedWorkflow,
|
||||
trackUserExecutedWorkflow,
|
||||
};
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,106 @@
|
||||
import type { WorkflowDataCreate } from '@n8n/rest-api-client';
|
||||
|
||||
export const AGENT_WITH_MEMORY: WorkflowDataCreate = {
|
||||
meta: {
|
||||
templateId: '035_template_onboarding-agent_with_memory',
|
||||
},
|
||||
name: '1. Agent with memory',
|
||||
nodes: [
|
||||
{
|
||||
id: '536fa635-c0c8-4fd1-84ef-d19585be64cf',
|
||||
name: 'When chat message received',
|
||||
webhookId: '9baee3d2-b9cb-4333-b4d5-3b07db8da9b2',
|
||||
type: '@n8n/n8n-nodes-langchain.chatTrigger',
|
||||
typeVersion: 1.1,
|
||||
position: [0, 0],
|
||||
parameters: {
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '1393095b-ec84-4514-b481-432609d1a5c5',
|
||||
name: 'AI Agent',
|
||||
type: '@n8n/n8n-nodes-langchain.agent',
|
||||
typeVersion: 2.1,
|
||||
position: [208, 0],
|
||||
parameters: {
|
||||
options: {
|
||||
systemMessage: '=You are a helpful assistant\n\nTodays date: {{ $now }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '658eb127-5a9d-4404-9270-72ef1da36ea3',
|
||||
name: 'Sticky Note',
|
||||
type: 'n8n-nodes-base.stickyNote',
|
||||
typeVersion: 1,
|
||||
position: [-464, -32],
|
||||
parameters: {
|
||||
content:
|
||||
'### Readme\nChat with an AI agent that remembers your previous messages during a conversation.\n\n**Quick Start**\n1. Open the **Model** node to claim your free API credits and connect to OpenAI. \n2. Click the **Open chat** button to start talking to the agent. Provide it with some information to remember, like your name.\n3. Ask a follow-up question about the information you shared: "What\'s my name?"\n\n---\n\n**Learn More**\n- [AI Agent node documentation](https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.agent/)\n- [Simple Memory node documentation](https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.memorybufferwindow/)',
|
||||
height: 396,
|
||||
width: 392,
|
||||
color: 4,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '186173c3-d043-4485-b939-9fca3d1e906f',
|
||||
name: 'Model',
|
||||
type: '@n8n/n8n-nodes-langchain.lmChatOpenAi',
|
||||
typeVersion: 1.2,
|
||||
position: [160, 240],
|
||||
parameters: {
|
||||
model: {
|
||||
__rl: true,
|
||||
mode: 'list',
|
||||
value: 'gpt-4.1-mini',
|
||||
},
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'dadaaa19-8378-4e23-9573-f9d3ff52c884',
|
||||
name: 'Memory',
|
||||
type: '@n8n/n8n-nodes-langchain.memoryBufferWindow',
|
||||
typeVersion: 1.3,
|
||||
position: [352, 240],
|
||||
parameters: {},
|
||||
},
|
||||
],
|
||||
connections: {
|
||||
'When chat message received': {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: 'AI Agent',
|
||||
type: 'main',
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
Model: {
|
||||
ai_languageModel: [
|
||||
[
|
||||
{
|
||||
node: 'AI Agent',
|
||||
type: 'ai_languageModel',
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
Memory: {
|
||||
ai_memory: [
|
||||
[
|
||||
{
|
||||
node: 'AI Agent',
|
||||
type: 'ai_memory',
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
// parentFolderId: newFolder.id,
|
||||
};
|
||||
@@ -0,0 +1,371 @@
|
||||
import type { WorkflowDataCreate } from '@n8n/rest-api-client';
|
||||
|
||||
export const AGENT_WITH_TOOLS: WorkflowDataCreate = {
|
||||
meta: {
|
||||
templateId: '035_template_onboarding-agent_with_tools',
|
||||
},
|
||||
name: '2. Agent with tools',
|
||||
nodes: [
|
||||
{
|
||||
parameters: {
|
||||
options: {},
|
||||
},
|
||||
type: '@n8n/n8n-nodes-langchain.chatTrigger',
|
||||
typeVersion: 1.1,
|
||||
position: [-48, -16],
|
||||
id: 'f6c9fe3c-cbde-4514-9fcf-9d618526965c',
|
||||
name: 'When chat message received',
|
||||
webhookId: '1bf95244-fbc3-4210-9420-f34a45c4f5f5',
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
options: {},
|
||||
},
|
||||
type: '@n8n/n8n-nodes-langchain.agent',
|
||||
typeVersion: 2.1,
|
||||
position: [208, -16],
|
||||
id: '5db1043f-de79-425a-a66b-8288c3aaa7df',
|
||||
name: 'AI Agent',
|
||||
},
|
||||
{
|
||||
parameters: {},
|
||||
type: '@n8n/n8n-nodes-langchain.memoryBufferWindow',
|
||||
typeVersion: 1.3,
|
||||
position: [208, 288],
|
||||
id: '29f1ba2f-7511-4771-958a-be6463a64d83',
|
||||
name: 'Simple Memory',
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
operation: 'update',
|
||||
documentId: {
|
||||
__rl: true,
|
||||
value: '1vbFb2dhys1VafAmX-hRtiyrEDgNKj_xaAA6ZmH09EL8',
|
||||
mode: 'list',
|
||||
cachedResultName: 'Demo',
|
||||
cachedResultUrl:
|
||||
'https://docs.google.com/spreadsheets/d/1vbFb2dhys1VafAmX-hRtiyrEDgNKj_xaAA6ZmH09EL8/edit?usp=drivesdk',
|
||||
},
|
||||
sheetName: {
|
||||
__rl: true,
|
||||
value: 'gid=0',
|
||||
mode: 'list',
|
||||
cachedResultName: 'Sheet1',
|
||||
cachedResultUrl:
|
||||
'https://docs.google.com/spreadsheets/d/1vbFb2dhys1VafAmX-hRtiyrEDgNKj_xaAA6ZmH09EL8/edit#gid=0',
|
||||
},
|
||||
columns: {
|
||||
mappingMode: 'defineBelow',
|
||||
value: {
|
||||
ID: "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('ID__using_to_match_', ``, 'string') }}",
|
||||
Name: "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Name', ``, 'string') }}",
|
||||
},
|
||||
matchingColumns: ['ID'],
|
||||
schema: [
|
||||
{
|
||||
id: 'ID',
|
||||
displayName: 'ID',
|
||||
required: false,
|
||||
defaultMatch: false,
|
||||
display: true,
|
||||
type: 'string',
|
||||
canBeUsedToMatch: true,
|
||||
removed: false,
|
||||
},
|
||||
{
|
||||
id: 'Name',
|
||||
displayName: 'Name',
|
||||
required: false,
|
||||
defaultMatch: false,
|
||||
display: true,
|
||||
type: 'string',
|
||||
canBeUsedToMatch: true,
|
||||
removed: false,
|
||||
},
|
||||
{
|
||||
id: 'row_number',
|
||||
displayName: 'row_number',
|
||||
required: false,
|
||||
defaultMatch: false,
|
||||
display: true,
|
||||
type: 'number',
|
||||
canBeUsedToMatch: true,
|
||||
readOnly: true,
|
||||
removed: true,
|
||||
},
|
||||
],
|
||||
attemptToConvertTypes: false,
|
||||
convertFieldsToString: false,
|
||||
},
|
||||
options: {},
|
||||
},
|
||||
type: 'n8n-nodes-base.googleSheetsTool',
|
||||
typeVersion: 4.6,
|
||||
position: [656, 640],
|
||||
id: '24d82ca2-b666-415b-9020-f88cf3e095e6',
|
||||
name: 'Update',
|
||||
credentials: {},
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
operation: 'append',
|
||||
documentId: {
|
||||
__rl: true,
|
||||
value: '1vbFb2dhys1VafAmX-hRtiyrEDgNKj_xaAA6ZmH09EL8',
|
||||
mode: 'list',
|
||||
cachedResultName: 'Demo',
|
||||
cachedResultUrl:
|
||||
'https://docs.google.com/spreadsheets/d/1vbFb2dhys1VafAmX-hRtiyrEDgNKj_xaAA6ZmH09EL8/edit?usp=drivesdk',
|
||||
},
|
||||
sheetName: {
|
||||
__rl: true,
|
||||
value: 'gid=0',
|
||||
mode: 'list',
|
||||
cachedResultName: 'Sheet1',
|
||||
cachedResultUrl:
|
||||
'https://docs.google.com/spreadsheets/d/1vbFb2dhys1VafAmX-hRtiyrEDgNKj_xaAA6ZmH09EL8/edit#gid=0',
|
||||
},
|
||||
columns: {
|
||||
mappingMode: 'defineBelow',
|
||||
value: {
|
||||
// eslint-disable-next-line n8n-local-rules/no-interpolation-in-regular-string
|
||||
ID: "={{ `${Math.random()}`.replace('0.', '') }}",
|
||||
Name: "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Name', ``, 'string') }}",
|
||||
},
|
||||
matchingColumns: ['ID'],
|
||||
schema: [
|
||||
{
|
||||
id: 'ID',
|
||||
displayName: 'ID',
|
||||
required: false,
|
||||
defaultMatch: false,
|
||||
display: true,
|
||||
type: 'string',
|
||||
canBeUsedToMatch: true,
|
||||
removed: false,
|
||||
},
|
||||
{
|
||||
id: 'Name',
|
||||
displayName: 'Name',
|
||||
required: false,
|
||||
defaultMatch: false,
|
||||
display: true,
|
||||
type: 'string',
|
||||
canBeUsedToMatch: true,
|
||||
removed: false,
|
||||
},
|
||||
{
|
||||
id: 'row_number',
|
||||
displayName: 'row_number',
|
||||
required: false,
|
||||
defaultMatch: false,
|
||||
display: true,
|
||||
type: 'number',
|
||||
canBeUsedToMatch: true,
|
||||
readOnly: true,
|
||||
removed: true,
|
||||
},
|
||||
],
|
||||
attemptToConvertTypes: false,
|
||||
convertFieldsToString: false,
|
||||
},
|
||||
options: {},
|
||||
},
|
||||
type: 'n8n-nodes-base.googleSheetsTool',
|
||||
typeVersion: 4.6,
|
||||
position: [464, 640],
|
||||
id: 'a0554e4a-8a7a-480c-a9e6-5f9746252cdb',
|
||||
name: 'Create',
|
||||
credentials: {},
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
documentId: {
|
||||
__rl: true,
|
||||
value: '1vbFb2dhys1VafAmX-hRtiyrEDgNKj_xaAA6ZmH09EL8',
|
||||
mode: 'list',
|
||||
cachedResultName: 'Demo',
|
||||
cachedResultUrl:
|
||||
'https://docs.google.com/spreadsheets/d/1vbFb2dhys1VafAmX-hRtiyrEDgNKj_xaAA6ZmH09EL8/edit?usp=drivesdk',
|
||||
},
|
||||
sheetName: {
|
||||
__rl: true,
|
||||
value: 'gid=0',
|
||||
mode: 'list',
|
||||
cachedResultName: 'Sheet1',
|
||||
cachedResultUrl:
|
||||
'https://docs.google.com/spreadsheets/d/1vbFb2dhys1VafAmX-hRtiyrEDgNKj_xaAA6ZmH09EL8/edit#gid=0',
|
||||
},
|
||||
options: {},
|
||||
},
|
||||
type: 'n8n-nodes-base.googleSheetsTool',
|
||||
typeVersion: 4.6,
|
||||
position: [480, 288],
|
||||
id: 'ef476f0d-bdfe-4f41-8690-fb270ed82469',
|
||||
name: 'Read',
|
||||
credentials: {},
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
operation: 'delete',
|
||||
documentId: {
|
||||
__rl: true,
|
||||
value: '1vbFb2dhys1VafAmX-hRtiyrEDgNKj_xaAA6ZmH09EL8',
|
||||
mode: 'list',
|
||||
cachedResultName: 'Demo',
|
||||
cachedResultUrl:
|
||||
'https://docs.google.com/spreadsheets/d/1vbFb2dhys1VafAmX-hRtiyrEDgNKj_xaAA6ZmH09EL8/edit?usp=drivesdk',
|
||||
},
|
||||
sheetName: {
|
||||
__rl: true,
|
||||
value: 'gid=0',
|
||||
mode: 'list',
|
||||
cachedResultName: 'Sheet1',
|
||||
cachedResultUrl:
|
||||
'https://docs.google.com/spreadsheets/d/1vbFb2dhys1VafAmX-hRtiyrEDgNKj_xaAA6ZmH09EL8/edit#gid=0',
|
||||
},
|
||||
startIndex:
|
||||
"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Start_Row_Number', ``, 'number') }}",
|
||||
numberToDelete:
|
||||
"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Number_of_Rows_to_Delete', ``, 'number') }}",
|
||||
},
|
||||
type: 'n8n-nodes-base.googleSheetsTool',
|
||||
typeVersion: 4.6,
|
||||
position: [864, 640],
|
||||
id: 'd0cca35f-9e74-4935-92e2-9b5e37f1c7f4',
|
||||
name: 'Delete',
|
||||
credentials: {},
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
content:
|
||||
"### Readme\nThis agent uses tools to interact with a simple spreadsheet of orders.\n\n**Quick Start**\n1. Copy this [spreadsheet](https://docs.google.com/spreadsheets/d/1vbFb2dhys1VafAmX-hRtiyrEDgNKj_xaAA6ZmH09EL8/edit?usp=sharing) into your Google Drive.\n2. Open the **Read** tool and connect your Google account by creating a credential and selecting the spreadsheet.\n3. Ask the Agent to calculate the total in the amount column, you should see it use the **Read** tool followed by the **Calculator**.\n4. Try some other questions and see how the agent responds.\n5. Use what you've learned to connect the other tools in the **Next steps** section.\n\n---\n\n**Learn More**\n- [Google sheet tool documentation](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.googlesheets/?utm_source=n8n_app&utm_medium=node_settings_modal-credential_link&utm_campaign=n8n-nodes-base.googleSheetsTool)\n- [Calculator tool documentation](https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.toolcalculator/)",
|
||||
height: 460,
|
||||
width: 440,
|
||||
color: 4,
|
||||
},
|
||||
type: 'n8n-nodes-base.stickyNote',
|
||||
position: [-576, -32],
|
||||
typeVersion: 1,
|
||||
id: 'e57c1fe3-3ef9-447c-81e3-bdf8717706b9',
|
||||
name: 'Sticky Note',
|
||||
},
|
||||
{
|
||||
parameters: {},
|
||||
type: '@n8n/n8n-nodes-langchain.toolCalculator',
|
||||
typeVersion: 1,
|
||||
position: [624, 288],
|
||||
id: '49030d8b-0818-455b-a472-356b620566c4',
|
||||
name: 'Calculator',
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
model: {
|
||||
__rl: true,
|
||||
mode: 'list',
|
||||
value: 'gpt-4.1-mini',
|
||||
},
|
||||
options: {},
|
||||
},
|
||||
type: '@n8n/n8n-nodes-langchain.lmChatOpenAi',
|
||||
typeVersion: 1.2,
|
||||
position: [48, 288],
|
||||
id: '67c78b12-b088-41b4-aeb4-70a7f056c9a7',
|
||||
name: 'Model',
|
||||
credentials: {},
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
content: '## 🛠️ Tools',
|
||||
height: 224,
|
||||
width: 368,
|
||||
color: 7,
|
||||
},
|
||||
type: 'n8n-nodes-base.stickyNote',
|
||||
position: [400, 224],
|
||||
typeVersion: 1,
|
||||
id: '14c03c2d-e0ea-4958-94c1-3598e5c273d9',
|
||||
name: 'Sticky Note1',
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
content:
|
||||
'## 🛠️ Next steps\n\nConnect these tools to perform create, read and update actions on your order list.',
|
||||
height: 320,
|
||||
width: 592,
|
||||
color: 7,
|
||||
},
|
||||
type: 'n8n-nodes-base.stickyNote',
|
||||
position: [400, 496],
|
||||
typeVersion: 1,
|
||||
id: 'a683cb43-e740-497e-bb01-edebfe39a832',
|
||||
name: 'Sticky Note2',
|
||||
},
|
||||
],
|
||||
connections: {
|
||||
'When chat message received': {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: 'AI Agent',
|
||||
type: 'main',
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
'Simple Memory': {
|
||||
ai_memory: [
|
||||
[
|
||||
{
|
||||
node: 'AI Agent',
|
||||
type: 'ai_memory',
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
Update: {
|
||||
ai_tool: [[]],
|
||||
},
|
||||
Create: {
|
||||
ai_tool: [[]],
|
||||
},
|
||||
Read: {
|
||||
ai_tool: [
|
||||
[
|
||||
{
|
||||
node: 'AI Agent',
|
||||
type: 'ai_tool',
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
Delete: {
|
||||
ai_tool: [[]],
|
||||
},
|
||||
Calculator: {
|
||||
ai_tool: [
|
||||
[
|
||||
{
|
||||
node: 'AI Agent',
|
||||
type: 'ai_tool',
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
Model: {
|
||||
ai_languageModel: [
|
||||
[
|
||||
{
|
||||
node: 'AI Agent',
|
||||
type: 'ai_languageModel',
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,250 @@
|
||||
import type { WorkflowDataCreate } from '@n8n/rest-api-client';
|
||||
|
||||
export const AGENT_WITH_KNOWLEDGE: WorkflowDataCreate = {
|
||||
meta: {
|
||||
templateId: '035_template_onboarding-agent_with_knowledge',
|
||||
},
|
||||
name: '3. Agent with knowledge',
|
||||
nodes: [
|
||||
{
|
||||
parameters: {
|
||||
formTitle: 'Upload your data to test RAG',
|
||||
formFields: {
|
||||
values: [
|
||||
{
|
||||
fieldLabel: 'Upload your file(s)',
|
||||
fieldType: 'file',
|
||||
acceptFileTypes: '.pdf, .csv',
|
||||
requiredField: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {},
|
||||
},
|
||||
type: 'n8n-nodes-base.formTrigger',
|
||||
typeVersion: 2.2,
|
||||
position: [-368, -304],
|
||||
id: 'e45eaedc-7ed9-4fd6-b79b-82a155734bce',
|
||||
name: 'Upload your file here',
|
||||
webhookId: '82848bc4-5ea2-4e5a-8bb6-3c09b94a8c5d',
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
options: {},
|
||||
},
|
||||
type: '@n8n/n8n-nodes-langchain.embeddingsOpenAi',
|
||||
typeVersion: 1.2,
|
||||
position: [288, 176],
|
||||
id: 'f9f1745a-9c6d-42cf-8f8b-19a1c4c91b77',
|
||||
name: 'Embeddings OpenAI',
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
dataType: 'binary',
|
||||
options: {},
|
||||
},
|
||||
type: '@n8n/n8n-nodes-langchain.documentDefaultDataLoader',
|
||||
typeVersion: 1.1,
|
||||
position: [80, -144],
|
||||
id: '56da285f-9ad9-4cb4-a7d4-fb0f035e9071',
|
||||
name: 'Default Data Loader',
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
content:
|
||||
'### Readme\nLoad your data into a vector database with the 📚 **Load Data** flow, and then use your data as chat context with the 🐕 **Retriever** flow.\n\n**Quick start**\n1. Click on the `Execute Workflow` button to run the 📚 **Load Data** flow.\n2. Click on `Open Chat` button to run the 🐕 **Retriever** flow. Then ask a question about content from your document(s)\n\n\nFor more info, check [our docs on RAG in n8n](https://docs.n8n.io/advanced-ai/rag-in-n8n/).',
|
||||
height: 300,
|
||||
width: 440,
|
||||
color: 4,
|
||||
},
|
||||
type: 'n8n-nodes-base.stickyNote',
|
||||
position: [-896, -368],
|
||||
typeVersion: 1,
|
||||
id: '72cb28c7-572b-41ce-ba4c-2dd0dc80acb4',
|
||||
name: 'Sticky Note',
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
content: '### 📚 Load Data Flow',
|
||||
height: 460,
|
||||
width: 700,
|
||||
color: 7,
|
||||
},
|
||||
type: 'n8n-nodes-base.stickyNote',
|
||||
position: [-416, -368],
|
||||
typeVersion: 1,
|
||||
id: '075a4895-8b5f-487b-b7ff-8766aa1d1450',
|
||||
name: 'Sticky Note1',
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
mode: 'insert',
|
||||
memoryKey: {
|
||||
__rl: true,
|
||||
value: 'vector_store_key',
|
||||
mode: 'list',
|
||||
cachedResultName: 'vector_store_key',
|
||||
},
|
||||
},
|
||||
type: '@n8n/n8n-nodes-langchain.vectorStoreInMemory',
|
||||
typeVersion: 1.2,
|
||||
position: [-176, -304],
|
||||
id: 'd24732cb-b6b4-4eb6-ad47-1f290f0da13d',
|
||||
name: 'Insert Data to Store',
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
mode: 'retrieve-as-tool',
|
||||
toolName: 'knowledge_base',
|
||||
toolDescription: 'Use this knowledge base to answer questions from the user',
|
||||
memoryKey: {
|
||||
__rl: true,
|
||||
mode: 'list',
|
||||
value: 'vector_store_key',
|
||||
},
|
||||
},
|
||||
type: '@n8n/n8n-nodes-langchain.vectorStoreInMemory',
|
||||
typeVersion: 1.2,
|
||||
position: [704, -96],
|
||||
id: '8915e9b6-2a6c-472c-b043-78c1d77888ae',
|
||||
name: 'Query Data Tool',
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
options: {},
|
||||
},
|
||||
type: '@n8n/n8n-nodes-langchain.agent',
|
||||
typeVersion: 2,
|
||||
position: [704, -320],
|
||||
id: 'a2baaa1d-beee-40a2-8b5f-757b2b1aaca9',
|
||||
name: 'AI Agent',
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
options: {},
|
||||
},
|
||||
type: '@n8n/n8n-nodes-langchain.chatTrigger',
|
||||
typeVersion: 1.1,
|
||||
position: [480, -320],
|
||||
id: 'c0a831dd-362c-4352-9409-bfe8c2e6f5ab',
|
||||
name: 'When chat message received',
|
||||
webhookId: '4091fa09-fb9a-4039-9411-7104d213f601',
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
model: {
|
||||
__rl: true,
|
||||
mode: 'list',
|
||||
value: 'gpt-4o-mini',
|
||||
},
|
||||
options: {},
|
||||
},
|
||||
type: '@n8n/n8n-nodes-langchain.lmChatOpenAi',
|
||||
typeVersion: 1.2,
|
||||
position: [480, -96],
|
||||
id: '2ba103b5-7783-49a7-9693-a156383ca697',
|
||||
name: 'OpenAI Chat Model',
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
content: '### 🐕 2. Retriever Flow',
|
||||
height: 460,
|
||||
width: 680,
|
||||
color: 7,
|
||||
},
|
||||
type: 'n8n-nodes-base.stickyNote',
|
||||
position: [368, -368],
|
||||
typeVersion: 1,
|
||||
id: '729f9492-3811-43d8-8230-d9ad78d910f7',
|
||||
name: 'Sticky Note2',
|
||||
},
|
||||
{
|
||||
parameters: {
|
||||
content:
|
||||
'### Embeddings\n\nThe Insert and Retrieve operation use the same embedding node.\n\nThis is to ensure that they are using the **exact same embeddings and settings**.\n\nDifferent embeddings might not work at all, or have unintended consequences.\n',
|
||||
height: 240,
|
||||
width: 320,
|
||||
color: 4,
|
||||
},
|
||||
type: 'n8n-nodes-base.stickyNote',
|
||||
position: [432, 144],
|
||||
typeVersion: 1,
|
||||
id: '20a6b946-5588-4df2-b1f6-952fc82d166c',
|
||||
name: 'Sticky Note3',
|
||||
},
|
||||
],
|
||||
connections: {
|
||||
'Upload your file here': {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: 'Insert Data to Store',
|
||||
type: 'main',
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
'Embeddings OpenAI': {
|
||||
ai_embedding: [
|
||||
[
|
||||
{
|
||||
node: 'Insert Data to Store',
|
||||
type: 'ai_embedding',
|
||||
index: 0,
|
||||
},
|
||||
{
|
||||
node: 'Query Data Tool',
|
||||
type: 'ai_embedding',
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
'Default Data Loader': {
|
||||
ai_document: [
|
||||
[
|
||||
{
|
||||
node: 'Insert Data to Store',
|
||||
type: 'ai_document',
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
'Query Data Tool': {
|
||||
ai_tool: [
|
||||
[
|
||||
{
|
||||
node: 'AI Agent',
|
||||
type: 'ai_tool',
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
'When chat message received': {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: 'AI Agent',
|
||||
type: 'main',
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
'OpenAI Chat Model': {
|
||||
ai_languageModel: [
|
||||
[
|
||||
{
|
||||
node: 'AI Agent',
|
||||
type: 'ai_languageModel',
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
pinData: {},
|
||||
};
|
||||
@@ -137,6 +137,7 @@ import { useLogsStore } from '@/stores/logs.store';
|
||||
import { canvasEventBus } from '@/event-bus/canvas';
|
||||
import CanvasChatButton from '@/components/canvas/elements/buttons/CanvasChatButton.vue';
|
||||
import { useFocusPanelStore } from '@/stores/focusPanel.store';
|
||||
import { useAITemplatesStarterCollectionStore } from '@/experiments/aiTemplatesStarterCollection/stores/aiTemplatesStarterCollection.store';
|
||||
|
||||
defineOptions({
|
||||
name: 'NodeView',
|
||||
@@ -197,6 +198,7 @@ const foldersStore = useFoldersStore();
|
||||
const posthogStore = usePostHog();
|
||||
const agentRequestStore = useAgentRequestStore();
|
||||
const logsStore = useLogsStore();
|
||||
const aiTemplatesStarterCollectionStore = useAITemplatesStarterCollectionStore();
|
||||
|
||||
const { addBeforeUnloadEventBindings, removeBeforeUnloadEventBindings } = useBeforeUnload({
|
||||
route,
|
||||
@@ -500,6 +502,12 @@ async function initializeWorkspaceForExistingWorkflow(id: string) {
|
||||
trackOpenWorkflowFromOnboardingTemplate();
|
||||
}
|
||||
|
||||
if (workflowData.meta?.templateId?.startsWith('035_template_onboarding')) {
|
||||
aiTemplatesStarterCollectionStore.trackUserOpenedWorkflow(
|
||||
workflowData.meta.templateId.split('-').pop() ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
await projectsStore.setProjectNavActiveIdByWorkflowHomeProject(workflowData.homeProject);
|
||||
} catch (error) {
|
||||
if (error.httpStatusCode === 404) {
|
||||
|
||||
@@ -69,6 +69,7 @@ import debounce from 'lodash/debounce';
|
||||
import { type IUser, PROJECT_ROOT } from 'n8n-workflow';
|
||||
import { computed, onBeforeUnmount, onMounted, ref, useTemplateRef, watch } from 'vue';
|
||||
import { type LocationQueryRaw, useRoute, useRouter } from 'vue-router';
|
||||
import { useAITemplatesStarterCollectionStore } from '@/experiments/aiTemplatesStarterCollection/stores/aiTemplatesStarterCollection.store';
|
||||
|
||||
const SEARCH_DEBOUNCE_TIME = 300;
|
||||
const FILTERS_DEBOUNCE_TIME = 100;
|
||||
@@ -112,6 +113,7 @@ const foldersStore = useFoldersStore();
|
||||
const usageStore = useUsageStore();
|
||||
const insightsStore = useInsightsStore();
|
||||
const templatesStore = useTemplatesStore();
|
||||
const aiStarterTemplatesStore = useAITemplatesStarterCollectionStore();
|
||||
|
||||
const documentTitle = useDocumentTitle();
|
||||
const { callDebounced } = useDebounce();
|
||||
@@ -369,6 +371,19 @@ const showRegisteredCommunityCTA = computed(
|
||||
() => isSelfHostedDeployment.value && !foldersEnabled.value && canUserRegisterCommunityPlus.value,
|
||||
);
|
||||
|
||||
const showAIStarterCollectionCallout = computed(() => {
|
||||
return (
|
||||
!loading.value &&
|
||||
aiStarterTemplatesStore.isFeatureEnabled &&
|
||||
!aiStarterTemplatesStore.calloutDismissed &&
|
||||
!readOnlyEnv.value &&
|
||||
// We want to show the callout only if the user has permissions to create folders and workflows
|
||||
// but also on the overview page
|
||||
(projectPages.isOverviewSubPage ||
|
||||
(hasPermissionToCreateFolders.value && hasPermissionToCreateWorkflows.value))
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* WATCHERS, STORE SUBSCRIPTIONS AND EVENT BUS HANDLERS
|
||||
*/
|
||||
@@ -778,6 +793,45 @@ function isValidProjectId(projectId: string) {
|
||||
return projectsStore.availableProjects.some((project) => project.id === projectId);
|
||||
}
|
||||
|
||||
const createAIStarterWorkflows = async (source: 'card' | 'callout') => {
|
||||
try {
|
||||
const projectId = projectPages.isOverviewSubPage
|
||||
? personalProject.value?.id
|
||||
: (route.params.projectId as string);
|
||||
if (typeof projectId !== 'string') {
|
||||
toast.showError(new Error(), i18n.baseText('workflows.ai.starter.collection.error'));
|
||||
return;
|
||||
}
|
||||
const newFolder = await aiStarterTemplatesStore.createStarterWorkflows(
|
||||
projectId,
|
||||
currentFolderId.value ?? undefined,
|
||||
);
|
||||
// If we are on the overview page, navigate to the new folder
|
||||
if (projectPages.isOverviewSubPage) {
|
||||
await router.push({
|
||||
name: VIEWS.PROJECTS_FOLDERS,
|
||||
params: { projectId, folderId: newFolder.id },
|
||||
});
|
||||
} else {
|
||||
// If we are in a specific folder, just add the new folder to the list
|
||||
workflowsAndFolders.value.unshift({
|
||||
id: newFolder.id,
|
||||
name: newFolder.name,
|
||||
resource: 'folder',
|
||||
createdAt: newFolder.createdAt,
|
||||
updatedAt: newFolder.updatedAt,
|
||||
subFolderCount: 0,
|
||||
workflowCount: 3,
|
||||
parentFolder: newFolder.parentFolder,
|
||||
});
|
||||
}
|
||||
aiStarterTemplatesStore.trackUserCreatedStarterCollection(source);
|
||||
} catch (error) {
|
||||
toast.showError(error, i18n.baseText('workflows.ai.starter.collection.error'));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const openAIWorkflow = async (source: string) => {
|
||||
dismissEasyAICallout();
|
||||
telemetry.track('User clicked test AI workflow', {
|
||||
@@ -793,6 +847,11 @@ const openAIWorkflow = async (source: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
const dismissStarterCollectionCallout = () => {
|
||||
aiStarterTemplatesStore.dismissCallout();
|
||||
aiStarterTemplatesStore.trackUserDismissedCallout();
|
||||
};
|
||||
|
||||
const dismissEasyAICallout = () => {
|
||||
easyAICalloutVisible.value = false;
|
||||
};
|
||||
@@ -1610,7 +1669,34 @@ const onNameSubmit = async (name: string) => {
|
||||
</template>
|
||||
<template #callout>
|
||||
<N8nCallout
|
||||
v-if="!loading && showEasyAIWorkflowCallout && easyAICalloutVisible"
|
||||
v-if="showAIStarterCollectionCallout"
|
||||
theme="secondary"
|
||||
icon="gift"
|
||||
:class="$style['easy-ai-workflow-callout']"
|
||||
>
|
||||
{{ i18n.baseText('workflows.ai.starter.collection.callout') }}
|
||||
<template #trailingContent>
|
||||
<div :class="$style['callout-trailing-content']">
|
||||
<N8nButton
|
||||
data-test-id="easy-ai-button"
|
||||
size="small"
|
||||
type="secondary"
|
||||
@click="createAIStarterWorkflows('callout')"
|
||||
>
|
||||
{{ i18n.baseText('generic.startNow') }}
|
||||
</N8nButton>
|
||||
<N8nIcon
|
||||
size="small"
|
||||
icon="x"
|
||||
:title="i18n.baseText('generic.dismiss')"
|
||||
class="clickable"
|
||||
@click="dismissStarterCollectionCallout"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</N8nCallout>
|
||||
<N8nCallout
|
||||
v-else-if="!loading && showEasyAIWorkflowCallout && easyAICalloutVisible"
|
||||
theme="secondary"
|
||||
icon="bot"
|
||||
:class="$style['easy-ai-workflow-callout']"
|
||||
@@ -1804,7 +1890,26 @@ const onNameSubmit = async (name: string) => {
|
||||
</div>
|
||||
</N8nCard>
|
||||
<N8nCard
|
||||
v-if="showEasyAIWorkflowCallout"
|
||||
v-if="showAIStarterCollectionCallout"
|
||||
:class="$style.emptyStateCard"
|
||||
hoverable
|
||||
data-test-id="easy-ai-workflow-card"
|
||||
@click="createAIStarterWorkflows('card')"
|
||||
>
|
||||
<div :class="$style.emptyStateCardContent">
|
||||
<N8nIcon
|
||||
:class="$style.emptyStateCardIcon"
|
||||
:stroke-width="1.5"
|
||||
icon="gift"
|
||||
color="foreground-dark"
|
||||
/>
|
||||
<N8nText size="large" class="mt-xs pl-2xs pr-2xs">
|
||||
{{ i18n.baseText('workflows.ai.starter.collection.card') }}
|
||||
</N8nText>
|
||||
</div>
|
||||
</N8nCard>
|
||||
<N8nCard
|
||||
v-else-if="showEasyAIWorkflowCallout"
|
||||
:class="$style.emptyStateCard"
|
||||
hoverable
|
||||
data-test-id="easy-ai-workflow-card"
|
||||
|
||||
Reference in New Issue
Block a user