Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion codeflash/languages/function_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
195 changes: 195 additions & 0 deletions tests/test_languages/test_adaptive_optimize_language_bug.py
Original file line number Diff line number Diff line change
@@ -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"])
Loading