Skip to content

Commit 3ecef5c

Browse files
committed
fix(workflows): keep the Run-button lint finding advisory and point at lint from apply warnings
1 parent 18d12ad commit 3ecef5c

7 files changed

Lines changed: 191 additions & 116 deletions

File tree

‎apps/docs/openapi-v2-workflows.json‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -739,7 +739,7 @@
739739
"notes": []
740740
},
741741
"warnings": [
742-
"Workflow lint found issues. Fix these before continuing: Blocks missing required fields: \"Triage\" (systemPrompt)"
742+
"Workflow lint found issues (Blocks missing required fields: 1). The findings are in `lint`."
743743
],
744744
"needsRedeployment": true,
745745
"dryRun": false
@@ -8885,7 +8885,7 @@
88858885
"type": "null"
88868886
}
88878887
],
8888-
"description": "Why a manual run from the editor's Run button would be refused before it starts: no enabled trigger it can start from, more than one API trigger, or a selected trigger with no outgoing connection. `null` when no manual-run issue is reported: the run can begin, only a chat trigger can start the workflow, or the graph is empty (reported in `notes` instead)."
8888+
"description": "Why a manual run from the editor's Run button would be refused before it starts: no enabled trigger it can start from, more than one API trigger, or a selected trigger with no outgoing connection. The API run endpoints do not apply these checks. `null` when no manual-run issue is reported: the run can begin, only a chat trigger can start the workflow, or the graph is empty (reported in `notes` instead)."
88898889
},
88908890
"notes": {
88918891
"type": "array",
@@ -9537,7 +9537,7 @@
95379537
"items": {
95389538
"type": "string"
95399539
},
9540-
"description": "Non-fatal notes about blocks and edges that were normalized or dropped before persistence and, when `lint` has findings, one summary of them, so the findings are not lost to a caller that reads only `warnings`. Empty when there is nothing to report."
9540+
"description": "Non-fatal notes about blocks and edges that were normalized or dropped before persistence and, when `lint` has findings, one line counting them by category, so a caller that reads only `warnings` still learns they exist. The findings themselves are in `lint`. Empty when there is nothing to report."
95419541
},
95429542
"needsRedeployment": {
95439543
"type": "boolean",
@@ -9673,7 +9673,7 @@
96739673
"notes": []
96749674
},
96759675
"warnings": [
9676-
"Workflow lint found issues. Fix these before continuing: Blocks missing required fields: \"Triage\" (systemPrompt)"
9676+
"Workflow lint found issues (Blocks missing required fields: 1). The findings are in `lint`."
96779677
],
96789678
"needsRedeployment": true,
96799679
"dryRun": false

‎apps/sim/lib/api/contracts/v2/openapi/workflows.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ const declaredRoutes = [
436436
notes: [],
437437
},
438438
warnings: [
439-
'Workflow lint found issues. Fix these before continuing: Blocks missing required fields: "Triage" (systemPrompt)',
439+
'Workflow lint found issues (Blocks missing required fields: 1). The findings are in `lint`.',
440440
],
441441
needsRedeployment: true,
442442
dryRun: false,

‎apps/sim/lib/api/contracts/v2/workflows.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ const v2WorkflowLintSchema = z
454454
})
455455
.nullable()
456456
.describe(
457-
"Why a manual run from the editor's Run button would be refused before it starts: no enabled trigger it can start from, more than one API trigger, or a selected trigger with no outgoing connection. `null` when no manual-run issue is reported: the run can begin, only a chat trigger can start the workflow, or the graph is empty (reported in `notes` instead)."
457+
"Why a manual run from the editor's Run button would be refused before it starts: no enabled trigger it can start from, more than one API trigger, or a selected trigger with no outgoing connection. The API run endpoints do not apply these checks. `null` when no manual-run issue is reported: the run can begin, only a chat trigger can start the workflow, or the graph is empty (reported in `notes` instead)."
458458
),
459459
notes: z.array(z.string()).describe('Advisory notes about the report itself.'),
460460
})
@@ -3646,7 +3646,7 @@ export const v2ApplyWorkflowOperationsDataSchema = v2WorkflowGraphWriteResultSch
36463646
warnings: z
36473647
.array(z.string())
36483648
.describe(
3649-
'Non-fatal notes about blocks and edges that were normalized or dropped before persistence and, when `lint` has findings, one summary of them, so the findings are not lost to a caller that reads only `warnings`. Empty when there is nothing to report.'
3649+
'Non-fatal notes about blocks and edges that were normalized or dropped before persistence and, when `lint` has findings, one line counting them by category, so a caller that reads only `warnings` still learns they exist. The findings themselves are in `lint`. Empty when there is nothing to report.'
36503650
),
36513651
dryRun: z
36523652
.boolean()

