From 7a5896ff5d02d829654797e79a180bde434a8fe5 Mon Sep 17 00:00:00 2001
From: Etienne <45695613+etiennejouan@users.noreply.github.com>
Date: Thu, 2 Jul 2026 13:05:46 +0200
Subject: [PATCH] feat(ai) - add delete_workflow tool (#22432)
## Summary
- Add a new `delete_workflow` agent tool that soft-deletes a workflow
and cleans up its sub-entities (versions, runs, triggers) via
`WorkflowCommonWorkspaceService.handleWorkflowSubEntities`
- Update the workflow skill system prompt to document the new capability
and instruct the agent to always confirm with the user before deleting
- Wire `WorkflowCommonModule` / `WorkflowCommonWorkspaceService` into
the workflow-tools dependency graph
## Test plan
- [x] Unit tests added (`delete-workflow.tool.spec.ts`) covering
successful deletion and error handling
- [ ] Verify the agent can resolve a workflow by name via
`list_workflows` then delete it with `delete_workflow`
- [ ] Confirm the agent asks for user confirmation before executing the
deletion
- [ ] Confirm sub-entities (versions, runs, triggers) are removed after
deletion
---
...reate-standard-flat-skill-metadata.util.ts | 9 ++
.../workflow-tool.workspace-service.ts | 9 ++
.../__tests__/delete-workflow.tool.spec.ts | 75 ++++++++++++++++
.../tools/delete-workflow.tool.ts | 85 +++++++++++++++++++
.../types/workflow-tool-dependencies.type.ts | 2 +
.../workflow-tools/workflow-tools.module.ts | 2 +
6 files changed, 182 insertions(+)
create mode 100644 packages/twenty-server/src/modules/workflow/workflow-tools/tools/__tests__/delete-workflow.tool.spec.ts
create mode 100644 packages/twenty-server/src/modules/workflow/workflow-tools/tools/delete-workflow.tool.ts
diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/skill-metadata/create-standard-flat-skill-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/skill-metadata/create-standard-flat-skill-metadata.util.ts
index dcbb25a38d..0e41318466 100644
--- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/skill-metadata/create-standard-flat-skill-metadata.util.ts
+++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/skill-metadata/create-standard-flat-skill-metadata.util.ts
@@ -24,6 +24,7 @@ You help users create and manage automation workflows.
- Create workflows from scratch
- Modify existing workflows (add, remove, update steps)
+- Delete workflows entirely (with their versions, runs and triggers) - IMPORTANT : Always confirm with the user before deleting
- Explain workflow structure and suggest improvements
- Troubleshoot workflow runs (inspect status, failed steps, and execution logs)
@@ -72,6 +73,14 @@ LOGIC_FUNCTION steps execute logic functions provided by installed applications.
To discover existing workflows in the workspace, use \`list_workflows\`. Use this before modifying a workflow when the user refers to it by name rather than id — resolve the \`id\` here first, then call \`get_workflow_current_version\` with it.
+## Deleting Workflows
+
+To delete a workflow entirely, use \`delete_workflow\` with its \`workflowId\`. This also removes the workflow's versions, runs and automated triggers, and deactivates any active version — it is a destructive, irreversible operation.
+
+- If the user refers to the workflow by name, resolve its \`workflowId\` with \`list_workflows\` first.
+- IMPORTANT : Always confirm with the user before deleting, and make sure you are deleting the correct workflow.
+- To simply stop a workflow from running without removing it, prefer \`deactivate_workflow_version\` instead of deleting.
+
## Troubleshooting Workflow Runs
When a user reports a failing or misbehaving workflow, diagnose it with two read-only tools:
diff --git a/packages/twenty-server/src/modules/workflow/workflow-tools/services/workflow-tool.workspace-service.ts b/packages/twenty-server/src/modules/workflow/workflow-tools/services/workflow-tool.workspace-service.ts
index 8e38cec735..365d3f43fd 100644
--- a/packages/twenty-server/src/modules/workflow/workflow-tools/services/workflow-tool.workspace-service.ts
+++ b/packages/twenty-server/src/modules/workflow/workflow-tools/services/workflow-tool.workspace-service.ts
@@ -8,6 +8,7 @@ import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadat
import { LogicFunctionFromSourceService } from 'src/engine/metadata-modules/logic-function/services/logic-function-from-source.service';
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
import { type RolePermissionConfig } from 'src/engine/twenty-orm/types/role-permission-config';
+import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
import { WorkflowSchemaWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-schema/workflow-schema.workspace-service';
import { WorkflowValidationWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-validation/workflow-validation.workspace-service';
import { WorkflowVersionEdgeWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-version-edge/workflow-version-edge.workspace-service';
@@ -21,6 +22,7 @@ import { createCreateDraftFromWorkflowVersionTool } from 'src/modules/workflow/w
import { createCreateWorkflowVersionEdgeTool } from 'src/modules/workflow/workflow-tools/tools/create-workflow-version-edge.tool';
import { createCreateWorkflowVersionStepTool } from 'src/modules/workflow/workflow-tools/tools/create-workflow-version-step.tool';
import { createDeactivateWorkflowVersionTool } from 'src/modules/workflow/workflow-tools/tools/deactivate-workflow-version.tool';
+import { createDeleteWorkflowTool } from 'src/modules/workflow/workflow-tools/tools/delete-workflow.tool';
import { createDeleteWorkflowVersionEdgeTool } from 'src/modules/workflow/workflow-tools/tools/delete-workflow-version-edge.tool';
import { createDeleteWorkflowVersionStepTool } from 'src/modules/workflow/workflow-tools/tools/delete-workflow-version-step.tool';
import { createGetWorkflowCurrentVersionTool } from 'src/modules/workflow/workflow-tools/tools/get-workflow-current-version.tool';
@@ -54,6 +56,7 @@ export class WorkflowToolWorkspaceService {
logicFunctionFromSourceService: LogicFunctionFromSourceService,
flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
agentService: AgentService,
+ workflowCommonService: WorkflowCommonWorkspaceService,
) {
this.deps = {
workflowVersionStepService,
@@ -68,6 +71,7 @@ export class WorkflowToolWorkspaceService {
logicFunctionFromSourceService,
flatEntityMapsCacheService,
agentService,
+ workflowCommonService,
};
}
@@ -139,6 +143,10 @@ export class WorkflowToolWorkspaceService {
this.deps,
contextWithPermissions,
);
+ const deleteWorkflow = createDeleteWorkflowTool(
+ this.deps,
+ contextWithPermissions,
+ );
const updateLogicFunctionSource = createUpdateLogicFunctionSourceTool(
this.deps,
context,
@@ -165,6 +173,7 @@ export class WorkflowToolWorkspaceService {
[computeStepOutputSchema.name]: computeStepOutputSchema,
[getWorkflowCurrentVersion.name]: getWorkflowCurrentVersion,
[listWorkflows.name]: listWorkflows,
+ [deleteWorkflow.name]: deleteWorkflow,
[getWorkflowRun.name]: getWorkflowRun,
[listWorkflowRuns.name]: listWorkflowRuns,
[updateLogicFunctionSource.name]: updateLogicFunctionSource,
diff --git a/packages/twenty-server/src/modules/workflow/workflow-tools/tools/__tests__/delete-workflow.tool.spec.ts b/packages/twenty-server/src/modules/workflow/workflow-tools/tools/__tests__/delete-workflow.tool.spec.ts
new file mode 100644
index 0000000000..09bae1daa5
--- /dev/null
+++ b/packages/twenty-server/src/modules/workflow/workflow-tools/tools/__tests__/delete-workflow.tool.spec.ts
@@ -0,0 +1,75 @@
+import { createDeleteWorkflowTool } from 'src/modules/workflow/workflow-tools/tools/delete-workflow.tool';
+
+const WORKFLOW_ID = 'b3b8a4f0-0000-4000-8000-000000000000';
+
+const buildTool = () => {
+ const workflowRepository = {
+ softDelete: jest.fn().mockResolvedValue({ affected: 1 }),
+ };
+ const globalWorkspaceOrmManager = {
+ executeInWorkspaceContext: jest.fn((callback: () => unknown) => callback()),
+ getRepository: jest.fn().mockResolvedValue(workflowRepository),
+ };
+ const workflowCommonService = {
+ handleWorkflowSubEntities: jest.fn().mockResolvedValue(undefined),
+ };
+
+ const tool = createDeleteWorkflowTool(
+ {
+ globalWorkspaceOrmManager,
+ workflowCommonService,
+ } as never,
+ {
+ workspaceId: 'workspace-id',
+ rolePermissionConfig: { shouldBypassPermissionChecks: true },
+ } as never,
+ );
+
+ return {
+ tool,
+ workflowRepository,
+ globalWorkspaceOrmManager,
+ workflowCommonService,
+ };
+};
+
+const baseInput = {
+ workflowId: WORKFLOW_ID,
+} as unknown as Parameters<
+ ReturnType['execute']
+>[0];
+
+describe('createDeleteWorkflowTool', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('should soft delete the workflow and clean up sub-entities', async () => {
+ const { tool, workflowRepository, workflowCommonService } = buildTool();
+
+ const result = (await tool.execute(baseInput)) as Record;
+
+ expect(workflowRepository.softDelete).toHaveBeenCalledWith(WORKFLOW_ID);
+ expect(
+ workflowCommonService.handleWorkflowSubEntities,
+ ).toHaveBeenCalledWith({
+ workflowIds: [WORKFLOW_ID],
+ workspaceId: 'workspace-id',
+ operation: 'delete',
+ });
+ expect(result.success).toBe(true);
+ expect(result.workflowId).toBe(WORKFLOW_ID);
+ });
+
+ it('should return a failure result when deletion throws', async () => {
+ const { tool, workflowRepository } = buildTool();
+
+ workflowRepository.softDelete.mockRejectedValue(new Error('boom'));
+
+ const result = (await tool.execute(baseInput)) as Record;
+
+ expect(result.success).toBe(false);
+ expect(result.error).toBe('boom');
+ expect(result.message).toContain('boom');
+ });
+});
diff --git a/packages/twenty-server/src/modules/workflow/workflow-tools/tools/delete-workflow.tool.ts b/packages/twenty-server/src/modules/workflow/workflow-tools/tools/delete-workflow.tool.ts
new file mode 100644
index 0000000000..192ad5e471
--- /dev/null
+++ b/packages/twenty-server/src/modules/workflow/workflow-tools/tools/delete-workflow.tool.ts
@@ -0,0 +1,85 @@
+import { z } from 'zod';
+
+import { type RolePermissionConfig } from 'src/engine/twenty-orm/types/role-permission-config';
+import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
+import { type WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
+import {
+ type WorkflowToolContext,
+ type WorkflowToolDependencies,
+} from 'src/modules/workflow/workflow-tools/types/workflow-tool-dependencies.type';
+import { isDefined } from 'twenty-shared/utils';
+
+type DeleteWorkflowToolContext = WorkflowToolContext & {
+ rolePermissionConfig: RolePermissionConfig;
+};
+
+const deleteWorkflowSchema = z.object({
+ workflowId: z.string().uuid().describe('The UUID of the workflow to delete'),
+});
+
+type DeleteWorkflowInput = z.infer;
+
+export const createDeleteWorkflowTool = (
+ deps: Pick<
+ WorkflowToolDependencies,
+ 'globalWorkspaceOrmManager' | 'workflowCommonService'
+ >,
+ context: DeleteWorkflowToolContext,
+) => ({
+ name: 'delete_workflow' as const,
+ description:
+ 'Delete a workflow by its ID. This also removes its versions, runs and automated triggers, and deactivates any active version. Use list_workflows to find the workflowId.',
+ inputSchema: deleteWorkflowSchema,
+ execute: async (parameters: DeleteWorkflowInput) => {
+ try {
+ const { workflowId } = parameters;
+ const { workspaceId } = context;
+
+ const authContext = buildSystemAuthContext(workspaceId);
+
+ const deleteResult =
+ await deps.globalWorkspaceOrmManager.executeInWorkspaceContext(
+ async () => {
+ const workflowRepository =
+ await deps.globalWorkspaceOrmManager.getRepository(
+ workspaceId,
+ 'workflow',
+ context.rolePermissionConfig,
+ );
+
+ return workflowRepository.softDelete(workflowId);
+ },
+ authContext,
+ );
+
+ if (!isDefined(deleteResult.affected)) {
+ return {
+ success: false,
+ error: 'Workflow not found',
+ message: `No workflow found with ID ${workflowId}`,
+ };
+ }
+
+ await deps.workflowCommonService.handleWorkflowSubEntities({
+ workflowIds: [workflowId],
+ workspaceId,
+ operation: 'delete',
+ });
+
+ return {
+ success: true,
+ message: `Successfully deleted workflow ${workflowId}`,
+ workflowId,
+ };
+ } catch (error) {
+ const errorMessage =
+ error instanceof Error ? error.message : String(error);
+
+ return {
+ success: false,
+ error: errorMessage,
+ message: `Failed to delete workflow: ${errorMessage}`,
+ };
+ }
+ },
+});
diff --git a/packages/twenty-server/src/modules/workflow/workflow-tools/types/workflow-tool-dependencies.type.ts b/packages/twenty-server/src/modules/workflow/workflow-tools/types/workflow-tool-dependencies.type.ts
index 67c75eeac7..c27aeb3f65 100644
--- a/packages/twenty-server/src/modules/workflow/workflow-tools/types/workflow-tool-dependencies.type.ts
+++ b/packages/twenty-server/src/modules/workflow/workflow-tools/types/workflow-tool-dependencies.type.ts
@@ -3,6 +3,7 @@ import type { AgentService } from 'src/engine/metadata-modules/ai/ai-agent/agent
import type { LogicFunctionFromSourceService } from 'src/engine/metadata-modules/logic-function/services/logic-function-from-source.service';
import type { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import type { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
+import type { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
import type { WorkflowSchemaWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-schema/workflow-schema.workspace-service';
import type { WorkflowValidationWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-validation/workflow-validation.workspace-service';
import type { WorkflowVersionEdgeWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-version-edge/workflow-version-edge.workspace-service';
@@ -24,6 +25,7 @@ export type WorkflowToolDependencies = {
logicFunctionFromSourceService: LogicFunctionFromSourceService;
flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService;
agentService: AgentService;
+ workflowCommonService: WorkflowCommonWorkspaceService;
};
export type WorkflowToolContext = {
diff --git a/packages/twenty-server/src/modules/workflow/workflow-tools/workflow-tools.module.ts b/packages/twenty-server/src/modules/workflow/workflow-tools/workflow-tools.module.ts
index 95fcf83fef..8efc77212d 100644
--- a/packages/twenty-server/src/modules/workflow/workflow-tools/workflow-tools.module.ts
+++ b/packages/twenty-server/src/modules/workflow/workflow-tools/workflow-tools.module.ts
@@ -5,6 +5,7 @@ import { WORKFLOW_TOOL_SERVICE_TOKEN } from 'src/engine/core-modules/tool-provid
import { AiAgentModule } from 'src/engine/metadata-modules/ai/ai-agent/ai-agent.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 { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-common.module';
import { WorkflowSchemaModule } from 'src/modules/workflow/workflow-builder/workflow-schema/workflow-schema.module';
import { WorkflowValidationModule } from 'src/modules/workflow/workflow-builder/workflow-validation/workflow-validation.module';
import { WorkflowVersionEdgeModule } from 'src/modules/workflow/workflow-builder/workflow-version-edge/workflow-version-edge.module';
@@ -23,6 +24,7 @@ import { WorkflowToolWorkspaceService } from './services/workflow-tool.workspace
WorkflowVersionEdgeModule,
WorkflowVersionModule,
WorkflowTriggerModule,
+ WorkflowCommonModule,
WorkflowSchemaModule,
WorkflowValidationModule,
RecordPositionModule,