-
-
Notifications
You must be signed in to change notification settings - Fork 52
feat(cli) : add offline diagnose command with safe fallback #300
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(cli) : add offline diagnose command with safe fallback #300
Conversation
|
Warning Rate limit exceeded@pavanimanchala53 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 22 minutes and 39 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughAdds a new Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant CLI as Cortex CLI
participant Router as LLMRouter
participant Claude as Claude Vision
participant TextLLM as Text LLM (fallback)
rect rgb(240,248,255)
User->>CLI: run `cortex diagnose` (--image/--clipboard/--text)
end
CLI->>Router: provide image or text input
alt image provided
Router->>Claude: send base64-encoded image (vision API)
alt Claude responds
Claude-->>Router: vision_analysis_text
Router-->>CLI: formatted diagnosis (stdout)
else Claude unavailable / error
Router->>Router: check _is_fallback flag
alt not _is_fallback
Router->>TextLLM: call text-based `complete` with _is_fallback=true
TextLLM-->>Router: fallback_text_diagnosis
Router-->>CLI: fallback diagnosis (annotated)
else already fallback
Router-->>CLI: guidance / failure message
end
end
else text provided
Router->>TextLLM: call `complete` (text path)
TextLLM-->>Router: text_diagnosis
Router-->>CLI: formatted diagnosis
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings, 1 inconclusive)
✅ Passed checks (2 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
cortex/cli.py (1)
585-597: Add "diagnose" command to help table.The help table shows the "notify" command (line 595) but is missing the newly added "diagnose" command. This creates an inconsistency where users won't discover the diagnose feature from the help output.
Apply this diff to add the diagnose command to the help table:
table.add_row("install <pkg>", "Install software") + table.add_row("diagnose <error>", "Diagnose system errors") table.add_row("history", "View history") table.add_row("rollback <id>", "Undo installation") table.add_row("notify", "Manage desktop notifications")
🧹 Nitpick comments (6)
cortex/llm_router.py (2)
132-138: Good implementation of guarded imports for optional dependencies.The try/except ImportError blocks appropriately handle missing SDK installations, allowing the CLI to function with only the dependencies that are actually needed. The fallback logic at lines 191-203 correctly handles None clients.
Consider enhancing the warning messages with installation hints:
except ImportError: self.claude_client = None - logger.warning("⚠️ anthropic not installed, Claude disabled") + logger.warning("⚠️ anthropic not installed, Claude disabled. Install: pip install anthropic")except ImportError: self.kimi_client = None - logger.warning("⚠️ openai not installed, Kimi disabled") + logger.warning("⚠️ openai not installed, Kimi disabled. Install: pip install openai")Also applies to: 143-152
506-508: Remove excessive trailing blank lines.PEP 8 recommends a single trailing newline. The extra blank lines should be removed.
Apply this diff:
stats = router.get_stats() print(json.dumps(stats, indent=2)) - - -cortex/cli.py (4)
55-56: Remove excessive blank lines.As per PEP 8 guidelines, limit blank lines between methods to a maximum of two.
Apply this diff:
if self.verbose: console.print(f"[dim][DEBUG] {message}[/dim]") - - +
317-319: Consider providing usage help when error is missing.When the error parameter is missing, the user might benefit from seeing example usage.
if not error: self._print_error("Please provide an error message to diagnose") + cx_print("Example: cortex diagnose 'apt install failed with dpkg error'", "info") return 1
347-347: Consider moving import to module level.The
from cortex.llm_router import complete_task, TaskTypeimport is inside a try block within a method. For better code organization and PEP 8 compliance, consider moving it to the module-level imports at the top of the file.If the import might fail due to missing dependencies, add a guard at the module level:
# At the top of the file, around line 40 try: from cortex.llm_router import complete_task, TaskType HAS_LLM_ROUTER = True except ImportError: HAS_LLM_ROUTER = FalseThen in the diagnose method:
try: if not HAS_LLM_ROUTER: raise ImportError("LLM router not available") response = complete_task( prompt=f"Diagnose this Linux error and suggest fixes:\n{error}", task_type=TaskType.ERROR_DEBUGGING, )Alternatively, if the import is expected to always succeed when API keys are configured, move it to the top-level imports.
313-313: Remove excessive blank lines around method.PEP 8 recommends exactly two blank lines between top-level function/method definitions.
Apply this diff:
return 1 - def diagnose(self, error: Optional[str] = None, image: Optional[str] = None, clipboard: bool = False): """Diagnose an error from text input (MVP: text-only).""" # ... method body ... return 1 - - + def history(self, limit: int = 20, status: Optional[str] = None, show_id: Optional[str] = None):Also applies to: 362-362
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
cortex/cli.py(4 hunks)cortex/llm_router.py(2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs
Files:
cortex/llm_router.pycortex/cli.py
🧠 Learnings (1)
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Implement audit logging to ~/.cortex/history.db for all package operations
Applied to files:
cortex/cli.py
🧬 Code graph analysis (2)
cortex/llm_router.py (1)
cortex/logging_system.py (2)
info(211-213)warning(215-217)
cortex/cli.py (2)
cortex/branding.py (1)
cx_print(55-75)cortex/llm_router.py (2)
complete_task(441-467)TaskType(27-36)
🔇 Additional comments (1)
cortex/cli.py (1)
706-711: LGTM: Command dispatcher integration is correct.The diagnose command is properly integrated into the main dispatcher, correctly passing all three parameters from the parsed arguments to the diagnose method.
Review Request@dhvll - This PR touches core files ( CI Status: All checks passing |
Merge Conflict After Recent MergesHey @pavanimanchala53! PRs #297 and #299 were just merged and created a conflict with this PR. Please:
Your PR is good to merge once conflicts are resolved! |
hi @mikejmorgan-ai , |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
cortex/llm_router.py (1)
22-22: Critical: Import error handling is ineffective.The try/except block at lines 139-145 cannot catch
ImportErrorbecause line 22 importsanthropicat module level. If the anthropic package is not installed, the module will fail to load immediately at line 22, before the try/except block is ever reached. This breaks the intended offline fallback behavior described in the PR objectives.🔎 Proposed fix
Move the anthropic import inside the try block and remove the module-level import:
-from anthropic import Anthropic from openai import OpenAI # Configure loggingThe import at line 140 inside the try block will then work correctly to provide graceful degradation when anthropic is not installed.
Also applies to: 139-145
cortex/cli.py (1)
7-7: Critical: MissingOptionalimport causes NameError.Line 436 uses
Optionalin type hints, butOptionalis not imported from thetypingmodule. This will cause a runtimeNameErrorwhen the module is loaded.🔎 Proposed fix
Add
Optionalto the typing import at line 7:-from typing import Any +from typing import Any, OptionalAlso applies to: 436-436
♻️ Duplicate comments (3)
cortex/cli.py (3)
448-461: Consider improving offline fallback advice.The offline fallback provides dpkg/apt-specific advice regardless of the actual error content, which could mislead users encountering unrelated errors. Previous review suggested making the advice more generic or adding basic pattern matching.
Example approach for more generic advice:
if provider == "ollama": print("\nDiagnosis:\n") print( f"Detected error:\n{error}\n\n" "⚠️ Offline mode provides general guidance only.\n" "For detailed AI-powered diagnosis, configure an API key.\n\n" "Common troubleshooting steps:\n" "1. Check system logs: journalctl -xe\n" "2. Verify package manager state: sudo dpkg --configure -a\n" "3. Fix broken dependencies: sudo apt --fix-broken install\n" "4. Update package lists: sudo apt update\n" ) return 0
436-437: Address previous feedback: Fix PEP 8 formatting and add complete docstring with return type.Previous reviews identified that this method signature violates PEP 8 (missing spaces after commas) and lacks a complete docstring with parameter descriptions and return type hint.
As per coding guidelines, docstrings required for all public APIs and type hints required in Python code.
🔎 Proposed fix (from previous review)
- def diagnose(self,error: Optional[str] = None,image: Optional[str] = None,clipboard: bool = False,): - """Diagnose an error from text input (MVP: text-only).""" + def diagnose(self, error: Optional[str] = None, image: Optional[str] = None, clipboard: bool = False) -> int: + """ + Diagnose an error from text input (MVP: text-only). + + Args: + error: Error message text to diagnose + image: Path to error screenshot (not yet implemented) + clipboard: Use image from clipboard (not yet implemented) + + Returns: + Exit code: 0 for success, 1 for failure + + Note: + Image and clipboard support are planned but not yet implemented. + Currently only text-based diagnosis is supported. + """
439-466: Address previous feedback: Handle unimplemented image/clipboard parameters.Previous review identified that
--imageand--clipboardarguments are defined but silently ignored in the diagnose method. This could confuse users attempting to use these flags.Consider adding early validation:
def diagnose(self, error: Optional[str] = None, image: Optional[str] = None, clipboard: bool = False) -> int: """Diagnose an error from text input (MVP: text-only).""" # Image and clipboard support planned for future release if image or clipboard: self._print_error("Image and clipboard support not yet implemented") cx_print("Currently only text-based diagnosis is supported", "info") cx_print("Example: cortex diagnose 'your error message here'", "info") return 1 if not error: self._print_error("Please provide an error message to diagnose") return 1 # ... rest of implementation
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
cortex/cli.py(2 hunks)cortex/llm_router.py(2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs
Files:
cortex/cli.pycortex/llm_router.py
🧬 Code graph analysis (2)
cortex/cli.py (3)
cortex/logging_system.py (1)
error(206-208)cortex/first_run_wizard.py (1)
_print_error(746-748)cortex/branding.py (1)
cx_print(49-69)
cortex/llm_router.py (1)
cortex/logging_system.py (2)
info(198-200)warning(202-204)
🪛 GitHub Actions: CI
cortex/cli.py
[error] 44-44: ruff: W293 Blank line contains whitespace.
🪛 GitHub Actions: Cortex Automation
cortex/cli.py
[error] 436-436: NameError: name 'Optional' is not defined in diagnose method signature. Ensure 'from typing import Optional' is present or import Optional at the top of the module.
🪛 GitHub Check: Lint
cortex/cli.py
[failure] 45-45: Ruff (W293)
cortex/cli.py:45:1: W293 Blank line contains whitespace
[failure] 44-44: Ruff (W293)
cortex/cli.py:44:1: W293 Blank line contains whitespace
[failure] 436-436: Ruff (F821)
cortex/cli.py:436:58: F821 Undefined name Optional
[failure] 436-436: Ruff (F821)
cortex/cli.py:436:30: F821 Undefined name Optional
[failure] 435-435: Ruff (W293)
cortex/cli.py:435:1: W293 Blank line contains whitespace
cortex/llm_router.py
[failure] 494-494: Ruff (W292)
cortex/llm_router.py:494:5: W292 No newline at end of file
[failure] 494-494: Ruff (W293)
cortex/llm_router.py:494:1: W293 Blank line contains whitespace
[failure] 493-493: Ruff (W293)
cortex/llm_router.py:493:1: W293 Blank line contains whitespace
[failure] 492-492: Ruff (W293)
cortex/llm_router.py:492:1: W293 Blank line contains whitespace
e78e880 to
7ffa272
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
cortex/cli.py (1)
116-177: Add complete docstring and type hints for public API.The
notifymethod is a public API but lacks comprehensive documentation and type hints. Per coding guidelines, docstrings and type hints are required for all public APIs.As per coding guidelines, docstrings required for all public APIs and type hints required in Python code.
🔎 Proposed enhancement
- def notify(self, args): - """Handle notification commands""" + def notify(self, args: argparse.Namespace) -> int: + """ + Handle notification management commands. + + Args: + args: Parsed command-line arguments containing notify_action and related params + + Returns: + Exit code: 0 for success, 1 for failure + """Also, remove review-related comments like "Addressing CodeRabbit feedback" from the code (lines 118, 135-136, 152).
♻️ Duplicate comments (6)
cortex/cli.py (6)
54-55: Fix PEP 8 formatting: remove trailing whitespace.These blank lines contain trailing whitespace, violating PEP 8 guidelines.
As per coding guidelines, follow PEP 8 style guide.
🔎 Proposed fix
if self.verbose: console.print(f"[dim][DEBUG] {message}[/dim]") - - +
312-312: Fix PEP 8 formatting: remove trailing whitespace.This blank line contains trailing whitespace, violating PEP 8 guidelines.
As per coding guidelines, follow PEP 8 style guide.
🔎 Proposed fix
return 1 - + def diagnose(self,error: Optional[str] = None,image: Optional[str] = None,clipboard: bool = False,):
313-313: Fix PEP 8 formatting: add space after comma.The parameter list is missing spaces after commas, violating PEP 8 style guidelines.
As per coding guidelines, follow PEP 8 style guide.
🔎 Proposed fix
- def diagnose(self,error: Optional[str] = None,image: Optional[str] = None,clipboard: bool = False,): + def diagnose(self, error: Optional[str] = None, image: Optional[str] = None, clipboard: bool = False) -> int:Note: Also added the return type hint and removed the trailing comma.
313-314: Enhance docstring and add return type hint.The method lacks comprehensive documentation and the return type hint. Per coding guidelines, docstrings are required for all public APIs and should describe parameters, return values, and behavior.
As per coding guidelines, docstrings required for all public APIs and type hints required in Python code.
🔎 Proposed enhancement
- def diagnose(self,error: Optional[str] = None,image: Optional[str] = None,clipboard: bool = False,): - """Diagnose an error from text input (MVP: text-only).""" + def diagnose(self, error: Optional[str] = None, image: Optional[str] = None, clipboard: bool = False) -> int: + """ + Diagnose an error from text input (MVP: text-only). + + Args: + error: Error message text to diagnose + image: Path to error screenshot (not yet implemented) + clipboard: Use image from clipboard (not yet implemented) + + Returns: + Exit code: 0 for success, 1 for failure + + Note: + Image and clipboard support are planned but not yet implemented. + Currently only text-based diagnosis is supported. + """
325-338: Generic fallback advice may not match the actual error.The offline fallback provides dpkg/apt-specific advice regardless of the actual error content. This could mislead users who encounter unrelated errors.
Consider making the advice more generic and applicable to various error types, or add a disclaimer:
🔎 Suggested improvement
if provider == "ollama": print("\nDiagnosis:\n") print( f"Detected error:\n{error}\n\n" + "⚠️ Offline mode provides general guidance only.\n" + "For detailed AI-powered diagnosis, configure an API key.\n\n" - "Possible causes:\n" - "- Interrupted package installation\n" - "- Broken dpkg state\n" - "- Locked apt database\n\n" - "Suggested fixes:\n" - "sudo dpkg --configure -a\n" - "sudo apt --fix-broken install\n" - "sudo apt update\n" + "Common troubleshooting steps:\n" + "1. Check system logs: journalctl -xe\n" + "2. Verify package manager state: sudo dpkg --configure -a\n" + "3. Fix broken dependencies: sudo apt --fix-broken install\n" + "4. Update package lists: sudo apt update\n" ) return 0
316-319: Validate unimplemented image and clipboard parameters.The
--imageand--clipboardarguments are defined but not implemented in the diagnose method. Users who attempt to use these flags will see them silently ignored, which could be confusing.🔎 Proposed validation
def diagnose(self, error: Optional[str] = None, image: Optional[str] = None, clipboard: bool = False) -> int: """Diagnose an error from text input (MVP: text-only).""" + # Image and clipboard support planned for future release + if image or clipboard: + self._print_error("Image and clipboard support not yet implemented") + cx_print("Currently only text-based diagnosis is supported", "info") + cx_print("Example: cortex diagnose 'your error message here'", "info") + return 1 + if not error: self._print_error("Please provide an error message to diagnose") return 1
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
cortex/cli.py(6 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs
Files:
cortex/cli.py
🧠 Learnings (1)
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Implement audit logging to ~/.cortex/history.db for all package operations
Applied to files:
cortex/cli.py
🔇 Additional comments (1)
cortex/cli.py (1)
471-471: Thestr | Nonesyntax is compatible with Python 3.10+, which is the project's minimum supported version. However, note thatOptionalis still used elsewhere in this file (e.g., line 435), suggesting inconsistent type hint style. Consider standardizing on the modern union syntax across the file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
cortex/llm_router.py (1)
22-22: Critical: Top-level import conflicts with optional dependency pattern.The top-level
from anthropic import Anthropicat line 22 will raise an ImportError immediately if the anthropic package is not installed, preventing the application from starting. This defeats the purpose of the try/except block at lines 139-145 that attempts to make the anthropic dependency optional.🔎 Proposed fix
Remove the top-level import and keep only the conditional import:
-from anthropic import Anthropic from openai import OpenAIThen ensure the try/except block correctly handles the import:
if self.claude_api_key: try: from anthropic import Anthropic self.claude_client = Anthropic(api_key=self.claude_api_key) logger.info("✅ Claude API client initialized") except ImportError: self.claude_client = None logger.warning("⚠️ anthropic not installed, Claude disabled")Also applies to: 139-145
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
cortex/cli.py(3 hunks)cortex/llm_router.py(2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs
Files:
cortex/llm_router.pycortex/cli.py
🧠 Learnings (1)
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Dry-run by default for all installations in command execution
Applied to files:
cortex/cli.py
🧬 Code graph analysis (2)
cortex/llm_router.py (1)
cortex/logging_system.py (2)
info(198-200)warning(202-204)
cortex/cli.py (4)
cortex/logging_system.py (1)
error(206-208)cortex/first_run_wizard.py (1)
_print_error(746-748)cortex/branding.py (1)
cx_print(49-69)cortex/llm_router.py (2)
complete_task(427-453)TaskType(30-40)
🪛 GitHub Actions: CI
cortex/cli.py
[error] 43-43: W293 Blank line contains whitespace
🪛 GitHub Actions: Cortex Automation
cortex/cli.py
[error] 475-475: SyntaxError: expected 'except' or 'finally' block while parsing 'def cache_stats(self) -> int:'. This blocks test collection.
🪛 GitHub Check: Lint
cortex/llm_router.py
[failure] 494-494: Ruff (W292)
cortex/llm_router.py:494:5: W292 No newline at end of file
[failure] 494-494: Ruff (W293)
cortex/llm_router.py:494:1: W293 Blank line contains whitespace
[failure] 493-493: Ruff (W293)
cortex/llm_router.py:493:1: W293 Blank line contains whitespace
[failure] 492-492: Ruff (W293)
cortex/llm_router.py:492:1: W293 Blank line contains whitespace
cortex/cli.py
[failure] 44-44: Ruff (W293)
cortex/cli.py:44:1: W293 Blank line contains whitespace
[failure] 43-43: Ruff (W293)
cortex/cli.py:43:1: W293 Blank line contains whitespace
[failure] 434-434: Ruff (W293)
cortex/cli.py:434:1: W293 Blank line contains whitespace
[failure] 654-654: Ruff (W293)
cortex/cli.py:654:1: W293 Blank line contains whitespace
0f36a86 to
9abe357
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
cortex/llm_router.py (1)
22-24: Top-level imports conflict with deferred import strategy.Lines 22-23 import
AnthropicandOpenAIat module load time, which will raiseImportErrorif those packages aren't installed. This defeats the purpose of the try/except ImportError guards added in__init__(lines 139-145 and 150-162).Remove the top-level imports since they're re-imported inside the guarded blocks.
🔎 Proposed fix
from dataclasses import dataclass, asdict from enum import Enum from typing import Any -from anthropic import Anthropic -from openai import OpenAI - # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__)cortex/cli.py (1)
7-7: Critical:Optionalis used but not imported.
Optionalis used in method signatures on lines 436 and 485 but is not imported fromtyping. This will cause aNameErrorat runtime.🔎 Proposed fix
-from typing import Any +from typing import Any, Optional
♻️ Duplicate comments (7)
cortex/llm_router.py (1)
499-501: Fix PEP 8 formatting: remove trailing whitespace and add final newline.The blank lines contain trailing whitespace, and the file is missing a newline at the end.
As per coding guidelines, follow PEP 8 style guide.
cortex/cli.py (6)
44-45: PEP 8: trailing whitespace on blank lines.These blank lines contain trailing whitespace. This was previously addressed but appears to have been reintroduced during rebase/merge.
As per coding guidelines, follow PEP 8 style guide.
435-435: PEP 8: trailing whitespace on blank line.This was previously addressed but appears to have been reintroduced.
436-436: PEP 8: missing spaces after commas in parameter list.The parameter list lacks spaces after commas, violating PEP 8. This was previously addressed but appears reintroduced.
483-484: PEP 8: trailing whitespace on blank lines.These blank lines contain trailing whitespace. Previously addressed but reintroduced.
448-461: Offline fallback provides dpkg-specific advice regardless of error type.The offline fallback always suggests dpkg/apt fixes even for unrelated errors (e.g., network issues, permission errors). Consider making the advice more generic or adding basic pattern matching.
This was noted in a previous review and remains unaddressed.
791-799: Image and clipboard options are declared but not implemented.The
--imageand--clipboardarguments are parsed but thediagnosemethod ignores them. Users who try these flags will get no feedback that the feature isn't available.Consider adding early validation or updating help text to indicate these are coming soon. This was noted in a previous review.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
cortex/cli.py(4 hunks)cortex/llm_router.py(3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs
Files:
cortex/llm_router.pycortex/cli.py
🧠 Learnings (1)
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Dry-run by default for all installations in command execution
Applied to files:
cortex/cli.py
🧬 Code graph analysis (2)
cortex/llm_router.py (1)
cortex/logging_system.py (2)
info(198-200)warning(202-204)
cortex/cli.py (3)
cortex/first_run_wizard.py (1)
_print_error(746-748)cortex/branding.py (1)
cx_print(49-69)cortex/llm_router.py (2)
complete_task(434-460)TaskType(30-40)
🪛 GitHub Actions: CI
cortex/cli.py
[error] 44-44: Ruff: W293 Blank line contains whitespace.
🪛 GitHub Actions: Cortex Automation
cortex/cli.py
[error] 884-885: IndentationError: expected an indented block after 'elif' statement on line 884 in cortex/cli.py during test collection (pytest).
🪛 GitHub Check: Lint
cortex/llm_router.py
[failure] 161-161: Ruff (invalid-syntax)
cortex/llm_router.py:161:5: invalid-syntax: Expected a statement
[failure] 161-161: Ruff (invalid-syntax)
cortex/llm_router.py:161:1: invalid-syntax: Expected a statement
[failure] 149-150: Ruff (invalid-syntax)
cortex/llm_router.py:149:30: invalid-syntax: Expected an indented block after if statement
cortex/cli.py
[failure] 45-45: Ruff (W293)
cortex/cli.py:45:1: W293 Blank line contains whitespace
[failure] 44-44: Ruff (W293)
cortex/cli.py:44:1: W293 Blank line contains whitespace
[failure] 484-484: Ruff (W293)
cortex/cli.py:484:1: W293 Blank line contains whitespace
[failure] 483-483: Ruff (W293)
cortex/cli.py:483:1: W293 Blank line contains whitespace
[failure] 435-435: Ruff (W293)
cortex/cli.py:435:1: W293 Blank line contains whitespace
[failure] 780-780: Ruff (W293)
cortex/cli.py:780:1: W293 Blank line contains whitespace
e21f21b to
5af4ca9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
cortex/cli.py (1)
573-600: Add diagnose command to help table.The new
diagnosecommand is not included in the Rich help table (line 596 shows notify but not diagnose). Users won't discover this feature through the help system.🔎 Proposed fix
table.add_row("install <pkg>", "Install software") + table.add_row("diagnose <error>", "Diagnose errors with AI") table.add_row("history", "View history") table.add_row("rollback <id>", "Undo installation") table.add_row("notify", "Manage desktop notifications")
♻️ Duplicate comments (3)
cortex/cli.py (3)
314-316: PEP 8 formatting and docstring issues may persist.The method signature appears to still have spacing issues (missing spaces after commas) and lacks a return type hint, despite past reviews marking these as addressed. The docstring also lacks parameter and return value documentation.
If these issues were resolved in later commits, please disregard. Otherwise, ensure:
- Proper spacing:
def diagnose(self, error: Optional[str] = None, image: Optional[str] = None, clipboard: bool = False) -> int:- Complete docstring with Args, Returns, and Note sections as suggested in previous reviews
As per coding guidelines, type hints required in Python code and docstrings required for all public APIs.
326-339: Generic offline advice may mislead users with non-apt errors.The offline fallback provides dpkg/apt-specific troubleshooting steps regardless of the actual error content. Past reviews suggested making the advice more generic or adding basic pattern matching.
Consider implementing one of the approaches suggested in previous reviews, such as providing more generic troubleshooting guidance or adding basic keyword detection to tailor the advice.
640-648: Unimplemented flags need handling or documentation.The
--imageand--clipboardarguments are declared but not implemented in thediagnosemethod, which could confuse users. Past reviews suggested adding validation or updating help text.Implement one of the approaches from previous reviews:
- Add early validation in
diagnosethat returns an error if these flags are used- Update help text to indicate "not yet implemented" or "coming soon"
This would improve user experience by setting clear expectations.
🧹 Nitpick comments (1)
cortex/cli.py (1)
38-42: Consider alternative to sys.path manipulation.The
sys.path.insertat line 42 is a code smell that suggests the package structure might benefit from proper installation (e.g., usingpip install -e .). While this works, it can cause issues with imports and makes the code less portable.Consider alternatives:
- Install the package in development mode:
pip install -e .- Use relative imports properly
- Document why this is necessary if it's a deployment constraint
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
cortex/cli.py(10 hunks)cortex/llm_router.py(18 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs
Files:
cortex/cli.pycortex/llm_router.py
🧠 Learnings (2)
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Dry-run by default for all installations in command execution
Applied to files:
cortex/cli.py
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Implement audit logging to ~/.cortex/history.db for all package operations
Applied to files:
cortex/cli.py
🧬 Code graph analysis (2)
cortex/cli.py (1)
cortex/llm_router.py (2)
complete_task(441-467)TaskType(27-36)
cortex/llm_router.py (1)
cortex/logging_system.py (3)
info(211-213)warning(215-217)error(219-221)
🔇 Additional comments (3)
cortex/llm_router.py (2)
131-140: LGTM: Deferred import pattern supports offline operation.The deferred import for Claude's Anthropic client correctly avoids requiring the
anthropicpackage at module load time, aligning with the PR's goal of enabling error diagnosis on fresh systems without forcing SDK installation.
214-222: LGTM: force_provider parameter well-documented and typed.The addition of the
force_providerparameter to thecompletemethod is properly typed withOptional[LLMProvider]and documented in the docstring. This enhances flexibility for testing and special routing scenarios.cortex/cli.py (1)
346-360: LGTM: LLM diagnosis path correctly implemented.The try/except block is properly closed (resolving the SyntaxError flagged in past reviews), and the integration with
llm_router.complete_taskis correct. The deferred import pattern avoids forcing the dependency at module load time, supporting the offline-safe goal.
43b3e8e to
5af4ca9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
cortex/cli.py (1)
1-878: Fix Black formatting violations to pass CI.The pipeline reports that this file would be reformatted by Black, causing CI to fail. Run
black .to automatically fix formatting issues.As per coding guidelines, follow PEP 8 style guide.
#!/bin/bash # Run Black formatter to fix style issues black cortex/cli.py
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
cortex/cli.py(2 hunks)cortex/llm_router.py(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- cortex/llm_router.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs
Files:
cortex/cli.py
🧠 Learnings (1)
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Dry-run by default for all installations in command execution
Applied to files:
cortex/cli.py
🪛 GitHub Actions: CI
cortex/cli.py
[error] 1-1: Black formatting check failed. This file would be reformatted by Black. The command that detected the issue: 'black --check . --exclude "(venv|.venv|build|dist)"'. Run 'black .' to format.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: test (3.11)
- GitHub Check: test (3.10)
- GitHub Check: test (3.12)
404ea7c to
c7a07f1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
cortex/cli.py (1)
624-631: Adddiagnosecommand to help table.The new
diagnosecommand is missing from theshow_rich_help()output. Users won't discover this feature through the default help display.🔎 Proposed fix
table.add_row("demo", "See Cortex in action") table.add_row("wizard", "Configure API key") table.add_row("status", "System status") table.add_row("install <pkg>", "Install software") + table.add_row("diagnose <error>", "Diagnose Linux errors") table.add_row("history", "View history") table.add_row("rollback <id>", "Undo installation") table.add_row("notify", "Manage desktop notifications")
♻️ Duplicate comments (2)
cortex/cli.py (2)
334-340: Add return type hint and complete docstring.The method is missing the
-> intreturn type hint and comprehensive documentation as previously noted. Per coding guidelines, type hints and docstrings are required for public APIs.As per coding guidelines, docstrings required for all public APIs and type hints required in Python code.
🔎 Proposed fix
def diagnose( self, error: Optional[str] = None, image: Optional[str] = None, clipboard: bool = False, - ): - """Diagnose an error from text input (MVP: text-only).""" + ) -> int: + """ + Diagnose an error from text input (MVP: text-only). + + Args: + error: Error message text to diagnose + image: Path to error screenshot (not yet implemented) + clipboard: Use image from clipboard (not yet implemented) + + Returns: + Exit code: 0 for success, 1 for failure + """
342-364: Provide early feedback when unimplemented flags are used.The
--imageand--clipboardarguments are defined but not implemented. Users attempting to use these flags receive no indication that they're ignored. Consider adding a clear message when these flags are provided.🔎 Proposed fix
def diagnose( self, error: Optional[str] = None, image: Optional[str] = None, clipboard: bool = False, ) -> int: """Diagnose an error from text input (MVP: text-only).""" + # Image and clipboard support planned for future release + if image or clipboard: + cx_print("Image and clipboard support not yet implemented", "warning") + cx_print("Currently only text-based diagnosis is supported", "info") + if not error: + return 1 + if not error: self._print_error("Please provide an error message to diagnose") return 1
🧹 Nitpick comments (2)
cortex/llm_router.py (1)
47-57: Consider using more specific type hint forraw_response.The
raw_responsefield usesDictwithout type parameters. For better type safety, consider usingDict[str, Any]to be explicit about the key-value types.As per coding guidelines, type hints are required in Python code.
🔎 Proposed fix
@dataclass class LLMResponse: """Standardized response from any LLM.""" content: str provider: LLMProvider model: str tokens_used: int cost_usd: float latency_seconds: float - raw_response: Optional[Dict] = None + raw_response: Optional[Dict[str, Any]] = Nonecortex/cli.py (1)
675-685: Consider adding "(coming soon)" to help text for unimplemented options.The
--imageand--clipboardhelp text doesn't indicate these features are not yet implemented. This could set incorrect user expectations.🔎 Proposed fix
diagnose_parser.add_argument( - "--image", help="Path to error screenshot (PNG, JPG, WebP)" + "--image", help="Path to error screenshot (coming soon)" ) diagnose_parser.add_argument( - "--clipboard", action="store_true", help="Use image from clipboard" + "--clipboard", action="store_true", help="Use image from clipboard (coming soon)" )
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
cortex/cli.py(19 hunks)cortex/llm_router.py(8 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs
Files:
cortex/llm_router.pycortex/cli.py
🧠 Learnings (2)
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Dry-run by default for all installations in command execution
Applied to files:
cortex/cli.py
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Implement audit logging to ~/.cortex/history.db for all package operations
Applied to files:
cortex/cli.py
🧬 Code graph analysis (2)
cortex/llm_router.py (1)
cortex/logging_system.py (3)
info(211-213)warning(215-217)error(219-221)
cortex/cli.py (6)
cortex/installation_history.py (4)
InstallationHistory(68-653)InstallationType(25-31)InstallationStatus(34-39)update_installation(310-362)cortex/branding.py (3)
cx_print(55-75)cx_step(78-85)cx_header(88-94)cortex/validators.py (1)
validate_api_key(21-41)cortex/notification_manager.py (3)
NotificationManager(12-146)_save_config(51-54)send(95-133)cortex/logging_system.py (1)
error(219-221)cortex/llm_router.py (2)
complete_task(445-471)TaskType(27-37)
🔇 Additional comments (4)
cortex/llm_router.py (2)
135-159: LGTM! Deferred import pattern correctly implemented.Both Claude and Kimi clients now use try/except blocks to handle missing SDK packages gracefully. This enables the offline-safe fallback behavior as intended by the PR objectives.
474-509: LGTM! Demo code provides clear usage examples.The
__main__block demonstrates routing behavior for different task types (USER_CHAT → Claude, SYSTEM_OPERATION → Kimi K2), which is helpful for understanding the router's behavior.cortex/cli.py (2)
371-385: LGTM! LLM diagnosis path correctly uses the router.The implementation properly uses
complete_taskwithTaskType.ERROR_DEBUGGING, which will route to Kimi K2 as the preferred provider for debugging tasks (per the routing rules inllm_router.py).
192-310: LGTM! Install command follows dry-run by default pattern.The install command correctly defaults to showing commands without execution (lines 306-308), requiring explicit
--executeflag for actual installation. This aligns with the safety-first approach. Based on learnings, dry-run by default for all installations in command execution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
cortex/llm_router.py (1)
22-23: Critical: Module-level imports defeat guarded import pattern.Lines 22-23 import
AnthropicandOpenAIat module-level, which will cause anImportErrorif these packages aren't installed—preventing the module from loading at all. This defeats the purpose of the guarded import pattern added at lines 139-146 for Claude.To enable offline operation when SDKs are missing, remove these module-level imports and rely entirely on the deferred imports within the initialization blocks.
🔎 Proposed fix
from typing import Any -from anthropic import Anthropic -from openai import OpenAI - # Configure logging logging.basicConfig(level=logging.INFO)Note: Line 23 (
from openai import OpenAI) should also be removed and moved to a guarded import for Kimi (see separate comment).
♻️ Duplicate comments (2)
cortex/llm_router.py (1)
150-156: Implement guarded import pattern for Kimi to match Claude.Kimi initialization should use the same try/except ImportError pattern as Claude (lines 139-146) to support offline operation when the
openaipackage is unavailable.🔎 Proposed fix
if self.kimi_api_key: - self.kimi_client = OpenAI( - api_key=self.kimi_api_key, base_url="https://api.moonshot.ai/v1" - ) - logger.info("✅ Kimi K2 API client initialized") + try: + from openai import OpenAI + + self.kimi_client = OpenAI( + api_key=self.kimi_api_key, + base_url="https://api.moonshot.ai/v1" + ) + logger.info("✅ Kimi K2 API client initialized") + except ImportError: + self.kimi_client = None + logger.warning("⚠️ openai not installed, Kimi disabled") else: logger.warning("⚠️ No Kimi K2 API key provided")Based on past review comments, Kimi should match Claude's deferred import pattern.
cortex/cli.py (1)
32-36: Remove duplicate logging and sys.path configuration.Lines 32-36 are exact duplicates of lines 9-13. This redundant code should be removed to maintain clarity and avoid confusion.
🔎 Proposed fix
from cortex.validators import ( validate_api_key, validate_install_request, ) -# Suppress noisy log messages in normal operation -logging.getLogger("httpx").setLevel(logging.WARNING) -logging.getLogger("cortex.installation_history").setLevel(logging.ERROR) - -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) - class CortexCLI:Based on past review comments, this duplicate block should have been removed during rebase.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
cortex/cli.py(7 hunks)cortex/llm_router.py(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs
Files:
cortex/llm_router.pycortex/cli.py
🧠 Learnings (2)
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Implement audit logging to ~/.cortex/history.db for all package operations
Applied to files:
cortex/cli.py
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Dry-run by default for all installations in command execution
Applied to files:
cortex/cli.py
🧬 Code graph analysis (1)
cortex/llm_router.py (1)
cortex/logging_system.py (2)
info(198-200)warning(202-204)
🪛 GitHub Actions: CI
cortex/cli.py
[error] 15-15: ruff check failed. Import block is unsorted or unformatted (I001) in cortex/cli.py:15. Command: 'ruff check . --output-format=github'.
🪛 GitHub Check: Lint
cortex/cli.py
[failure] 26-26: Ruff (F811)
cortex/cli.py:26:81: F811 Redefinition of unused VERSION from line 15
[failure] 26-26: Ruff (F811)
cortex/cli.py:26:68: F811 Redefinition of unused show_banner from line 15
[failure] 26-26: Ruff (F811)
cortex/cli.py:26:57: F811 Redefinition of unused cx_header from line 15
[failure] 26-26: Ruff (F811)
cortex/cli.py:26:38: F811 Redefinition of unused cx_print from line 15
[failure] 26-26: Ruff (F811)
cortex/cli.py:26:29: F811 Redefinition of unused console from line 15
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: test (3.12)
- GitHub Check: test (3.11)
- GitHub Check: test (3.10)
cee6e2e to
8cff3dc
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
cortex/cli.py (1)
607-633: Add diagnose command to the help table.The
diagnosecommand is implemented and functional but isn't listed in the Rich help table, making it undiscoverable to users.🔎 Proposed fix
table.add_row("demo", "See Cortex in action") table.add_row("wizard", "Configure API key") table.add_row("status", "System status") table.add_row("install <pkg>", "Install software") +table.add_row("diagnose <error>", "Diagnose errors") table.add_row("history", "View history") table.add_row("rollback <id>", "Undo installation") table.add_row("notify", "Manage desktop notifications")
♻️ Duplicate comments (5)
cortex/cli.py (4)
674-684: Update help text to indicate image/clipboard are not yet implemented.The argument help text doesn't inform users that these features are planned but not available, which could lead to confusion.
🔎 Suggested fix
diagnose_parser.add_argument( '--image', - help='Path to error screenshot (PNG, JPG, WebP)' + help='Path to error screenshot (coming soon)' ) diagnose_parser.add_argument( '--clipboard', action='store_true', - help='Use image from clipboard' + help='Use image from clipboard (coming soon)' )
333-339: Add return type hint and comprehensive docstring.The method is missing a return type annotation and has a minimal docstring that doesn't document parameters, return values, or behavior.
🔎 Suggested improvement
def diagnose( self, error: Optional[str] = None, image: Optional[str] = None, clipboard: bool = False, -): - """Diagnose an error from text input (MVP: text-only).""" +) -> int: + """ + Diagnose an error from text input (MVP: text-only). + + Args: + error: Error message text to diagnose + image: Path to error screenshot (not yet implemented) + clipboard: Use image from clipboard (not yet implemented) + + Returns: + Exit code: 0 for success, 1 for failure + + Note: + Image and clipboard support are planned but not yet implemented. + Currently only text-based diagnosis is supported. + """As per coding guidelines, type hints required in Python code and docstrings required for all public APIs.
333-344: Validate or reject unimplemented image and clipboard parameters.The method accepts
imageandclipboardparameters but doesn't implement them. Users who pass these flags won't receive clear feedback that the feature isn't ready.🔎 Recommended fix: Add early validation
def diagnose( self, error: Optional[str] = None, image: Optional[str] = None, clipboard: bool = False, ) -> int: """Diagnose an error from text input (MVP: text-only).""" + # Image and clipboard support planned for future release + if image or clipboard: + self._print_error("Image and clipboard support not yet implemented") + cx_print("Currently only text-based diagnosis is supported", "info") + cx_print("Example: cortex diagnose 'your error message here'", "info") + return 1 + if not error: self._print_error("Please provide an error message to diagnose") return 1
350-363: Generic fallback advice may not match the actual error.The offline fallback provides dpkg/apt-specific advice regardless of the error content, which could mislead users encountering unrelated errors.
Consider making the advice more generic:
🔎 Suggested improvement
if provider == "ollama": print("\nDiagnosis:\n") print( f"Detected error:\n{error}\n\n" - "Possible causes:\n" - "- Interrupted package installation\n" - "- Broken dpkg state\n" - "- Locked apt database\n\n" - "Suggested fixes:\n" - "sudo dpkg --configure -a\n" - "sudo apt --fix-broken install\n" - "sudo apt update\n" + "⚠️ Offline mode provides general guidance only.\n" + "For detailed AI-powered diagnosis, configure an API key.\n\n" + "Common troubleshooting steps:\n" + "1. Check system logs: journalctl -xe\n" + "2. Verify package manager state: sudo dpkg --configure -a\n" + "3. Fix broken dependencies: sudo apt --fix-broken install\n" + "4. Update package lists: sudo apt update\n" ) return 0cortex/llm_router.py (1)
263-284: Critical: Infinite recursion risk remains unaddressed.The fallback logic can still cause infinite recursion if both providers fail. When the fallback provider also fails and
enable_fallbackisTrue, it will recursively alternate between providers indefinitely.As suggested in the previous review, add a mechanism to track fallback attempts:
🔎 Recommended fix
def complete( self, messages: List[Dict[str, str]], task_type: TaskType = TaskType.USER_CHAT, force_provider: Optional[LLMProvider] = None, temperature: float = 0.7, max_tokens: int = 4096, tools: Optional[List[Dict]] = None, + _is_fallback: bool = False, ) -> LLMResponse: """Generate completion using the most appropriate LLM.""" ... except Exception as e: logger.error(f"❌ Error with {routing.provider.value}: {e}") # Try fallback if enabled - if self.enable_fallback: + if self.enable_fallback and not _is_fallback: fallback_provider = ( LLMProvider.KIMI_K2 if routing.provider == LLMProvider.CLAUDE else LLMProvider.CLAUDE ) logger.info(f"🔄 Attempting fallback to {fallback_provider.value}") return self.complete( messages=messages, task_type=task_type, force_provider=fallback_provider, temperature=temperature, max_tokens=max_tokens, tools=tools, + _is_fallback=True, ) else: raise
🧹 Nitpick comments (1)
cortex/llm_router.py (1)
60-68: Consider documenting the confidence field in the docstring.The
confidencefield is properly typed, but the class docstring doesn't mention it. Adding a brief note would improve API documentation.🔎 Suggested enhancement
@dataclass class RoutingDecision: - """Details about why a specific LLM was chosen.""" + """ + Details about why a specific LLM was chosen. + + Attributes: + provider: The selected LLM provider + task_type: Type of task being routed + reasoning: Human-readable explanation for the choice + confidence: Confidence score from 0.0 (low) to 1.0 (high) + """As per coding guidelines, docstrings required for all public APIs.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
cortex/cli.py(19 hunks)cortex/llm_router.py(8 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs
Files:
cortex/cli.pycortex/llm_router.py
🧠 Learnings (2)
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Dry-run by default for all installations in command execution
Applied to files:
cortex/cli.py
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Implement audit logging to ~/.cortex/history.db for all package operations
Applied to files:
cortex/cli.py
🧬 Code graph analysis (2)
cortex/cli.py (3)
cortex/installation_history.py (4)
InstallationHistory(68-653)InstallationStatus(34-39)InstallationType(25-31)update_installation(310-362)cortex/notification_manager.py (3)
NotificationManager(12-146)_save_config(51-54)send(95-133)cortex/branding.py (1)
cx_print(55-75)
cortex/llm_router.py (1)
cortex/logging_system.py (3)
info(211-213)warning(215-217)error(219-221)
🔇 Additional comments (7)
cortex/llm_router.py (3)
135-159: LGTM: Guarded imports implemented correctly.The deferred import pattern for both Claude and Kimi clients is properly implemented with try/except blocks that gracefully handle missing dependencies. This allows the router to work in offline mode without requiring SDK installation.
169-216: LGTM: force_provider and fallback routing implemented correctly.The routing logic properly handles forced provider selection and gracefully falls back when the preferred provider is unavailable. The confidence scores (1.0 for forced, 0.95 for routed) are reasonable.
506-509: No action needed: File complies with PEP 8.Both trailing whitespace and final newline issues have been resolved. The file ends correctly with no whitespace violations.
cortex/cli.py (4)
31-36: LGTM: Logging configuration is properly consolidated.The logging suppression and sys.path configuration appear only once in the file, as expected. Previous concerns about duplication have been addressed.
370-384: LGTM: LLM-based diagnosis path implemented correctly.The integration with
llm_router.complete_taskis properly implemented with appropriate error handling and return codes. The use ofTaskType.ERROR_DEBUGGINGensures correct routing to the optimal LLM.
750-753: LGTM: Command dispatch properly implemented.The diagnose command is correctly wired into the main dispatch logic with appropriate argument passing.
72-86: LGTM: Provider selection logic supports offline mode.The provider detection correctly prioritizes explicit configuration, auto-detects from API keys, and falls back to Ollama for offline operation. This aligns well with the PR objective of providing an offline-safe fallback.
51b9e61 to
8cff3dc
Compare
3245365 to
4da6b73
Compare
CLA Verification FailedThe following contributors have not signed the Contributor License Agreement:
How to Sign
Verified SignersThis check runs automatically. Maintainers can update |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
cortex/llm_router.py (1)
544-610: Critical: Infinite recursion still possible inacompletemethod.The
acompletemethod lacks the_is_fallbackguard that was added to thecompletemethod. If both providers fail, the async path will recurse indefinitely between them.Flow demonstrating infinite recursion:
acomplete()routes to Claude → fails- Fallback to Kimi K2 via
force_provider(line 601-608) → fails- Fallback to Claude again → fails → loop continues
The synchronous
completemethod was fixed with the_is_fallbackparameter (lines 269, 310, 325), butacompletewas not updated with the same protection.🔎 Proposed fix: Add _is_fallback guard to acomplete
async def acomplete( self, messages: list[dict[str, str]], task_type: TaskType = TaskType.USER_CHAT, force_provider: LLMProvider | None = None, temperature: float = 0.7, max_tokens: int = 4096, tools: list[dict] | None = None, + _is_fallback: bool = False, ) -> LLMResponse: """ Async version of complete() - Generate completion using the most appropriate LLM. Args: messages: Chat messages in OpenAI format task_type: Type of task (determines routing) force_provider: Override routing decision temperature: Sampling temperature max_tokens: Maximum response length tools: Tool definitions for function calling Returns: LLMResponse with content and metadata """ start_time = time.time() # Route to appropriate LLM routing = self.route_task(task_type, force_provider) logger.info(f"🧭 Routing: {routing.reasoning}") try: if routing.provider == LLMProvider.CLAUDE: response = await self._acomplete_claude(messages, temperature, max_tokens, tools) elif routing.provider == LLMProvider.KIMI_K2: response = await self._acomplete_kimi(messages, temperature, max_tokens, tools) else: # OLLAMA response = await self._acomplete_ollama(messages, temperature, max_tokens, tools) response.latency_seconds = time.time() - start_time # Track stats if self.track_costs: self._update_stats(response) return response except Exception as e: logger.error(f"❌ Error with {routing.provider.value}: {e}") - # Try fallback if enabled - if self.enable_fallback: + if self.enable_fallback and not _is_fallback: fallback_provider = ( LLMProvider.KIMI_K2 if routing.provider == LLMProvider.CLAUDE else LLMProvider.CLAUDE ) logger.info(f"🔄 Attempting fallback to {fallback_provider.value}") return await self.acomplete( messages=messages, task_type=task_type, force_provider=fallback_provider, temperature=temperature, max_tokens=max_tokens, tools=tools, + _is_fallback=True, ) - else: - raise + + raise
🧹 Nitpick comments (2)
cortex/llm_router.py (2)
20-20: Remove unused import.The
asdictfunction is imported but never used in this file.🔎 Proposed fix
-from dataclasses import asdict, dataclass +from dataclasses import dataclassAs per coding guidelines, follow PEP 8 style guide.
73-73: Consider adding validation for the confidence field.The comment indicates confidence should be between 0.0 and 1.0, but there's no runtime validation to enforce this constraint. Consider adding validation in
__post_init__or using a property setter if strict bounds checking is desired.🔎 Example validation approach
@dataclass class RoutingDecision: """Details about why a specific LLM was chosen.""" provider: LLMProvider task_type: TaskType reasoning: str confidence: float # 0.0 to 1.0 def __post_init__(self): if not 0.0 <= self.confidence <= 1.0: raise ValueError(f"confidence must be between 0.0 and 1.0, got {self.confidence}")
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
cortex/cli.pycortex/llm_router.py
🚧 Files skipped from review as they are similar to previous changes (1)
- cortex/cli.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs
Files:
cortex/llm_router.py
🧬 Code graph analysis (1)
cortex/llm_router.py (1)
cortex/logging_system.py (1)
info(200-202)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Build Package
- GitHub Check: test (3.11)
- GitHub Check: test (3.12)
- GitHub Check: test (3.10)
🔇 Additional comments (2)
cortex/llm_router.py (2)
169-169: LGTM: Appropriate log level for optional component.Changing from warning to info is correct since Kimi K2 is an optional provider. This reduces unnecessary noise when the provider is not configured.
269-269: LGTM: Fallback recursion protection correctly implemented.The
_is_fallbackparameter effectively prevents infinite recursion by ensuring that a fallback attempt cannot itself trigger another fallback. The logic correctly:
- Accepts fallback attempts only when not already in a fallback state (line 310)
- Marks recursive calls with
_is_fallback=True(line 325)- Raises the exception if fallback is disabled or already attempted (line 328)
Note: The
_is_fallbackparameter is not documented in the method's docstring. While it's a private parameter (indicated by the leading underscore), consider adding a brief note for maintainability.Also applies to: 310-328
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pavanimanchala53 CLA verification is failing, Kindly update your branch.
Also, tests are missing in PR.
Anshgrover23
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pavanimanchala53 Please follow the updated contribution guidelines. We’ve added new rules around AI usage in CONTRIBUTING.md. 2e68b29
Kindly update all your PRs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
cortex/cli.py (1)
1-1944: The diagnose command implementation is completely missing — this is a critical blocker.This PR's primary objective is to add the
cortex diagnosecommand with offline fallback, but the entire implementation is absent from the codebase:
- No
diagnose()method in theCortexCLIclass- No
diagnose_parserin the argument parsing section- No dispatch handler for the
diagnosecommand inmain()Per prior review comments, the diagnose command was implemented across commits e694b28 to cdd5b25 and marked as addressed. Given the merge conflicts mentioned in this PR (after PRs #297 and #299) and the duplicate code regression present in the file, the diagnose implementation was lost during conflict resolution.
Restore the complete diagnose command implementation, including:
- The
CortexCLI.diagnose()method with proper docstring- The argument parser with
--imageand--clipboardoptions- The dispatch handler in
main()- The offline fallback logic for when no LLM provider is configured
Without this, the PR delivers none of its stated functionality.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
cortex/cli.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs
Files:
cortex/cli.py
🧠 Learnings (2)
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Implement audit logging to ~/.cortex/history.db for all package operations
Applied to files:
cortex/cli.py
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Dry-run by default for all installations in command execution
Applied to files:
cortex/cli.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: test (3.10)
- GitHub Check: test (3.11)
- GitHub Check: test (3.12)
c819d1d to
b7a6db2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
♻️ Duplicate comments (1)
cortex/cli.py (1)
35-39: Critical: Remove duplicate logging and sys.path configuration.Lines 35-39 are exact duplicates of lines 29-33. This redundant code was previously addressed in commit bbb036b but has regressed, likely due to merge conflict resolution.
Based on past review comments, this was previously fixed but regressed during rebase.
🔎 Proposed fix
-# Suppress noisy log messages in normal operation -logging.getLogger("httpx").setLevel(logging.WARNING) -logging.getLogger("cortex.installation_history").setLevel(logging.ERROR) - -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) -
🧹 Nitpick comments (1)
cortex/llm_router.py (1)
332-380: Enhance docstring to meet coding guidelines requirements.While the method has a basic docstring, the coding guidelines require comprehensive documentation for all public APIs, including parameter descriptions, return value details, and exception information.
As per coding guidelines, docstrings required for all public APIs and type hints required in Python code.
🔎 Proposed enhancement
def diagnose_image(self, image: Image.Image) -> str: """ Diagnose an error screenshot using Claude Vision. - Safe fallback if Claude is unavailable. + + Args: + image: PIL Image object containing the error screenshot. + + Returns: + Diagnosis text with suggested fixes, or a fallback message if Claude Vision + is unavailable. In case of analysis failure, returns a generic error message. + + Notes: + - Converts image to PNG format before sending to Claude Vision + - Uses claude-3-opus-20240229 model with 500 token limit + - Safe fallback provided when Claude API is not configured + - Does not raise exceptions; returns error messages as strings """
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
cortex/cli.pycortex/llm_router.pytests/test_diagnose_image.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs
Files:
tests/test_diagnose_image.pycortex/llm_router.pycortex/cli.py
tests/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
Maintain >80% test coverage for pull requests
Files:
tests/test_diagnose_image.py
🧠 Learnings (1)
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Dry-run by default for all installations in command execution
Applied to files:
cortex/cli.py
🧬 Code graph analysis (2)
tests/test_diagnose_image.py (1)
cortex/llm_router.py (1)
diagnose_image(332-380)
cortex/cli.py (1)
cortex/llm_router.py (1)
diagnose_image(332-380)
🪛 GitHub Actions: CI
cortex/cli.py
[error] 1928-1928: Ruff: I001 Import block is un-sorted or un-formatted.
🪛 GitHub Actions: Cortex Automation
cortex/llm_router.py
[error] 22-22: ModuleNotFoundError: No module named 'PIL'. Importing Image failed during test collection.
cortex/cli.py
[error] 1928-1928: I001 Import block is unsorted or un-formatted. Ruff: 'Import block is unsorted or un-formatted'.
🪛 GitHub Check: lint
tests/test_diagnose_image.py
[failure] 28-28: Ruff (W292)
tests/test_diagnose_image.py:28:45: W292 No newline at end of file
[failure] 1-4: Ruff (I001)
tests/test_diagnose_image.py:1:1: I001 Import block is un-sorted or un-formatted
cortex/cli.py
[failure] 1928-1929: Ruff (I001)
cortex/cli.py:1928:13: I001 Import block is un-sorted or un-formatted
🪛 GitHub Check: Lint
tests/test_diagnose_image.py
[failure] 28-28: Ruff (W292)
tests/test_diagnose_image.py:28:45: W292 No newline at end of file
[failure] 1-4: Ruff (I001)
tests/test_diagnose_image.py:1:1: I001 Import block is un-sorted or un-formatted
cortex/cli.py
[failure] 1928-1929: Ruff (I001)
cortex/cli.py:1928:13: I001 Import block is un-sorted or un-formatted
🔇 Additional comments (5)
cortex/cli.py (2)
23-23: LGTM: Import of LLMRouter enables diagnose functionality.This import is necessary for the new diagnose command implementation that leverages
LLMRouter.diagnose_image().
1645-1666: LGTM: Diagnose subcommand parser correctly defines --image, --clipboard, and --text.The parser structure is correct and defines the expected arguments for the diagnose command.
cortex/llm_router.py (3)
20-23: LGTM: New imports support image diagnosis functionality.The new imports (
io,base64,PIL.Image, and dataclass utilities) are necessary for thediagnose_imagemethod implementation.
272-272: Excellent: Prevents infinite recursion in fallback logic.The addition of the
_is_fallbackparameter and its usage at lines 313 and 328 correctly prevents infinite recursion when both providers fail. This addresses a critical issue identified in previous reviews.Based on past review comments, this was previously identified and has now been correctly fixed.
Also applies to: 313-313, 328-329
172-172: LGTM: Improved log level for missing Kimi key.Changed from warning to info level is appropriate since a missing Kimi key is informational (not a warning) when other providers are available.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (4)
cortex/cli.py (3)
1928-1929: Fix import sorting to comply with PEP 8The deferred imports are unsorted. Standard library imports (
io) should come before third-party imports (PIL.Image).As per coding guidelines, follow PEP 8 style guide.
🔎 Proposed fix
elif args.command == "diagnose": + import io + from PIL import Image - import io
35-40: Remove duplicate logging and sys.path configuration (regression)Lines 35-40 are exact duplicates of lines 29-33. This redundant code was previously addressed in commit bbb036b but has regressed, likely during merge conflict resolution.
Based on past review comments, this was previously fixed but regressed during rebase.
🔎 Proposed fix
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) - -# Suppress noisy log messages in normal operation -logging.getLogger("httpx").setLevel(logging.WARNING) -logging.getLogger("cortex.installation_history").setLevel(logging.ERROR) - -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) - class CortexCLI:
1927-1967: Critical: Fix argument name mismatch and missing return valueTwo critical bugs in the diagnose command implementation:
- Line 1959:
returnstatement without a value should bereturn 0- Line 1961: References
args.messagebut the parser defines--text(line 1663), so it should beargs.text🔎 Proposed fix
if image: cx_print("🔍 Analyzing error screenshot...") diagnosis = router.diagnose_image(image) cx_print(diagnosis) - return + return 0 - if args.message: + if args.text: print("📝 Text diagnosis placeholder") - print(args.message) + print(args.text) return 0cortex/llm_router.py (1)
28-28: Critical: PIL import causes ModuleNotFoundError for users without PillowThe module-level
from PIL import Imageimport (line 28) will cause a ModuleNotFoundError for any user who doesn't have Pillow installed, breaking the entirecortex.llm_routermodule and all commands—not justdiagnose.The pipeline failure confirms this: "ModuleNotFoundError: No module named 'PIL'".
Solution: Move the PIL import into
diagnose_image()and handle ImportError gracefully:🔎 Proposed fix
Remove the module-level import:
from anthropic import Anthropic, AsyncAnthropic from openai import AsyncOpenAI, OpenAI -from PIL import ImageMove it into the method with error handling:
def diagnose_image(self, image: Image.Image) -> str: """ Diagnose an error screenshot using Claude Vision. Safe fallback if Claude is unavailable. """ + try: + from PIL import Image + except ImportError: + logger.warning("PIL not installed, image diagnosis unavailable") + return ( + "Image diagnosis requires Pillow.\n" + "Install with: pip install Pillow\n" + ) if not self.claude_client:Also update the type hint to use string annotation to avoid runtime import:
- def diagnose_image(self, image: Image.Image) -> str: + def diagnose_image(self, image: "Image.Image") -> str:
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
cortex/cli.pycortex/llm_router.pytests/test_diagnose_image.py
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/test_diagnose_image.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs
Files:
cortex/cli.pycortex/llm_router.py
🧠 Learnings (1)
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Dry-run by default for all installations in command execution
Applied to files:
cortex/cli.py
🧬 Code graph analysis (1)
cortex/cli.py (1)
cortex/llm_router.py (2)
LLMRouter(79-900)diagnose_image(333-381)
🪛 GitHub Actions: Cortex Automation
cortex/llm_router.py
[error] 1-1: ModuleNotFoundError: No module named 'PIL' when importing Image from PIL in cortex/llm_router.py.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Lint
🔇 Additional comments (7)
cortex/cli.py (2)
23-23: LGTM: LLMRouter importThe import is correctly placed and necessary for the new diagnose command implementation at line 1953.
1645-1666: Parser definition looks correct, but check implementationThe diagnose parser correctly defines --image, --clipboard, and --text arguments. However, note that the implementation at line 1961 incorrectly references
args.messageinstead ofargs.text.cortex/llm_router.py (5)
76-76: LGTM: Added confidence field to RoutingDecisionThe new
confidencefield is properly typed and documented. It's correctly initialized inroute_task()(lines 227 and 261) and provides a foundation for future confidence-based routing decisions.
172-172: LGTM: Appropriate logging level for optional Kimi providerChanging from
logger.warningtologger.infois correct. Since Kimi K2 is an optional provider (with fallback to Claude or Ollama), its unavailability is informational rather than a warning.
272-272: LGTM: Fallback recursion guard prevents infinite loopsThe
_is_fallbackparameter correctly prevents infinite recursion in the fallback logic:
- Primary provider fails → attempts fallback with
_is_fallback=True- Fallback fails → check
not _is_fallbackprevents another attempt → raises exceptionThis implementation properly addresses the infinite recursion issue flagged in past reviews.
Based on past review comments, this was addressed in commits e694b28 to 4da6b73.
Also applies to: 313-331
436-436: LGTM: Improved readability with parenthesized expressionsAdding parentheses around the conditional expressions for
raw_responseimproves code clarity without changing functionality. This is a good stylistic improvement for consistency.Also applies to: 479-479
556-556: LGTM: Docstring capitalization consistencyChanging "Dictionary" to "dictionary" improves consistency with typical Python docstring conventions for return type descriptions.
fea17cb to
671bb33
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
cortex/llm_router.py (1)
652-673: Asyncacomplete()lacks the_is_fallbackguard, causing potential infinite recursion.The sync
complete()method was correctly updated with_is_fallbackto prevent infinite recursion (lines 271, 312, 327), but the asyncacomplete()method still has the same vulnerability. If both providers fail, the fallback will recurse indefinitely.🔎 Proposed fix
async def acomplete( self, messages: list[dict[str, str]], task_type: TaskType = TaskType.USER_CHAT, force_provider: LLMProvider | None = None, temperature: float = 0.7, max_tokens: int = 4096, tools: list[dict] | None = None, + _is_fallback: bool = False, ) -> LLMResponse: ... except Exception as e: logger.error(f"❌ Error with {routing.provider.value}: {e}") # Try fallback if enabled - if self.enable_fallback: + if self.enable_fallback and not _is_fallback: fallback_provider = ( LLMProvider.KIMI_K2 if routing.provider == LLMProvider.CLAUDE else LLMProvider.CLAUDE ) logger.info(f"🔄 Attempting fallback to {fallback_provider.value}") return await self.acomplete( messages=messages, task_type=task_type, force_provider=fallback_provider, temperature=temperature, max_tokens=max_tokens, tools=tools, + _is_fallback=True, ) - else: - raise + + raise
♻️ Duplicate comments (3)
cortex/llm_router.py (1)
332-391: Enhance error handling and docstring indiagnose_image().The method has several areas for improvement:
- Missing type hint on
imageparameter (per coding guidelines, type hints are required)- Bare
except Exceptionat line 389 catches all errors including authentication and rate-limit failures- Incomplete docstring: Missing Args, Returns, and Raises documentation
As per coding guidelines, type hints and docstrings are required for all public APIs.
🔎 Proposed improvements
- def diagnose_image(self, image) -> str: + def diagnose_image(self, image: "Image.Image") -> str: """ Diagnose an error screenshot using Claude Vision. - Safe fallback if Claude or vision support is unavailable. + + Args: + image: PIL Image object containing the error screenshot + + Returns: + String containing the diagnosis and suggested fixes + + Raises: + RuntimeError: If Claude Vision API call fails after retries """ ... - except Exception as e: + except Exception as e: # Consider specific exceptions: APIError, RateLimitError logger.error(f"Claude Vision failed: {e}") - return "Failed to analyze image. Please try again." + raise RuntimeError(f"Image diagnosis failed: {e}") from ecortex/cli.py (2)
35-39: Remove duplicate logging and sys.path configuration.Lines 35-39 duplicate the configuration already present at lines 29-33. This redundant code should be removed.
🔎 Proposed fix
-# Suppress noisy log messages in normal operation -logging.getLogger("httpx").setLevel(logging.WARNING) -logging.getLogger("cortex.installation_history").setLevel(logging.ERROR) - -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) -
1955-1964: Fix missing return value and incorrect argument name.Two bugs in the diagnose command implementation:
- Line 1959:
returnwithout a value should bereturn 0- Lines 1961, 1963: References
args.messagebut the parser defines--text(line 1663), so it should beargs.text🔎 Proposed fix
if image: cx_print("🔍 Analyzing error screenshot...") diagnosis = router.diagnose_image(image) cx_print(diagnosis) - return + return 0 - if args.message: + if args.text: print("📝 Text diagnosis placeholder") - print(args.message) + print(args.text) return 0
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
cortex/cli.pycortex/llm_router.pytests/test_diagnose_image.py
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/test_diagnose_image.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs
Files:
cortex/cli.pycortex/llm_router.py
🧠 Learnings (1)
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Dry-run by default for all installations in command execution
Applied to files:
cortex/cli.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Test (Python 3.11)
- GitHub Check: test (3.11)
- GitHub Check: test (3.12)
- GitHub Check: test (3.10)
🔇 Additional comments (5)
cortex/cli.py (2)
23-23: LGTM!The
LLMRouterimport properly exposes the router for the new diagnose functionality.
1645-1666: LGTM!The diagnose subparser is well-structured with clear help text for the
--image,--clipboard, and--textarguments.cortex/llm_router.py (3)
15-16: LGTM!The
base64andioimports are correctly added to support image encoding indiagnose_image.
271-271: Good implementation of the_is_fallbackguard.The
_is_fallbackparameter correctly prevents infinite recursion in the fallback logic.
446-446: LGTM!The parenthesized tuple expression for
raw_responseis a valid style choice.
eba3372 to
12f28e7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (2)
cortex/cli.py (2)
1928-1930: Fix import sorting to comply with PEP 8.The deferred imports are not in the correct order. Standard library imports (
io) must come before third-party imports (PIL.Image).As per coding guidelines, follow PEP 8 style guide.
🔎 Proposed fix
- elif args.command == "diagnose": - from PIL import Image + elif args.command == "diagnose": import io + from PIL import Image +Based on past review comments, this was previously addressed in commit b7a6db2 but may have regressed.
35-39: Critical regression: Remove duplicate logging and sys.path configuration.Lines 35-39 are exact duplicates of lines 29-33. This redundant code was previously addressed in commit bbb036b but has reappeared, likely due to incorrect merge conflict resolution during rebase.
This duplication serves no purpose and should be removed immediately.
🔎 Proposed fix
-# Suppress noisy log messages in normal operation -logging.getLogger("httpx").setLevel(logging.WARNING) -logging.getLogger("cortex.installation_history").setLevel(logging.ERROR) - -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) -Based on past review comments, this was previously fixed but regressed during rebase.
🧹 Nitpick comments (2)
cortex/llm_router.py (2)
14-22: Fix import ordering to comply with PEP 8.The standard library imports are not in alphabetical order.
base64andioshould come beforeasyncio, and the entire block should be sorted alphabetically.As per coding guidelines, follow PEP 8 style guide.
🔎 Proposed fix
-import asyncio -import base64 -import io import json import logging import os +import asyncio +import base64 +import io import threading import timeActually, the correct alphabetical order for all standard library imports should be:
+import asyncio +import base64 +import io import json import logging import os import threading import time
332-397: Address remaining issues from past reviews: type hints and error specificity.While the core implementation is sound, there are still improvements needed based on past review feedback:
Remaining issues:
- Missing type hint for
imageparameter (line 332): Should beimage: "Image.Image"or use proper typing- Incomplete docstring: Missing Args, Returns, and Raises sections per coding guidelines
- Generic fallback messages (lines 342-346, 352-356): Messages about "Sudo disabled" and "Permission error" don't make sense for image diagnosis—these are copy-pasted from another context
As per coding guidelines, type hints required in Python code and docstrings required for all public APIs.
🔎 Proposed improvements
- def diagnose_image(self, image) -> str: + def diagnose_image(self, image: "Image.Image") -> str: """ Diagnose an error screenshot using Claude Vision. - Safe fallback if Claude or vision support is unavailable. + + Args: + image: PIL Image object containing the error screenshot + + Returns: + String containing the diagnosis and suggested fixes, or a + fallback message if Claude Vision is unavailable + + Raises: + No exceptions raised; errors return descriptive fallback strings """ try: from PIL import Image except ImportError: logger.warning("Pillow not installed, using fallback diagnosis") return ( - "Image diagnosis unavailable (missing Pillow).\n" - "Possible causes:\n" - "- Sudo disabled\n" - "- Permission error\n" - "- Missing dependency\n" + "Image diagnosis unavailable.\n" + "Install Pillow to enable image analysis:\n" + " pip install pillow>=9.0.0\n" ) if not self.claude_client: logger.warning("Claude Vision unavailable, using fallback diagnosis") return ( - "Claude Vision unavailable.\n" - "Possible causes:\n" - "- Sudo disabled\n" - "- Permission error\n" - "- Missing dependency\n" + "Claude Vision unavailable.\n" + "Configure Claude API key to enable image diagnosis:\n" + " export ANTHROPIC_API_KEY=your_key\n" + "Or run: cortex wizard\n" )
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
cortex/cli.pycortex/llm_router.pypyproject.tomlrequirements-dev.txtrequirements.txttests/test_diagnose_image.py
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/test_diagnose_image.py
🧰 Additional context used
📓 Path-based instructions (2)
{setup.py,setup.cfg,pyproject.toml,**/__init__.py}
📄 CodeRabbit inference engine (AGENTS.md)
Use Python 3.10 or higher as the minimum supported version
Files:
pyproject.toml
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs
Files:
cortex/cli.pycortex/llm_router.py
🧠 Learnings (1)
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Dry-run by default for all installations in command execution
Applied to files:
cortex/cli.py
🧬 Code graph analysis (2)
cortex/cli.py (1)
cortex/llm_router.py (2)
LLMRouter(78-916)diagnose_image(332-397)
cortex/llm_router.py (1)
cortex/logging_system.py (3)
info(200-202)format(41-60)format(75-87)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Test (Python 3.10)
- GitHub Check: test (3.12)
- GitHub Check: test (3.11)
- GitHub Check: test (3.10)
🔇 Additional comments (10)
requirements-dev.txt (1)
11-11: LGTM! Development dependency addition is appropriate.The addition of
pillow>=9.0.0to development dependencies is consistent with the new image-based diagnosis feature and aligns with the corresponding additions inrequirements.txtandpyproject.toml.requirements.txt (1)
7-7: LGTM! Production dependency addition is correct.The addition of
pillow>=9.0.0is necessary for the new image diagnosis functionality and is consistent across all dependency files (requirements.txt,requirements-dev.txt, andpyproject.toml).pyproject.toml (1)
50-50: LGTM! Dependency declaration is consistent.The addition of
pillow>=9.0.0to the project dependencies is correct and consistent with the additions inrequirements.txtandrequirements-dev.txt. The version constraint is appropriate for Python 3.10+ projects.cortex/llm_router.py (4)
171-171: LGTM! Log level change is appropriate.Changing from
logger.warningtologger.infofor the Kimi unavailability message is correct. Missing Kimi K2 is not necessarily a problem since other providers (Claude, Ollama) may be available, so an info-level message is more appropriate than a warning.
271-271: LGTM! Infinite recursion fix is correctly implemented.The addition of the
_is_fallbackparameter and associated logic correctly prevents infinite recursion when both providers fail. The guard ensures that fallback is only attempted once:
- Line 271: Parameter added with default
False- Line 312: Fallback only triggered if
not _is_fallback- Line 327: Recursive call passes
_is_fallback=TrueThis addresses the critical issue flagged in past reviews where fallback could alternate between providers indefinitely.
Also applies to: 312-330
452-452: LGTM! Parentheses improve readability.Wrapping the
raw_responseternary expressions in parentheses improves code readability. This is a good stylistic improvement that makes the conditional assignment more clear.Also applies to: 495-495
572-572: LGTM! Docstring capitalization fix.Changing "Dictionary" to "dictionary" improves consistency with standard Python documentation style, which typically uses lowercase for type names in prose.
cortex/cli.py (3)
23-23: LGTM! Import addition is necessary and correctly placed.The
from cortex.llm_router import LLMRouterimport is required for the new diagnose functionality and is placed appropriately within the cortex module imports section.
1645-1666: LGTM! Diagnose subcommand parser is well-defined.The diagnose subcommand parser correctly defines three input methods:
--image: Path to screenshot file--clipboard: Read from clipboard--text: Raw error text fallbackThe argument definitions are clear and properly typed, with helpful descriptions for users.
1927-1967: Verify error handling for malformed images.The image loading code handles
Exceptionbroadly (lines 1937-1939, 1949-1951), which is good for user experience. However, consider whether specific PIL exceptions (likePIL.UnidentifiedImageErrorfor corrupt files) should be caught separately to provide more helpful error messages.This is a nice-to-have improvement rather than a critical issue. The current generic exception handling is acceptable for an MVP.
12f28e7 to
fe975fd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
cortex/llm_router.py (1)
1-1135: Critical: Fix Black formatting to pass CI pipeline.The pipeline reports: "Black formatting check failed. 1 file would be reformatted (llm_router.py)."
Run Black to auto-format the file:
#!/bin/bash # Description: Format the file with Black black cortex/llm_router.py --line-length 100 # Verify formatting black --check cortex/llm_router.py --line-length 100Note: The project's
pyproject.tomlconfigures Black withline-length = 100(line 96), so ensure you use the same setting.
♻️ Duplicate comments (4)
tests/test_diagnose_image.py (2)
1-6: Fix import sorting and clarify importorskip usage.Two issues:
- Import order violates PEP 8: Third-party imports (PIL) should come before local imports (cortex), but after standard library (pytest).
- Redundant import pattern: Line 3 uses
pytest.importorskip("PIL")to skip tests if Pillow is missing, but line 4 importsfrom PIL import Imageunconditionally, which would fail if Pillow is not installed.As per coding guidelines, follow PEP 8 style guide.
🔎 Proposed fix
-import pytest - -PIL = pytest.importorskip("PIL", reason="Pillow not installed") -from PIL import Image - -from cortex.llm_router import LLMRouter +import pytest + +from cortex.llm_router import LLMRouter + +# Skip entire module if Pillow not available +pytest.importorskip("PIL", reason="Pillow not installed") +from PIL import ImageNote: The
importorskipshould come before thefrom PIL import Imageto prevent import errors.
30-30: Add missing newline at end of file.PEP 8 requires files to end with a newline character.
As per coding guidelines, follow PEP 8 style guide.
🔎 Proposed fix
router = LLMRouter() assert hasattr(router, "diagnose_image") +cortex/cli.py (2)
35-40: Critical regression: Remove duplicate logging and sys.path configuration.Lines 35-39 exactly duplicate lines 29-33. This redundant configuration was previously flagged and marked as "Addressed in commit bbb036b" but has reappeared in the current code, indicating a merge conflict resolution error.
🔎 Proposed fix
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) -# Suppress noisy log messages in normal operation -logging.getLogger("httpx").setLevel(logging.WARNING) -logging.getLogger("cortex.installation_history").setLevel(logging.ERROR) - -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) - class CortexCLI:Based on past review comments, this was previously fixed but regressed during rebase.
1928-1930: Fix import sorting to comply with PEP 8.The deferred imports are out of order. Standard library imports (
io) must come before third-party imports (PIL.Image).As per coding guidelines, follow PEP 8 style guide.
🔎 Proposed fix
elif args.command == "diagnose": import io from PIL import Image - import io
🧹 Nitpick comments (2)
cortex/cli.py (1)
1961-1964: Text diagnosis is a non-functional placeholder.The text diagnosis path (lines 1961-1964) simply echoes the input text without any actual diagnosis. This contradicts the PR description which states: "Implements a text-based diagnosis command."
Current behavior:
- ❌ No actual error analysis
- ❌ No suggestions or fixes provided
- ❌ Just prints the input back to the user
Based on the PR objectives stating this is an "MVP implementation" with "offline-safe fallback," consider implementing basic text diagnosis using
LLMRouter.complete()or document this as explicitly not implemented yet.💡 Suggested implementation using LLMRouter
if args.text: - print("📝 Text diagnosis placeholder") - print(args.text) + cx_print("🔍 Analyzing error message...") + try: + response = router.complete( + messages=[{ + "role": "user", + "content": f"Diagnose this Linux error and suggest fixes:\n{args.text}" + }], + task_type=TaskType.ERROR_DEBUGGING + ) + print("\nDiagnosis:\n") + print(response.content) + except Exception as e: + self._print_error(f"Diagnosis failed: {e}") + return 1 return 0Note: You'll need to import
TaskTypefromcortex.llm_routerif implementing this suggestion.cortex/llm_router.py (1)
332-397: Missing type hint and incomplete docstring for public API.The
diagnose_imagemethod is a public API but:
- Missing return type hint in the signature (should be
-> str)- Incomplete docstring - missing Args, Returns, and Raises sections
As per coding guidelines, type hints required in Python code and docstrings required for all public APIs.
🔎 Proposed enhancement
- def diagnose_image(self, image) -> str: + def diagnose_image(self, image: "Image.Image") -> str: """ Diagnose an error screenshot using Claude Vision. - Safe fallback if Claude or vision support is unavailable. + + Provides safe fallbacks when Claude Vision or Pillow are unavailable. + + Args: + image: PIL Image object containing the error screenshot + + Returns: + String containing diagnosis and suggested fixes, or fallback guidance + + Raises: + No exceptions raised - returns error messages as strings instead """Note: The type hint uses a string literal
"Image.Image"to avoid requiring PIL at import time.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
cortex/cli.pycortex/llm_router.pypyproject.tomlrequirements-dev.txtrequirements.txttests/test_diagnose_image.py
🚧 Files skipped from review as they are similar to previous changes (2)
- requirements.txt
- requirements-dev.txt
🧰 Additional context used
📓 Path-based instructions (3)
{setup.py,setup.cfg,pyproject.toml,**/__init__.py}
📄 CodeRabbit inference engine (AGENTS.md)
Use Python 3.10 or higher as the minimum supported version
Files:
pyproject.toml
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs
Files:
tests/test_diagnose_image.pycortex/llm_router.pycortex/cli.py
tests/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
Maintain >80% test coverage for pull requests
Files:
tests/test_diagnose_image.py
🧠 Learnings (1)
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Dry-run by default for all installations in command execution
Applied to files:
cortex/cli.py
🧬 Code graph analysis (2)
tests/test_diagnose_image.py (1)
cortex/llm_router.py (1)
diagnose_image(332-397)
cortex/cli.py (1)
cortex/llm_router.py (1)
diagnose_image(332-397)
🪛 GitHub Actions: CI
cortex/llm_router.py
[error] 1-1: Black formatting check failed. 1 file would be reformatted ( llm_router.py ). Run 'black' to auto-format the code. Command: black --check . --exclude "(venv|.venv|build|dist)"
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: test (3.10)
- GitHub Check: test (3.11)
- GitHub Check: test (3.12)
🔇 Additional comments (8)
tests/test_diagnose_image.py (1)
9-22: LGTM: Fallback test coverage is appropriate.The test correctly verifies that
diagnose_imagereturns a fallback message when Claude is unavailable, which aligns with the offline-safe fallback design goal stated in the PR objectives.cortex/cli.py (2)
1645-1666: LGTM: Diagnose subcommand parser definition is well-structured.The argument parser clearly defines three input options (--image, --clipboard, --text) with appropriate help text. This aligns with the MVP scope mentioned in the PR objectives.
1934-1959: LGTM: Image loading logic handles errors appropriately.The implementation correctly:
- Opens images from file paths with error handling
- Reads from clipboard using ImageGrab with proper exception handling
- Provides clear error messages when operations fail
- Returns appropriate exit codes
cortex/llm_router.py (4)
15-22: LGTM: New imports support image diagnosis feature.The addition of
base64andioimports is necessary for thediagnose_imagemethod's image encoding functionality. The import organization follows PEP 8 ordering (standard library, then third-party).
271-271: LGTM:_is_fallbackparameter prevents infinite recursion.The addition of the
_is_fallbackparameter (with a leading underscore indicating it's internal) is the correct fix for the infinite recursion issue flagged in past reviews. This prevents the fallback mechanism from recursing indefinitely when both providers fail.Based on past review comments, this addresses the infinite recursion concern raised previously.
312-330: LGTM: Fallback logic correctly guards against infinite recursion.The guard
if self.enable_fallback and not _is_fallback:(line 312) combined with passing_is_fallback=Truein the recursive call (line 327) ensures that fallback only happens once. If both providers fail, the exception is re-raised instead of looping infinitely.Based on past review comments, this implementation properly addresses the infinite recursion risk.
452-452: LGTM: raw_response assignments use safe attribute access.The parenthesized conditional expressions
(response.model_dump() if hasattr(response, "model_dump") else None)correctly handle cases where the response object might not have amodel_dumpmethod. This is good defensive coding.Also applies to: 495-495
pyproject.toml (1)
50-50: Pillow 9.0.0 appears overly restrictive for the features actually used.The codebase only uses basic Pillow operations:
Image.new(),Image.open(),ImageGrab.grabclipboard(), andimage.save()with PNG format. All of these have been available in Pillow for many years, well before 9.0.0 (January 2022). No advanced features requiring 9.0.0+ (AVIF, WebP, ImageOps, ImageFilter, etc.) are in use.Consider either:
- Lowering the minimum version to reflect actual requirements (e.g.,
>=8.0.0or earlier)- Documenting if 9.0.0+ is chosen for other project policy reasons (e.g., maintaining recent dependencies across the board)
4538425 to
543ae6e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (4)
cortex/cli.py (3)
35-40: CRITICAL REGRESSION: Remove duplicate logging and sys.path configuration.Lines 35-40 are exact duplicates of lines 29-33. This code block was flagged in a previous review and marked as "✅ Addressed in commit bbb036b," but the duplication has reappeared—likely during a merge conflict resolution.
This redundant configuration serves no purpose and violates DRY principles.
Based on past review comments, this was previously fixed but regressed during rebase.
🔎 Proposed fix
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) -# Suppress noisy log messages in normal operation -logging.getLogger("httpx").setLevel(logging.WARNING) -logging.getLogger("cortex.installation_history").setLevel(logging.ERROR) - -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) - class CortexCLI:
1927-1930: CRITICAL REGRESSION: Fix import ordering to comply with PEP 8.Standard library imports (
import io) must come before third-party imports (from PIL import Image). This was flagged in a previous review and marked as "✅ Addressed in commit b7a6db2," but the imports remain unsorted—likely reintroduced during merge conflict resolution.As per coding guidelines, follow PEP 8 style guide.
🔎 Proposed fix
elif args.command == "diagnose": + import io + from PIL import Image - import io
1961-1964: Text diagnosis provides no actual functionality.The text path (lines 1961-1964) simply echoes the user's input back without any analysis or diagnosis. This is inconsistent with the PR objectives, which state the PR "implements a text-based diagnosis command" and "provides an offline-safe fallback."
Per the PR objectives and linked issue #266, image support is the primary goal, but this placeholder is misleading—it appears functional but does nothing useful.
Based on past review comments, this placeholder was previously flagged but not addressed.
Consider one of these approaches:
Implement basic text diagnosis using
LLMRouter.complete():if args.text: cx_print("🔍 Analyzing error message...") router = LLMRouter() response = router.complete( messages=[{ "role": "user", "content": f"Diagnose this Linux error and suggest fixes:\n{args.text}" }], task_type=TaskType.ERROR_DEBUGGING ) print(response.content) return 0Mark as not implemented if deferred:
if args.text: print("❌ Text diagnosis not yet implemented") print("Use --image or --clipboard for AI-powered diagnosis") return 1cortex/llm_router.py (1)
332-400: Enhance diagnose_image() with complete type hints and docstring.The implementation is functionally sound, but the public API is missing complete documentation required by the coding guidelines.
As per coding guidelines, type hints required in Python code and docstrings required for all public APIs.
🔎 Proposed improvements
- def diagnose_image(self, image) -> str: + def diagnose_image(self, image: "Image.Image") -> str: """ Diagnose an error screenshot using Claude Vision. - Safe fallback if Claude or vision support is unavailable. + + Args: + image: PIL Image object containing the error screenshot + + Returns: + String containing the diagnosis and suggested fixes, or a fallback + message if Claude Vision is unavailable + + Raises: + Does not raise exceptions; returns user-friendly fallback messages + if Pillow is not installed or Claude Vision API is unavailable + + Note: + Requires Pillow (PIL) and a configured Claude API key to function. + Falls back gracefully with installation/configuration instructions + if prerequisites are missing. """
🧹 Nitpick comments (2)
cortex/cli.py (1)
1955-1959: Add error handling for image diagnosis failures.The code assumes
router.diagnose_image(image)always returns a valid string, but exceptions or None returns could causecx_print()to fail. Whilediagnose_image()has internal error handling, defensive validation here improves robustness.🔎 Proposed improvement
if image: cx_print("🔍 Analyzing error screenshot...") diagnosis = router.diagnose_image(image) + if not diagnosis: + print("❌ Failed to diagnose image") + return 1 cx_print(diagnosis) return 0cortex/llm_router.py (1)
389-400: Consider more specific error logging in diagnose_image exception handler.The broad
except Exceptionat line 389 catches all errors (network failures, rate limits, auth errors, malformed responses) but logs them all with the same generic message. While the fallback message is user-friendly, more specific logging would aid debugging.🔎 Suggested improvement
except Exception as e: - logger.warning( - "Claude Vision unavailable, using fallback diagnosis", + logger.warning( + f"Claude Vision API call failed ({type(e).__name__}): {e}", exc_info=True, ) return ( "Claude Vision unavailable.\n" "Possible reasons:\n" "- Invalid or missing API key\n" "- Network or rate limit error\n" "- Claude service unavailable\n" )This preserves the user-facing fallback message while improving observability in logs.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
cortex/cli.pycortex/llm_router.pypyproject.tomlrequirements-dev.txtrequirements.txttests/test_diagnose_image.py
🚧 Files skipped from review as they are similar to previous changes (3)
- requirements.txt
- pyproject.toml
- tests/test_diagnose_image.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs
Files:
cortex/cli.pycortex/llm_router.py
🧠 Learnings (1)
📚 Learning: 2025-12-11T12:03:24.071Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-11T12:03:24.071Z
Learning: Applies to **/*install*.py : Dry-run by default for all installations in command execution
Applied to files:
cortex/cli.py
🧬 Code graph analysis (2)
cortex/cli.py (2)
cortex/llm_router.py (2)
LLMRouter(78-919)diagnose_image(332-400)cortex/branding.py (1)
cx_print(49-69)
cortex/llm_router.py (1)
cortex/logging_system.py (3)
info(200-202)format(41-60)format(75-87)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Test (Python 3.11)
- GitHub Check: test (3.10)
- GitHub Check: test (3.11)
- GitHub Check: test (3.12)
🔇 Additional comments (6)
cortex/cli.py (2)
23-23: LGTM: LLMRouter import is correct.The import is properly placed and enables the diagnose command to use the new
diagnose_image()method.
1645-1666: LGTM: Diagnose parser arguments are well-structured.The argument parser correctly defines
--image,--clipboard, and--textflags for the diagnose command, matching the PR objectives for image-based error diagnosis with text fallback.cortex/llm_router.py (3)
15-16: LGTM: Imports added for image diagnosis feature.The
base64andioimports are necessary for the newdiagnose_image()method to convert PIL Image objects to base64-encoded bytes for Claude Vision API.
271-271: LGTM: _is_fallback parameter prevents infinite recursion.The
_is_fallbackguard correctly prevents infinite fallback loops when both providers fail. This addresses a critical issue flagged in previous reviews.Based on past review comments, this fix was previously requested and is now properly implemented.
312-330: LGTM: Fallback logic correctly guards against infinite recursion.The updated fallback implementation:
- Checks
not _is_fallbackbefore attempting fallback (line 312)- Passes
_is_fallback=Trueon recursive call (line 327)- Raises exception if fallback is disabled or already attempted (line 330)
This prevents the infinite loop that was flagged in previous reviews.
Based on past review comments, this addresses the critical recursion issue that was identified earlier.
requirements-dev.txt (1)
11-11: Pillow is already in runtime dependencies (requirements.txt and pyproject.toml), so this is redundant.The diagnose command does import and use Pillow at runtime (in
cortex/cli.pyandcortex/llm_router.py), but Pillow is properly declared as a runtime dependency in bothrequirements.txtandpyproject.toml. Adding it torequirements-dev.txtis redundant since runtime dependencies are automatically included in development environments. Consider removing this entry fromrequirements-dev.txt.
543ae6e to
0631731
Compare
|
|
@pavanimanchala53 Duplicate of #484 Right ? |



Summary
Adds a minimal MVP implementation of
cortex diagnose.What’s included
Why
Example
cortex diagnose "apt install failed with dpkg error"closes cortexlinux/cortex-pro#2
Summary by CodeRabbit
New Features
Improvements
Bug Fixes
Tests
Chores
✏️ Tip: You can customize this high-level summary in your review settings.