chore: remove IS_AI_ENABLED feature flag (#19916)
## Summary - AI is now GA, so the public/lab `IS_AI_ENABLED` flag is removed from `FeatureFlagKey`, the public flag catalog, and the dev seeder. - Drops every backend `@RequireFeatureFlag(IS_AI_ENABLED)` guard (agent, agent chat, chat subscription, role-to-agent assignment, workflow AI step creation) and the now-unused `FeatureFlagModule`/`FeatureFlagGuard` wiring in the AI and workflow modules. - Removes frontend gating from settings nav, role permissions/assignment/applicability, command menu hotkeys, side panel, mobile/drawer nav, and the agent chat provider so AI UI is always on. Tests and generated GraphQL/SDK schemas updated accordingly. ## Test plan - [x] `npx nx typecheck twenty-shared` - [x] `npx nx typecheck twenty-server` - [x] `npx nx typecheck twenty-front` - [x] `npx nx lint:diff-with-main twenty-server` - [x] `npx nx lint:diff-with-main twenty-front` - [x] `npx jest --config=packages/twenty-server/jest.config.mjs feature-flag` - [x] `npx jest --config=packages/twenty-server/jest.config.mjs workspace-entity-manager` - [ ] Manual smoke test: AI features still accessible without any flag row in `featureFlag` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
-8
@@ -12,14 +12,6 @@ export type PublicFeatureFlag = {
|
||||
};
|
||||
|
||||
export const PUBLIC_FEATURE_FLAGS: PublicFeatureFlag[] = [
|
||||
{
|
||||
key: FeatureFlagKey.IS_AI_ENABLED,
|
||||
metadata: {
|
||||
label: 'AI',
|
||||
description: 'Enable AI-powered features including the agent chat',
|
||||
imagePath: 'https://twenty.com/images/lab/is-ai-enabled.png',
|
||||
},
|
||||
},
|
||||
{
|
||||
key: FeatureFlagKey.IS_JUNCTION_RELATIONS_ENABLED,
|
||||
metadata: {
|
||||
|
||||
+10
-6
@@ -37,7 +37,7 @@ describe('FeatureFlagService', () => {
|
||||
};
|
||||
|
||||
const workspaceId = 'workspace-id';
|
||||
const featureFlag = FeatureFlagKey.IS_AI_ENABLED;
|
||||
const featureFlag = FeatureFlagKey.IS_JUNCTION_RELATIONS_ENABLED;
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks();
|
||||
@@ -121,11 +121,11 @@ describe('FeatureFlagService', () => {
|
||||
// Prepare
|
||||
mockWorkspaceCacheService.getOrRecompute.mockResolvedValue({
|
||||
featureFlagsMap: {
|
||||
[FeatureFlagKey.IS_AI_ENABLED]: false,
|
||||
[FeatureFlagKey.IS_JUNCTION_RELATIONS_ENABLED]: false,
|
||||
},
|
||||
});
|
||||
const mockFeatureFlags = [
|
||||
{ key: FeatureFlagKey.IS_AI_ENABLED, value: false },
|
||||
{ key: FeatureFlagKey.IS_JUNCTION_RELATIONS_ENABLED, value: false },
|
||||
];
|
||||
|
||||
// Act
|
||||
@@ -144,7 +144,11 @@ describe('FeatureFlagService', () => {
|
||||
it('should return a map of feature flags for a workspace', async () => {
|
||||
// Prepare
|
||||
const mockFeatureFlags = [
|
||||
{ key: FeatureFlagKey.IS_AI_ENABLED, value: false, workspaceId },
|
||||
{
|
||||
key: FeatureFlagKey.IS_JUNCTION_RELATIONS_ENABLED,
|
||||
value: false,
|
||||
workspaceId,
|
||||
},
|
||||
];
|
||||
|
||||
mockFeatureFlagRepository.find.mockResolvedValue(mockFeatureFlags);
|
||||
@@ -154,7 +158,7 @@ describe('FeatureFlagService', () => {
|
||||
|
||||
// Assert
|
||||
expect(result).toEqual({
|
||||
[FeatureFlagKey.IS_AI_ENABLED]: false,
|
||||
[FeatureFlagKey.IS_JUNCTION_RELATIONS_ENABLED]: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -162,7 +166,7 @@ describe('FeatureFlagService', () => {
|
||||
describe('enableFeatureFlags', () => {
|
||||
it('should enable multiple feature flags for a workspace', async () => {
|
||||
// Prepare
|
||||
const keys = [FeatureFlagKey.IS_AI_ENABLED];
|
||||
const keys = [FeatureFlagKey.IS_JUNCTION_RELATIONS_ENABLED];
|
||||
|
||||
mockFeatureFlagRepository.upsert.mockResolvedValue({});
|
||||
mockWorkspaceCacheService.invalidateAndRecompute.mockResolvedValue(
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ describe('featureFlagValidator', () => {
|
||||
it('should not throw error if featureFlagKey is valid', () => {
|
||||
expect(() =>
|
||||
featureFlagValidator.assertIsFeatureFlagKey(
|
||||
'IS_AI_ENABLED',
|
||||
'IS_JUNCTION_RELATIONS_ENABLED',
|
||||
new UnknownException('Error', 'Error', {
|
||||
userFriendlyMessage: msg`Error`,
|
||||
}),
|
||||
|
||||
-17
@@ -2,10 +2,8 @@ import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
|
||||
import { Args, Mutation } from '@nestjs/graphql';
|
||||
|
||||
import { PermissionFlagType } from 'twenty-shared/constants';
|
||||
import { FeatureFlagKey } from 'twenty-shared/types';
|
||||
|
||||
import { CoreResolver } from 'src/engine/api/graphql/graphql-config/decorators/core-resolver.decorator';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
|
||||
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
|
||||
import { HttpTool } from 'src/engine/core-modules/tool/tools/http-tool/http-tool';
|
||||
@@ -27,7 +25,6 @@ import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
|
||||
import { WorkflowVersionStepWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step.workspace-service';
|
||||
import { WorkflowActionType } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type';
|
||||
import { WorkflowRunWorkspaceService } from 'src/modules/workflow/workflow-runner/workflow-run/workflow-run.workspace-service';
|
||||
import { WorkflowRunnerWorkspaceService } from 'src/modules/workflow/workflow-runner/workspace-services/workflow-runner.workspace-service';
|
||||
|
||||
@@ -49,7 +46,6 @@ export class WorkflowVersionStepResolver {
|
||||
private readonly workflowRunnerWorkspaceService: WorkflowRunnerWorkspaceService,
|
||||
private readonly workflowRunWorkspaceService: WorkflowRunWorkspaceService,
|
||||
private readonly httpTool: HttpTool,
|
||||
private readonly featureFlagService: FeatureFlagService,
|
||||
) {}
|
||||
|
||||
@Mutation(() => WorkflowVersionStepChangesDTO)
|
||||
@@ -58,19 +54,6 @@ export class WorkflowVersionStepResolver {
|
||||
@Args('input')
|
||||
input: CreateWorkflowVersionStepInput,
|
||||
): Promise<WorkflowVersionStepChangesDTO> {
|
||||
if (input.stepType === WorkflowActionType.AI_AGENT) {
|
||||
const isAiEnabled = await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IS_AI_ENABLED,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
if (!isAiEnabled) {
|
||||
throw new Error(
|
||||
'AI features are not available in your current workspace. Please contact support to enable them.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return this.workflowVersionStepWorkspaceService.createWorkflowVersionStep({
|
||||
workspaceId,
|
||||
input,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
||||
import { ToolModule } from 'src/engine/core-modules/tool/tool.module';
|
||||
import { WorkflowTriggerController } from 'src/engine/core-modules/workflow/controllers/workflow-trigger.controller';
|
||||
import { WorkflowBuilderResolver } from 'src/engine/core-modules/workflow/resolvers/workflow-builder.resolver';
|
||||
@@ -24,7 +23,6 @@ import { WorkflowTriggerModule } from 'src/modules/workflow/workflow-trigger/wor
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([WorkspaceEntity]),
|
||||
FeatureFlagModule,
|
||||
WorkflowTriggerModule,
|
||||
WorkflowBuilderModule,
|
||||
WorkflowCommonModule,
|
||||
|
||||
Reference in New Issue
Block a user