mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-11 12:57:29 -08:00
fix(editor): Update easy AI workflow setup instructions when user is in free AI credits experiment (no-changelog) (#12479)
This commit is contained in:
parent
10148c9ad3
commit
6f00c74c1f
|
@ -5,11 +5,15 @@ import {
|
|||
WorkflowPage,
|
||||
visitPublicApiPage,
|
||||
getPublicApiUpgradeCTA,
|
||||
WorkflowsPage,
|
||||
} from '../pages';
|
||||
|
||||
const NUMBER_OF_AI_CREDITS = 100;
|
||||
|
||||
const mainSidebar = new MainSidebar();
|
||||
const bannerStack = new BannerStack();
|
||||
const workflowPage = new WorkflowPage();
|
||||
const workflowsPage = new WorkflowsPage();
|
||||
|
||||
describe('Cloud', () => {
|
||||
before(() => {
|
||||
|
@ -22,6 +26,10 @@ describe('Cloud', () => {
|
|||
cy.overrideSettings({
|
||||
deployment: { type: 'cloud' },
|
||||
n8nMetadata: { userId: '1' },
|
||||
aiCredits: {
|
||||
enabled: true,
|
||||
credits: NUMBER_OF_AI_CREDITS,
|
||||
},
|
||||
});
|
||||
cy.intercept('GET', '/rest/admin/cloud-plan', planData).as('getPlanData');
|
||||
cy.intercept('GET', '/rest/cloud/proxy/user/me', {}).as('getCloudUserInfo');
|
||||
|
@ -64,4 +72,66 @@ describe('Cloud', () => {
|
|||
getPublicApiUpgradeCTA().should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Easy AI workflow experiment', () => {
|
||||
it('should not show option to take you to the easy AI workflow if experiment is control', () => {
|
||||
window.localStorage.setItem(
|
||||
'N8N_EXPERIMENT_OVERRIDES',
|
||||
JSON.stringify({ '026_easy_ai_workflow': 'control' }),
|
||||
);
|
||||
|
||||
cy.visit(workflowsPage.url);
|
||||
|
||||
cy.getByTestId('easy-ai-workflow-card').should('not.exist');
|
||||
});
|
||||
|
||||
it('should show option to take you to the easy AI workflow if experiment is variant', () => {
|
||||
window.localStorage.setItem(
|
||||
'N8N_EXPERIMENT_OVERRIDES',
|
||||
JSON.stringify({ '026_easy_ai_workflow': 'variant' }),
|
||||
);
|
||||
|
||||
cy.visit(workflowsPage.url);
|
||||
|
||||
cy.getByTestId('easy-ai-workflow-card').should('to.exist');
|
||||
});
|
||||
|
||||
it('should show default instructions if free AI credits experiment is control', () => {
|
||||
window.localStorage.setItem(
|
||||
'N8N_EXPERIMENT_OVERRIDES',
|
||||
JSON.stringify({ '027_free_openai_calls': 'control', '026_easy_ai_workflow': 'variant' }),
|
||||
);
|
||||
|
||||
cy.visit(workflowsPage.url);
|
||||
|
||||
cy.getByTestId('easy-ai-workflow-card').click();
|
||||
|
||||
workflowPage.getters
|
||||
.stickies()
|
||||
.eq(0)
|
||||
.should(($el) => {
|
||||
expect($el).contains.text('Set up your OpenAI credentials in the OpenAI Model node');
|
||||
});
|
||||
});
|
||||
|
||||
it('should show updated instructions if free AI credits experiment is variant', () => {
|
||||
window.localStorage.setItem(
|
||||
'N8N_EXPERIMENT_OVERRIDES',
|
||||
JSON.stringify({ '027_free_openai_calls': 'variant', '026_easy_ai_workflow': 'variant' }),
|
||||
);
|
||||
|
||||
cy.visit(workflowsPage.url);
|
||||
|
||||
cy.getByTestId('easy-ai-workflow-card').click();
|
||||
|
||||
workflowPage.getters
|
||||
.stickies()
|
||||
.eq(0)
|
||||
.should(($el) => {
|
||||
expect($el).contains.text(
|
||||
`Claim your free ${NUMBER_OF_AI_CREDITS} OpenAI calls in the OpenAI model node`,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,7 +18,7 @@ import type { PushMessage } from '@n8n/api-types';
|
|||
|
||||
import { useNodeHelpers } from '@/composables/useNodeHelpers';
|
||||
import { useToast } from '@/composables/useToast';
|
||||
import { WORKFLOW_SETTINGS_MODAL_KEY } from '@/constants';
|
||||
import { AI_CREDITS_EXPERIMENT, WORKFLOW_SETTINGS_MODAL_KEY } from '@/constants';
|
||||
import { getTriggerNodeServiceName } from '@/utils/nodeTypesUtils';
|
||||
import { codeNodeEditorEventBus, globalLinkActionsEventBus } from '@/event-bus';
|
||||
import { useUIStore } from '@/stores/ui.store';
|
||||
|
@ -36,8 +36,9 @@ import type { PushMessageQueueItem } from '@/types';
|
|||
import { useAssistantStore } from '@/stores/assistant.store';
|
||||
import NodeExecutionErrorMessage from '@/components/NodeExecutionErrorMessage.vue';
|
||||
import type { IExecutionResponse } from '@/Interface';
|
||||
import { EASY_AI_WORKFLOW_JSON } from '@/constants.workflows';
|
||||
import { clearPopupWindowState } from '../utils/executionUtils';
|
||||
import { usePostHog } from '@/stores/posthog.store';
|
||||
import { getEasyAiWorkflowJson } from '@/utils/easyAiWorkflowUtils';
|
||||
|
||||
export function usePushConnection({ router }: { router: ReturnType<typeof useRouter> }) {
|
||||
const workflowHelpers = useWorkflowHelpers({ router });
|
||||
|
@ -54,6 +55,7 @@ export function usePushConnection({ router }: { router: ReturnType<typeof useRou
|
|||
const uiStore = useUIStore();
|
||||
const workflowsStore = useWorkflowsStore();
|
||||
const assistantStore = useAssistantStore();
|
||||
const posthogStore = usePostHog();
|
||||
|
||||
const retryTimeout = ref<NodeJS.Timeout | null>(null);
|
||||
const pushMessageQueue = ref<PushMessageQueueItem[]>([]);
|
||||
|
@ -205,8 +207,13 @@ export function usePushConnection({ router }: { router: ReturnType<typeof useRou
|
|||
clearPopupWindowState();
|
||||
const workflow = workflowsStore.getWorkflowById(receivedData.data.workflowId);
|
||||
if (workflow?.meta?.templateId) {
|
||||
const isEasyAIWorkflow =
|
||||
workflow.meta.templateId === EASY_AI_WORKFLOW_JSON.meta.templateId;
|
||||
const isAiCreditsExperimentEnabled =
|
||||
posthogStore.getVariant(AI_CREDITS_EXPERIMENT.name) === AI_CREDITS_EXPERIMENT.variant;
|
||||
const easyAiWorkflowJson = getEasyAiWorkflowJson({
|
||||
isInstanceInAiFreeCreditsExperiment: isAiCreditsExperimentEnabled,
|
||||
withOpenAiFreeCredits: settingsStore.aiCreditsQuota,
|
||||
});
|
||||
const isEasyAIWorkflow = workflow.meta.templateId === easyAiWorkflowJson.meta.templateId;
|
||||
if (isEasyAIWorkflow) {
|
||||
telemetry.track(
|
||||
'User executed test AI workflow',
|
||||
|
|
|
@ -1,172 +1,6 @@
|
|||
import { NodeConnectionType } from 'n8n-workflow';
|
||||
import type { INodeUi, WorkflowDataWithTemplateId } from './Interface';
|
||||
|
||||
export const EASY_AI_WORKFLOW_JSON: WorkflowDataWithTemplateId = {
|
||||
name: 'Demo: My first AI Agent in n8n',
|
||||
meta: {
|
||||
templateId: 'PT1i+zU92Ii5O2XCObkhfHJR5h9rNJTpiCIkYJk9jHU=',
|
||||
},
|
||||
nodes: [
|
||||
{
|
||||
id: '0d7e4666-bc0e-489a-9e8f-a5ef191f4954',
|
||||
name: 'Google Calendar',
|
||||
type: 'n8n-nodes-base.googleCalendarTool',
|
||||
typeVersion: 1.2,
|
||||
position: [880, 220],
|
||||
parameters: {
|
||||
operation: 'getAll',
|
||||
calendar: {
|
||||
__rl: true,
|
||||
mode: 'list',
|
||||
},
|
||||
returnAll: true,
|
||||
options: {
|
||||
timeMin:
|
||||
"={{ $fromAI('after', 'The earliest datetime we want to look for events for') }}",
|
||||
timeMax: "={{ $fromAI('before', 'The latest datetime we want to look for events for') }}",
|
||||
query:
|
||||
"={{ $fromAI('query', 'The search query to look for in the calendar. Leave empty if no search query is needed') }}",
|
||||
singleEvents: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '5b410409-5b0b-47bd-b413-5b9b1000a063',
|
||||
name: 'When chat message received',
|
||||
type: '@n8n/n8n-nodes-langchain.chatTrigger',
|
||||
typeVersion: 1.1,
|
||||
position: [360, 20],
|
||||
webhookId: 'a889d2ae-2159-402f-b326-5f61e90f602e',
|
||||
parameters: {
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '29963449-1dc1-487d-96f2-7ff0a5c3cd97',
|
||||
name: 'AI Agent',
|
||||
type: '@n8n/n8n-nodes-langchain.agent',
|
||||
typeVersion: 1.7,
|
||||
position: [560, 20],
|
||||
parameters: {
|
||||
options: {
|
||||
systemMessage:
|
||||
"=You're a helpful assistant that the user to answer questions about their calendar.\n\nToday is {{ $now.format('cccc') }} the {{ $now.format('yyyy-MM-dd HH:mm') }}.",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'eae35513-07c2-4de2-a795-a153b6934c1b',
|
||||
name: 'Sticky Note',
|
||||
type: 'n8n-nodes-base.stickyNote',
|
||||
typeVersion: 1,
|
||||
position: [0, 0],
|
||||
parameters: {
|
||||
content:
|
||||
'## 👋 Welcome to n8n!\nThis example shows how to build an AI Agent that interacts with your \ncalendar.\n\n### 1. Connect your accounts\n- Set up your [OpenAI credentials](https://docs.n8n.io/integrations/builtin/credentials/openai/?utm_source=n8n_app&utm_medium=credential_settings&utm_campaign=create_new_credentials_modal) in the `OpenAI Model` node\n- Connect your Google account in the `Google Calendar` node credentials section\n\n### 2. Ready to test it?\nClick Chat below and start asking questions! For example you can try `What meetings do I have today?`',
|
||||
height: 389,
|
||||
width: 319,
|
||||
color: 6,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '68b59889-7aca-49fd-a49b-d86fa6239b96',
|
||||
name: 'Sticky Note1',
|
||||
type: 'n8n-nodes-base.stickyNote',
|
||||
typeVersion: 1,
|
||||
position: [820, 200],
|
||||
parameters: {
|
||||
content:
|
||||
"\n\n\n\n\n\n\n\n\n\n\n\nDon't have **Google Calendar**? Simply exchange this with the **Microsoft Outlook** or other tools",
|
||||
height: 253,
|
||||
width: 226,
|
||||
color: 7,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'cbaedf86-9153-4778-b893-a7e50d3e04ba',
|
||||
name: 'OpenAI Model',
|
||||
type: '@n8n/n8n-nodes-langchain.lmChatOpenAi',
|
||||
typeVersion: 1,
|
||||
position: [520, 220],
|
||||
parameters: {
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '75481370-bade-4d90-a878-3a3b0201edcc',
|
||||
name: 'Memory',
|
||||
type: '@n8n/n8n-nodes-langchain.memoryBufferWindow',
|
||||
typeVersion: 1.3,
|
||||
position: [680, 220],
|
||||
parameters: {},
|
||||
},
|
||||
{
|
||||
id: '907552eb-6e0f-472e-9d90-4513a67a31db',
|
||||
name: 'Sticky Note3',
|
||||
type: 'n8n-nodes-base.stickyNote',
|
||||
typeVersion: 1,
|
||||
position: [0, 400],
|
||||
parameters: {
|
||||
content:
|
||||
'### Want to learn more?\nWant to learn more about AI and how to apply it best in n8n? Have a look at our [new tutorial series on YouTube](https://www.youtube.com/watch?v=yzvLfHb0nqE&lc).',
|
||||
height: 100,
|
||||
width: 317,
|
||||
color: 6,
|
||||
},
|
||||
},
|
||||
] as INodeUi[],
|
||||
connections: {
|
||||
'Google Calendar': {
|
||||
ai_tool: [
|
||||
[
|
||||
{
|
||||
node: 'AI Agent',
|
||||
type: NodeConnectionType.AiTool,
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
'When chat message received': {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: 'AI Agent',
|
||||
type: NodeConnectionType.Main,
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
'OpenAI Model': {
|
||||
ai_languageModel: [
|
||||
[
|
||||
{
|
||||
node: 'AI Agent',
|
||||
type: NodeConnectionType.AiLanguageModel,
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
Memory: {
|
||||
ai_memory: [
|
||||
[
|
||||
{
|
||||
node: 'AI Agent',
|
||||
type: NodeConnectionType.AiMemory,
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
settings: {
|
||||
executionOrder: 'v1',
|
||||
},
|
||||
pinData: {},
|
||||
};
|
||||
|
||||
export const SAMPLE_SUBWORKFLOW_WORKFLOW: WorkflowDataWithTemplateId = {
|
||||
name: 'My Sub-Workflow',
|
||||
meta: {
|
||||
|
|
38
packages/editor-ui/src/utils/easyAiWorkflowUtils.test.ts
Normal file
38
packages/editor-ui/src/utils/easyAiWorkflowUtils.test.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getEasyAiWorkflowJson } from './easyAiWorkflowUtils';
|
||||
|
||||
describe('getEasyAiWorkflowJson', () => {
|
||||
it('should update sticky note content for AI free credits experiment', () => {
|
||||
const workflow = getEasyAiWorkflowJson({
|
||||
isInstanceInAiFreeCreditsExperiment: true,
|
||||
withOpenAiFreeCredits: 25,
|
||||
});
|
||||
|
||||
if (!workflow?.nodes) fail();
|
||||
|
||||
const stickyNote = workflow.nodes.find(
|
||||
(node) => node.type === 'n8n-nodes-base.stickyNote' && node.name === 'Sticky Note',
|
||||
);
|
||||
|
||||
expect(stickyNote?.parameters.content).toContain(
|
||||
'Claim your `free` 25 OpenAI calls in the `OpenAI model` node',
|
||||
);
|
||||
});
|
||||
|
||||
it('should show default content when not in AI free credits experiment', () => {
|
||||
const workflow = getEasyAiWorkflowJson({
|
||||
isInstanceInAiFreeCreditsExperiment: false,
|
||||
withOpenAiFreeCredits: 0,
|
||||
});
|
||||
|
||||
if (!workflow?.nodes) fail();
|
||||
|
||||
const stickyNote = workflow.nodes.find(
|
||||
(node) => node.type === 'n8n-nodes-base.stickyNote' && node.name === 'Sticky Note',
|
||||
);
|
||||
|
||||
expect(stickyNote?.parameters.content).toContain(
|
||||
'Set up your [OpenAI credentials](https://docs.n8n.io/integrations/builtin/credentials/openai/?utm_source=n8n_app&utm_medium=credential_settings&utm_campaign=create_new_credentials_modal) in the `OpenAI Model` node',
|
||||
);
|
||||
});
|
||||
});
|
193
packages/editor-ui/src/utils/easyAiWorkflowUtils.ts
Normal file
193
packages/editor-ui/src/utils/easyAiWorkflowUtils.ts
Normal file
|
@ -0,0 +1,193 @@
|
|||
import type { INodeUi, WorkflowDataWithTemplateId } from '@/Interface';
|
||||
import { NodeConnectionType } from 'n8n-workflow';
|
||||
|
||||
/**
|
||||
* Generates a workflow JSON object for an AI Agent in n8n.
|
||||
*
|
||||
* @param {Object} params - The parameters for generating the workflow JSON.
|
||||
* @param {boolean} params.isInstanceInAiFreeCreditsExperiment - Indicates if the instance is part of the AI free credits experiment.
|
||||
* @param {number} params.withOpenAiFreeCredits - The number of free OpenAI calls available.
|
||||
*
|
||||
* @remarks
|
||||
* This function can be deleted once the free AI credits experiment is removed.
|
||||
*/
|
||||
export const getEasyAiWorkflowJson = ({
|
||||
isInstanceInAiFreeCreditsExperiment,
|
||||
withOpenAiFreeCredits,
|
||||
}: {
|
||||
withOpenAiFreeCredits: number;
|
||||
isInstanceInAiFreeCreditsExperiment: boolean;
|
||||
}): WorkflowDataWithTemplateId => {
|
||||
let instructionsFirstStep =
|
||||
'Set up your [OpenAI credentials](https://docs.n8n.io/integrations/builtin/credentials/openai/?utm_source=n8n_app&utm_medium=credential_settings&utm_campaign=create_new_credentials_modal) in the `OpenAI Model` node';
|
||||
|
||||
if (isInstanceInAiFreeCreditsExperiment) {
|
||||
instructionsFirstStep = `Claim your \`free\` ${withOpenAiFreeCredits} OpenAI calls in the \`OpenAI model\` node`;
|
||||
}
|
||||
|
||||
return {
|
||||
name: 'Demo: My first AI Agent in n8n',
|
||||
meta: {
|
||||
templateId: 'PT1i+zU92Ii5O2XCObkhfHJR5h9rNJTpiCIkYJk9jHU=',
|
||||
},
|
||||
nodes: [
|
||||
{
|
||||
id: '0d7e4666-bc0e-489a-9e8f-a5ef191f4954',
|
||||
name: 'Google Calendar',
|
||||
type: 'n8n-nodes-base.googleCalendarTool',
|
||||
typeVersion: 1.2,
|
||||
position: [880, 220],
|
||||
parameters: {
|
||||
operation: 'getAll',
|
||||
calendar: {
|
||||
__rl: true,
|
||||
mode: 'list',
|
||||
},
|
||||
returnAll: true,
|
||||
options: {
|
||||
timeMin:
|
||||
"={{ $fromAI('after', 'The earliest datetime we want to look for events for') }}",
|
||||
timeMax:
|
||||
"={{ $fromAI('before', 'The latest datetime we want to look for events for') }}",
|
||||
query:
|
||||
"={{ $fromAI('query', 'The search query to look for in the calendar. Leave empty if no search query is needed') }}",
|
||||
singleEvents: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '5b410409-5b0b-47bd-b413-5b9b1000a063',
|
||||
name: 'When chat message received',
|
||||
type: '@n8n/n8n-nodes-langchain.chatTrigger',
|
||||
typeVersion: 1.1,
|
||||
position: [360, 20],
|
||||
webhookId: 'a889d2ae-2159-402f-b326-5f61e90f602e',
|
||||
parameters: {
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '29963449-1dc1-487d-96f2-7ff0a5c3cd97',
|
||||
name: 'AI Agent',
|
||||
type: '@n8n/n8n-nodes-langchain.agent',
|
||||
typeVersion: 1.7,
|
||||
position: [560, 20],
|
||||
parameters: {
|
||||
options: {
|
||||
systemMessage:
|
||||
"=You're a helpful assistant that the user to answer questions about their calendar.\n\nToday is {{ $now.format('cccc') }} the {{ $now.format('yyyy-MM-dd HH:mm') }}.",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'eae35513-07c2-4de2-a795-a153b6934c1b',
|
||||
name: 'Sticky Note',
|
||||
type: 'n8n-nodes-base.stickyNote',
|
||||
typeVersion: 1,
|
||||
position: [0, 0],
|
||||
parameters: {
|
||||
content: `## 👋 Welcome to n8n!\nThis example shows how to build an AI Agent that interacts with your \ncalendar.\n\n### 1. Connect your accounts\n- ${instructionsFirstStep} \n- Connect your Google account in the \`Google Calendar\` node credentials section\n\n### 2. Ready to test it?\nClick Chat below and start asking questions! For example you can try \`What meetings do I have today?\``,
|
||||
height: 389,
|
||||
width: 319,
|
||||
color: 6,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '68b59889-7aca-49fd-a49b-d86fa6239b96',
|
||||
name: 'Sticky Note1',
|
||||
type: 'n8n-nodes-base.stickyNote',
|
||||
typeVersion: 1,
|
||||
position: [820, 200],
|
||||
parameters: {
|
||||
content:
|
||||
"\n\n\n\n\n\n\n\n\n\n\n\nDon't have **Google Calendar**? Simply exchange this with the **Microsoft Outlook** or other tools",
|
||||
height: 253,
|
||||
width: 226,
|
||||
color: 7,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'cbaedf86-9153-4778-b893-a7e50d3e04ba',
|
||||
name: 'OpenAI Model',
|
||||
type: '@n8n/n8n-nodes-langchain.lmChatOpenAi',
|
||||
typeVersion: 1,
|
||||
position: [520, 220],
|
||||
parameters: {
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '75481370-bade-4d90-a878-3a3b0201edcc',
|
||||
name: 'Memory',
|
||||
type: '@n8n/n8n-nodes-langchain.memoryBufferWindow',
|
||||
typeVersion: 1.3,
|
||||
position: [680, 220],
|
||||
parameters: {},
|
||||
},
|
||||
{
|
||||
id: '907552eb-6e0f-472e-9d90-4513a67a31db',
|
||||
name: 'Sticky Note3',
|
||||
type: 'n8n-nodes-base.stickyNote',
|
||||
typeVersion: 1,
|
||||
position: [0, 400],
|
||||
parameters: {
|
||||
content:
|
||||
'### Want to learn more?\nWant to learn more about AI and how to apply it best in n8n? Have a look at our [new tutorial series on YouTube](https://www.youtube.com/watch?v=yzvLfHb0nqE&lc).',
|
||||
height: 100,
|
||||
width: 317,
|
||||
color: 6,
|
||||
},
|
||||
},
|
||||
] as INodeUi[],
|
||||
connections: {
|
||||
'Google Calendar': {
|
||||
ai_tool: [
|
||||
[
|
||||
{
|
||||
node: 'AI Agent',
|
||||
type: NodeConnectionType.AiTool,
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
'When chat message received': {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
node: 'AI Agent',
|
||||
type: NodeConnectionType.Main,
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
'OpenAI Model': {
|
||||
ai_languageModel: [
|
||||
[
|
||||
{
|
||||
node: 'AI Agent',
|
||||
type: NodeConnectionType.AiLanguageModel,
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
Memory: {
|
||||
ai_memory: [
|
||||
[
|
||||
{
|
||||
node: 'AI Agent',
|
||||
type: NodeConnectionType.AiMemory,
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
settings: {
|
||||
executionOrder: 'v1',
|
||||
},
|
||||
pinData: {},
|
||||
};
|
||||
};
|
|
@ -62,6 +62,7 @@ import {
|
|||
STICKY_NODE_TYPE,
|
||||
VALID_WORKFLOW_IMPORT_URL_REGEX,
|
||||
VIEWS,
|
||||
AI_CREDITS_EXPERIMENT,
|
||||
} from '@/constants';
|
||||
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
||||
import { useNodeCreatorStore } from '@/stores/nodeCreator.store';
|
||||
|
@ -85,6 +86,7 @@ import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
|
|||
import { useTelemetry } from '@/composables/useTelemetry';
|
||||
import { useHistoryStore } from '@/stores/history.store';
|
||||
import { useProjectsStore } from '@/stores/projects.store';
|
||||
import { usePostHog } from '@/stores/posthog.store';
|
||||
import { useNodeHelpers } from '@/composables/useNodeHelpers';
|
||||
import { useExecutionDebugging } from '@/composables/useExecutionDebugging';
|
||||
import { useUsersStore } from '@/stores/users.store';
|
||||
|
@ -108,7 +110,7 @@ import { getResourcePermissions } from '@/permissions';
|
|||
import NodeViewUnfinishedWorkflowMessage from '@/components/NodeViewUnfinishedWorkflowMessage.vue';
|
||||
import { createCanvasConnectionHandleString } from '@/utils/canvasUtilsV2';
|
||||
import { isValidNodeConnectionType } from '@/utils/typeGuards';
|
||||
import { EASY_AI_WORKFLOW_JSON } from '@/constants.workflows';
|
||||
import { getEasyAiWorkflowJson } from '@/utils/easyAiWorkflowUtils';
|
||||
|
||||
const LazyNodeCreation = defineAsyncComponent(
|
||||
async () => await import('@/components/Node/NodeCreation.vue'),
|
||||
|
@ -155,6 +157,7 @@ const tagsStore = useTagsStore();
|
|||
const pushConnectionStore = usePushConnectionStore();
|
||||
const ndvStore = useNDVStore();
|
||||
const templatesStore = useTemplatesStore();
|
||||
const posthogStore = usePostHog();
|
||||
|
||||
const canvasEventBus = createEventBus<CanvasEventBusEvents>();
|
||||
|
||||
|
@ -325,7 +328,14 @@ async function initializeRoute(force = false) {
|
|||
const loadWorkflowFromJSON = route.query.fromJson === 'true';
|
||||
|
||||
if (loadWorkflowFromJSON) {
|
||||
await openTemplateFromWorkflowJSON(EASY_AI_WORKFLOW_JSON);
|
||||
const isAiCreditsExperimentEnabled =
|
||||
posthogStore.getVariant(AI_CREDITS_EXPERIMENT.name) === AI_CREDITS_EXPERIMENT.variant;
|
||||
|
||||
const easyAiWorkflowJson = getEasyAiWorkflowJson({
|
||||
isInstanceInAiFreeCreditsExperiment: isAiCreditsExperimentEnabled,
|
||||
withOpenAiFreeCredits: settingsStore.aiCreditsQuota,
|
||||
});
|
||||
await openTemplateFromWorkflowJSON(easyAiWorkflowJson);
|
||||
} else {
|
||||
await openWorkflowTemplate(templateId.toString());
|
||||
}
|
||||
|
|
|
@ -181,7 +181,8 @@ import { useNpsSurveyStore } from '@/stores/npsSurvey.store';
|
|||
import { getResourcePermissions } from '@/permissions';
|
||||
import { useBeforeUnload } from '@/composables/useBeforeUnload';
|
||||
import NodeViewUnfinishedWorkflowMessage from '@/components/NodeViewUnfinishedWorkflowMessage.vue';
|
||||
import { EASY_AI_WORKFLOW_JSON } from '@/constants.workflows';
|
||||
import { AI_CREDITS_EXPERIMENT } from '@/constants';
|
||||
import { getEasyAiWorkflowJson } from '@/utils/easyAiWorkflowUtils';
|
||||
|
||||
interface AddNodeOptions {
|
||||
position?: XYPosition;
|
||||
|
@ -220,6 +221,7 @@ export default defineComponent({
|
|||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
const posthogStore = usePostHog();
|
||||
const ndvStore = useNDVStore();
|
||||
const externalHooks = useExternalHooks();
|
||||
const i18n = useI18n();
|
||||
|
@ -254,6 +256,7 @@ export default defineComponent({
|
|||
nodeViewRef,
|
||||
onMouseMoveEnd,
|
||||
workflowHelpers,
|
||||
posthogStore,
|
||||
runWorkflow,
|
||||
stopCurrentExecution,
|
||||
callDebounced,
|
||||
|
@ -3401,7 +3404,15 @@ export default defineComponent({
|
|||
const templateId = this.$route.params.id;
|
||||
const loadWorkflowFromJSON = this.$route.query.fromJson === 'true';
|
||||
if (loadWorkflowFromJSON) {
|
||||
await this.openWorkflowTemplateFromJson({ workflow: EASY_AI_WORKFLOW_JSON });
|
||||
const isAiCreditsExperimentEnabled =
|
||||
this.posthogStore.getVariant(AI_CREDITS_EXPERIMENT.name) ===
|
||||
AI_CREDITS_EXPERIMENT.variant;
|
||||
|
||||
const easyAiWorkflowJson = getEasyAiWorkflowJson({
|
||||
isInstanceInAiFreeCreditsExperiment: isAiCreditsExperimentEnabled,
|
||||
withOpenAiFreeCredits: useSettingsStore().aiCreditsQuota,
|
||||
});
|
||||
await this.openWorkflowTemplateFromJson({ workflow: easyAiWorkflowJson });
|
||||
} else {
|
||||
await this.openWorkflowTemplate(templateId.toString());
|
||||
}
|
||||
|
|
|
@ -6,7 +6,12 @@ import ResourcesListLayout, {
|
|||
} from '@/components/layouts/ResourcesListLayout.vue';
|
||||
import WorkflowCard from '@/components/WorkflowCard.vue';
|
||||
import WorkflowTagsDropdown from '@/components/WorkflowTagsDropdown.vue';
|
||||
import { EASY_AI_WORKFLOW_EXPERIMENT, EnterpriseEditionFeature, VIEWS } from '@/constants';
|
||||
import {
|
||||
EASY_AI_WORKFLOW_EXPERIMENT,
|
||||
AI_CREDITS_EXPERIMENT,
|
||||
EnterpriseEditionFeature,
|
||||
VIEWS,
|
||||
} from '@/constants';
|
||||
import type { IUser, IWorkflowDb } from '@/Interface';
|
||||
import { useUIStore } from '@/stores/ui.store';
|
||||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
|
@ -32,7 +37,7 @@ import {
|
|||
} from 'n8n-design-system';
|
||||
import { pickBy } from 'lodash-es';
|
||||
import ProjectHeader from '@/components/Projects/ProjectHeader.vue';
|
||||
import { EASY_AI_WORKFLOW_JSON } from '@/constants.workflows';
|
||||
import { getEasyAiWorkflowJson } from '@/utils/easyAiWorkflowUtils';
|
||||
|
||||
const i18n = useI18n();
|
||||
const route = useRoute();
|
||||
|
@ -269,9 +274,18 @@ const openAIWorkflow = async (source: string) => {
|
|||
},
|
||||
{ withPostHog: true },
|
||||
);
|
||||
|
||||
const isAiCreditsExperimentEnabled =
|
||||
posthogStore.getVariant(AI_CREDITS_EXPERIMENT.name) === AI_CREDITS_EXPERIMENT.variant;
|
||||
|
||||
const easyAiWorkflowJson = getEasyAiWorkflowJson({
|
||||
isInstanceInAiFreeCreditsExperiment: isAiCreditsExperimentEnabled,
|
||||
withOpenAiFreeCredits: settingsStore.aiCreditsQuota,
|
||||
});
|
||||
|
||||
await router.push({
|
||||
name: VIEWS.TEMPLATE_IMPORT,
|
||||
params: { id: EASY_AI_WORKFLOW_JSON.meta.templateId },
|
||||
params: { id: easyAiWorkflowJson.meta.templateId },
|
||||
query: { fromJson: 'true' },
|
||||
});
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue