diff --git a/skyvern-frontend/src/routes/workflows/editor/helpContent.ts b/skyvern-frontend/src/routes/workflows/editor/helpContent.ts index 9b8285cc..d0bc4e69 100644 --- a/skyvern-frontend/src/routes/workflows/editor/helpContent.ts +++ b/skyvern-frontend/src/routes/workflows/editor/helpContent.ts @@ -23,7 +23,7 @@ export const baseHelpTooltipContent = { "If you are running multiple workflows at once, you will need to give the block an identifier to know that this TOTP goes with this block.", continueOnFailure: "Allow the workflow to continue if it encounters a failure.", - nextIterationOnFailure: + nextLoopOnFailure: "When inside a for loop, continue to the next iteration if this block fails.", includeActionHistoryInVerification: "Include the action history in the completion verification.", @@ -74,7 +74,7 @@ export const helpTooltips = { ...baseHelpTooltipContent, loopValue: "Define the values to iterate over. Use a parameter reference or natural language (e.g., 'Extract links of the top 2 posts'). Natural language automatically creates an extraction block that generates a list of string values. Use {{ current_value }} in the loop to get the current iteration value.", - nextIterationOnFailure: + nextLoopOnFailure: "When enabled, if any block inside the loop fails, the loop will immediately jump to the next iteration instead of stopping.", }, sendEmail: { diff --git a/skyvern-frontend/src/routes/workflows/editor/nodes/ActionNode/ActionNode.tsx b/skyvern-frontend/src/routes/workflows/editor/nodes/ActionNode/ActionNode.tsx index ffdd5e88..b6fad87e 100644 --- a/skyvern-frontend/src/routes/workflows/editor/nodes/ActionNode/ActionNode.tsx +++ b/skyvern-frontend/src/routes/workflows/editor/nodes/ActionNode/ActionNode.tsx @@ -255,15 +255,15 @@ function ActionNode({ id, data, type }: NodeProps) { { update({ continueOnFailure: checked }); }} - onNextIterationOnFailureChange={(checked) => { - update({ nextIterationOnFailure: checked }); + onNextLoopOnFailureChange={(checked) => { + update({ nextLoopOnFailure: checked }); }} /> ) { { update({ continueOnFailure: checked }); }} - onNextIterationOnFailureChange={(checked) => { - update({ nextIterationOnFailure: checked }); + onNextLoopOnFailureChange={(checked) => { + update({ nextLoopOnFailure: checked }); }} /> ) { { update({ continueOnFailure: checked }); }} - onNextIterationOnFailureChange={(checked) => { - update({ nextIterationOnFailure: checked }); + onNextLoopOnFailureChange={(checked) => { + update({ nextLoopOnFailure: checked }); }} /> ) { { update({ continueOnFailure: checked }); }} - onNextIterationOnFailureChange={(checked) => { - update({ nextIterationOnFailure: checked }); + onNextLoopOnFailureChange={(checked) => { + update({ nextLoopOnFailure: checked }); }} /> ) {
{ update({ - nextIterationOnFailure: + nextLoopOnFailure: checked === "indeterminate" ? false : checked, }); }} @@ -175,7 +175,7 @@ function LoopNode({ id, data }: NodeProps) { Next Loop on Failure
diff --git a/skyvern-frontend/src/routes/workflows/editor/nodes/LoopNode/types.ts b/skyvern-frontend/src/routes/workflows/editor/nodes/LoopNode/types.ts index 25268116..5c62c06c 100644 --- a/skyvern-frontend/src/routes/workflows/editor/nodes/LoopNode/types.ts +++ b/skyvern-frontend/src/routes/workflows/editor/nodes/LoopNode/types.ts @@ -7,7 +7,7 @@ export type LoopNodeData = NodeBaseData & { loopVariableReference: string; completeIfEmpty: boolean; continueOnFailure: boolean; - nextIterationOnFailure?: boolean; + nextLoopOnFailure?: boolean; }; export type LoopNode = Node; @@ -20,7 +20,7 @@ export const loopNodeDefaultData: LoopNodeData = { loopVariableReference: "", completeIfEmpty: false, continueOnFailure: false, - nextIterationOnFailure: false, + nextLoopOnFailure: false, model: null, } as const; diff --git a/skyvern-frontend/src/routes/workflows/editor/nodes/NavigationNode/NavigationNode.tsx b/skyvern-frontend/src/routes/workflows/editor/nodes/NavigationNode/NavigationNode.tsx index 55d3d742..d8b0a349 100644 --- a/skyvern-frontend/src/routes/workflows/editor/nodes/NavigationNode/NavigationNode.tsx +++ b/skyvern-frontend/src/routes/workflows/editor/nodes/NavigationNode/NavigationNode.tsx @@ -294,7 +294,7 @@ function NavigationNode({ id, data, type }: NodeProps) { ) { blockType="navigation" showOptions={{ continueOnFailure: true, - nextIterationOnFailure: true, + nextLoopOnFailure: true, includeActionHistoryInVerification: true, }} onContinueOnFailureChange={(checked) => { update({ continueOnFailure: checked }); }} - onNextIterationOnFailureChange={(checked) => { - update({ nextIterationOnFailure: checked }); + onNextLoopOnFailureChange={(checked) => { + update({ nextLoopOnFailure: checked }); }} onIncludeActionHistoryInVerificationChange={(checked) => { update({ diff --git a/skyvern-frontend/src/routes/workflows/editor/nodes/TaskNode/TaskNode.tsx b/skyvern-frontend/src/routes/workflows/editor/nodes/TaskNode/TaskNode.tsx index 48232874..5ed3d6b1 100644 --- a/skyvern-frontend/src/routes/workflows/editor/nodes/TaskNode/TaskNode.tsx +++ b/skyvern-frontend/src/routes/workflows/editor/nodes/TaskNode/TaskNode.tsx @@ -310,7 +310,7 @@ function TaskNode({ id, data, type }: NodeProps) { ) { blockType="task" showOptions={{ continueOnFailure: true, - nextIterationOnFailure: true, + nextLoopOnFailure: true, includeActionHistoryInVerification: true, }} onContinueOnFailureChange={(checked) => { update({ continueOnFailure: checked }); }} - onNextIterationOnFailureChange={(checked) => { - update({ nextIterationOnFailure: checked }); + onNextLoopOnFailureChange={(checked) => { + update({ nextLoopOnFailure: checked }); }} onIncludeActionHistoryInVerificationChange={(checked) => { update({ diff --git a/skyvern-frontend/src/routes/workflows/editor/nodes/ValidationNode/ValidationNode.tsx b/skyvern-frontend/src/routes/workflows/editor/nodes/ValidationNode/ValidationNode.tsx index aee652f7..25c01ef2 100644 --- a/skyvern-frontend/src/routes/workflows/editor/nodes/ValidationNode/ValidationNode.tsx +++ b/skyvern-frontend/src/routes/workflows/editor/nodes/ValidationNode/ValidationNode.tsx @@ -218,15 +218,15 @@ function ValidationNode({ id, data, type }: NodeProps) { { update({ continueOnFailure: checked }); }} - onNextIterationOnFailureChange={(checked) => { - update({ nextIterationOnFailure: checked }); + onNextLoopOnFailureChange={(checked) => { + update({ nextLoopOnFailure: checked }); }} /> void; - onNextIterationOnFailureChange: (checked: boolean) => void; + onNextLoopOnFailureChange: (checked: boolean) => void; onIncludeActionHistoryInVerificationChange?: (checked: boolean) => void; showOptions?: { continueOnFailure?: boolean; - nextIterationOnFailure?: boolean; + nextLoopOnFailure?: boolean; includeActionHistoryInVerification?: boolean; }; } export function BlockExecutionOptions({ continueOnFailure, - nextIterationOnFailure = false, + nextLoopOnFailure = false, includeActionHistoryInVerification = false, editable, isInsideForLoop, blockType, onContinueOnFailureChange, - onNextIterationOnFailureChange, + onNextLoopOnFailureChange, onIncludeActionHistoryInVerificationChange, showOptions = { continueOnFailure: true, - nextIterationOnFailure: true, + nextLoopOnFailure: true, includeActionHistoryInVerification: false, }, }: BlockExecutionOptionsProps) { const showContinueOnFailure = showOptions.continueOnFailure ?? true; - const showNextIterationOnFailure = showOptions.nextIterationOnFailure ?? true; + const showNextLoopOnFailure = showOptions.nextLoopOnFailure ?? true; const showIncludeActionHistory = showOptions.includeActionHistoryInVerification ?? false; @@ -101,7 +101,7 @@ export function BlockExecutionOptions({ )} - {showNextIterationOnFailure && isInsideForLoop && ( + {showNextLoopOnFailure && isInsideForLoop && (
{ if (!editable) { return; } - onNextIterationOnFailureChange(checked); + onNextLoopOnFailureChange(checked); }} />
diff --git a/skyvern-frontend/src/routes/workflows/editor/nodes/types.ts b/skyvern-frontend/src/routes/workflows/editor/nodes/types.ts index 143d397b..6ff3e663 100644 --- a/skyvern-frontend/src/routes/workflows/editor/nodes/types.ts +++ b/skyvern-frontend/src/routes/workflows/editor/nodes/types.ts @@ -5,7 +5,7 @@ export type NodeBaseData = { debuggable: boolean; label: string; continueOnFailure: boolean; - nextIterationOnFailure?: boolean; + nextLoopOnFailure?: boolean; editable: boolean; model: WorkflowModel | null; showCode?: boolean; diff --git a/skyvern-frontend/src/routes/workflows/editor/workflowEditorUtils.ts b/skyvern-frontend/src/routes/workflows/editor/workflowEditorUtils.ts index b216eebd..259ff1b1 100644 --- a/skyvern-frontend/src/routes/workflows/editor/workflowEditorUtils.ts +++ b/skyvern-frontend/src/routes/workflows/editor/workflowEditorUtils.ts @@ -223,7 +223,7 @@ function convertToNode( debuggable: debuggableWorkflowBlockTypes.has(block.block_type), label: block.label, continueOnFailure: block.continue_on_failure, - nextIterationOnFailure: block.next_iteration_on_failure, + nextLoopOnFailure: block.next_loop_on_failure, editable, model: block.model, }; @@ -490,7 +490,7 @@ function convertToNode( loopValue: block.loop_over?.key ?? "", loopVariableReference: loopVariableReference, completeIfEmpty: block.complete_if_empty, - nextIterationOnFailure: block.next_iteration_on_failure, + nextLoopOnFailure: block.next_loop_on_failure, }, }; } @@ -1075,7 +1075,7 @@ function getWorkflowBlock(node: WorkflowBlockNode): BlockYAML { const base = { label: node.data.label, continue_on_failure: node.data.continueOnFailure, - next_iteration_on_failure: node.data.nextIterationOnFailure, + next_loop_on_failure: node.data.nextLoopOnFailure, model: node.data.model, }; switch (node.type) { @@ -1425,7 +1425,7 @@ function getOrderedChildrenBlocks( block_type: "for_loop", label: currentNode.data.label, continue_on_failure: currentNode.data.continueOnFailure, - next_iteration_on_failure: currentNode.data.nextIterationOnFailure, + next_loop_on_failure: currentNode.data.nextLoopOnFailure, loop_blocks: loopChildren, loop_variable_reference: currentNode.data.loopVariableReference, complete_if_empty: currentNode.data.completeIfEmpty, @@ -1456,7 +1456,7 @@ function getWorkflowBlocksUtil( block_type: "for_loop", label: node.data.label, continue_on_failure: node.data.continueOnFailure, - next_iteration_on_failure: node.data.nextIterationOnFailure, + next_loop_on_failure: node.data.nextLoopOnFailure, loop_blocks: getOrderedChildrenBlocks(nodes, edges, node.id), loop_variable_reference: node.data.loopVariableReference, complete_if_empty: node.data.completeIfEmpty, @@ -1957,7 +1957,7 @@ function convertBlocksToBlockYAML( const base = { label: block.label, continue_on_failure: block.continue_on_failure, - next_iteration_on_failure: block.next_iteration_on_failure, + next_loop_on_failure: block.next_loop_on_failure, next_block_label: block.next_block_label, }; switch (block.block_type) { diff --git a/skyvern-frontend/src/routes/workflows/types/workflowTypes.ts b/skyvern-frontend/src/routes/workflows/types/workflowTypes.ts index c0e55e09..676576ce 100644 --- a/skyvern-frontend/src/routes/workflows/types/workflowTypes.ts +++ b/skyvern-frontend/src/routes/workflows/types/workflowTypes.ts @@ -287,7 +287,7 @@ export type WorkflowBlockBase = { block_type: WorkflowBlockType; output_parameter: OutputParameter; continue_on_failure: boolean; - next_iteration_on_failure?: boolean; + next_loop_on_failure?: boolean; model: WorkflowModel | null; next_block_label?: string | null; }; diff --git a/skyvern-frontend/src/routes/workflows/types/workflowYamlTypes.ts b/skyvern-frontend/src/routes/workflows/types/workflowYamlTypes.ts index 090a7780..feba5cd3 100644 --- a/skyvern-frontend/src/routes/workflows/types/workflowYamlTypes.ts +++ b/skyvern-frontend/src/routes/workflows/types/workflowYamlTypes.ts @@ -145,7 +145,7 @@ export type BlockYAMLBase = { block_type: WorkflowBlockType; label: string; continue_on_failure?: boolean; - next_iteration_on_failure?: boolean; + next_loop_on_failure?: boolean; next_block_label?: string | null; }; diff --git a/skyvern/forge/sdk/workflow/models/block.py b/skyvern/forge/sdk/workflow/models/block.py index 0ea4498e..2cb05704 100644 --- a/skyvern/forge/sdk/workflow/models/block.py +++ b/skyvern/forge/sdk/workflow/models/block.py @@ -137,7 +137,7 @@ class Block(BaseModel, abc.ABC): # Only valid for blocks inside a for loop block # Whether to continue to the next iteration when the block fails - next_iteration_on_failure: bool = False + next_loop_on_failure: bool = False @property def override_llm_key(self) -> str | None: @@ -1390,15 +1390,15 @@ class ForLoopBlock(Block): organization_id=organization_id, ) block_outputs.append(failure_block_result) - # If next_iteration_on_failure is False, stop the entire loop - if not self.next_iteration_on_failure: + # If next_loop_on_failure is False, stop the entire loop + if not self.next_loop_on_failure: outputs_with_loop_values.append(each_loop_output_values) return LoopBlockExecutedResult( outputs_with_loop_values=outputs_with_loop_values, block_outputs=block_outputs, last_block=current_block, ) - # If next_iteration_on_failure is True, break out of the block loop for this iteration + # If next_loop_on_failure is True, break out of the block loop for this iteration break if block_output.status == BlockStatus.canceled: @@ -1419,8 +1419,8 @@ class ForLoopBlock(Block): if ( not block_output.success and not loop_block.continue_on_failure - and not loop_block.next_iteration_on_failure - and not self.next_iteration_on_failure + and not loop_block.next_loop_on_failure + and not self.next_loop_on_failure ): LOG.info( f"ForLoopBlock: Encountered a failure processing block {block_idx} during loop {loop_idx}, terminating early", @@ -1430,8 +1430,7 @@ class ForLoopBlock(Block): loop_over_value=loop_over_value, loop_block_continue_on_failure=loop_block.continue_on_failure, failure_reason=block_output.failure_reason, - next_iteration_on_failure=loop_block.next_iteration_on_failure - or self.next_iteration_on_failure, + next_loop_on_failure=loop_block.next_loop_on_failure or self.next_loop_on_failure, ) outputs_with_loop_values.append(each_loop_output_values) return LoopBlockExecutedResult( @@ -1443,15 +1442,14 @@ class ForLoopBlock(Block): if block_output.success or loop_block.continue_on_failure: continue - if loop_block.next_iteration_on_failure or self.next_iteration_on_failure: + if loop_block.next_loop_on_failure or self.next_loop_on_failure: LOG.info( f"ForLoopBlock: Block {block_idx} during loop {loop_idx} failed but will continue to next iteration", block_outputs=block_outputs, loop_idx=loop_idx, block_idx=block_idx, loop_over_value=loop_over_value, - loop_block_next_iteration_on_failure=loop_block.next_iteration_on_failure - or self.next_iteration_on_failure, + loop_block_next_loop_on_failure=loop_block.next_loop_on_failure or self.next_loop_on_failure, ) break diff --git a/skyvern/forge/sdk/workflow/service.py b/skyvern/forge/sdk/workflow/service.py index 911d9bf2..7c4d766d 100644 --- a/skyvern/forge/sdk/workflow/service.py +++ b/skyvern/forge/sdk/workflow/service.py @@ -2951,7 +2951,7 @@ class WorkflowService: "next_block_label": block_yaml.next_block_label, "output_parameter": output_parameter, "continue_on_failure": block_yaml.continue_on_failure, - "next_iteration_on_failure": block_yaml.next_iteration_on_failure, + "next_loop_on_failure": block_yaml.next_loop_on_failure, "model": block_yaml.model, } diff --git a/skyvern/schemas/workflows.py b/skyvern/schemas/workflows.py index d5688868..4c2e43c4 100644 --- a/skyvern/schemas/workflows.py +++ b/skyvern/schemas/workflows.py @@ -208,7 +208,7 @@ class BlockYAML(BaseModel, abc.ABC): model: dict[str, Any] | None = None # Only valid for blocks inside a for loop block # Whether to continue to the next iteration when the block fails - next_iteration_on_failure: bool = False + next_loop_on_failure: bool = False @field_validator("label") @classmethod