diff --git a/runner/arazzo_runner/executor/action_handler.py b/runner/arazzo_runner/executor/action_handler.py index e3f6cdc..6af4d48 100644 --- a/runner/arazzo_runner/executor/action_handler.py +++ b/runner/arazzo_runner/executor/action_handler.py @@ -30,7 +30,7 @@ def __init__(self, source_descriptions: dict[str, Any]): """ self.source_descriptions = source_descriptions - def determine_next_action(self, step: dict, success: bool, state: ExecutionState) -> dict: + def determine_next_action(self, step: dict, success: bool, state: ExecutionState, response: dict | None = None) -> dict: """ Determine the next action based on step success/failure @@ -38,6 +38,7 @@ def determine_next_action(self, step: dict, success: bool, state: ExecutionState step: Step definition success: Whether the step succeeded state: Current execution state + response: HTTP response from the step execution (used to evaluate $statusCode criteria) Returns: Dictionary with action type and parameters @@ -59,7 +60,7 @@ def determine_next_action(self, step: dict, success: bool, state: ExecutionState if "criteria" in action: criteria = action.get("criteria", []) logger.info(f"Action {action_name} has {len(criteria)} criteria") - criteria_met = self._check_action_criteria(criteria, state) + criteria_met = self._check_action_criteria(criteria, state, response) if not criteria_met: logger.info(f"Action {action_name} criteria not met, skipping") @@ -99,7 +100,7 @@ def determine_next_action(self, step: dict, success: bool, state: ExecutionState if "criteria" in action: criteria = action.get("criteria", []) logger.info(f"Failure action {action_name} has {len(criteria)} criteria") - criteria_met = self._check_action_criteria(criteria, state) + criteria_met = self._check_action_criteria(criteria, state, response) if not criteria_met: logger.info(f"Failure action {action_name} criteria not met, skipping") @@ -151,21 +152,24 @@ def determine_next_action(self, step: dict, success: bool, state: ExecutionState ) return {"type": ActionType.END} - def _check_action_criteria(self, criteria: list[dict], state: ExecutionState) -> bool: + def _check_action_criteria(self, criteria: list[dict], state: ExecutionState, response: dict | None = None) -> bool: """ Check if action criteria are met Args: criteria: List of criteria to check state: Current execution state + response: HTTP response from the step execution (provides $statusCode and $response) Returns: True if all criteria are met, False otherwise """ logger.info(f"Checking {len(criteria)} action criteria") - # Context for evaluating criteria - context = {} + # Build evaluation context — populate statusCode and response from the step response + # so that conditions like "$statusCode == 200" and "$response.body#/..." resolve correctly. + status_code = response.get("status_code") if response else None + context = {"statusCode": status_code, "response": response} if response is not None else {} # Check each criterion for i, criterion in enumerate(criteria): @@ -192,7 +196,7 @@ def _check_action_criteria(self, criteria: list[dict], state: ExecutionState) -> # Check criterion based on type if criterion_type == "simple": result = ExpressionEvaluator.evaluate_simple_condition( - condition, state, self.source_descriptions, context + condition, state, self.source_descriptions, local_context ) if not result: logger.warning(f"Simple condition failed: {condition}") diff --git a/runner/arazzo_runner/executor/step_executor.py b/runner/arazzo_runner/executor/step_executor.py index 30571ef..e7f6d31 100644 --- a/runner/arazzo_runner/executor/step_executor.py +++ b/runner/arazzo_runner/executor/step_executor.py @@ -261,14 +261,20 @@ def _execute_nested_workflow(self, step: dict, state: ExecutionState) -> dict: """ raise NotImplementedError("Nested workflow execution is handled by the runner") - def determine_next_action(self, step: dict, success: bool, state: ExecutionState) -> dict: + def determine_next_action(self, step: dict, success: bool, state: ExecutionState, response: dict | None = None) -> dict: """ Determine the next action based on step success/failure + Args: + step: Step definition + success: Whether the step succeeded + state: Current execution state + response: HTTP response from the step execution (used to evaluate $statusCode and $response criteria) + Returns: action: Dictionary with action type and parameters """ - return self.action_handler.determine_next_action(step, success, state) + return self.action_handler.determine_next_action(step, success, state, response) def execute_operation( self, diff --git a/runner/arazzo_runner/runner.py b/runner/arazzo_runner/runner.py index 6a186d5..dd6ff8c 100644 --- a/runner/arazzo_runner/runner.py +++ b/runner/arazzo_runner/runner.py @@ -503,7 +503,9 @@ def execute_next_step(self, execution_id: str) -> dict[str, Any]: state.workflow_outputs[output_name] = value # Determine next action - next_action = self.step_executor.determine_next_action(next_step, success, state) + next_action = self.step_executor.determine_next_action( + next_step, success, state, step_result.get("response") + ) # Trigger step_complete event self._trigger_event(