Standard Agent, Role, Role target (#16499)

# Introduction
In this pullrequest have been migrated to the flat standard entities:
Role, Agent and RoleTargets.

## What happens
- Removed createStandardMorph tool util in favor of dynamic typing of
`createMorphOrRelationStandardField`
- Implemented a command to remove standard agents and their role that
has been removed in https://github.com/twentyhq/twenty/pull/16513 also
added a default role target to data manipulator role to the only
remaining agent
- Implemented an agent deleteMany service handler
This commit is contained in:
Paul Rastoin
2025-12-16 14:17:31 +01:00
committed by GitHub
parent 553efe0cee
commit 75bba5a8ee
66 changed files with 1046 additions and 434 deletions
@@ -0,0 +1,141 @@
import { InjectRepository } from '@nestjs/typeorm';
import { Command } from 'nest-commander';
import { isDefined } from 'twenty-shared/utils';
import { type Repository } from 'typeorm';
import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner';
import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { AgentService } from 'src/engine/metadata-modules/ai/ai-agent/agent.service';
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
import { FlatAgentMaps } from 'src/engine/metadata-modules/flat-agent/types/flat-agent-maps.type';
import { MetadataFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity-maps.type';
import { RoleService } from 'src/engine/metadata-modules/role/role.service';
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
const REMOVED_AGENT_STANDARD_IDS = [
'20202020-0002-0001-0001-000000000006', // dashboard-builder
'20202020-0002-0001-0001-000000000003', // data-manipulator
'20202020-0002-0001-0001-000000000007', // metadata-builder
'20202020-0002-0001-0001-000000000005', // researcher
'20202020-0002-0001-0001-000000000001', // workflow-builder
];
const REMOVED_ROLE_STANDARD_IDS = [
'20202020-0001-0001-0001-000000000002', // workflow-manager
'20202020-0001-0001-0001-000000000004', // data-manipulator
'20202020-0001-0001-0001-000000000005', // dashboard-manager
'20202020-0001-0001-0001-000000000006', // data-model-manager
];
@Command({
name: 'upgrade:1-14:delete-removed-agents',
description: 'Delete agents and roles that were removed from the codebase',
})
export class DeleteRemovedAgentsCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner {
constructor(
@InjectRepository(WorkspaceEntity)
protected readonly workspaceRepository: Repository<WorkspaceEntity>,
protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager,
protected readonly dataSourceService: DataSourceService,
private readonly workspaceCacheService: WorkspaceCacheService,
private readonly agentService: AgentService,
private readonly roleService: RoleService,
) {
super(workspaceRepository, twentyORMGlobalManager, dataSourceService);
}
override async runOnWorkspace({
options,
workspaceId,
}: RunOnWorkspaceArgs): Promise<void> {
const isDryRun = options.dryRun || false;
const { flatAgentMaps, flatRoleMaps } =
await this.workspaceCacheService.getOrRecompute(workspaceId, [
'flatAgentMaps',
'flatRoleMaps',
]);
await this.deleteRemovedAgents({ flatAgentMaps, workspaceId, isDryRun });
await this.deleteRemovedRoles({ flatRoleMaps, workspaceId, isDryRun });
}
private async deleteRemovedAgents({
flatAgentMaps,
workspaceId,
isDryRun,
}: {
flatAgentMaps: FlatAgentMaps;
workspaceId: string;
isDryRun: boolean;
}): Promise<void> {
const allAgents = Object.values(flatAgentMaps.byId).filter(isDefined);
const agentsToDelete = allAgents.filter((agent) =>
REMOVED_AGENT_STANDARD_IDS.includes(agent.standardId ?? ''),
);
const agentNames = agentsToDelete.map((agent) => agent.name).join(', ');
this.logger.log(
`DRY RUN: Would delete ${agentsToDelete.length} removed agent(s): ${agentNames}`,
);
if (agentsToDelete.length === 0 || isDryRun) {
return;
}
const agentIds = agentsToDelete.map((agent) => agent.id);
await this.agentService.deleteManyAgents({
ids: agentIds,
workspaceId,
isSystemBuild: true,
});
this.logger.log(
`Deleted ${agentsToDelete.length} removed agent(s): ${agentNames}`,
);
}
private async deleteRemovedRoles({
flatRoleMaps,
workspaceId,
isDryRun,
}: {
flatRoleMaps: MetadataFlatEntityMaps<'role'>;
workspaceId: string;
isDryRun: boolean;
}): Promise<void> {
const allRoles = Object.values(flatRoleMaps.byId).filter(isDefined);
const rolesToDelete = allRoles.filter((role) =>
REMOVED_ROLE_STANDARD_IDS.includes(role.standardId ?? ''),
);
const roleLabels = rolesToDelete.map((role) => role.label).join(', ');
this.logger.log(
`DRY RUN: Would delete ${rolesToDelete.length} removed role(s): ${roleLabels}`,
);
if (rolesToDelete.length === 0 || isDryRun) {
return;
}
const roleIds = rolesToDelete.map((role) => role.id);
await this.roleService.deleteManyRoles({
ids: roleIds,
workspaceId,
isSystemBuild: true,
});
this.logger.log(
`Deleted ${rolesToDelete.length} removed role(s): ${roleLabels}`,
);
}
}
@@ -1,18 +1,25 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { DeleteRemovedAgentsCommand } from 'src/database/commands/upgrade-version-command/1-14/1-14-delete-removed-agents.command';
import { UpdateCreatedByEnumCommand } from 'src/database/commands/upgrade-version-command/1-14/1-14-update-created-by-enum.command';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { AiAgentModule } from 'src/engine/metadata-modules/ai/ai-agent/ai-agent.module';
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
import { RoleModule } from 'src/engine/metadata-modules/role/role.module';
import { WorkspaceSchemaManagerModule } from 'src/engine/twenty-orm/workspace-schema-manager/workspace-schema-manager.module';
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
@Module({
imports: [
TypeOrmModule.forFeature([WorkspaceEntity]),
DataSourceModule,
AiAgentModule,
RoleModule,
WorkspaceSchemaManagerModule,
WorkspaceCacheModule,
],
providers: [UpdateCreatedByEnumCommand],
exports: [UpdateCreatedByEnumCommand],
providers: [UpdateCreatedByEnumCommand, DeleteRemovedAgentsCommand],
exports: [DeleteRemovedAgentsCommand, UpdateCreatedByEnumCommand],
})
export class V1_14_UpgradeVersionCommandModule {}
@@ -2,10 +2,10 @@ import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { V1_13_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-13/1-13-upgrade-version-command.module';
import { V1_14_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-14/1-14-upgrade-version-command.module';
import { UpgradeCommand } from 'src/database/commands/upgrade-version-command/upgrade.command';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
import { V1_14_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-14/1-14-upgrade-version-command.module';
@Module({
imports: [
@@ -16,11 +16,12 @@ import { MigrateStandardInvalidEntitiesCommand } from 'src/database/commands/upg
import { MigrateTimelineActivityToMorphRelationsCommand } from 'src/database/commands/upgrade-version-command/1-13/1-13-migrate-timeline-activity-to-morph-relations.command';
import { RenameIndexNameCommand } from 'src/database/commands/upgrade-version-command/1-13/1-13-rename-index.command';
import { UpdateRoleTargetsUniqueConstraintMigrationCommand } from 'src/database/commands/upgrade-version-command/1-13/1-13-update-role-targets-unique-constraint-migration.command';
import { DeleteRemovedAgentsCommand } from 'src/database/commands/upgrade-version-command/1-14/1-14-delete-removed-agents.command';
import { UpdateCreatedByEnumCommand } from 'src/database/commands/upgrade-version-command/1-14/1-14-update-created-by-enum.command';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
import { UpdateCreatedByEnumCommand } from 'src/database/commands/upgrade-version-command/1-14/1-14-update-created-by-enum.command';
@Command({
name: 'upgrade',
@@ -47,6 +48,7 @@ export class UpgradeCommand extends UpgradeCommandRunner {
// 1.14 Commands
protected readonly updateCreatedByEnumCommand: UpdateCreatedByEnumCommand,
protected readonly deleteRemovedAgentsCommand: DeleteRemovedAgentsCommand,
) {
super(
workspaceRepository,
@@ -68,7 +70,10 @@ export class UpgradeCommand extends UpgradeCommandRunner {
this.renameIndexNameCommand,
];
const commands_1140: VersionCommands = [this.updateCreatedByEnumCommand];
const commands_1140: VersionCommands = [
this.updateCreatedByEnumCommand,
this.deleteRemovedAgentsCommand,
];
this.allCommands = {
'1.12.0': commands_1120,