diff --git a/api/core/helper/code_executor/javascript/javascript_transformer.py b/api/core/helper/code_executor/javascript/javascript_transformer.py index 62489cdf29..439608bebd 100644 --- a/api/core/helper/code_executor/javascript/javascript_transformer.py +++ b/api/core/helper/code_executor/javascript/javascript_transformer.py @@ -11,16 +11,57 @@ class NodeJsTemplateTransformer(TemplateTransformer): // declare main function {cls._code_placeholder} - // decode and prepare input object - var inputs_obj = JSON.parse(Buffer.from('{cls._inputs_placeholder}', 'base64').toString('utf-8')) + try {{ + // decode and prepare input object + var inputs_obj = JSON.parse(Buffer.from('{cls._inputs_placeholder}', 'base64').toString('utf-8')) - // execute main function - var output_obj = main(inputs_obj) + // Preprocess inputs to handle number precision issues + function preprocessInputs(obj) {{ + if (typeof obj === 'object' && obj !== null) {{ + for (var key in obj) {{ + if (obj.hasOwnProperty(key)) {{ + if (typeof obj[key] === 'string') {{ + // Try to parse string as number if it looks like a number + var num = parseFloat(obj[key]); + if (!isNaN(num) && obj[key].trim() === num.toString()) {{ + obj[key] = num; + }} + }} else if (typeof obj[key] === 'object') {{ + preprocessInputs(obj[key]); + }} + }} + }} + }} + return obj; + }} + + // Preprocess inputs + inputs_obj = preprocessInputs(inputs_obj); - // convert output to json and print - var output_json = JSON.stringify(output_obj) - var result = `<>${{output_json}}<>` - console.log(result) + // execute main function + var output_obj = main(inputs_obj) + + // Handle precision numbers properly in JSON.stringify + var output_json = JSON.stringify(output_obj, function(key, value) {{ + // Ensure numbers are properly serialized + if (typeof value === 'number') {{ + // Handle very small numbers that might cause precision issues + if (Math.abs(value) < 1e-1 && Math.abs(value) > 0) {{ + // Convert to string to preserve precision + return value.toString(); + }} + }} + return value; + }}) + + var result = `<>${{output_json}}<>` + console.log(result) + }} catch (error) {{ + console.error('JavaScript execution error:', error.message) + // Provide more detailed error information + var errorResult = `<>{{"error": "JavaScript execution failed: " + error.message}}<>` + console.log(errorResult) + }} """ ) - return runner_script + return runner_script \ No newline at end of file diff --git a/api/core/helper/code_executor/template_transformer.py b/api/core/helper/code_executor/template_transformer.py index baa792b5bc..f6e9c8a3e8 100644 --- a/api/core/helper/code_executor/template_transformer.py +++ b/api/core/helper/code_executor/template_transformer.py @@ -28,7 +28,7 @@ class TemplateTransformer(ABC): def extract_result_str_from_response(cls, response: str): result = re.search(rf"{cls._result_tag}(.*){cls._result_tag}", response, re.DOTALL) if not result: - raise ValueError("Failed to parse result") + raise ValueError(f"Failed to parse result: no result tag found in response. Response: {response[:200]}...") return result.group(1) @classmethod @@ -39,13 +39,24 @@ class TemplateTransformer(ABC): :return: """ try: - result = json.loads(cls.extract_result_str_from_response(response)) - except json.JSONDecodeError: - raise ValueError("failed to parse response") + result_str = cls.extract_result_str_from_response(response) + result = json.loads(result_str) + except json.JSONDecodeError as e: + raise ValueError(f"Failed to parse JSON response: {str(e)}. Response content: {result_str[:200]}...") + except ValueError as e: + # Re-raise ValueError from extract_result_str_from_response + raise e + except Exception as e: + raise ValueError(f"Unexpected error during response transformation: {str(e)}") + + # Check if the result contains an error + if isinstance(result, dict) and "error" in result: + raise ValueError(f"JavaScript execution error: {result['error']}") + if not isinstance(result, dict): - raise ValueError("result must be a dict") + raise ValueError(f"Result must be a dict, got {type(result).__name__}") if not all(isinstance(k, str) for k in result): - raise ValueError("result keys must be strings") + raise ValueError("Result keys must be strings") return result @classmethod