AI tools to create a demo workspace (#18236)

This PR adds the necessary tool to create a demo workspace with :
relevant custom objects and fields, mock data and a real dashboard with
graph widgets.

It is still a bit under-optimized and slow but it works.

This PR also adds an AI tool that allows to see what happens in real
time, it navigates the app and waits when necessary.

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
Lucas Bordeau
2026-03-05 11:39:31 +01:00
committed by GitHub
parent a2f80d882b
commit 2a82df7073
84 changed files with 2449 additions and 315 deletions
@@ -81,6 +81,22 @@ const DeleteObjectMetadataInputSchema = z.object({
id: z.string().uuid().describe('ID of the object to delete'),
});
const CreateManyObjectMetadataInputSchema = z.object({
objects: z
.array(CreateObjectMetadataInputSchema)
.min(1)
.max(20)
.describe('Array of object metadata to create (1-20 items).'),
});
const UpdateManyObjectMetadataInputSchema = z.object({
objects: z
.array(UpdateObjectMetadataInputSchema)
.min(1)
.max(20)
.describe('Array of object metadata updates to apply (1-20 items).'),
});
@Injectable()
export class ObjectMetadataToolsFactory {
constructor(private readonly objectMetadataService: ObjectMetadataService) {}
@@ -202,6 +218,83 @@ export class ObjectMetadataToolsFactory {
}
},
},
create_many_object_metadata: {
description:
'Create multiple object metadata at once in the workspace data model. More efficient than calling create_object_metadata multiple times. Each item follows the same schema as create_object_metadata.',
inputSchema: CreateManyObjectMetadataInputSchema,
execute: async (parameters: {
objects: Array<{
nameSingular: string;
namePlural: string;
labelSingular: string;
labelPlural: string;
description?: string;
icon?: string;
shortcut?: string;
isRemote?: boolean;
isLabelSyncedWithName?: boolean;
}>;
}) => {
try {
await Promise.all(
parameters.objects.map(async (createObjectInput) => {
await this.objectMetadataService.createOneObject({
createObjectInput: createObjectInput as Parameters<
typeof this.objectMetadataService.createOneObject
>[0]['createObjectInput'],
workspaceId,
});
}),
);
return true;
} catch (error) {
if (error instanceof WorkspaceMigrationBuilderException) {
throw new Error(formatValidationErrors(error));
}
throw error;
}
},
},
update_many_object_metadata: {
description:
'Update multiple object metadata at once. More efficient than calling update_object_metadata multiple times. Each item must include the object ID and the properties to update.',
inputSchema: UpdateManyObjectMetadataInputSchema,
execute: async (parameters: {
objects: Array<{
id: string;
labelSingular?: string;
labelPlural?: string;
nameSingular?: string;
namePlural?: string;
description?: string;
icon?: string;
shortcut?: string;
isActive?: boolean;
labelIdentifierFieldMetadataId?: string;
imageIdentifierFieldMetadataId?: string;
isLabelSyncedWithName?: boolean;
}>;
}) => {
try {
await Promise.all(
parameters.objects.map(async ({ id, ...update }) => {
await this.objectMetadataService.updateOneObject({
updateObjectInput: { id, update },
workspaceId,
});
}),
);
return true;
} catch (error) {
if (error instanceof WorkspaceMigrationBuilderException) {
throw new Error(formatValidationErrors(error));
}
throw error;
}
},
},
};
}
}