Skip to content

Commit

Permalink
feat: Expose license feature flags for free AI credits feature to fro…
Browse files Browse the repository at this point in the history
…ntend (no-changelog) (#12363)
  • Loading branch information
RicardoE105 authored Dec 27, 2024
1 parent ac4e042 commit 7ea6c8b
Show file tree
Hide file tree
Showing 10 changed files with 57 additions and 2 deletions.
4 changes: 4 additions & 0 deletions packages/@n8n/api-types/src/frontend-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ export interface FrontendSettings {
pruneTime: number;
licensePruneTime: number;
};
aiCredits: {
enabled: boolean;
credits: number;
};
pruning?: {
isEnabled: boolean;
maxAge: number;
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export const LICENSE_FEATURES = {
AI_ASSISTANT: 'feat:aiAssistant',
ASK_AI: 'feat:askAi',
COMMUNITY_NODES_CUSTOM_REGISTRY: 'feat:communityNodes:customRegistry',
AI_CREDITS: 'feat:aiCredits',
} as const;

export const LICENSE_QUOTAS = {
Expand All @@ -101,6 +102,7 @@ export const LICENSE_QUOTAS = {
USERS_LIMIT: 'quota:users',
WORKFLOW_HISTORY_PRUNE_LIMIT: 'quota:workflowHistoryPrune',
TEAM_PROJECT_LIMIT: 'quota:maxTeamProjects',
AI_CREDITS: 'quota:aiCredits',
} as const;
export const UNLIMITED_LICENSE_QUOTA = -1;

Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/controllers/e2e.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export class E2EController {
[LICENSE_FEATURES.AI_ASSISTANT]: false,
[LICENSE_FEATURES.COMMUNITY_NODES_CUSTOM_REGISTRY]: false,
[LICENSE_FEATURES.ASK_AI]: false,
[LICENSE_FEATURES.AI_CREDITS]: false,
};

private numericFeatures: Record<NumericLicenseFeature, number> = {
Expand All @@ -108,6 +109,7 @@ export class E2EController {
[LICENSE_QUOTAS.USERS_LIMIT]: -1,
[LICENSE_QUOTAS.WORKFLOW_HISTORY_PRUNE_LIMIT]: -1,
[LICENSE_QUOTAS.TEAM_PROJECT_LIMIT]: 0,
[LICENSE_QUOTAS.AI_CREDITS]: 0,
};

constructor(
Expand Down
8 changes: 8 additions & 0 deletions packages/cli/src/license.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,10 @@ export class License {
return this.isFeatureEnabled(LICENSE_FEATURES.ASK_AI);
}

isAiCreditsEnabled() {
return this.isFeatureEnabled(LICENSE_FEATURES.AI_CREDITS);
}

isAdvancedExecutionFiltersEnabled() {
return this.isFeatureEnabled(LICENSE_FEATURES.ADVANCED_EXECUTION_FILTERS);
}
Expand Down Expand Up @@ -365,6 +369,10 @@ export class License {
return this.getFeatureValue(LICENSE_QUOTAS.VARIABLES_LIMIT) ?? UNLIMITED_LICENSE_QUOTA;
}

getAiCredits() {
return this.getFeatureValue(LICENSE_QUOTAS.AI_CREDITS) ?? 0;
}

getWorkflowHistoryPruneLimit() {
return (
this.getFeatureValue(LICENSE_QUOTAS.WORKFLOW_HISTORY_PRUNE_LIMIT) ?? UNLIMITED_LICENSE_QUOTA
Expand Down
10 changes: 10 additions & 0 deletions packages/cli/src/services/frontend.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,10 @@ export class FrontendService {
askAi: {
enabled: false,
},
aiCredits: {
enabled: false,
credits: 0,
},
workflowHistory: {
pruneTime: -1,
licensePruneTime: -1,
Expand Down Expand Up @@ -283,6 +287,7 @@ export class FrontendService {
const isS3Licensed = this.license.isBinaryDataS3Licensed();
const isAiAssistantEnabled = this.license.isAiAssistantEnabled();
const isAskAiEnabled = this.license.isAskAiEnabled();
const isAiCreditsEnabled = this.license.isAiCreditsEnabled();

this.settings.license.planName = this.license.getPlanName();
this.settings.license.consumerId = this.license.getConsumerId();
Expand Down Expand Up @@ -343,6 +348,11 @@ export class FrontendService {
this.settings.askAi.enabled = isAskAiEnabled;
}

if (isAiCreditsEnabled) {
this.settings.aiCredits.enabled = isAiCreditsEnabled;
this.settings.aiCredits.credits = this.license.getAiCredits();
}

this.settings.mfa.enabled = config.get('mfa.enabled');

this.settings.executionMode = config.getEnv('executions.mode');
Expand Down
4 changes: 4 additions & 0 deletions packages/editor-ui/src/__tests__/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ export const defaultSettings: FrontendSettings = {
aiAssistant: {
enabled: false,
},
aiCredits: {
enabled: false,
credits: 0,
},
betaFeatures: [],
easyAIWorkflowOnboarded: false,
};
11 changes: 10 additions & 1 deletion packages/editor-ui/src/api/ai.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { IRestApiContext } from '@/Interface';
import type { ICredentialsResponse, IRestApiContext } from '@/Interface';
import type { AskAiRequest, ChatRequest, ReplaceCodeRequest } from '@/types/assistant.types';
import { makeRestApiRequest, streamRequest } from '@/utils/apiUtils';
import type { IDataObject } from 'n8n-workflow';
Expand Down Expand Up @@ -42,3 +42,12 @@ export async function generateCodeForPrompt(
forNode,
} as IDataObject);
}

export async function claimFreeAiCredits(
ctx: IRestApiContext,
{ projectId }: { projectId?: string },
): Promise<ICredentialsResponse> {
return await makeRestApiRequest(ctx, 'POST', '/ai/free-credits', {
projectId,
} as IDataObject);
}
7 changes: 7 additions & 0 deletions packages/editor-ui/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -706,12 +706,19 @@ export const EASY_AI_WORKFLOW_EXPERIMENT = {
variant: 'variant',
};

export const AI_CREDITS_EXPERIMENT = {
name: '027_free_openai_calls',
control: 'control',
variant: 'variant',
};

export const EXPERIMENTS_TO_TRACK = [
TEMPLATE_CREDENTIAL_SETUP_EXPERIMENT,
CANVAS_AUTO_ADD_MANUAL_TRIGGER_EXPERIMENT.name,
AI_ASSISTANT_EXPERIMENT.name,
CREDENTIAL_DOCS_EXPERIMENT.name,
EASY_AI_WORKFLOW_EXPERIMENT.name,
AI_CREDITS_EXPERIMENT.name,
];

export const WORKFLOW_EVALUATION_EXPERIMENT = '025_workflow_evaluation';
Expand Down
6 changes: 6 additions & 0 deletions packages/editor-ui/src/stores/settings.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, () => {

const isCloudDeployment = computed(() => settings.value.deployment?.type === 'cloud');

const isAiCreditsEnabled = computed(() => settings.value.aiCredits?.enabled);

const aiCreditsQuota = computed(() => settings.value.aiCredits?.credits);

const isSmtpSetup = computed(() => userManagement.value.smtpSetup);

const isPersonalizationSurveyEnabled = computed(
Expand Down Expand Up @@ -425,6 +429,8 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, () => {
isCommunityPlan,
isAskAiEnabled,
isCanvasV2Enabled,
isAiCreditsEnabled,
aiCreditsQuota,
reset,
testLdapConnection,
getLdapConfig,
Expand Down
5 changes: 4 additions & 1 deletion packages/editor-ui/src/stores/users.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ export const useUsersStore = defineStore(STORES.USERS, () => {

const globalRoleName = computed(() => currentUser.value?.role ?? 'default');

const userClaimedAiCredits = computed(() => currentUser.value?.settings?.userClaimedAiCredits);

const isEasyAIWorkflowOnboardingDone = computed(() =>
Boolean(currentUser.value?.settings?.easyAIWorkflowOnboarded),
);
Expand Down Expand Up @@ -388,6 +390,8 @@ export const useUsersStore = defineStore(STORES.USERS, () => {
mfaEnabled,
globalRoleName,
personalizedNodeTypes,
userClaimedAiCredits,
isEasyAIWorkflowOnboardingDone,
addUsers,
loginWithCookie,
initialize,
Expand Down Expand Up @@ -420,7 +424,6 @@ export const useUsersStore = defineStore(STORES.USERS, () => {
sendConfirmationEmail,
updateGlobalRole,
reset,
isEasyAIWorkflowOnboardingDone,
setEasyAIWorkflowOnboardingDone,
};
});

0 comments on commit 7ea6c8b

Please sign in to comment.