Fix code step and logic function step in workflows (#17856)
- AI still often forgets to update the code step after creating it. Adding a next step - Starting by loading logic functions, so it avoids creating code steps when a function exists - Fix create complete workflow logic. Should not create code steps directly
This commit is contained in:
+9
@@ -3,6 +3,7 @@ import { Injectable } from '@nestjs/common';
|
||||
import { type ToolSet } from 'ai';
|
||||
|
||||
import { RecordPositionService } from 'src/engine/core-modules/record-position/services/record-position.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.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';
|
||||
@@ -21,6 +22,7 @@ import { createDeactivateWorkflowVersionTool } from 'src/modules/workflow/workfl
|
||||
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';
|
||||
import { createListLogicFunctionToolsTool } from 'src/modules/workflow/workflow-tools/tools/list-logic-function-tools.tool';
|
||||
import { createUpdateLogicFunctionSourceTool } from 'src/modules/workflow/workflow-tools/tools/update-logic-function-source.tool';
|
||||
import { createUpdateWorkflowVersionPositionsTool } from 'src/modules/workflow/workflow-tools/tools/update-workflow-version-positions.tool';
|
||||
import { createUpdateWorkflowVersionStepTool } from 'src/modules/workflow/workflow-tools/tools/update-workflow-version-step.tool';
|
||||
@@ -42,6 +44,7 @@ export class WorkflowToolWorkspaceService {
|
||||
globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
|
||||
recordPositionService: RecordPositionService,
|
||||
logicFunctionService: LogicFunctionService,
|
||||
flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
|
||||
) {
|
||||
this.deps = {
|
||||
workflowVersionStepService,
|
||||
@@ -53,6 +56,7 @@ export class WorkflowToolWorkspaceService {
|
||||
globalWorkspaceOrmManager,
|
||||
recordPositionService,
|
||||
logicFunctionService,
|
||||
flatEntityMapsCacheService,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -116,6 +120,10 @@ export class WorkflowToolWorkspaceService {
|
||||
this.deps,
|
||||
context,
|
||||
);
|
||||
const listLogicFunctionTools = createListLogicFunctionToolsTool(
|
||||
this.deps,
|
||||
context,
|
||||
);
|
||||
|
||||
return {
|
||||
[createCompleteWorkflow.name]: createCompleteWorkflow,
|
||||
@@ -132,6 +140,7 @@ export class WorkflowToolWorkspaceService {
|
||||
[computeStepOutputSchema.name]: computeStepOutputSchema,
|
||||
[getWorkflowCurrentVersion.name]: getWorkflowCurrentVersion,
|
||||
[updateLogicFunctionSource.name]: updateLogicFunctionSource,
|
||||
[listLogicFunctionTools.name]: listLogicFunctionTools,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -92,6 +92,7 @@ Common mistakes to avoid:
|
||||
- Missing the "name" and "valid" fields in steps
|
||||
- Missing the "objectRecord" field in CREATE_RECORD actions
|
||||
- Using "fieldsToUpdate" instead of "objectRecord" in CREATE_RECORD actions
|
||||
- Including CODE steps in this tool — this tool does NOT create the underlying logic function needed by CODE steps. Instead, create the workflow without CODE steps first, then add CODE steps individually using create_workflow_version_step (which properly creates the logic function), then call update_logic_function_source to define the code.
|
||||
|
||||
IMPORTANT: The tool schema provides comprehensive field descriptions, examples, and validation rules. Always refer to the schema for:
|
||||
- Field requirements and data types
|
||||
|
||||
+66
-11
@@ -3,19 +3,17 @@ import { TRIGGER_STEP_ID } from 'twenty-shared/workflow';
|
||||
import { z } from 'zod';
|
||||
|
||||
import type { CreateWorkflowVersionStepInput } from 'src/engine/core-modules/workflow/dtos/create-workflow-version-step-input.dto';
|
||||
import { type WorkflowVersionStepChangesDTO } from 'src/engine/core-modules/workflow/dtos/workflow-version-step-changes.dto';
|
||||
import { WorkflowActionType } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-type.enum';
|
||||
import {
|
||||
type WorkflowToolContext,
|
||||
type WorkflowToolDependencies,
|
||||
} from 'src/modules/workflow/workflow-tools/types/workflow-tool-dependencies.type';
|
||||
|
||||
const createWorkflowVersionStepSchema = z.object({
|
||||
const baseStepFields = {
|
||||
workflowVersionId: z
|
||||
.string()
|
||||
.describe('The ID of the workflow version to add the step to'),
|
||||
stepType: z
|
||||
.enum(Object.values(WorkflowActionType) as [string, ...string[]])
|
||||
.describe('The type of step to create'),
|
||||
parentStepId: z
|
||||
.string()
|
||||
.optional()
|
||||
@@ -40,7 +38,58 @@ const createWorkflowVersionStepSchema = z.object({
|
||||
})
|
||||
.optional()
|
||||
.describe('Optional position coordinates for the step'),
|
||||
});
|
||||
};
|
||||
|
||||
const nonLogicFunctionStepTypes = Object.values(WorkflowActionType).filter(
|
||||
(type) => type !== WorkflowActionType.LOGIC_FUNCTION,
|
||||
) as [string, ...string[]];
|
||||
|
||||
const createWorkflowVersionStepSchema = z.discriminatedUnion('stepType', [
|
||||
z.object({
|
||||
...baseStepFields,
|
||||
stepType: z.literal(WorkflowActionType.LOGIC_FUNCTION),
|
||||
defaultSettings: z
|
||||
.object({
|
||||
input: z.object({
|
||||
logicFunctionId: z
|
||||
.string()
|
||||
.describe(
|
||||
'The ID of the logic function. Use list_logic_function_tools to discover available IDs.',
|
||||
),
|
||||
}),
|
||||
})
|
||||
.describe(
|
||||
'Settings for the LOGIC_FUNCTION step. Must include input.logicFunctionId.',
|
||||
),
|
||||
}),
|
||||
z.object({
|
||||
...baseStepFields,
|
||||
stepType: z.enum(nonLogicFunctionStepTypes),
|
||||
defaultSettings: z
|
||||
.record(z.string(), z.unknown())
|
||||
.optional()
|
||||
.describe('Optional default settings for the step.'),
|
||||
}),
|
||||
]);
|
||||
|
||||
const enrichResultWithNextStep = ({
|
||||
result,
|
||||
stepType,
|
||||
}: {
|
||||
result: WorkflowVersionStepChangesDTO;
|
||||
stepType: WorkflowActionType;
|
||||
}) => {
|
||||
switch (stepType) {
|
||||
case WorkflowActionType.CODE:
|
||||
return {
|
||||
...result,
|
||||
nextStep:
|
||||
'This CODE step was created with a default placeholder function. You MUST now call update_logic_function_source with the logicFunctionId from this step to define the actual code.',
|
||||
};
|
||||
default:
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
export const createCreateWorkflowVersionStepTool = (
|
||||
deps: Pick<
|
||||
@@ -84,12 +133,18 @@ export const createCreateWorkflowVersionStepTool = (
|
||||
}
|
||||
}
|
||||
|
||||
return await deps.workflowVersionStepService.createWorkflowVersionStep({
|
||||
workspaceId: context.workspaceId,
|
||||
input: {
|
||||
...parameters,
|
||||
parentStepId: effectiveParentStepId,
|
||||
},
|
||||
const result =
|
||||
await deps.workflowVersionStepService.createWorkflowVersionStep({
|
||||
workspaceId: context.workspaceId,
|
||||
input: {
|
||||
...parameters,
|
||||
parentStepId: effectiveParentStepId,
|
||||
},
|
||||
});
|
||||
|
||||
return enrichResultWithNextStep({
|
||||
result,
|
||||
stepType: parameters.stepType,
|
||||
});
|
||||
} catch (error) {
|
||||
return {
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { type WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
|
||||
import { type WorkflowToolContext } from 'src/modules/workflow/workflow-tools/types/workflow-tool-dependencies.type';
|
||||
|
||||
const listLogicFunctionToolsSchema = z.object({});
|
||||
|
||||
export const createListLogicFunctionToolsTool = (
|
||||
deps: {
|
||||
flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService;
|
||||
},
|
||||
context: WorkflowToolContext,
|
||||
) => ({
|
||||
name: 'list_logic_function_tools' as const,
|
||||
description:
|
||||
'List all logic functions marked as tools that can be added as LOGIC_FUNCTION steps in workflows. Returns their IDs, names, and descriptions.',
|
||||
inputSchema: listLogicFunctionToolsSchema,
|
||||
execute: async () => {
|
||||
const { flatLogicFunctionMaps } =
|
||||
await deps.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId: context.workspaceId,
|
||||
flatMapsKeys: ['flatLogicFunctionMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const toolFunctions = Object.values(
|
||||
flatLogicFunctionMaps.byUniversalIdentifier,
|
||||
).filter(
|
||||
(fn): fn is FlatLogicFunction =>
|
||||
isDefined(fn) && fn.isTool === true && fn.deletedAt === null,
|
||||
);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
logicFunctions: toolFunctions.map((fn) => ({
|
||||
id: fn.id,
|
||||
name: fn.name,
|
||||
description: fn.description,
|
||||
})),
|
||||
};
|
||||
},
|
||||
});
|
||||
+2
@@ -1,4 +1,5 @@
|
||||
import type { RecordPositionService } from 'src/engine/core-modules/record-position/services/record-position.service';
|
||||
import type { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import type { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service';
|
||||
import type { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import type { WorkflowSchemaWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-schema/workflow-schema.workspace-service';
|
||||
@@ -18,6 +19,7 @@ export type WorkflowToolDependencies = {
|
||||
globalWorkspaceOrmManager: GlobalWorkspaceOrmManager;
|
||||
recordPositionService: RecordPositionService;
|
||||
logicFunctionService: LogicFunctionService;
|
||||
flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService;
|
||||
};
|
||||
|
||||
export type WorkflowToolContext = {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Global, Module } from '@nestjs/common';
|
||||
|
||||
import { RecordPositionModule } from 'src/engine/core-modules/record-position/record-position.module';
|
||||
import { WORKFLOW_TOOL_SERVICE_TOKEN } from 'src/engine/core-modules/tool-provider/constants/workflow-tool-service.token';
|
||||
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 { WorkflowSchemaModule } from 'src/modules/workflow/workflow-builder/workflow-schema/workflow-schema.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
|
||||
WorkflowSchemaModule,
|
||||
RecordPositionModule,
|
||||
LogicFunctionModule,
|
||||
WorkspaceManyOrAllFlatEntityMapsCacheModule,
|
||||
],
|
||||
providers: [
|
||||
WorkflowToolWorkspaceService,
|
||||
|
||||
Reference in New Issue
Block a user