‎apps/sim/lib/workflows/application/apply-workflow-operations.test.ts‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,17 +269,20 @@ describe('applyWorkflowOperations', () => {
269269
* An agent piping the apply response through a projection of `warnings`
270270
* never saw lint findings, which lived only under `lint`.
271271
*/
272-
it('summarizes lint findings in warnings, on commit and on dry run', async () => {
272+
it('points at lint findings from warnings, on commit and on dry run', async () => {
273273
const orphan = { blockId: 'block-1', blockName: 'Start', blockType: 'starter' }
274-
mocks.lintGraph.mockReturnValue({ ...EMPTY_GRAPH_LINT, orphanBlocks: [orphan] })
274+
mocks.lintGraph.mockReturnValue({
275+
...EMPTY_GRAPH_LINT,
276+
orphanBlocks: [orphan, { ...orphan, blockId: 'block-2', blockName: 'Fn' }],
277+
})
275278

276279
for (const dryRun of [false, true]) {
277280
const result = await applyWorkflowOperations.execute({
278281
principal: sessionPrincipal,
279282
input: { workflowId: 'workflow-1', operations, dryRun },
280283
})
281284
expect(result.warnings).toEqual([
282-
'Workflow lint found issues. Fix these before continuing: Blocks with no incoming edge: "Start" (starter)',
285+
'Workflow lint found issues (Blocks with no incoming edge: 2). The findings are in `lint`.',
283286
])
284287
}
285288
})

‎apps/sim/lib/workflows/application/apply-workflow-operations.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import {
3939
} from '@/lib/workflows/editing/block-enablement'
4040
import { applyOperationsToWorkflowState } from '@/lib/workflows/editing/engine'
4141
import type { WorkflowLintReport } from '@/lib/workflows/editing/lint'
42-
import { formatWorkflowLintMessage, hasWorkflowLintIssues } from '@/lib/workflows/editing/lint'
42+
import { hasWorkflowLintIssues, summarizeWorkflowLintIssues } from '@/lib/workflows/editing/lint'
4343
import { buildWorkflowLintReport } from '@/lib/workflows/editing/lint-report'
4444
import { operationsReferenceSimSandbox } from '@/lib/workflows/editing/sandbox-projection'
4545
import {
@@ -365,10 +365,10 @@ export const applyWorkflowOperations = defineAuthorizedWorkflowUseCase({
365365
input.checkAborted?.()
366366

367367
/**
368-
* The findings also ride in `warnings`, where a caller that projects the
369-
* response down to its warnings still sees them.
368+
* A caller that projects the response down to its warnings still learns
369+
* the findings exist; the findings themselves stay only in `lint`.
370370
*/
371-
const lintWarnings = hasWorkflowLintIssues(lint) ? [formatWorkflowLintMessage(lint)] : []
371+
const lintWarnings = hasWorkflowLintIssues(lint) ? [summarizeWorkflowLintIssues(lint)] : []
372372

373373
/**
374374
* A dry run still runs the whole engine — operations are applied, refusals

‎apps/sim/lib/workflows/editing/lint.test.ts‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import {
66
collectTableBlockFieldIssues,
77
collectWorkflowFieldIssues,
88
collectWorkflowTableIds,
9+
formatWorkflowLintMessage,
910
hasWorkflowLintIssues,
1011
lintEditedWorkflowState,
12+
summarizeWorkflowLintIssues,
1113
} from './lint'
1214

1315
const mockGetToolParams = getToolParams as Mock
@@ -535,3 +537,54 @@ describe('collectWorkflowTableIds', () => {
535537
expect(ids).toEqual(['tbl_1'])
536538
})
537539
})
540+
541+
/**
542+
* The agent's own runs name their trigger and skip the Run button's checks, so
543+
* a Run-button refusal told under "Fix these before continuing" pushed agents
544+
* to wire a stray Start into the graph instead of removing it.
545+
*/
546+
describe('formatWorkflowLintMessage', () => {
547+
const clean = {
548+
sources: [],
549+
sinks: [],
550+
orphanBlocks: [],
551+
emptyOutgoingPorts: [],
552+
invalidBranchPorts: [],
553+
invalidConnectionTargets: [],
554+
}
555+
const strayStart = {
556+
reason: 'trigger-not-connected' as const,
557+
message: 'Start must be connected to other blocks to execute',
558+
blockId: 'start-1',
559+
blockName: 'Start',
560+
blockType: 'start_trigger',
561+
}
562+
563+
it('reports a Run-button refusal as advice outside the blocking findings, naming both remedies', () => {
564+
const message = formatWorkflowLintMessage({ ...clean, manualRunIssue: strayStart })
565+
expect(message).not.toContain('Fix these before continuing')
566+
expect(message).toBe(
567+
'The editor\'s Run button would fail: Start must be connected to other blocks to execute. Run starts from "Start" (start_trigger) ahead of any other trigger: connect it, or delete it if the workflow starts from another trigger. Runs that name their trigger are not affected.'
568+
)
569+
})
570+
571+
it('points at a Run-button refusal alone without calling it a lint issue', () => {
572+
expect(summarizeWorkflowLintIssues({ ...clean, manualRunIssue: strayStart })).toBe(
573+
"The editor's Run button would fail. The findings are in `lint`."
574+
)
575+
})
576+
577+
it('keeps blocking findings first and the Run-button advice after them', () => {
578+
const message = formatWorkflowLintMessage({
579+
...clean,
580+
orphanBlocks: [{ blockId: 'fn', blockName: 'Fn', blockType: 'function' }],
581+
manualRunIssue: {
582+
reason: 'multiple-api-triggers',
583+
message: 'Multiple API Trigger blocks found. Keep only one.',
584+
},
585+
})
586+
expect(message).toBe(
587+
'Workflow lint found issues. Fix these before continuing: Blocks with no incoming edge: "Fn" (function). The editor\'s Run button would fail: Multiple API Trigger blocks found. Keep only one.'
588+
)
589+
})
590+
})

0 commit comments

Comments
 (0)