feat(API): Accept the engineType workflow setting and ignore it (no-changelog) (#41658)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
Alex Grozav
2026-10-23 13:43:05 +00:00
committed by GitHub
co-authored by Claude Opus 5.5 multica-agent
parent 2c4264c8a4
commit b907f7be42
11 changed files with 100 additions and 1 deletions
@@ -101,6 +101,21 @@ describe('CreateWorkflowPublicDto', () => {
}
});
test.each([['v2'], ['v1'], [null], ['unknown']])(
'accepts settings.engineType %s but ignores it',
(engineType) => {
const result = CreateWorkflowPublicDto.safeParse({
...validPayload,
settings: { ...validPayload.settings, engineType },
});
expect(result.success).toBe(true);
if (result.success) {
expect(result.data.settings).toEqual({ executionOrder: 'v1' });
}
},
);
test.each([
['accepts', 155, true],
['rejects', 156, false],
@@ -82,6 +82,8 @@ const workflowSettingsWritePublicSchema = z
.enum(['separate', 'combined'])
.optional()
.openapi(workflowSettingsFieldDocs.binaryMode),
// Accepted but ignored: a stored workflow can hold any value here, so a GET-then-PUT must not fail on it
engineType: z.string().nullable().optional().openapi(workflowSettingsFieldDocs.engineType),
callerPolicy: z
.enum(['any', 'none', 'workflowsFromAList', 'workflowsFromSameOwner'])
.optional()
@@ -112,7 +114,12 @@ const workflowSettingsWritePublicSchema = z
})
.strict()
.transform(
({ binaryMode: _binaryMode, credentialResolverId: _resolverId, ...settings }) => settings,
({
binaryMode: _binaryMode,
engineType: _engineType,
credentialResolverId: _resolverId,
...settings
}) => settings,
);
const sharedWorkflowWritePublicSchema = z
@@ -49,6 +49,12 @@ export const workflowSettingsFieldDocs = {
'workflow responses for reference, but any value sent when creating or updating a ' +
'workflow is ignored.',
},
engineType: {
example: 'v1',
description:
'The execution engine that runs this workflow. It is included in workflow responses ' +
'for reference, but any value sent when creating or updating a workflow is ignored.',
},
callerPolicy: {
example: 'workflowsFromSameOwner',
description:
@@ -249,6 +255,7 @@ export const settingsOpenApi: ZodOpenAPIMetadata = alsoNullable({
enum: ['separate', 'combined'],
...workflowSettingsFieldDocs.binaryMode,
},
engineType: { type: 'string', nullable: true, ...workflowSettingsFieldDocs.engineType },
callerPolicy: {
type: 'string',
enum: ['any', 'none', 'workflowsFromAList', 'workflowsFromSameOwner'],
@@ -184,6 +184,11 @@ requestBody:
- separate
- combined
description: Controls how binary data is resolved from a node's input. This is a derived, internal setting rather than something intended to be set programmatically. It is included in workflow responses for reference, but any value sent when creating or updating a workflow is ignored.
engineType:
type: string
nullable: true
description: The execution engine that runs this workflow. It is included in workflow responses for reference, but any value sent when creating or updating a workflow is ignored.
example: v1
callerPolicy:
type: string
enum:
@@ -768,6 +773,11 @@ responses:
- separate
- combined
description: Controls how binary data is resolved from a node's input. This is a derived, internal setting rather than something intended to be set programmatically. It is included in workflow responses for reference, but any value sent when creating or updating a workflow is ignored.
engineType:
type: string
nullable: true
example: v1
description: The execution engine that runs this workflow. It is included in workflow responses for reference, but any value sent when creating or updating a workflow is ignored.
callerPolicy:
type: string
enum:
@@ -211,6 +211,11 @@ responses:
- separate
- combined
description: Controls how binary data is resolved from a node's input. This is a derived, internal setting rather than something intended to be set programmatically. It is included in workflow responses for reference, but any value sent when creating or updating a workflow is ignored.
engineType:
type: string
nullable: true
example: v1
description: The execution engine that runs this workflow. It is included in workflow responses for reference, but any value sent when creating or updating a workflow is ignored.
callerPolicy:
type: string
enum:
@@ -220,6 +220,11 @@ responses:
- separate
- combined
description: Controls how binary data is resolved from a node's input. This is a derived, internal setting rather than something intended to be set programmatically. It is included in workflow responses for reference, but any value sent when creating or updating a workflow is ignored.
engineType:
type: string
nullable: true
example: v1
description: The execution engine that runs this workflow. It is included in workflow responses for reference, but any value sent when creating or updating a workflow is ignored.
callerPolicy:
type: string
enum:
@@ -247,6 +247,11 @@ responses:
- separate
- combined
description: Controls how binary data is resolved from a node's input. This is a derived, internal setting rather than something intended to be set programmatically. It is included in workflow responses for reference, but any value sent when creating or updating a workflow is ignored.
engineType:
type: string
nullable: true
example: v1
description: The execution engine that runs this workflow. It is included in workflow responses for reference, but any value sent when creating or updating a workflow is ignored.
callerPolicy:
type: string
enum:
@@ -199,6 +199,11 @@ requestBody:
- separate
- combined
description: Controls how binary data is resolved from a node's input. This is a derived, internal setting rather than something intended to be set programmatically. It is included in workflow responses for reference, but any value sent when creating or updating a workflow is ignored.
engineType:
type: string
nullable: true
description: The execution engine that runs this workflow. It is included in workflow responses for reference, but any value sent when creating or updating a workflow is ignored.
example: v1
callerPolicy:
type: string
enum:
@@ -780,6 +785,11 @@ responses:
- separate
- combined
description: Controls how binary data is resolved from a node's input. This is a derived, internal setting rather than something intended to be set programmatically. It is included in workflow responses for reference, but any value sent when creating or updating a workflow is ignored.
engineType:
type: string
nullable: true
example: v1
description: The execution engine that runs this workflow. It is included in workflow responses for reference, but any value sent when creating or updating a workflow is ignored.
callerPolicy:
type: string
enum:
@@ -192,6 +192,11 @@ properties:
- separate
- combined
description: Controls how binary data is resolved from a node's input. This is a derived, internal setting rather than something intended to be set programmatically. It is included in workflow responses for reference, but any value sent when creating or updating a workflow is ignored.
engineType:
type: string
nullable: true
example: v1
description: The execution engine that runs this workflow. It is included in workflow responses for reference, but any value sent when creating or updating a workflow is ignored.
callerPolicy:
type: string
enum:
@@ -192,6 +192,11 @@ properties:
- separate
- combined
description: Controls how binary data is resolved from a node's input. This is a derived, internal setting rather than something intended to be set programmatically. It is included in workflow responses for reference, but any value sent when creating or updating a workflow is ignored.
engineType:
type: string
nullable: true
example: v1
description: The execution engine that runs this workflow. It is included in workflow responses for reference, but any value sent when creating or updating a workflow is ignored.
callerPolicy:
type: string
enum:
@@ -2315,6 +2315,7 @@ describe('POST /workflows', () => {
test.each([
{ key: 'binaryMode', value: 'combined' },
{ key: 'engineType', value: 'v2' },
{ key: 'credentialResolverId', value: 'some-resolver-id' },
] as const)('should ignore $key when creating a workflow', async ({ key, value }) => {
const payload = {
@@ -3320,8 +3321,32 @@ describe('PUT /workflows/:id', () => {
expect(sharedWorkflow?.workflow.activeVersionId).toBeNull();
});
test('should accept the settings that GET returned and keep the stored engine', async () => {
const workflow = await createWorkflowWithHistory(
{ settings: { executionOrder: 'v1', engineType: 'v2' } },
member,
);
const getResponse = await authMemberAgent.get(`/workflows/${workflow.id}`);
expect(getResponse.body.settings.engineType).toBe('v2');
const response = await authMemberAgent.put(`/workflows/${workflow.id}`).send({
name: getResponse.body.name,
nodes: getResponse.body.nodes,
connections: getResponse.body.connections,
settings: getResponse.body.settings,
});
expect(response.statusCode).toBe(200);
expect(response.body.settings.engineType).toBe('v2');
const workflowAfter = await workflowRepository.findOneBy({ id: workflow.id });
expect(workflowAfter?.settings?.engineType).toBe('v2');
});
test.each([
{ key: 'binaryMode', original: 'combined', attempted: 'separate' },
{ key: 'engineType', original: 'v2', attempted: 'v1' },
{
key: 'credentialResolverId',
original: 'original-resolver-id',