diff --git a/codeflash/languages/function_optimizer.py b/codeflash/languages/function_optimizer.py index b348a6e46..1d21a7383 100644 --- a/codeflash/languages/function_optimizer.py +++ b/codeflash/languages/function_optimizer.py @@ -1263,7 +1263,9 @@ def process_single_candidate( aiservice_client = self.aiservice_client if exp_type == "EXP0" else self.local_aiservice_client - if is_candidate_refined_before: + # adaptive_optimize is Python-only (uses libcst for AST parsing) + # For JavaScript/TypeScript, continue using optimize_code_refinement + if is_candidate_refined_before and self.function_to_optimize.language == "python": future_adaptive_optimization = self.call_adaptive_optimize( trace_id=self.get_trace_id(exp_type), original_source_code=code_context.read_writable_code.markdown, diff --git a/tests/test_languages/test_adaptive_optimize_language_bug.py b/tests/test_languages/test_adaptive_optimize_language_bug.py new file mode 100644 index 000000000..170fc5e3f --- /dev/null +++ b/tests/test_languages/test_adaptive_optimize_language_bug.py @@ -0,0 +1,195 @@ +""" +Test for Issue #8: CLI incorrectly calls adaptive_optimize for JavaScript/TypeScript + +Bug: When a refined candidate (source=REFINE) succeeds for JS/TS, the next iteration +calls adaptive_optimize (Python-only) instead of optimize_code_refinement (all languages). + +This results in "422 - Invalid code generated" from the AI service because adaptive_optimize +tries to parse JS/TS code using libcst (Python AST parser). + +Trace ID: 1417a6da-796c-4a38-8c44-00401dbab6c7 +Function: formatBytes (TypeScript) +""" + +import pytest +from unittest.mock import Mock, MagicMock, patch +from pathlib import Path +from concurrent.futures import ThreadPoolExecutor + +from codeflash.models.models import OptimizedCandidateSource +from codeflash.models.function_types import FunctionToOptimize +from codeflash.languages.function_optimizer import FunctionOptimizer + + +def test_should_not_call_adaptive_optimize_for_javascript(): + """Verify adaptive_optimize is NOT called for JavaScript when REFINE candidate exists""" + + # Setup: JavaScript function + function_to_optimize = FunctionToOptimize( + function_name="formatBytes", + file_path=Path("src/helpers.js"), + starting_line=1, + language="javascript" + ) + + # Mock FunctionOptimizer + optimizer = Mock(spec=FunctionOptimizer) + optimizer.function_to_optimize = function_to_optimize + optimizer.executor = ThreadPoolExecutor(max_workers=1) + optimizer.aiservice_client = Mock() + optimizer.local_aiservice_client = Mock() + + # Simulate a REFINE candidate in the tree + refined_candidate = Mock() + refined_candidate.source = OptimizedCandidateSource.REFINE + + candidate_node = Mock() + candidate_node.path_to_root.return_value = [refined_candidate] + + # The bug check: is_candidate_refined_before + current_tree_candidates = candidate_node.path_to_root() + is_candidate_refined_before = any( + c.source == OptimizedCandidateSource.REFINE for c in current_tree_candidates + ) + + assert is_candidate_refined_before, "Test setup: REFINE candidate should exist" + + # Current buggy behavior (lines 1266-1275 in function_optimizer.py): + # if is_candidate_refined_before: + # call_adaptive_optimize() # BUG: Called for JS/TS! + + # Expected: Should NOT call adaptive_optimize for JavaScript + # Should call optimize_code_refinement instead + + # We can't directly test the buggy code path without mocking the entire + # handle_successful_candidate flow, but we can verify the language check logic + + # Fixed logic: Check language before calling adaptive_optimize + should_use_adaptive = ( + is_candidate_refined_before + and function_to_optimize.language == "python" + ) + + assert not should_use_adaptive, ( + "JavaScript should NOT trigger adaptive_optimize call. " + "adaptive_optimize is Python-only and will return 422 error for JS/TS." + ) + + optimizer.executor.shutdown(wait=False) + + +def test_should_call_adaptive_optimize_for_python(): + """Verify adaptive_optimize IS called for Python when REFINE candidate exists""" + + # Setup: Python function + function_to_optimize = FunctionToOptimize( + function_name="calculate_sum", + file_path=Path("src/utils.py"), + starting_line=1, + language="python" + ) + + # Simulate a REFINE candidate + refined_candidate = Mock() + refined_candidate.source = OptimizedCandidateSource.REFINE + + candidate_node = Mock() + candidate_node.path_to_root.return_value = [refined_candidate] + + current_tree_candidates = candidate_node.path_to_root() + is_candidate_refined_before = any( + c.source == OptimizedCandidateSource.REFINE for c in current_tree_candidates + ) + + assert is_candidate_refined_before, "Test setup: REFINE candidate should exist" + + # Fixed logic: Python should use adaptive_optimize + should_use_adaptive = ( + is_candidate_refined_before + and function_to_optimize.language == "python" + ) + + assert should_use_adaptive, ( + "Python SHOULD trigger adaptive_optimize call after REFINE candidate succeeds" + ) + + +def test_should_not_call_adaptive_optimize_for_typescript(): + """Verify adaptive_optimize is NOT called for TypeScript when REFINE candidate exists""" + + # Setup: TypeScript function (this was the original bug scenario) + function_to_optimize = FunctionToOptimize( + function_name="formatBytes", + file_path=Path("packages/shared-core/src/helpers/readableHelpers.ts"), + starting_line=1, + language="javascript" # TypeScript uses "javascript" language string + ) + + # Simulate a REFINE candidate + refined_candidate = Mock() + refined_candidate.source = OptimizedCandidateSource.REFINE + + candidate_node = Mock() + candidate_node.path_to_root.return_value = [refined_candidate] + + current_tree_candidates = candidate_node.path_to_root() + is_candidate_refined_before = any( + c.source == OptimizedCandidateSource.REFINE for c in current_tree_candidates + ) + + assert is_candidate_refined_before, "Test setup: REFINE candidate should exist" + + # Fixed logic: TypeScript should NOT use adaptive_optimize + should_use_adaptive = ( + is_candidate_refined_before + and function_to_optimize.language == "python" + ) + + assert not should_use_adaptive, ( + "TypeScript should NOT trigger adaptive_optimize call. " + "This caused trace 1417a6da-796c-4a38-8c44-00401dbab6c7 to fail with " + "'422 - Invalid code generated'" + ) + + +def test_should_use_refinement_when_no_refine_candidate(): + """Verify optimize_code_refinement is used when no REFINE candidate exists yet""" + + # Setup: Any language (JS/TS/Python) + for language in ["javascript", "python"]: + function_to_optimize = FunctionToOptimize( + function_name="test_func", + file_path=Path(f"src/test.{{'javascript': 'js', 'python': 'py'}}[language]"), + starting_line=1, + language=language + ) + + # No REFINE candidate yet - this is the first iteration + optimize_candidate = Mock() + optimize_candidate.source = OptimizedCandidateSource.OPTIMIZE + + candidate_node = Mock() + candidate_node.path_to_root.return_value = [optimize_candidate] + + current_tree_candidates = candidate_node.path_to_root() + is_candidate_refined_before = any( + c.source == OptimizedCandidateSource.REFINE for c in current_tree_candidates + ) + + assert not is_candidate_refined_before, "Test setup: No REFINE candidate" + + # Both paths should use optimize_code_refinement on first iteration + # (line 1277-1300 in function_optimizer.py) + should_use_adaptive = ( + is_candidate_refined_before + and function_to_optimize.language == "python" + ) + + assert not should_use_adaptive, ( + f"First iteration for {language} should use optimize_code_refinement, " + "not adaptive_optimize" + ) + + +if __name__ == "__main__": + pytest.main([__file__, "-v"])