-
Notifications
You must be signed in to change notification settings - Fork 61
LiteLLM integration #40
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
Conversation
WalkthroughThe pull request introduces a new module Changes
Sequence DiagramsequenceDiagram
participant User
participant LiteModel
participant LiteLLM
participant OllamaClient
User->>LiteModel: Initialize with model name
LiteModel->>LiteModel: Check API keys
LiteModel->>LiteLLM: Validate model
alt Model is Ollama
LiteModel->>OllamaClient: Check/Pull model
end
User->>LiteModel: Start chat session
LiteModel->>LiteModelChatSession: Create session
User->>LiteModelChatSession: Send message
LiteModelChatSession->>LiteLLM: Request completion
LiteLLM-->>LiteModelChatSession: Return response
LiteModelChatSession-->>User: Deliver response
Poem
Tip CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration 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: 7
🧹 Outside diff range and nitpick comments (4)
tests/test_kg_litellm_openai.py (1)
97-102: Enhance deletion test verificationThe deletion test could be more thorough in verifying cleanup.
Add additional verification:
def test_kg_delete(self): self.kg.delete() db = FalkorDB() graphs = db.list_graphs() self.assertNotIn(self.graph_name, graphs) + # Verify no orphaned nodes remain + actor_count = db.query("MATCH (a:Actor) RETURN COUNT(a)")[0][0] + movie_count = db.query("MATCH (m:Movie) RETURN COUNT(m)")[0][0] + self.assertEqual(actor_count + movie_count, 0, "Orphaned nodes found after deletion")graphrag_sdk/models/litellm.py (3)
85-85: Avoid using magic numbers; define a constant for message truncation limitThe truncation limit of
14385characters inmessage[:14385]is a magic number and may not be immediately clear to future developers. Consider defining a constant or making it a configurable parameter to improve code readability and maintainability.Apply this diff to define a constant:
+# At the top of the file or class, define the constant +MAX_MESSAGE_LENGTH = 14385 # In the `send_message` method: def send_message(self, message: str, output_method: OutputMethod = OutputMethod.DEFAULT) -> GenerationResponse: generation_config = self._get_generation_config(output_method) prompt = [] prompt.extend(self._history) - prompt.append({"role": "user", "content": message[:14385]}) + prompt.append({"role": "user", "content": message[:MAX_MESSAGE_LENGTH]}) response = completion( model=self._model.model_name, messages=prompt,
29-31: Update return type annotation toLiteLLMGenerativeModelfor method chainingThe
with_system_instructionmethod returnsself, which is an instance ofLiteLLMGenerativeModel. Updating the return type annotation toLiteLLMGenerativeModelimproves clarity and supports method chaining with subclass methods.Apply this diff to update the return type:
def with_system_instruction(self, system_instruction: str) -> "GenerativeModel": - self.system_instruction = system_instruction - return self + self.system_instruction = system_instruction + return self + def with_system_instruction(self, system_instruction: str) -> "LiteLLMGenerativeModel": + self.system_instruction = system_instruction + return self
96-103: Avoid mutating shared configuration dictionaryIn
_get_generation_config, modifying the dictionary returned byself._model.generation_config.to_json()could inadvertently affect other parts of the code if the same dictionary is used elsewhere. To prevent side effects, make a copy of the dictionary before modifying it.Apply this diff to make a copy of the configuration:
def _get_generation_config(self, output_method: OutputMethod): - config = self._model.generation_config.to_json() + config = self._model.generation_config.to_json().copy() if output_method == OutputMethod.JSON: config['temperature'] = 0 config['response_format'] = { "type": "json_object" }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (2)
graphrag_sdk/models/litellm.py(1 hunks)tests/test_kg_litellm_openai.py(1 hunks)
🔇 Additional comments (1)
tests/test_kg_litellm_openai.py (1)
80-84: Verify test data file contents and access
The test processes an external file which could pose security risks if not properly validated.
✅ Verification successful
Let me check the actual content of the file to better understand what kind of data we're dealing with.
Test data file is safe for use
The file madoff.txt contains publicly available IMDb content about a documentary series. It's non-sensitive test data that's consistently used across multiple test files for knowledge graph processing. The file has appropriate read-only permissions and contains no security-sensitive information.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check test data file permissions and content
echo "Checking test data file..."
if [ -f "tests/data/madoff.txt" ]; then
ls -l tests/data/madoff.txt
echo "File contents preview:"
head -n 5 tests/data/madoff.txt
else
echo "Warning: Test data file not found"
fi
# Check for other potential test data files that might contain sensitive information
echo "Checking for other data files..."
find tests/data -type f -name "*.txt" -exec ls -l {} \;
Length of output: 513
Script:
#!/bin/bash
# Get full content of the test file
echo "Full content of madoff.txt:"
cat tests/data/madoff.txt
# Check if this file is used in other tests
echo -e "\nChecking file usage in tests:"
rg "madoff.txt" tests/
Length of output: 6015
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
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (1)
poetry.lockis excluded by!**/*.lock
📒 Files selected for processing (1)
pyproject.toml(1 hunks)
🔇 Additional comments (1)
pyproject.toml (1)
29-29: Verify litellm version constraints
Let's verify if version ^1.52.14 is the latest stable version and check for any security advisories.
✅ Verification successful
litellm version 1.52.14 is up-to-date and secure
The specified version 1.52.14 is currently the latest stable version (released on November 22, 2024) and is well above all known vulnerability patches:
- SSRF vulnerability (patched in 1.44.8)
- Access control vulnerability (patched in 1.40.15)
- Remote code execution vulnerability (patched in 1.40.16)
- File deletion vulnerability (patched in 1.35.36)
- SQL injection vulnerability (patched in 1.40.0)
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check latest version and security advisories for litellm
# Check PyPI for latest versions
echo "Latest version from PyPI:"
curl -s https://pypi.org/pypi/litellm/json | jq -r '.info.version'
# Check release date of current version
echo -e "\nRelease date of specified version:"
curl -s https://pypi.org/pypi/litellm/1.52.14/json | jq -r '.urls[0].upload_time'
# Check for security advisories
echo -e "\nSecurity advisories:"
gh api graphql -f query='
{
securityVulnerabilities(first: 5, ecosystem: PIP, package: "litellm") {
nodes {
advisory {
summary
severity
publishedAt
}
vulnerableVersionRange
firstPatchedVersion {
identifier
}
}
}
}'
Length of output: 1814
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.
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 suggestions.
Comments skipped due to low confidence (1)
tests/test_kg_litellm_openai.py:95
- Use 'self.assertGreater' instead of 'assert' for better readability and consistency with other tests.
assert num_actors > 10, "The number of actors found should be greater than 10"
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
🧹 Outside diff range and nitpick comments (3)
graphrag_sdk/models/litellm.py (3)
36-47: Enhance method chaining by returning a new instanceThe
with_system_instructionmethod modifies the instance in place and returnsself. To make the model immutable and support method chaining without side effects, consider returning a new instance with the updatedsystem_instruction.Apply this diff to return a new instance:
def with_system_instruction(self, system_instruction: str) -> "GenerativeModel": self.system_instruction = system_instruction - return self + return LiteLLMGenerativeModel( + model_name=self.model_name, + generation_config=self.generation_config, + system_instruction=system_instruction, + )
122-136: Ensureargsare utilized or remove the parameterThe
__init__method accepts anargsparameter, but it is not used anywhere in the class. This might cause confusion or indicate incomplete implementation. Consider usingargswithin the class or removing the parameter if it's unnecessary.
159-159: Avoid hardcoding magic numbersUsing a hardcoded value
14385inmessage[:14385]can lead to maintainability issues and might not be clear to other developers. Consider defining a constant with a meaningful name or adding a comment explaining its significance.Apply this diff to define a constant:
+MAX_MESSAGE_LENGTH = 14385 # Maximum allowed message length def send_message(self, message: str, output_method: OutputMethod = OutputMethod.DEFAULT) -> GenerationResponse: generation_config = self._adjust_generation_config(output_method) - self._chat_history.append({"role": "user", "content": message[:14385]}) + self._chat_history.append({"role": "user", "content": message[:MAX_MESSAGE_LENGTH]}) response = completion( model=self._model.model_name, messages=self._chat_history,
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (1)
poetry.lockis excluded by!**/*.lock
📒 Files selected for processing (1)
graphrag_sdk/models/litellm.py(1 hunks)
🔇 Additional comments (2)
graphrag_sdk/models/litellm.py (2)
186-216: LGTM
The delete_last_message method correctly handles the removal of the last message exchange, preserving the system message when present.
169-184: Verify response_format support in LiteLLM API
In the _adjust_generation_config method, the response_format parameter is set when output_method is OutputMethod.JSON. Ensure that the LiteLLM completion function supports the response_format parameter; otherwise, this could lead to unexpected errors.
Run the following script to check if response_format is a valid parameter:
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
🧹 Outside diff range and nitpick comments (2)
graphrag_sdk/models/litellm.py (2)
38-44: Improve provider parsing logicThe current provider parsing logic could be more robust and maintainable.
Consider using a dictionary for provider mapping:
- if "/" in model_name: - self.provider = model_name.split("/")[0] - self.model_name = model_name.split("/")[1] - else: - self.provider = "openai" - self.model_name = model_name + PROVIDER_MAP = { + "openai": ["gpt", "text-"], + "azure": ["azure"], + "gemini": ["gemini"], + "ollama": ["ollama"] + } + + parts = model_name.split("/", 1) + if len(parts) == 2: + self.provider, self.model_name = parts + else: + self.model_name = model_name + self.provider = next( + (provider for provider, prefixes in PROVIDER_MAP.items() + if any(self.model_name.startswith(prefix) for prefix in prefixes)), + "openai" + )
50-72: Enhance credentials validationThe credentials validation could be more robust and maintainable.
Consider using a more structured approach:
def credentials_validation(self) -> None: + REQUIRED_CREDENTIALS = { + "openai": [("OPENAI_API_KEY", "OpenAI API key")], + "azure": [ + ("AZURE_API_KEY", "Azure API key"), + ("AZURE_API_BASE", "Azure API base URL"), + ("AZURE_API_VERSION", "Azure API version") + ], + "gemini": [("GEMINI_API_KEY", "Gemini API key")], + "ollama": [] + } + + if self.provider not in REQUIRED_CREDENTIALS: + raise ValueError(f"Unsupported provider: {self.provider}") + + missing_credentials = [ + desc for env_var, desc in REQUIRED_CREDENTIALS[self.provider] + if not os.getenv(env_var) + ] + + if missing_credentials: + raise ValueError( + f"Missing {self.provider} credentials: {', '.join(missing_credentials)}" + ) + + if self.provider == "ollama": + self.ollama_client = Client() + self.check_and_pull_model()
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (2)
graphrag_sdk/models/litellm.py(1 hunks)tests/test_kg_litellm_openai.py(1 hunks)
🔇 Additional comments (8)
tests/test_kg_litellm_openai.py (4)
97-102: LGTM!
The test method properly verifies the deletion of the knowledge graph.
14-17: 🛠️ Refactor suggestion
Consider test-specific logging configuration
The current setup has potential issues:
- Setting logging to DEBUG level globally could expose sensitive information in test logs
- Loading environment variables at module level could affect other tests
Consider moving these configurations into the test class setup:
-load_dotenv()
-logging.basicConfig(level=logging.DEBUG)
-logger = logging.getLogger(__name__)
+logger = logging.getLogger(__name__)
+
+@classmethod
+def setUpClass(cls):
+ load_dotenv()
+ cls.log_handler = logging.StreamHandler()
+ cls.log_handler.setLevel(logging.INFO)
+ logger.addHandler(cls.log_handler)Likely invalid or redundant comment.
71-71: 🛠️ Refactor suggestion
Add error handling for model initialization
The model initialization lacks error handling and uses a hardcoded model name. This could make tests brittle and fail silently if the model is unavailable.
Consider making the model configurable:
- model = LiteModel(model_name="gpt-4o")
+ model_name = os.getenv("TEST_LLM_MODEL", "gpt-4o")
+ try:
+ model = LiteModel(model_name=model_name)
+ except Exception as e:
+ raise unittest.SkipTest(f"Failed to initialize LLM model: {e}")Likely invalid or redundant comment.
80-95: 🛠️ Refactor suggestion
Improve test reliability and validation
The current test implementation has several reliability issues:
- Uses a hardcoded file path which could break in different environments
- Relies on regex parsing of LLM responses which could be unstable
- Uses an arbitrary success criterion (>10 actors)
Consider these improvements:
- file_path = "tests/data/madoff.txt"
+ file_path = os.path.join(os.path.dirname(__file__), "data", "madoff.txt")
+ self.assertTrue(os.path.exists(file_path), "Test data file not found")
sources = [Source(file_path)]
self.kg.process_sources(sources)
chat = self.kg.chat_session()
- answer = chat.send_message("How many actors acted in a movie?")
- answer = answer['response']
+ try:
+ answer = chat.send_message("Count the total number of unique Actor nodes in the graph")
+ answer = answer['response']
+ except Exception as e:
+ self.fail(f"Chat session failed: {e}")
- actors_count = re.findall(r'\d+', answer)
- num_actors = 0 if len(actors_count) == 0 else int(actors_count[0])
+ # Verify through direct graph query instead of parsing LLM response
+ db = FalkorDB()
+ actual_count = db.query(f"MATCH (a:Actor) RETURN COUNT(DISTINCT a)")[0][0]
+ self.assertGreater(actual_count, 0, "No actors found in the graph")Likely invalid or redundant comment.
graphrag_sdk/models/litellm.py (4)
180-199: LGTM!
The chat session implementation properly manages the chat history and handles system instructions correctly.
160-177: 🛠️ Refactor suggestion
Add input validation to from_json method
The method directly accesses dictionary keys without validation, which could raise KeyError.
Add proper input validation:
@staticmethod
def from_json(json: dict) -> "GenerativeModel":
+ required_fields = ['model_name', 'generation_config']
+ missing_fields = [field for field in required_fields if field not in json]
+ if missing_fields:
+ raise ValueError(f"Missing required fields: {', '.join(missing_fields)}")
+
return LiteModel(
- json["model_name"],
+ json['model_name'],
generation_config=GenerativeModelConfig.from_json(
- json["generation_config"]
+ json['generation_config']
),
- system_instruction=json["system_instruction"],
+ system_instruction=json.get('system_instruction'),
)Likely invalid or redundant comment.
210-230: 🛠️ Refactor suggestion
Add error handling and message validation
The method lacks error handling for the completion call and message length validation.
Add proper error handling and validation:
+ MAX_MESSAGE_LENGTH = 4096 # Adjust based on model limits
+
def send_message(self, message: str, output_method: OutputMethod = OutputMethod.DEFAULT) -> GenerationResponse:
+ if not message.strip():
+ raise ValueError("Message cannot be empty")
+
+ if len(message) > self.MAX_MESSAGE_LENGTH:
+ logger.warning(f"Message truncated from {len(message)} to {self.MAX_MESSAGE_LENGTH} characters")
+ message = message[:self.MAX_MESSAGE_LENGTH]
+
generation_config = self._adjust_generation_config(output_method)
self._chat_history.append({"role": "user", "content": message})
- response = completion(
- model=self._model.model,
- messages=self._chat_history,
- **generation_config
+ try:
+ response = completion(
+ model=self._model.model,
+ messages=self._chat_history,
+ **generation_config
)
- content = self._model.parse_generate_content_response(response)
+ content = self._model.parse_generate_content_response(response)
+ except Exception as e:
+ logger.error(f"Error during message completion: {e}")
+ raise RuntimeError(f"Failed to generate response: {e}") from e
+
self._chat_history.append({"role": "assistant", "content": content.text})
return contentLikely invalid or redundant comment.
124-145: 🛠️ Refactor suggestion
Add error handling for unexpected response structure
The method assumes that response.choices[0].message.content and response.choices[0].finish_reason are always present. This could raise exceptions with malformed responses.
Add proper error handling:
def parse_generate_content_response(self, response: any) -> GenerationResponse:
+ if not hasattr(response, 'choices') or not response.choices:
+ raise ValueError("Invalid response: missing choices")
+
+ choice = response.choices[0]
+ if not hasattr(choice, 'message') or not hasattr(choice.message, 'content'):
+ raise ValueError("Invalid response: missing message content")
+
+ if not hasattr(choice, 'finish_reason'):
+ raise ValueError("Invalid response: missing finish reason")
+
return GenerationResponse(
- text=response.choices[0].message.content,
+ text=choice.message.content,
finish_reason=(
FinishReason.STOP
- if response.choices[0].finish_reason == "stop"
+ if choice.finish_reason == "stop"
else (
FinishReason.MAX_TOKENS
- if response.choices[0].finish_reason == "length"
+ if choice.finish_reason == "length"
else FinishReason.OTHER
)
),
)Likely invalid or redundant 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: 7
♻️ Duplicate comments (3)
tests/test_kg_litellm_openai.py (1)
19-77:⚠️ Potential issueAdd tearDown method for cleanup
The test class is missing cleanup code to remove test artifacts.
Add a tearDown method as suggested in the previous review:
@classmethod def tearDownClass(cls): try: # Clean up the knowledge graph if hasattr(cls, 'kg'): cls.kg.delete() # Remove logging handler if hasattr(cls, 'log_handler'): logger.removeHandler(cls.log_handler) except Exception as e: logger.warning(f"Cleanup failed: {e}")graphrag_sdk/models/litellm.py (2)
165-182:⚠️ Potential issueHandle missing keys in from_json method.
The method directly accesses dictionary keys without validation, which could lead to KeyError exceptions.
Apply this diff to add proper error handling:
@staticmethod def from_json(json: dict) -> "GenerativeModel": + model_name = json.get("model_name") + generation_config_json = json.get("generation_config") + system_instruction = json.get("system_instruction") + + if model_name is None or generation_config_json is None: + raise ValueError("Invalid input: 'model_name' and 'generation_config' are required") + return LiteModel( - json["model_name"], - generation_config=GenerativeModelConfig.from_json( - json["generation_config"] - ), - system_instruction=json["system_instruction"], + model_name, + generation_config=GenerativeModelConfig.from_json(generation_config_json), + system_instruction=system_instruction, )
129-150:⚠️ Potential issueAdd error handling for unexpected response structure.
The parse_generate_content_response method assumes the response structure without validation.
Apply this diff to add proper error handling:
def parse_generate_content_response(self, response: any) -> GenerationResponse: + if not response.choices or not hasattr(response.choices[0], 'message') or not hasattr(response.choices[0].message, 'content'): + raise ValueError("Invalid response format: 'content' not found in response.") + if not hasattr(response.choices[0], 'finish_reason'): + raise ValueError("Invalid response format: 'finish_reason' not found in response.") return GenerationResponse( text=response.choices[0].message.content, finish_reason=(
🧹 Nitpick comments (3)
tests/test_kg_litellm_openai.py (1)
4-4: Remove unused importThe
FalkorDBimport is not used in the test class.-from falkordb import FalkorDB🧰 Tools
🪛 Ruff (0.8.2)
4-4:
falkordb.FalkorDBimported but unusedRemove unused import:
falkordb.FalkorDB(F401)
graphrag_sdk/steps/create_ontology_step.py (1)
80-81: Add validation for empty or missing document contentThe code should validate document content before processing.
+ if not document.content: + logger.warning(f"Empty document content: {document}") + return o + text = document.content[: self.config["max_input_tokens"]]graphrag_sdk/models/litellm.py (1)
258-288: Consider adding validation for chat history integrity.The delete_last_message method modifies the chat history without validating its structure.
Consider adding validation to ensure the chat history maintains a valid structure:
def delete_last_message(self): + def is_valid_message(msg: dict) -> bool: + return isinstance(msg, dict) and "role" in msg and "content" in msg + # Keep at least the system message if present min_length = 1 if self._model.system_instruction else 0 - if len(self._chat_history) - 2 >= min_length: + if (len(self._chat_history) >= 2 and + all(is_valid_message(msg) for msg in self._chat_history[-2:])): self._chat_history.pop() self._chat_history.pop() else:
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
.env.template(1 hunks).wordlist.txt(1 hunks)README.md(2 hunks)graphrag_sdk/models/litellm.py(1 hunks)graphrag_sdk/steps/create_ontology_step.py(1 hunks)graphrag_sdk/steps/extract_data_step.py(2 hunks)tests/test_kg_litellm_openai.py(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- .wordlist.txt
🧰 Additional context used
🪛 Ruff (0.8.2)
graphrag_sdk/steps/create_ontology_step.py
78-78: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
tests/test_kg_litellm_openai.py
4-4: falkordb.FalkorDB imported but unused
Remove unused import: falkordb.FalkorDB
(F401)
graphrag_sdk/steps/extract_data_step.py
98-98: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
203-203: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
graphrag_sdk/models/litellm.py
236-236: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
🔇 Additional comments (4)
.env.template (1)
10-11: LGTM: GEMINI_API_KEY addition for LiteLLM integration
The addition of GEMINI_API_KEY is appropriate for the LiteLLM integration.
tests/test_kg_litellm_openai.py (2)
80-80:
Use path-independent file resolution
Hardcoded file paths can break when tests are run from different directories.
-file_path = "tests/data/madoff.txt"
+import os
+file_path = os.path.join(os.path.dirname(__file__), "data", "madoff.txt")Likely invalid or redundant comment.
92-95: 🛠️ Refactor suggestion
Enhance assertion with proper error messages
The current assertion lacks proper error messages and validation.
-actors_count = re.findall(r'\d+', answer)
-num_actors = 0 if len(actors_count) == 0 else int(actors_count[0])
-
-assert num_actors > 10, "The number of actors found should be greater than 10"
+try:
+ actors_count = re.findall(r'\d+', response)
+ if not actors_count:
+ raise ValueError("No numeric value found in response")
+ num_actors = int(actors_count[0])
+ self.assertGreater(
+ num_actors,
+ 10,
+ f"Expected more than 10 actors, but found {num_actors}"
+ )
+except ValueError as e:
+ self.fail(f"Failed to parse actor count: {e}")Likely invalid or redundant comment.
README.md (1)
16-16: LGTM!
The addition of LiteLLM to the list of supported LLMs is accurate and well-documented.
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
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
graphrag_sdk/models/litellm.py(1 hunks)
🧰 Additional context used
🪛 Ruff (0.8.2)
graphrag_sdk/models/litellm.py
241-241: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
🔇 Additional comments (3)
graphrag_sdk/models/litellm.py (3)
134-155: Add error handling for malformed responses
The parse_generate_content_response method assumes a specific response structure without proper validation.
171-187: Add error handling for missing keys in from_json
The from_json method needs to handle missing keys to prevent KeyError exceptions.
49-54: 🛠️ Refactor suggestion
Improve provider handling to prevent confusion
The current implementation assumes OpenAI as the default provider when no provider is specified, which could lead to confusion and potential errors.
Apply this diff to make the provider explicit:
if "/" in model_name:
self.provider = model_name.split("/")[0]
self.model_name = model_name.split("/")[1]
else:
- self.provider = "openai"
- self.model_name = model_name
+ raise ValueError(
+ "Provider must be explicitly specified in model_name. "
+ "Format: <provider>/<model_name> (e.g., openai/gpt-4)"
+ )Likely invalid or redundant 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
♻️ Duplicate comments (3)
graphrag_sdk/models/litellm.py (3)
142-153: 🛠️ Refactor suggestionAdd error handling for unexpected response structure
The
parse_generate_content_responsemethod assumes thatresponse.choices[0].message.contentandresponse.choices[0].finish_reasonare always present. If the response is malformed or ifchoicesis empty, this could raise anIndexErrororAttributeError.Apply this diff to add error handling:
def parse_generate_content_response(self, response: any) -> GenerationResponse: + if not response.choices or not hasattr(response.choices[0], 'message') or not hasattr(response.choices[0].message, 'content'): + raise ValueError("Invalid response format: 'content' not found in response.") + if not hasattr(response.choices[0], 'finish_reason'): + raise ValueError("Invalid response format: 'finish_reason' not found in response.") return GenerationResponse( text=response.choices[0].message.content, finish_reason=(
179-185: 🛠️ Refactor suggestionHandle missing keys in
from_jsonto preventKeyErrorThe
from_jsonmethod accesses keys directly from the input dictionary without checking if they exist. If any keys are missing, aKeyErrorwill occur. Consider usingdict.get()with default values or adding error handling.Apply this diff to handle missing keys safely:
@staticmethod def from_json(json: dict) -> "GenerativeModel": + model_name = json.get("model_name") + generation_config_json = json.get("generation_config") + system_instruction = json.get("system_instruction") + + if model_name is None or generation_config_json is None: + raise ValueError("Invalid input: 'model_name' and 'generation_config' are required.") + return LiteModel( - json["model_name"], - generation_config=GenerativeModelConfig.from_json( - json["generation_config"] - ), - system_instruction=json["system_instruction"], + model_name, + generation_config=GenerativeModelConfig.from_json(generation_config_json), + system_instruction=system_instruction, )
238-239: 🛠️ Refactor suggestionImprove exception handling in
send_messagemethodWhen re-raising an exception after catching it, include the original exception using
from eto preserve the traceback. This helps in debugging by providing the original error context.Apply this diff to enhance exception handling:
except Exception as e: - raise ValueError(f"Error during completion request, please check the credentials - {e}") + raise ValueError( + "Error during completion request. Please verify:\n" + "1. Your credentials are correct.\n" + "2. The model name is valid.\n" + "3. The API endpoint is accessible." + ) from e🧰 Tools
🪛 Ruff (0.8.2)
238-238: Within an
exceptclause, raise exceptions withraise ... from errorraise ... from Noneto distinguish them from errors in exception handling(B904)
🧹 Nitpick comments (3)
graphrag_sdk/models/litellm.py (1)
1-1: Remove unused import 'os'The
osmodule is imported but not used anywhere in the code. Removing it will clean up the code.Apply this diff to remove the unused import:
-import os🧰 Tools
🪛 Ruff (0.8.2)
1-1:
osimported but unusedRemove unused import:
os(F401)
tests/test_kg_litellm_openai.py (2)
4-4: Remove unused import 'FalkorDB'The import of
FalkorDBis not used in this test file. Removing it will clean up the code.Apply this diff to remove the unused import:
import re import logging import unittest -from falkordb import FalkorDB from dotenv import load_dotenv🧰 Tools
🪛 Ruff (0.8.2)
4-4:
falkordb.FalkorDBimported but unusedRemove unused import:
falkordb.FalkorDB(F401)
14-17: Avoid configuring logging at the module level in testsConfiguring logging globally using
logging.basicConfigat the module level can affect other tests and modules. Consider configuring logging within the test class or methods to prevent unintended side effects.Apply this diff to configure logging within the test class:
-load_dotenv() -logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger(__name__) class TestKGLiteLLM(unittest.TestCase): """ Test Knowledge Graph """ + @classmethod + def setUpClass(cls): + load_dotenv() + logging.basicConfig(level=logging.DEBUG)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
.env.template(1 hunks)graphrag_sdk/models/litellm.py(1 hunks)graphrag_sdk/steps/create_ontology_step.py(0 hunks)tests/test_kg_litellm_openai.py(1 hunks)
💤 Files with no reviewable changes (1)
- graphrag_sdk/steps/create_ontology_step.py
🚧 Files skipped from review as they are similar to previous changes (1)
- .env.template
🧰 Additional context used
🪛 Ruff (0.8.2)
graphrag_sdk/models/litellm.py
1-1: os imported but unused
Remove unused import: os
(F401)
78-78: Do not use bare except
(E722)
238-238: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
tests/test_kg_litellm_openai.py
4-4: falkordb.FalkorDB imported but unused
Remove unused import: falkordb.FalkorDB
(F401)
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
♻️ Duplicate comments (2)
graphrag_sdk/models/litellm.py (2)
181-186: 🛠️ Refactor suggestionHandle Missing Keys in
from_jsonto PreventKeyErrorThe
from_jsonmethod directly accesses keys from the input dictionary without checking if they exist. This could lead to aKeyErrorif any of the expected keys are missing. Consider usingdict.get()with default values or adding explicit error handling to make the method more robust.Apply this diff to handle missing keys:
@staticmethod def from_json(json: dict) -> "GenerativeModel": + model_name = json.get("model_name") + generation_config_json = json.get("generation_config") + system_instruction = json.get("system_instruction") + + if model_name is None or generation_config_json is None: + raise ValueError("Invalid input: 'model_name' and 'generation_config' are required.") + return LiteModel( - json["model_name"], + model_name, generation_config=GenerativeModelConfig.from_json( - json["generation_config"] + generation_config_json ), - system_instruction=json["system_instruction"], + system_instruction=system_instruction, )
143-154: 🛠️ Refactor suggestionAdd Error Handling for Unexpected Response Structure
The
parse_generate_content_responsemethod assumes thatresponse.choices[0].message.contentandresponse.choices[0].finish_reasonare always present. If the response is malformed or ifchoicesis empty, this could raise anIndexErrororAttributeError. Consider adding checks to ensure these fields are present before accessing them.Apply this diff to add error handling:
def parse_generate_content_response(self, response: any) -> GenerationResponse: + if not response.choices or not hasattr(response.choices[0], 'message') or not hasattr(response.choices[0].message, 'content'): + raise ValueError("Invalid response format: 'content' not found in response.") + if not hasattr(response.choices[0], 'finish_reason'): + raise ValueError("Invalid response format: 'finish_reason' not found in response.") return GenerationResponse( text=response.choices[0].message.content, finish_reason=(
🧹 Nitpick comments (1)
graphrag_sdk/models/litellm.py (1)
1-1: Remove unused import 'os'The import of
osat line 1 is unused in the code and should be removed to keep the codebase clean.Apply this diff to remove the unused import:
-import os🧰 Tools
🪛 Ruff (0.8.2)
1-1:
osimported but unusedRemove unused import:
os(F401)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
.env.template(1 hunks)graphrag_sdk/models/litellm.py(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- .env.template
🧰 Additional context used
🪛 Ruff (0.8.2)
graphrag_sdk/models/litellm.py
1-1: os imported but unused
Remove unused import: os
(F401)
78-78: Do not use bare except
(E722)
106-106: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
239-239: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
🔇 Additional comments (1)
graphrag_sdk/models/litellm.py (1)
78-79: 🛠️ Refactor suggestion
Specify Exception Type in 'except' Block
Using a bare except clause can catch unexpected exceptions and make debugging difficult. Specify the exception type to catch, such as Exception.
Apply this diff to update the except clause:
try:
completion(
model=model, messages=messages, max_tokens=10
)
return True
- except:
+ except Exception:
return FalseLikely invalid or redundant comment.
🧰 Tools
🪛 Ruff (0.8.2)
78-78: Do not use bare except
(E722)
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
.env.templateto include new environment variable declarations.Chores