Skip to content

Commit 3ac68eb

Browse files
Merge branch 'main' of github.com:codeflash-ai/codeflash into lsp/demo-optimization
2 parents beef54e + 73b5539 commit 3ac68eb

File tree

6 files changed

+53
-21
lines changed

6 files changed

+53
-21
lines changed

codeflash/api/cfapi.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Module for interacting with the Codeflash API."""
2+
13
from __future__ import annotations
24

35
import json
@@ -14,6 +16,7 @@
1416
from pydantic.json import pydantic_encoder
1517

1618
from codeflash.cli_cmds.console import console, logger
19+
from codeflash.code_utils.code_utils import exit_with_message
1720
from codeflash.code_utils.env_utils import ensure_codeflash_api_key, get_codeflash_api_key, get_pr_number
1821
from codeflash.code_utils.git_utils import get_current_branch, get_repo_owner_and_name
1922
from codeflash.github.PrComment import FileDiffContent, PrComment
@@ -101,13 +104,18 @@ def make_cfapi_request(
101104
def get_user_id(api_key: Optional[str] = None) -> Optional[str]:
102105
"""Retrieve the user's userid by making a request to the /cfapi/cli-get-user endpoint.
103106
107+
:param api_key: The API key to use. If None, uses get_codeflash_api_key().
104108
:return: The userid or None if the request fails.
105109
"""
106110
if not api_key and not ensure_codeflash_api_key():
107111
return None
108112

109113
response = make_cfapi_request(
110-
endpoint="/cli-get-user", method="GET", extra_headers={"cli_version": __version__}, api_key=api_key
114+
endpoint="/cli-get-user",
115+
method="GET",
116+
extra_headers={"cli_version": __version__},
117+
api_key=api_key,
118+
suppress_errors=True,
111119
)
112120
if response.status_code == 200:
113121
if "min_version" not in response.text:
@@ -128,6 +136,20 @@ def get_user_id(api_key: Optional[str] = None) -> Optional[str]:
128136
logger.error("Failed to retrieve userid from the response.")
129137
return None
130138

139+
# Handle 403 (Invalid API key) - exit with error message
140+
if response.status_code == 403:
141+
msg = (
142+
"Invalid Codeflash API key. The API key you provided is not valid.\n"
143+
"Please generate a new one at https://app.codeflash.ai/app/apikeys ,\n"
144+
"then set it as a CODEFLASH_API_KEY environment variable.\n"
145+
"For more information, refer to the documentation at \n"
146+
"https://docs.codeflash.ai/optimizing-with-codeflash/codeflash-github-actions#manual-setup\n"
147+
"or\n"
148+
"https://docs.codeflash.ai/optimizing-with-codeflash/codeflash-github-actions#automated-setup-recommended"
149+
)
150+
exit_with_message(msg, error_on_exit=True)
151+
152+
# For other errors, log and return None (backward compatibility)
131153
logger.error(f"Failed to look up your userid; is your CF API key valid? ({response.reason})")
132154
return None
133155

codeflash/code_utils/github_utils.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from codeflash.api.cfapi import is_github_app_installed_on_repo
66
from codeflash.cli_cmds.cli_common import apologize_and_exit
7-
from codeflash.cli_cmds.console import logger
7+
from codeflash.cli_cmds.console import paneled_text
88
from codeflash.code_utils.compat import LF
99
from codeflash.code_utils.git_utils import get_repo_owner_and_name
1010

@@ -18,15 +18,20 @@ def get_github_secrets_page_url(repo: Optional[Repo] = None) -> str:
1818

1919

2020
def require_github_app_or_exit(owner: str, repo: str) -> None:
21-
if not is_github_app_installed_on_repo(owner, repo):
22-
logger.error(
23-
f"It looks like the Codeflash GitHub App is not installed on the repository {owner}/{repo} or the GitHub"
24-
f" account linked to your CODEFLASH_API_KEY does not have access to the repository {owner}/{repo}.{LF}"
25-
"Before continuing, please install the Codeflash GitHub App on your repository by visiting "
26-
f"https://github.com/apps/codeflash-ai/installations/select_target{LF}"
21+
# Suppress low-level HTTP error logging to avoid duplicate logs; we present a friendly panel instead
22+
if not is_github_app_installed_on_repo(owner, repo, suppress_errors=True):
23+
# Show a clear, user-friendly panel instead of raw error logs
24+
message = (
25+
f"It looks like the Codeflash GitHub App is not installed on the repository {owner}/{repo} "
26+
f"or the GitHub account linked to your CODEFLASH_API_KEY does not have access to the repository {owner}/{repo}.{LF}{LF}"
27+
"To continue, install the Codeflash GitHub App on your repository:"
28+
f"{LF}https://github.com/apps/codeflash-ai/installations/select_target{LF}{LF}"
29+
"Tip: If you want to find optimizations without opening PRs, run Codeflash with the --no-pr flag."
2730
)
28-
logger.error(
29-
f"Note: if you want to find optimizations without opening PRs, you can run Codeflash with the --no-pr flag.{LF}"
31+
paneled_text(
32+
message,
33+
panel_args={"title": "GitHub App Required", "border_style": "red", "expand": False},
34+
text_args={"style": "bold red"},
3035
)
3136
apologize_and_exit()
3237

codeflash/lsp/beta.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
get_functions_within_git_diff,
3232
)
3333
from codeflash.either import is_successful
34+
from codeflash.lsp.context import execution_context_vars
3435
from codeflash.lsp.features.perform_optimization import get_cancelled_reponse, sync_perform_optimization
3536
from codeflash.lsp.server import CodeflashLanguageServer, CodeflashLanguageServerProtocol
3637

@@ -341,12 +342,12 @@ def provide_api_key(params: ProvideApiKeyParams) -> dict[str, str]:
341342
def execution_context(**kwargs: str) -> None:
342343
"""Temporarily set context values for the current async task."""
343344
# Create a fresh copy per use
344-
current = {**server.execution_context_vars.get(), **kwargs}
345-
token = server.execution_context_vars.set(current)
345+
current = {**execution_context_vars.get(), **kwargs}
346+
token = execution_context_vars.set(current)
346347
try:
347348
yield
348349
finally:
349-
server.execution_context_vars.reset(token)
350+
execution_context_vars.reset(token)
350351

351352

352353
@server.feature("cleanupCurrentOptimizerSession")

codeflash/lsp/context.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from __future__ import annotations
2+
3+
import contextvars
4+
5+
# Shared execution context for tracking task IDs and other metadata
6+
execution_context_vars: contextvars.ContextVar[dict[str, str]] = contextvars.ContextVar(
7+
"execution_context_vars",
8+
default={}, # noqa: B039
9+
)

codeflash/lsp/lsp_message.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ def type(self) -> str:
4444
def serialize(self) -> str:
4545
if not is_LSP_enabled():
4646
return ""
47-
from codeflash.lsp.beta import server
47+
from codeflash.lsp.context import execution_context_vars
4848

49-
execution_ctx = server.execution_context_vars.get()
49+
execution_ctx = execution_context_vars.get()
5050
current_task_id = execution_ctx.get("task_id", None)
5151
data = self._loop_through(asdict(self))
5252
ordered = {"type": self.type(), "task_id": current_task_id, **data}

codeflash/lsp/server.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from __future__ import annotations
22

3-
import contextvars
43
from pathlib import Path
54
from typing import TYPE_CHECKING
65

@@ -29,11 +28,7 @@ def __init__(self, name: str, version: str, protocol_cls: type[LanguageServerPro
2928
self.initialized: bool = False
3029
self.optimizer: Optimizer | None = None
3130
self.args = None
32-
self.current_optimization_init_result: InitializationResultT | None = None
33-
self.execution_context_vars: contextvars.ContextVar[dict[str, str]] = contextvars.ContextVar(
34-
"execution_context_vars",
35-
default={}, # noqa: B039
36-
)
31+
self.current_optimization_init_result: tuple[bool, CodeOptimizationContext, dict[Path, str]] | None = None
3732

3833
def prepare_optimizer_arguments(self, config_file: Path) -> None:
3934
from codeflash.cli_cmds.cli import parse_args

0 commit comments

Comments
 (0)