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
@@ -5,6 +5,7 @@ export enum ToolCategory {
METADATA = 'METADATA',
NATIVE_MODEL = 'NATIVE_MODEL',
VIEW = 'VIEW',
VIEW_FIELD = 'VIEW_FIELD',
DASHBOARD = 'DASHBOARD',
LOGIC_FUNCTION = 'LOGIC_FUNCTION',
}
@@ -19,10 +19,11 @@ import {
type ToolIndexEntry,
} from 'src/engine/core-modules/tool-provider/types/tool-descriptor.type';
import { CodeInterpreterTool } from 'src/engine/core-modules/tool/tools/code-interpreter-tool/code-interpreter-tool';
import { HttpTool } from 'src/engine/core-modules/tool/tools/http-tool/http-tool';
import { SearchHelpCenterTool } from 'src/engine/core-modules/tool/tools/search-help-center-tool/search-help-center-tool';
import { DraftEmailTool } from 'src/engine/core-modules/tool/tools/email-tool/draft-email-tool';
import { SendEmailTool } from 'src/engine/core-modules/tool/tools/email-tool/send-email-tool';
import { HttpTool } from 'src/engine/core-modules/tool/tools/http-tool/http-tool';
import { NavigateAppTool } from 'src/engine/core-modules/tool/tools/navigate-tool/navigate-app-tool';
import { SearchHelpCenterTool } from 'src/engine/core-modules/tool/tools/search-help-center-tool/search-help-center-tool';
import { type ToolInput } from 'src/engine/core-modules/tool/types/tool-input.type';
import { type Tool } from 'src/engine/core-modules/tool/types/tool.type';
import { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service';
@@ -39,6 +40,7 @@ export class ActionToolProvider implements ToolProvider {
private readonly draftEmailTool: DraftEmailTool,
private readonly searchHelpCenterTool: SearchHelpCenterTool,
private readonly codeInterpreterTool: CodeInterpreterTool,
private readonly navigateAppTool: NavigateAppTool,
private readonly permissionsService: PermissionsService,
private readonly toolExecutorService: ToolExecutorService,
) {
@@ -48,6 +50,7 @@ export class ActionToolProvider implements ToolProvider {
['draft_email', this.draftEmailTool],
['search_help_center', this.searchHelpCenterTool],
['code_interpreter', this.codeInterpreterTool],
['navigate_app', this.navigateAppTool],
]);
// Register each action tool as a static handler in the executor
@@ -116,6 +119,14 @@ export class ActionToolProvider implements ToolProvider {
),
);
descriptors.push(
this.buildDescriptor(
'navigate_app',
this.navigateAppTool,
includeSchemas,
),
);
const hasCodeInterpreterPermission =
await this.permissionsService.hasToolPermission(
context.rolePermissionConfig,
@@ -0,0 +1,98 @@
import { Injectable, OnModuleInit } from '@nestjs/common';
import { PermissionFlagType } from 'twenty-shared/constants';
import {
type GenerateDescriptorOptions,
type ToolProvider,
type ToolProviderContext,
} from 'src/engine/core-modules/tool-provider/interfaces/tool-provider.interface';
import { ToolCategory } from 'src/engine/core-modules/tool-provider/enums/tool-category.enum';
import { ToolExecutorService } from 'src/engine/core-modules/tool-provider/services/tool-executor.service';
import {
type ToolDescriptor,
type ToolIndexEntry,
} from 'src/engine/core-modules/tool-provider/types/tool-descriptor.type';
import { toolSetToDescriptors } from 'src/engine/core-modules/tool-provider/utils/tool-set-to-descriptors.util';
import { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service';
import { ViewFieldToolsFactory } from 'src/engine/metadata-modules/view-field/tools/view-field-tools.factory';
@Injectable()
export class ViewFieldToolProvider implements ToolProvider, OnModuleInit {
readonly category = ToolCategory.VIEW_FIELD;
constructor(
private readonly viewFieldToolsFactory: ViewFieldToolsFactory,
private readonly permissionsService: PermissionsService,
private readonly toolExecutorService: ToolExecutorService,
) {}
onModuleInit(): void {
const factory = this.viewFieldToolsFactory;
this.toolExecutorService.registerCategoryGenerator(
ToolCategory.VIEW_FIELD,
async (context) => {
const readTools = factory.generateReadTools(context.workspaceId);
const hasViewPermission =
await this.permissionsService.checkRolesPermissions(
context.rolePermissionConfig,
context.workspaceId,
PermissionFlagType.VIEWS,
);
if (hasViewPermission) {
const writeTools = factory.generateWriteTools(context.workspaceId);
return { ...readTools, ...writeTools };
}
return readTools;
},
);
}
async isAvailable(_context: ToolProviderContext): Promise<boolean> {
return true;
}
async generateDescriptors(
context: ToolProviderContext,
options?: GenerateDescriptorOptions,
): Promise<(ToolIndexEntry | ToolDescriptor)[]> {
const schemaOptions = {
includeSchemas: options?.includeSchemas ?? true,
};
const readTools = this.viewFieldToolsFactory.generateReadTools(
context.workspaceId,
);
const hasViewPermission =
await this.permissionsService.checkRolesPermissions(
context.rolePermissionConfig,
context.workspaceId,
PermissionFlagType.VIEWS,
);
if (hasViewPermission) {
const writeTools = this.viewFieldToolsFactory.generateWriteTools(
context.workspaceId,
);
return toolSetToDescriptors(
{ ...readTools, ...writeTools },
ToolCategory.VIEW_FIELD,
schemaOptions,
);
}
return toolSetToDescriptors(
readTools,
ToolCategory.VIEW_FIELD,
schemaOptions,
);
}
}
@@ -7,9 +7,10 @@ import { TOOL_PROVIDERS } from 'src/engine/core-modules/tool-provider/constants/
import { ActionToolProvider } from 'src/engine/core-modules/tool-provider/providers/action-tool.provider';
import { DashboardToolProvider } from 'src/engine/core-modules/tool-provider/providers/dashboard-tool.provider';
import { DatabaseToolProvider } from 'src/engine/core-modules/tool-provider/providers/database-tool.provider';
import { LogicFunctionToolProvider } from 'src/engine/core-modules/tool-provider/providers/logic-function-tool.provider';
import { MetadataToolProvider } from 'src/engine/core-modules/tool-provider/providers/metadata-tool.provider';
import { NativeModelToolProvider } from 'src/engine/core-modules/tool-provider/providers/native-model-tool.provider';
import { LogicFunctionToolProvider } from 'src/engine/core-modules/tool-provider/providers/logic-function-tool.provider';
import { ViewFieldToolProvider } from 'src/engine/core-modules/tool-provider/providers/view-field-tool.provider';
import { ViewToolProvider } from 'src/engine/core-modules/tool-provider/providers/view-tool.provider';
import { WorkflowToolProvider } from 'src/engine/core-modules/tool-provider/providers/workflow-tool.provider';
import { ToolExecutorService } from 'src/engine/core-modules/tool-provider/services/tool-executor.service';
@@ -19,10 +20,11 @@ import { AiAgentExecutionModule } from 'src/engine/metadata-modules/ai/ai-agent-
import { AiModelsModule } from 'src/engine/metadata-modules/ai/ai-models/ai-models.module';
import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.module';
import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module';
import { LogicFunctionModule } from 'src/engine/metadata-modules/logic-function/logic-function.module';
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
import { LogicFunctionModule } from 'src/engine/metadata-modules/logic-function/logic-function.module';
import { UserRoleModule } from 'src/engine/metadata-modules/user-role/user-role.module';
import { ViewFieldModule } from 'src/engine/metadata-modules/view-field/view-field.module';
import { ViewModule } from 'src/engine/metadata-modules/view/view.module';
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
@@ -45,6 +47,7 @@ import { ToolRegistryService } from './services/tool-registry.service';
FieldMetadataModule,
PermissionsModule,
ViewModule,
ViewFieldModule,
WorkspaceCacheModule,
WorkspaceManyOrAllFlatEntityMapsCacheModule,
LogicFunctionModule,
@@ -60,6 +63,7 @@ import { ToolRegistryService } from './services/tool-registry.service';
MetadataToolProvider,
NativeModelToolProvider,
LogicFunctionToolProvider,
ViewFieldToolProvider,
ViewToolProvider,
WorkflowToolProvider,
{
@@ -72,6 +76,7 @@ import { ToolRegistryService } from './services/tool-registry.service';
databaseProvider: DatabaseToolProvider,
metadataProvider: MetadataToolProvider,
logicFunctionProvider: LogicFunctionToolProvider,
viewFieldProvider: ViewFieldToolProvider,
viewProvider: ViewToolProvider,
workflowProvider: WorkflowToolProvider,
) => [
@@ -80,6 +85,7 @@ import { ToolRegistryService } from './services/tool-registry.service';
databaseProvider,
metadataProvider,
logicFunctionProvider,
viewFieldProvider,
viewProvider,
workflowProvider,
],
@@ -89,6 +95,7 @@ import { ToolRegistryService } from './services/tool-registry.service';
DatabaseToolProvider,
MetadataToolProvider,
LogicFunctionToolProvider,
ViewFieldToolProvider,
ViewToolProvider,
WorkflowToolProvider,
],
@@ -1,16 +1,21 @@
import { z } from 'zod';
import { ToolCategory } from 'src/engine/core-modules/tool-provider/enums/tool-category.enum';
import { type ToolRegistryService } from 'src/engine/core-modules/tool-provider/services/tool-registry.service';
import { type ToolIndexEntry } from 'src/engine/core-modules/tool-provider/types/tool-descriptor.type';
export const GET_TOOL_CATALOG_TOOL_NAME = 'get_tool_catalog';
const availableCategories = Object.values(ToolCategory)
.map((entry) => entry.toString())
.join(', ');
export const getToolCatalogInputSchema = z.object({
categories: z
.array(z.string())
.optional()
.describe(
'Filter by category (e.g. DATABASE_CRUD, METADATA, VIEW, WORKFLOW, DASHBOARD, LOGIC_FUNCTION, ACTION). Omit to get all.',
`Filter by category. Available categories: ${availableCategories}. Omit to get all.`,
),
});