Skip to content

Conversation

@mohammedahmed18
Copy link
Contributor

@mohammedahmed18 mohammedahmed18 commented Nov 4, 2025

PR Type

Enhancement, Bug fix


Description

  • Avoid exiting in LSP flows

  • Improve API key sourcing for LSP

  • Add LSP feature listing endpoint

  • Refactor version/API-key error handling


Diagram Walkthrough

flowchart LR A["LSP helpers (is_LSP_enabled)"] -- "influences" --> B["exit_with_message behavior"] A -- "selects" --> C["API key source preference"] D["get_user_id"] -- "uses" --> A D -- "returns prefixed errors" --> E["LSP error handling"] F["LSP server"] -- "adds" --> G["server/listFeatures endpoint"] H["init_project"] -- "uses" --> I["process_args"] 
Loading

File Walkthrough

Relevant files
Enhancement
cfapi.py
LSP-aware get_user_id with graceful error handling             

codeflash/api/cfapi.py

  • Cache and branch on LSP mode in get_user_id.
  • Convert hard exit to LSP-friendly return via exit_with_message.
  • Return LSP-friendly error on 403 invalid API key.
  • Remove direct sys.exit dependency.
+8/-6     
env_utils.py
LSP-specific API key precedence logic                                       

codeflash/code_utils/env_utils.py

  • Prefer shell RC API key over env in LSP mode.
  • Add LSP helper import for mode detection.
  • Clarify rationale in comments.
+5/-1     
beta.py
LSP feature listing and init/refinement fixes                       

codeflash/lsp/beta.py

  • Add server/listFeatures endpoint to expose capabilities.
  • Use process_args instead of _init during init_project.
  • Normalize API key error prefix handling.
  • Remove unused OnPatchAppliedParams dataclass.
+9/-8     
Bug fix
code_utils.py
Prevent hard exits inside LSP process                                       

codeflash/code_utils/code_utils.py

  • Import LSP helper and guard exits during LSP.
  • Log error instead of exiting in LSP.
  • Document exit_with_message LSP caveat.
+5/-0     

@github-actions
Copy link

github-actions bot commented Nov 4, 2025

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Control Flow

In LSP mode, version-outdated path now returns an error string while non-LSP calls exit; confirm all non-LSP callers are safe with process termination via exit_with_message and that mixed contexts won’t mis-handle returned strings vs. exits.

 return response.text resp_json = response.json() userid: str | None = resp_json.get("userId") min_version: str | None = resp_json.get("min_version") if userid: if min_version and version.parse(min_version) > version.parse(__version__): msg = "Your Codeflash CLI version is outdated. Please update to the latest version using `pip install --upgrade codeflash`." console.print(f"[bold red]{msg}[/bold red]") if lsp_enabled: logger.debug(msg) return f"Error: {msg}" exit_with_message(msg, error_on_exit=True) return userid
Config Preference

LSP flips API key precedence to prefer shell RC over env; validate this doesn’t break environments relying on dynamically injected env vars (e.g., CI) when LSP is used, and that caching does not make the key stale.

 from codeflash.either import is_successful result = save_api_key_to_rc(env_api_key) if is_successful(result): logger.debug(f"Automatically saved API key from environment to shell config: {result.unwrap()}") except Exception as e: logger.debug(f"Failed to automatically save API key to shell config: {e}") # Prefer the shell configuration over environment variables for lsp, # as the API key may change in the RC file during lsp runtime. Since the LSP client (extension) can restart # within the same process, the environment variable could become outdated. api_key = shell_api_key or env_api_key if is_LSP_enabled() else env_api_key or shell_api_key api_secret_docs_message = "For more information, refer to the documentation at [https://docs.codeflash.ai/getting-started/codeflash-github-actions#add-your-api-key-to-your-repository-secrets]." # noqa
Behavior Change

exit_with_message now no-ops under LSP and only logs; ensure callers expecting termination handle the non-exit path and that user-facing feedback is still surfaced to clients.

def exit_with_message(message: str, *, error_on_exit: bool = False) -> None: """Don't Call it inside the lsp process, it will terminate the lsp server.""" if is_LSP_enabled(): logger.error(message) return paneled_text(message, panel_args={"style": "red"}) sys.exit(1 if error_on_exit else 0)
@github-actions
Copy link

