Skip to content
Merged
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
14 changes: 9 additions & 5 deletions codeflash/api/aiservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from codeflash.models.models import (
AIServiceRefinerRequest,
CodeStringsMarkdown,
OptimizationReviewResult,
OptimizedCandidate,
OptimizedCandidateSource,
)
Expand Down Expand Up @@ -652,7 +653,7 @@ def get_optimization_review(
replay_tests: str,
concolic_tests: str, # noqa: ARG002
calling_fn_details: str,
) -> str:
) -> OptimizationReviewResult:
"""Compute the optimization review of current Pull Request.

Args:
Expand All @@ -670,7 +671,7 @@ def get_optimization_review(

Returns:
-------
- 'high', 'medium' or 'low' optimization review
OptimizationReviewResult with review ('high', 'medium', 'low', or '') and explanation

"""
diff_str = "\n".join(
Expand Down Expand Up @@ -706,18 +707,21 @@ def get_optimization_review(
except requests.exceptions.RequestException as e:
logger.exception(f"Error generating optimization refinements: {e}")
ph("cli-optimize-error-caught", {"error": str(e)})
return ""
return OptimizationReviewResult(review="", explanation="")

if response.status_code == 200:
return cast("str", response.json()["review"])
data = response.json()
return OptimizationReviewResult(
review=cast("str", data["review"]), explanation=cast("str", data.get("review_explanation", ""))
)
try:
error = cast("str", response.json()["error"])
except Exception:
error = response.text
logger.error(f"Error generating optimization review: {response.status_code} - {error}")
ph("cli-optimize-error-response", {"response_status_code": response.status_code, "error": error})
console.rule()
return ""
return OptimizationReviewResult(review="", explanation="")

def generate_workflow_steps(
self,
Expand Down
9 changes: 8 additions & 1 deletion codeflash/models/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from enum import Enum, IntEnum
from pathlib import Path
from re import Pattern
from typing import Annotated, Optional, cast
from typing import Annotated, NamedTuple, Optional, cast

from jedi.api.classes import Name
from pydantic import AfterValidator, BaseModel, ConfigDict, Field, PrivateAttr, ValidationError
Expand Down Expand Up @@ -95,6 +95,13 @@ class AIServiceCodeRepairRequest:
test_diffs: list[TestDiff]


class OptimizationReviewResult(NamedTuple):
"""Result from the optimization review API."""

review: str # "high", "medium", "low", or ""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

datatype could be Literal -> https://peps.python.org/pep-0586/

explanation: str


# If the method spam is in the class Ham, which is at the top level of the module eggs in the package foo, the fully
# qualified name of the method is foo.eggs.Ham.spam, its qualified name is Ham.spam, and its name is spam. The full name
# of the module is foo.eggs.
Expand Down
32 changes: 27 additions & 5 deletions codeflash/optimization/function_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
CodeOptimizationContext,
GeneratedTests,
GeneratedTestsList,
OptimizationReviewResult,
OptimizationSet,
OptimizedCandidate,
OptimizedCandidateResult,
Expand Down Expand Up @@ -1840,19 +1841,40 @@ def process_review(

raise_pr = not self.args.no_pr
staging_review = self.args.staging_review
opt_review_response = ""
opt_review_result = OptimizationReviewResult(review="", explanation="")
# this will now run regardless of pr, staging review flags
try:
opt_review_response = self.aiservice_client.get_optimization_review(
opt_review_result = self.aiservice_client.get_optimization_review(
**data, calling_fn_details=function_references
)
except Exception as e:
logger.debug(f"optimization review response failed, investigate {e}")
data["optimization_review"] = opt_review_response
self.optimization_review = opt_review_response
data["optimization_review"] = opt_review_result.review
self.optimization_review = opt_review_result.review

# Display the reviewer result to the user
if opt_review_result.review:
review_display = {
"high": ("[bold green]High[/bold green]", "green", "Recommended to merge"),
"medium": ("[bold yellow]Medium[/bold yellow]", "yellow", "Review recommended before merging"),
"low": ("[bold red]Low[/bold red]", "red", "Not recommended to merge"),
}
display_info = review_display.get(opt_review_result.review.lower(), ("[bold]Unknown[/bold]", "white", ""))
explanation_text = opt_review_result.explanation.strip() if opt_review_result.explanation else ""
if is_LSP_enabled():
md_content = f"### Reviewer Assessment: {opt_review_result.review.capitalize()}\n{display_info[2]}"
if explanation_text:
md_content += f"\n\n{explanation_text}"
lsp_log(LspMarkdownMessage(markdown=md_content))
else:
panel_content = f"Reviewer Assessment: {display_info[0]}\n{display_info[2]}"
if explanation_text:
panel_content += f"\n\n[dim]{explanation_text}[/dim]"
console.print(Panel(panel_content, title="Optimization Review", border_style=display_info[1]))

if raise_pr or staging_review:
data["root_dir"] = git_root_dir()
if raise_pr and not staging_review and opt_review_response != "low":
if raise_pr and not staging_review and opt_review_result.review != "low":
# Ensure root_dir is set for PR creation (needed for async functions that skip opt_review)
if "root_dir" not in data:
data["root_dir"] = git_root_dir()
Expand Down
Loading