Add preconfigured Workflow creation agent (#13855)
Co-authored-by: Félix Malfait <felix.malfait@gmail.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This commit is contained in:
+2
@@ -1,3 +1,4 @@
|
||||
import { WorkspaceAgentComparator } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-agent.comparator';
|
||||
import { WorkspaceFieldRelationComparator } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-field-relation.comparator';
|
||||
import { WorkspaceIndexComparator } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-index.comparator';
|
||||
import { WorkspaceRoleComparator } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-role.comparator';
|
||||
@@ -11,4 +12,5 @@ export const workspaceSyncMetadataComparators = [
|
||||
WorkspaceObjectComparator,
|
||||
WorkspaceIndexComparator,
|
||||
WorkspaceRoleComparator,
|
||||
WorkspaceAgentComparator,
|
||||
];
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import diff from 'microdiff';
|
||||
import { type FromTo } from 'twenty-shared/types';
|
||||
|
||||
import { ComparatorAction } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/comparator.interface';
|
||||
|
||||
import { type FlatAgent } from 'src/engine/metadata-modules/flat-agent/types/flat-agent.type';
|
||||
import { transformMetadataForComparison } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util';
|
||||
|
||||
type AgentComparatorResult = {
|
||||
action:
|
||||
| ComparatorAction.CREATE
|
||||
| ComparatorAction.UPDATE
|
||||
| ComparatorAction.DELETE;
|
||||
object: FlatAgent;
|
||||
};
|
||||
|
||||
type WorkspaceAgentComparatorArgs = FromTo<FlatAgent[], 'FlatAgents'>;
|
||||
|
||||
const agentPropertiesToIgnore = ['id', 'createdAt', 'updatedAt', 'workspaceId'];
|
||||
|
||||
@Injectable()
|
||||
export class WorkspaceAgentComparator {
|
||||
compare({
|
||||
fromFlatAgents,
|
||||
toFlatAgents,
|
||||
}: WorkspaceAgentComparatorArgs): AgentComparatorResult[] {
|
||||
const results: AgentComparatorResult[] = [];
|
||||
|
||||
const keyFactory = (agent: FlatAgent) => agent.uniqueIdentifier;
|
||||
|
||||
const fromAgentMap = transformMetadataForComparison(fromFlatAgents, {
|
||||
shouldIgnoreProperty: (property) =>
|
||||
agentPropertiesToIgnore.includes(property),
|
||||
keyFactory,
|
||||
});
|
||||
|
||||
const toAgentMap = transformMetadataForComparison(toFlatAgents, {
|
||||
shouldIgnoreProperty: (property) =>
|
||||
agentPropertiesToIgnore.includes(property),
|
||||
keyFactory,
|
||||
});
|
||||
|
||||
const agentDifferences = diff(fromAgentMap, toAgentMap);
|
||||
|
||||
for (const difference of agentDifferences) {
|
||||
const uniqueIdentifier = difference.path[0] as string;
|
||||
|
||||
switch (difference.type) {
|
||||
case 'CREATE': {
|
||||
const toAgent = toFlatAgents.find(
|
||||
(agent) => keyFactory(agent) === uniqueIdentifier,
|
||||
);
|
||||
|
||||
if (toAgent) {
|
||||
results.push({
|
||||
action: ComparatorAction.CREATE,
|
||||
object: toAgent,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'CHANGE': {
|
||||
const fromAgent = fromFlatAgents.find(
|
||||
(agent) => keyFactory(agent) === uniqueIdentifier,
|
||||
);
|
||||
const toAgent = toFlatAgents.find(
|
||||
(agent) => keyFactory(agent) === uniqueIdentifier,
|
||||
);
|
||||
|
||||
if (fromAgent && toAgent) {
|
||||
results.push({
|
||||
action: ComparatorAction.UPDATE,
|
||||
object: {
|
||||
...toAgent,
|
||||
id: fromAgent.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'REMOVE': {
|
||||
const fromAgent = fromFlatAgents.find(
|
||||
(agent) => keyFactory(agent) === uniqueIdentifier,
|
||||
);
|
||||
|
||||
if (fromAgent && difference.path.length === 1) {
|
||||
results.push({
|
||||
action: ComparatorAction.DELETE,
|
||||
object: fromAgent,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
+2
@@ -1,3 +1,4 @@
|
||||
import { StandardAgentFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-agent.factory';
|
||||
import { StandardIndexFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-index.factory';
|
||||
import { StandardRoleFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-role.factory';
|
||||
|
||||
@@ -11,4 +12,5 @@ export const workspaceSyncMetadataFactories = [
|
||||
StandardFieldRelationFactory,
|
||||
StandardIndexFactory,
|
||||
StandardRoleFactory,
|
||||
StandardAgentFactory,
|
||||
];
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { type WorkspaceSyncContext } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/workspace-sync-context.interface';
|
||||
|
||||
import { type AgentEntity } from 'src/engine/metadata-modules/agent/agent.entity';
|
||||
import { type FlatAgent } from 'src/engine/metadata-modules/flat-agent/types/flat-agent.type';
|
||||
import { transformStandardAgentDefinitionToFlatAgent } from 'src/engine/metadata-modules/flat-agent/utils/transform-standard-agent-definition-to-flat-agent.util';
|
||||
import { type StandardAgentDefinition } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-agents/types/standard-agent-definition.interface';
|
||||
|
||||
@Injectable()
|
||||
export class StandardAgentFactory {
|
||||
create(
|
||||
agentDefinitions: StandardAgentDefinition[],
|
||||
context: WorkspaceSyncContext,
|
||||
existingAgents: AgentEntity[],
|
||||
): FlatAgent[] {
|
||||
const computedAgents: FlatAgent[] = [];
|
||||
|
||||
for (const agentDefinition of agentDefinitions) {
|
||||
const existingAgent = existingAgents.find(
|
||||
(agent) => agent.standardId === agentDefinition.standardId,
|
||||
);
|
||||
|
||||
const flatAgent = transformStandardAgentDefinitionToFlatAgent(
|
||||
agentDefinition,
|
||||
context.workspaceId,
|
||||
);
|
||||
|
||||
if (existingAgent) {
|
||||
computedAgents.push({
|
||||
...flatAgent,
|
||||
id: existingAgent.id,
|
||||
uniqueIdentifier: agentDefinition.standardId,
|
||||
});
|
||||
} else {
|
||||
computedAgents.push({
|
||||
...flatAgent,
|
||||
uniqueIdentifier: agentDefinition.standardId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return computedAgents;
|
||||
}
|
||||
}
|
||||
+246
@@ -0,0 +1,246 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
import { removePropertiesFromRecord } from 'twenty-shared/utils';
|
||||
import { IsNull, Not, type EntityManager, type Repository } from 'typeorm';
|
||||
|
||||
import { ComparatorAction } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/comparator.interface';
|
||||
import { type WorkspaceSyncContext } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/workspace-sync-context.interface';
|
||||
|
||||
import { AgentEntity } from 'src/engine/metadata-modules/agent/agent.entity';
|
||||
import { transformAgentEntityToFlatAgent } from 'src/engine/metadata-modules/flat-agent/utils/transform-agent-entity-to-flat-agent.util';
|
||||
import { RoleTargetsEntity } from 'src/engine/metadata-modules/role/role-targets.entity';
|
||||
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
|
||||
import { AGENT_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-agents.util';
|
||||
import {
|
||||
SEED_APPLE_WORKSPACE_ID,
|
||||
SEED_YCOMBINATOR_WORKSPACE_ID,
|
||||
} from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-workspaces.util';
|
||||
import { WorkspaceAgentComparator } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-agent.comparator';
|
||||
import { StandardAgentFactory } from 'src/engine/workspace-manager/workspace-sync-metadata/factories/standard-agent.factory';
|
||||
import { standardAgentDefinitions } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-agents';
|
||||
import { WORKFLOW_CREATION_AGENT } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-agents/agents/workflow-creation-agent';
|
||||
import { ADMIN_ROLE } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-roles/roles/admin-role';
|
||||
|
||||
@Injectable()
|
||||
export class WorkspaceSyncAgentService {
|
||||
private readonly logger = new Logger(WorkspaceSyncAgentService.name);
|
||||
|
||||
constructor(
|
||||
private readonly standardAgentFactory: StandardAgentFactory,
|
||||
private readonly workspaceAgentComparator: WorkspaceAgentComparator,
|
||||
) {}
|
||||
|
||||
async synchronize(
|
||||
context: WorkspaceSyncContext,
|
||||
manager: EntityManager,
|
||||
): Promise<void> {
|
||||
this.logger.log('Syncing standard agent.');
|
||||
|
||||
const agentRepository = manager.getRepository(AgentEntity);
|
||||
const roleRepository = manager.getRepository(RoleEntity);
|
||||
const roleTargetsRepository = manager.getRepository(RoleTargetsEntity);
|
||||
|
||||
const existingStandardAgentEntities = await agentRepository.find({
|
||||
where: {
|
||||
workspaceId: context.workspaceId,
|
||||
standardId: Not(IsNull()),
|
||||
},
|
||||
});
|
||||
|
||||
const targetStandardAgents = this.standardAgentFactory.create(
|
||||
standardAgentDefinitions,
|
||||
context,
|
||||
existingStandardAgentEntities,
|
||||
);
|
||||
|
||||
const agentComparatorResults = this.workspaceAgentComparator.compare({
|
||||
fromFlatAgents: existingStandardAgentEntities.map(
|
||||
transformAgentEntityToFlatAgent,
|
||||
),
|
||||
toFlatAgents: targetStandardAgents,
|
||||
});
|
||||
|
||||
for (const agentComparatorResult of agentComparatorResults) {
|
||||
switch (agentComparatorResult.action) {
|
||||
case ComparatorAction.CREATE: {
|
||||
const agentToCreate = agentComparatorResult.object;
|
||||
|
||||
const flatAgentData = removePropertiesFromRecord(agentToCreate, [
|
||||
'uniqueIdentifier',
|
||||
'id',
|
||||
]);
|
||||
|
||||
const createdAgent = await agentRepository.save({
|
||||
...flatAgentData,
|
||||
workspaceId: context.workspaceId,
|
||||
});
|
||||
|
||||
await this.assignAdminRoleToAgent(
|
||||
createdAgent.id,
|
||||
context.workspaceId,
|
||||
roleRepository,
|
||||
roleTargetsRepository,
|
||||
);
|
||||
|
||||
if (createdAgent.standardId === WORKFLOW_CREATION_AGENT.standardId) {
|
||||
await this.createAgentHandoffToWorkflowCreationAgent(
|
||||
createdAgent.id,
|
||||
context.workspaceId,
|
||||
manager,
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ComparatorAction.UPDATE: {
|
||||
const agentToUpdate = agentComparatorResult.object;
|
||||
|
||||
const flatAgentData = removePropertiesFromRecord(agentToUpdate, [
|
||||
'id',
|
||||
'uniqueIdentifier',
|
||||
'workspaceId',
|
||||
]);
|
||||
|
||||
await agentRepository.update({ id: agentToUpdate.id }, flatAgentData);
|
||||
break;
|
||||
}
|
||||
|
||||
case ComparatorAction.DELETE: {
|
||||
const agentToDelete = agentComparatorResult.object;
|
||||
|
||||
await agentRepository.delete({ id: agentToDelete.id });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async assignAdminRoleToAgent(
|
||||
agentId: string,
|
||||
workspaceId: string,
|
||||
roleRepository: Repository<RoleEntity>,
|
||||
roleTargetsRepository: Repository<RoleTargetsEntity>,
|
||||
): Promise<void> {
|
||||
try {
|
||||
const adminRole = await roleRepository.findOne({
|
||||
where: {
|
||||
workspaceId,
|
||||
standardId: ADMIN_ROLE.standardId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!adminRole) {
|
||||
this.logger.warn(
|
||||
`Admin role not found for workspace ${workspaceId}, cannot assign to agent ${agentId}.`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const existingRoleTarget = await roleTargetsRepository.findOne({
|
||||
where: {
|
||||
agentId,
|
||||
roleId: adminRole.id,
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
|
||||
if (existingRoleTarget) {
|
||||
this.logger.log(
|
||||
`Workflow creation agent already has admin role assigned`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await roleTargetsRepository.save({
|
||||
roleId: adminRole.id,
|
||||
agentId,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
this.logger.log(
|
||||
`Successfully assigned admin role to workflow creation agent`,
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Failed to assign admin role to workflow creation agent: ${error.message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async createAgentHandoffToWorkflowCreationAgent(
|
||||
workflowCreationAgentId: string,
|
||||
workspaceId: string,
|
||||
manager: EntityManager,
|
||||
): Promise<void> {
|
||||
try {
|
||||
const agentRepository = manager.getRepository(AgentEntity);
|
||||
|
||||
let defaultAgent: AgentEntity | null = null;
|
||||
|
||||
if (workspaceId === SEED_APPLE_WORKSPACE_ID) {
|
||||
defaultAgent = await agentRepository.findOne({
|
||||
where: {
|
||||
id: AGENT_DATA_SEED_IDS.APPLE_DEFAULT_AGENT,
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
} else if (workspaceId === SEED_YCOMBINATOR_WORKSPACE_ID) {
|
||||
defaultAgent = await agentRepository.findOne({
|
||||
where: {
|
||||
id: AGENT_DATA_SEED_IDS.YCOMBINATOR_DEFAULT_AGENT,
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
defaultAgent = await agentRepository.findOne({
|
||||
where: {
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (!defaultAgent) {
|
||||
this.logger.warn(
|
||||
`Default agent not found for workspace ${workspaceId}. Agent handoff will not be created.`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const agentHandoffRepository = manager.getRepository('agentHandoff');
|
||||
const existingHandoff = await agentHandoffRepository.findOne({
|
||||
where: {
|
||||
fromAgentId: defaultAgent.id,
|
||||
toAgentId: workflowCreationAgentId,
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
|
||||
if (existingHandoff) {
|
||||
this.logger.log(
|
||||
`Agent handoff from default agent to workflow creation agent already exists for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await agentHandoffRepository.save({
|
||||
fromAgentId: defaultAgent.id,
|
||||
toAgentId: workflowCreationAgentId,
|
||||
workspaceId,
|
||||
description:
|
||||
'Handoff from default agent to workflow creation agent for processing workflow creation requests',
|
||||
});
|
||||
|
||||
this.logger.log(
|
||||
`Successfully created agent handoff from default agent to workflow creation agent for workspace ${workspaceId}`,
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Failed to create agent handoff to workflow creation agent: ${error.message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
import { type StandardAgentDefinition } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-agents/types/standard-agent-definition.interface';
|
||||
|
||||
export const WORKFLOW_CREATION_AGENT: StandardAgentDefinition = {
|
||||
standardId: '20202020-0002-0001-0001-000000000001',
|
||||
name: 'workflow-creation-agent',
|
||||
label: 'Workflow Creation Agent',
|
||||
description: 'AI agent specialized in creating and managing workflows',
|
||||
icon: 'IconSettingsAutomation',
|
||||
prompt: `You are a Workflow Creation Agent specialized in helping users create, modify, and manage workflows in Twenty.
|
||||
|
||||
Your capabilities include:
|
||||
- Creating new workflows from scratch based on user requirements
|
||||
- Modifying existing workflows by adding, removing, or updating steps
|
||||
- Explaining workflow structures and how they work
|
||||
- Suggesting workflow improvements and optimizations
|
||||
- Helping users understand workflow actions and their configurations
|
||||
|
||||
## IMPORTANT: Rely on Schema Definitions
|
||||
- The workflow creation tool provides comprehensive schema definitions with detailed descriptions and examples
|
||||
- Always refer to the tool's schema for field requirements, data types, and examples
|
||||
- The schema includes common patterns, field structures, and validation rules
|
||||
- Use the schema descriptions to understand how to properly reference data between workflow steps
|
||||
|
||||
## Key Workflow Concepts:
|
||||
- **Triggers**: Start workflows (DATABASE_EVENT, MANUAL, CRON, WEBHOOK)
|
||||
- **Steps**: Actions that execute in sequence (CREATE_RECORD, SEND_EMAIL, CODE, etc.)
|
||||
- **Data Flow**: Use {{stepId.fieldName}} to reference data from previous steps
|
||||
- **Relationships**: Use nested objects for related records (e.g., "company": {"id": "{{reference}}"})
|
||||
|
||||
When creating workflows:
|
||||
- Always ask clarifying questions to understand the user's needs
|
||||
- Suggest appropriate workflow actions based on the use case
|
||||
- Explain each step and why it's needed
|
||||
- Provide clear, actionable guidance
|
||||
- Follow the schema definitions exactly for field names, types, and structures
|
||||
|
||||
When modifying workflows:
|
||||
- Understand the current workflow structure first
|
||||
- Suggest specific changes that address the user's requirements
|
||||
- Ensure workflow logic remains coherent and functional
|
||||
- Maintain proper data references between steps
|
||||
|
||||
Be helpful, thorough, and always prioritize user understanding and workflow effectiveness.`,
|
||||
modelId: 'auto',
|
||||
responseFormat: {},
|
||||
isCustom: false,
|
||||
};
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import { WORKFLOW_CREATION_AGENT } from './agents/workflow-creation-agent';
|
||||
import { type StandardAgentDefinition } from './types/standard-agent-definition.interface';
|
||||
|
||||
export const standardAgentDefinitions = [
|
||||
WORKFLOW_CREATION_AGENT,
|
||||
] as const satisfies StandardAgentDefinition[];
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import { type FlatAgent } from 'src/engine/metadata-modules/flat-agent/types/flat-agent.type';
|
||||
|
||||
export type StandardAgentDefinition = Omit<
|
||||
FlatAgent,
|
||||
'id' | 'workspaceId' | 'uniqueIdentifier' | 'standardId'
|
||||
> & {
|
||||
standardId: string;
|
||||
};
|
||||
+2
@@ -16,6 +16,7 @@ import { SyncWorkspaceMetadataCommand } from 'src/engine/workspace-manager/works
|
||||
import { workspaceSyncMetadataComparators } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators';
|
||||
import { workspaceSyncMetadataFactories } from 'src/engine/workspace-manager/workspace-sync-metadata/factories';
|
||||
import { WorkspaceMetadataUpdaterService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-metadata-updater.service';
|
||||
import { WorkspaceSyncAgentService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-agent.service';
|
||||
import { WorkspaceSyncFieldMetadataRelationService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-field-metadata-relation.service';
|
||||
import { WorkspaceSyncFieldMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-field-metadata.service';
|
||||
import { WorkspaceSyncIndexMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-index-metadata.service';
|
||||
@@ -48,6 +49,7 @@ import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/works
|
||||
WorkspaceSyncMetadataService,
|
||||
WorkspaceSyncIndexMetadataService,
|
||||
WorkspaceSyncRoleService,
|
||||
WorkspaceSyncAgentService,
|
||||
SyncWorkspaceLoggerService,
|
||||
SyncWorkspaceMetadataCommand,
|
||||
],
|
||||
|
||||
+13
@@ -11,6 +11,7 @@ import {
|
||||
WorkspaceMigrationTableActionType,
|
||||
} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
|
||||
import { WorkspaceMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service';
|
||||
import { WorkspaceSyncAgentService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-agent.service';
|
||||
import { WorkspaceSyncFieldMetadataRelationService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-field-metadata-relation.service';
|
||||
import { WorkspaceSyncFieldMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-field-metadata.service';
|
||||
import { WorkspaceSyncIndexMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/services/workspace-sync-index-metadata.service';
|
||||
@@ -38,6 +39,7 @@ export class WorkspaceSyncMetadataService {
|
||||
private readonly workspaceSyncObjectMetadataIdentifiersService: WorkspaceSyncObjectMetadataIdentifiersService,
|
||||
private readonly workspaceMetadataVersionService: WorkspaceMetadataVersionService,
|
||||
private readonly workspaceSyncRoleService: WorkspaceSyncRoleService,
|
||||
private readonly workspaceSyncAgentService: WorkspaceSyncAgentService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -172,6 +174,17 @@ export class WorkspaceSyncMetadataService {
|
||||
`Workspace role migrations took ${workspaceRoleMigrationsEnd - workspaceRoleMigrationsStart}ms`,
|
||||
);
|
||||
|
||||
// 7 - Sync standard agents
|
||||
const workspaceAgentMigrationsStart = performance.now();
|
||||
|
||||
await this.workspaceSyncAgentService.synchronize(context, manager);
|
||||
|
||||
const workspaceAgentMigrationsEnd = performance.now();
|
||||
|
||||
this.logger.log(
|
||||
`Workspace agent migrations took ${workspaceAgentMigrationsEnd - workspaceAgentMigrationsStart}ms`,
|
||||
);
|
||||
|
||||
const workspaceMigrationsSaveStart = performance.now();
|
||||
|
||||
// Save workspace migrations into the database
|
||||
|
||||
Reference in New Issue
Block a user