github-actions bot commented Nov 4, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Stop returning error-labeled strings

Avoid returning "Error: ..." strings indistinguishable from valid user IDs. Use a
structured return or raise a controlled exception to prevent false positives and
fragile prefix parsing downstream. Maintain backward compatibility by keeping the
return type Optional[str] but never return error messages in the success channel.

codeflash/api/cfapi.py [91-133]

 def get_user_id(api_key: Optional[str] = None) -> Optional[str]: # noqa: PLR0911 ... lsp_enabled = is_LSP_enabled() if not api_key and not ensure_codeflash_api_key(): return None ... if userid: if min_version and version.parse(min_version) > version.parse(__version__): msg = "Your Codeflash CLI version is outdated. Please update to the latest version using `pip install --upgrade codeflash`." console.print(f"[bold red]{msg}[/bold red]") if lsp_enabled: logger.debug(msg) - return f"Error: {msg}" + return None exit_with_message(msg, error_on_exit=True) return userid ... if response.status_code == 403: error_title = "Invalid Codeflash API key. The API key you provided is not valid." if lsp_enabled: - return f"Error: {error_title}" + logger.error(error_title) + return None msg = ( f"{error_title}\n" "Please generate a new one at https://app.codeflash.ai/app/apikeys ,\n" "then set it as a CODEFLASH_API_KEY environment variable.\n" "For more information, refer to the documentation at \n" "https://docs.codeflash.ai/optimizing-with-codeflash/codeflash-github-actions#manual-setup\n" + ) + exit_with_message(msg, error_on_exit=True) + ...
Suggestion importance[1-10]: 8

__

Why: Returning "Error: ..." in get_user_id conflates success and error channels and forces brittle prefix parsing downstream; replacing with None improves correctness and API clarity without breaking Optional[str] typing. The suggested changes align with nearby PR intent (LSP-aware handling) and reduce potential bugs.

Medium
Remove fragile error prefix parsing

Remove brittle string-prefix checks that assume get_user_id returns "Error: ...".
Treat only None as failure and proceed otherwise. This avoids attribute errors if
user_id is None and aligns with a clean success/failure contract.

codeflash/lsp/beta.py [267-276]

 def _check_api_key_validity(api_key: Optional[str]) -> dict[str, str]: user_id = get_user_id(api_key=api_key) if user_id is None: return {"status": "error", "message": "api key not found or invalid"} - - error_prefix = "Error: " - if user_id.startswith(error_prefix): - error_msg = user_id[len(error_prefix) :] - return {"status": "error", "message": error_msg} - return {"status": "success", "user_id": user_id}
Suggestion importance[1-10]: 7

__

Why: The PR already moves toward not using "Error: ..." strings and introduces a cleaner error_prefix handling; simplifying to treat only None as failure would further reduce brittleness but depends on adopting suggestion 1. Useful and coherent, but interdependent with upstream behavior.

Medium
General
Preserve exit semantics in LSP

Honor the error_on_exit flag consistently in LSP mode by returning a status
indicator, not just logging. This allows callers to differentiate error vs.
non-error exits without terminating the server.

codeflash/code_utils/code_utils.py [355-362]

 def exit_with_message(message: str, *, error_on_exit: bool = False) -> None: """Don't Call it inside the lsp process, it will terminate the lsp server.""" if is_LSP_enabled(): - logger.error(message) + if error_on_exit: + logger.error(message) + else: + logger.warning(message) return paneled_text(message, panel_args={"style": "red"}) - sys.exit(1 if error_on_exit else 0)
Suggestion importance[1-10]: 5

__

Why: Differentiating error vs warning logs in LSP mode adds clarity without changing control flow; however, it’s a minor improvement and returns no explicit status to callers as proposed, limiting impact.

Low
Copy link
Contributor

@Saga4 Saga4 left a comment

Choose a reason for hiding this comment

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

LGTM, we can start adding tests to VSC extension too.

@Saga4 Saga4 merged commit 6b89534 into main Nov 4, 2025
22 of 23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

3 participants