Skip to content

Commit c4efb1b

Browse files
Merge branch 'main' into lsp/task-execution-context
2 parents dc6336a + 0598150 commit c4efb1b

File tree

7 files changed

+86
-17
lines changed

7 files changed

+86
-17
lines changed

codeflash/LICENSE

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Business Source License 1.1
33
Parameters
44

55
Licensor: CodeFlash Inc.
6-
Licensed Work: Codeflash Client version 0.17.x
6+
Licensed Work: Codeflash Client version 0.18.x
77
The Licensed Work is (c) 2024 CodeFlash Inc.
88

99
Additional Use Grant: None. Production use of the Licensed Work is only permitted
@@ -13,7 +13,7 @@ Additional Use Grant: None. Production use of the Licensed Work is only permitte
1313
Platform. Please visit codeflash.ai for further
1414
information.
1515

16-
Change Date: 2029-09-23
16+
Change Date: 2029-10-21
1717

1818
Change License: MIT
1919

codeflash/api/aiservice.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ def optimize_python_code( # noqa: D417
144144
logger.info("!lsp|Generating optimized candidates…")
145145
console.rule()
146146
try:
147-
response = self.make_ai_service_request("/optimize", payload=payload, timeout=600)
147+
response = self.make_ai_service_request("/optimize", payload=payload, timeout=60)
148148
except requests.exceptions.RequestException as e:
149149
logger.exception(f"Error generating optimized candidates: {e}")
150150
ph("cli-optimize-error-caught", {"error": str(e)})
@@ -209,7 +209,7 @@ def optimize_python_code_line_profiler( # noqa: D417
209209
console.rule()
210210
return []
211211
try:
212-
response = self.make_ai_service_request("/optimize-line-profiler", payload=payload, timeout=600)
212+
response = self.make_ai_service_request("/optimize-line-profiler", payload=payload, timeout=60)
213213
except requests.exceptions.RequestException as e:
214214
logger.exception(f"Error generating optimized candidates: {e}")
215215
ph("cli-optimize-error-caught", {"error": str(e)})
@@ -261,7 +261,7 @@ def optimize_python_code_refinement(self, request: list[AIServiceRefinerRequest]
261261
logger.debug(f"Refining {len(request)} optimizations…")
262262
console.rule()
263263
try:
264-
response = self.make_ai_service_request("/refinement", payload=payload, timeout=600)
264+
response = self.make_ai_service_request("/refinement", payload=payload, timeout=120)
265265
except requests.exceptions.RequestException as e:
266266
logger.exception(f"Error generating optimization refinements: {e}")
267267
ph("cli-optimize-error-caught", {"error": str(e)})
@@ -506,7 +506,7 @@ def generate_regression_tests( # noqa: D417
506506
"is_async": function_to_optimize.is_async,
507507
}
508508
try:
509-
response = self.make_ai_service_request("/testgen", payload=payload, timeout=600)
509+
response = self.make_ai_service_request("/testgen", payload=payload, timeout=90)
510510
except requests.exceptions.RequestException as e:
511511
logger.exception(f"Error generating tests: {e}")
512512
ph("cli-testgen-error-caught", {"error": str(e)})
@@ -597,7 +597,7 @@ def get_optimization_review(
597597
}
598598
console.rule()
599599
try:
600-
response = self.make_ai_service_request("/optimization_review", payload=payload, timeout=600)
600+
response = self.make_ai_service_request("/optimization_review", payload=payload, timeout=120)
601601
except requests.exceptions.RequestException as e:
602602
logger.exception(f"Error generating optimization refinements: {e}")
603603
ph("cli-optimize-error-caught", {"error": str(e)})

codeflash/api/cfapi.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@
2828

2929
if os.environ.get("CODEFLASH_CFAPI_SERVER", "prod").lower() == "local":
3030
CFAPI_BASE_URL = "http://localhost:3001"
31+
CFWEBAPP_BASE_URL = "http://localhost:3000"
3132
logger.info(f"Using local CF API at {CFAPI_BASE_URL}.")
3233
console.rule()
3334
else:
3435
CFAPI_BASE_URL = "https://app.codeflash.ai"
36+
CFWEBAPP_BASE_URL = "https://app.codeflash.ai"
3537

3638

3739
def make_cfapi_request(
@@ -156,7 +158,7 @@ def suggest_changes(
156158
"coverage_message": coverage_message,
157159
"replayTests": replay_tests,
158160
"concolicTests": concolic_tests,
159-
"optimizationImpact": optimization_review, # impact keyword left for legacy reasons, touches js/ts code
161+
"optimizationReview": optimization_review, # impact keyword left for legacy reasons, touches js/ts code
160162
}
161163
return make_cfapi_request(endpoint="/suggest-pr-changes", method="POST", payload=payload)
162164

@@ -198,7 +200,7 @@ def create_pr(
198200
"coverage_message": coverage_message,
199201
"replayTests": replay_tests,
200202
"concolicTests": concolic_tests,
201-
"optimizationImpact": optimization_review, # Impact keyword left for legacy reasons, it touches js/ts codebase
203+
"optimizationReview": optimization_review, # Impact keyword left for legacy reasons, it touches js/ts codebase
202204
}
203205
return make_cfapi_request(endpoint="/create-pr", method="POST", payload=payload)
204206

@@ -255,7 +257,7 @@ def create_staging(
255257
"coverage_message": coverage_message,
256258
"replayTests": replay_tests,
257259
"concolicTests": concolic_tests,
258-
"optimizationImpact": optimization_review, # Impact keyword left for legacy reasons, it touches js/ts codebase
260+
"optimizationReview": optimization_review, # Impact keyword left for legacy reasons, it touches js/ts codebase
259261
}
260262

261263
return make_cfapi_request(endpoint="/create-staging", method="POST", payload=payload)

codeflash/context/unused_definition_remover.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,7 @@ def detect_unused_helper_functions(
679679
imported_names_map = _analyze_imports_in_optimized_code(optimized_ast, code_context)
680680

681681
# Extract all function calls in the entrypoint function
682-
called_function_names = set()
682+
called_function_names = {function_to_optimize.function_name}
683683
for node in ast.walk(entrypoint_function_ast):
684684
if isinstance(node, ast.Call):
685685
if isinstance(node.func, ast.Name):

codeflash/optimization/function_optimizer.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from rich.tree import Tree
2020

2121
from codeflash.api.aiservice import AiServiceClient, AIServiceRefinerRequest, LocalAiServiceClient
22-
from codeflash.api.cfapi import CFAPI_BASE_URL, add_code_context_hash, create_staging, mark_optimization_success
22+
from codeflash.api.cfapi import CFWEBAPP_BASE_URL, add_code_context_hash, create_staging, mark_optimization_success
2323
from codeflash.benchmarking.utils import process_benchmark_data
2424
from codeflash.cli_cmds.console import code_print, console, logger, lsp_log, progress_bar
2525
from codeflash.code_utils import env_utils
@@ -1458,7 +1458,7 @@ def process_review(
14581458

14591459
raise_pr = not self.args.no_pr
14601460
staging_review = self.args.staging_review
1461-
1461+
opt_review_response = ""
14621462
if raise_pr or staging_review:
14631463
data["root_dir"] = git_root_dir()
14641464
calling_fn_details = get_opt_review_metrics(
@@ -1468,21 +1468,21 @@ def process_review(
14681468
self.project_root,
14691469
self.test_cfg.tests_root,
14701470
)
1471-
opt_review_response = ""
14721471
try:
14731472
opt_review_response = self.aiservice_client.get_optimization_review(
14741473
**data, calling_fn_details=calling_fn_details
14751474
)
14761475
except Exception as e:
14771476
logger.debug(f"optimization review response failed, investigate {e}")
14781477
data["optimization_review"] = opt_review_response
1479-
if raise_pr and not staging_review:
1478+
if raise_pr and not staging_review and opt_review_response != "low":
14801479
data["git_remote"] = self.args.git_remote
14811480
check_create_pr(**data)
14821481
elif staging_review:
14831482
response = create_staging(**data)
14841483
if response.status_code == 200:
1485-
staging_url = f"{CFAPI_BASE_URL}/review-optimizations/{self.function_trace_id[:-4] + exp_type if self.experiment_id else self.function_trace_id}"
1484+
trace_id = self.function_trace_id[:-4] + exp_type if self.experiment_id else self.function_trace_id
1485+
staging_url = f"{CFWEBAPP_BASE_URL}/review-optimizations/{trace_id}"
14861486
console.print(
14871487
Panel(
14881488
f"[bold green]✅ Staging created:[/bold green]\n[link={staging_url}]{staging_url}[/link]",

codeflash/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# These version placeholders will be replaced by uv-dynamic-versioning during build.
2-
__version__ = "0.17.3"
2+
__version__ = "0.18.1"

tests/test_unused_helper_revert.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1959,6 +1959,73 @@ async def async_entrypoint(n):
19591959
shutil.rmtree(temp_dir, ignore_errors=True)
19601960

19611961

1962+
def test_recursive_helper_function_not_detected_as_unused():
1963+
"""Test that recursive helper functions are NOT incorrectly detected as unused."""
1964+
temp_dir = Path(tempfile.mkdtemp())
1965+
1966+
try:
1967+
# Main file with recursive helper function
1968+
main_file = temp_dir / "main.py"
1969+
main_file.write_text("""
1970+
def gcd_recursive(a: int, b: int) -> int:
1971+
\"\"\"Calculate greatest common divisor using Euclidean algorithm with recursion.\"\"\"
1972+
if b == 0:
1973+
return a
1974+
return gcd_recursive(b, a % b)
1975+
""")
1976+
1977+
# Optimized version that still uses the recursive helper
1978+
optimized_code = """
1979+
```python:main.py
1980+
def gcd_recursive(a: int, b: int) -> int:
1981+
\"\"\"Calculate greatest common divisor using Euclidean algorithm with recursion.\"\"\"
1982+
if b == 0:
1983+
return a
1984+
return gcd_recursive(b, a % b)
1985+
```
1986+
"""
1987+
1988+
# Create test config
1989+
test_cfg = TestConfig(
1990+
tests_root=temp_dir / "tests",
1991+
tests_project_rootdir=temp_dir,
1992+
project_root_path=temp_dir,
1993+
test_framework="pytest",
1994+
pytest_cmd="pytest",
1995+
)
1996+
1997+
# Create FunctionToOptimize instance
1998+
function_to_optimize = FunctionToOptimize(
1999+
file_path=main_file, function_name="gcd_recursive", parents=[]
2000+
)
2001+
2002+
# Create function optimizer
2003+
optimizer = FunctionOptimizer(
2004+
function_to_optimize=function_to_optimize,
2005+
test_cfg=test_cfg,
2006+
function_to_optimize_source_code=main_file.read_text(),
2007+
)
2008+
2009+
# Get original code context
2010+
ctx_result = optimizer.get_code_optimization_context()
2011+
assert ctx_result.is_successful(), f"Failed to get context: {ctx_result.failure()}"
2012+
2013+
code_context = ctx_result.unwrap()
2014+
2015+
# Test unused helper detection
2016+
unused_helpers = detect_unused_helper_functions(optimizer.function_to_optimize, code_context, CodeStringsMarkdown.parse_markdown_code(optimized_code))
2017+
2018+
# Should NOT detect gcd_recursive as unused
2019+
unused_names = {uh.qualified_name for uh in unused_helpers}
2020+
2021+
assert "gcd_recursive" not in unused_names, f"Recursive function gcd_recursive should NOT be detected as unused, but got unused: {unused_names}"
2022+
2023+
finally:
2024+
# Cleanup
2025+
import shutil
2026+
shutil.rmtree(temp_dir, ignore_errors=True)
2027+
2028+
19622029
def test_async_generators_and_coroutines():
19632030
"""Test detection with async generators and coroutines."""
19642031
temp_dir = Path(tempfile.mkdtemp())

0 commit comments

Comments
 (0)