feat(novita): add Novita AI provider integration#1118
feat(novita): add Novita AI provider integration#1118Alex-wuhu wants to merge 3 commits intoMervinPraison:mainfrom
Conversation
Add novita-basic.py demonstrating how to use Novita AI's OpenAI-compatible endpoint with PraisonAI Agents. Uses NOVITA_API_KEY env var and base_url=https://api.novita.ai/openai following the same pattern as existing ollama and gemini examples. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds tests/unit/test_novita_provider.py with coverage for Novita AI's OpenAI-compatible endpoint (https://api.novita.ai/openai), verifying that Agent correctly accepts base_url, api_key, and Novita model names (Kimi, DeepSeek, GLM). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds a Novita AI example script for PraisonAI Agents and a unit test suite validating Novita-compatible configuration, model selection, and environment-based API key handling. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
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 Tip CodeRabbit can generate a title for your PR based on the changes with custom instructions.Set the |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a new integration for Novita AI, allowing PraisonAI agents to leverage Novita's OpenAI-compatible endpoint. This expands the range of available high-quality open-source models like Kimi, DeepSeek, and GLM, providing more flexibility and options for users without altering existing functionalities. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces support for the Novita AI provider by adding an example script and unit tests. My review focuses on improving the robustness of the example and the maintainability of the tests.
In novita-basic.py, I've suggested adding a check to ensure the NOVITA_API_KEY environment variable is set. This will provide a clearer error message to users if the key is missing, improving the user experience.
In test_novita_provider.py, I've proposed refactoring several similar tests for different Novita models into a single, parameterized test. This improves code maintainability and readability. I've also strengthened an assertion to be more precise.
| agent = Agent( | ||
| instructions="You are a helpful assistant", | ||
| llm="openai/moonshotai/kimi-k2.5", | ||
| base_url="https://api.novita.ai/openai", | ||
| api_key=os.environ.get("NOVITA_API_KEY"), | ||
| ) |
There was a problem hiding this comment.
The script currently passes None to the Agent constructor if the NOVITA_API_KEY environment variable is not set. This can lead to a less-than-obvious authentication error when agent.start() is called. It would be more user-friendly to explicitly check for the presence of the API key and raise a ValueError if it's missing. This provides a clear and immediate error message to the user.
| agent = Agent( | |
| instructions="You are a helpful assistant", | |
| llm="openai/moonshotai/kimi-k2.5", | |
| base_url="https://api.novita.ai/openai", | |
| api_key=os.environ.get("NOVITA_API_KEY"), | |
| ) | |
| api_key = os.environ.get("NOVITA_API_KEY") | |
| if not api_key: | |
| raise ValueError("The NOVITA_API_KEY environment variable is not set. Please set it to your Novita AI API key.") | |
| agent = Agent( | |
| instructions="You are a helpful assistant", | |
| llm="openai/moonshotai/kimi-k2.5", | |
| base_url="https://api.novita.ai/openai", | |
| api_key=api_key, | |
| ) |
| def test_agent_novita_kimi_model(self): | ||
| """Agent should accept Novita's Kimi model.""" | ||
| from praisonaiagents import Agent | ||
|
|
||
| agent = Agent( | ||
| name="KimiTest", | ||
| instructions="You are a helpful assistant", | ||
| llm="openai/moonshotai/kimi-k2.5", | ||
| base_url="https://api.novita.ai/openai", | ||
| api_key="test-key", | ||
| ) | ||
| assert agent is not None | ||
|
|
||
| def test_agent_novita_deepseek_model(self): | ||
| """Agent should accept Novita's DeepSeek model.""" | ||
| from praisonaiagents import Agent | ||
|
|
||
| agent = Agent( | ||
| name="DeepSeekNovitaTest", | ||
| instructions="You are a helpful assistant", | ||
| llm="openai/deepseek/deepseek-v3.2", | ||
| base_url="https://api.novita.ai/openai", | ||
| api_key="test-key", | ||
| ) | ||
| assert agent is not None | ||
|
|
||
| def test_agent_novita_glm_model(self): | ||
| """Agent should accept Novita's GLM model.""" | ||
| from praisonaiagents import Agent | ||
|
|
||
| agent = Agent( | ||
| name="GLMNovitaTest", | ||
| instructions="You are a helpful assistant", | ||
| llm="openai/zai-org/glm-5", | ||
| base_url="https://api.novita.ai/openai", | ||
| api_key="test-key", | ||
| ) | ||
| assert agent is not None | ||
|
|
||
| def test_agent_novita_model_stored(self): | ||
| """Agent should store the Novita model name correctly.""" | ||
| from praisonaiagents import Agent | ||
|
|
||
| agent = Agent( | ||
| name="ModelStoreTest", | ||
| instructions="You are a helpful assistant", | ||
| llm="openai/moonshotai/kimi-k2.5", | ||
| base_url="https://api.novita.ai/openai", | ||
| api_key="test-key", | ||
| ) | ||
| assert "kimi-k2.5" in agent.llm or "moonshotai" in agent.llm |
There was a problem hiding this comment.
The tests for different Novita models (test_agent_novita_kimi_model, test_agent_novita_deepseek_model, test_agent_novita_glm_model) are very similar and can be consolidated into a single parameterized test using pytest.mark.parametrize. This will make the test suite more concise and easier to maintain.
Additionally, the assertion in test_agent_novita_model_stored can be made more precise. Instead of checking for substrings, it should assert that agent.llm is exactly equal to the model name provided.
I've combined these improvements into a single parameterized test that covers all model variations and includes a more robust assertion.
@pytest.mark.parametrize(
"model_name",
[
"openai/moonshotai/kimi-k2.5",
"openai/deepseek/deepseek-v3.2",
"openai/zai-org/glm-5",
],
)
def test_agent_novita_models(self, model_name):
"""Agent should accept various Novita models and store them correctly."""
from praisonaiagents import Agent
agent = Agent(
name=f"NovitaModelTest-{model_name.split('/')[-1]}",
instructions="You are a helpful assistant",
llm=model_name,
base_url="https://api.novita.ai/openai",
api_key="test-key",
)
assert agent is not None
assert agent.llm == model_name
Review Summary by QodoAdd Novita AI provider integration with tests
WalkthroughsDescription• Adds Novita AI provider integration example with OpenAI-compatible endpoint • Implements unit tests for Novita configuration and model support • Supports Kimi, DeepSeek, and GLM models via Novita's API • Fully backward-compatible with no changes to existing code Diagramflowchart LR
A["Novita AI Provider"] -->|"OpenAI-compatible endpoint"| B["Agent Configuration"]
B -->|"base_url + api_key"| C["Kimi/DeepSeek/GLM Models"]
D["Example Code"] -->|"demonstrates usage"| B
E["Unit Tests"] -->|"validates configuration"| B
File Changes1. src/praisonai-agents/novita-basic.py
|
Code Review by Qodo
1. No NOVITA_API_KEY guard
|
There was a problem hiding this comment.
🧹 Nitpick comments (4)
src/praisonai-agents/novita-basic.py (1)
17-22: Add validation for missing API key to improve error messaging.If
NOVITA_API_KEYis not set,os.environ.get()returnsNone, which may cause a confusing runtime error deep in the API call. Adding early validation would make this example more user-friendly.💡 Proposed fix to validate API key
import os from praisonaiagents import Agent +api_key = os.environ.get("NOVITA_API_KEY") +if not api_key: + raise ValueError("Please set NOVITA_API_KEY environment variable") + agent = Agent( instructions="You are a helpful assistant", llm="openai/moonshotai/kimi-k2.5", base_url="https://api.novita.ai/openai", - api_key=os.environ.get("NOVITA_API_KEY"), + api_key=api_key, )Based on learnings: "Code examples must run without modification (copy-paste success)" - clear error messages improve the copy-paste experience.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/praisonai-agents/novita-basic.py` around lines 17 - 22, The Agent instantiation uses os.environ.get("NOVITA_API_KEY") which can be None; add an early validation before creating Agent: read the env var into a variable (e.g., novita_api_key), check if it's falsy, and if so raise a clear error or exit with a message like "NOVITA_API_KEY environment variable is required", otherwise pass that variable into the Agent constructor's api_key parameter; update references around Agent(...) to use this validated novita_api_key.src/praisonai-agents/tests/unit/test_novita_provider.py (3)
47-84: Consider parameterizing similar model tests to reduce duplication.These three tests (
test_agent_novita_kimi_model,test_agent_novita_deepseek_model,test_agent_novita_glm_model) are nearly identical, differing only in the model name. Usingpytest.mark.parametrizewould be more maintainable and make it easier to add new models.♻️ Proposed parameterized version
`@pytest.mark.parametrize`("model_id,expected_substring", [ ("openai/moonshotai/kimi-k2.5", "kimi"), ("openai/deepseek/deepseek-v3.2", "deepseek"), ("openai/zai-org/glm-5", "glm"), ]) def test_agent_accepts_novita_models(self, model_id, expected_substring): """Agent should accept various Novita model identifiers.""" from praisonaiagents import Agent agent = Agent( name="NovitaModelTest", instructions="You are a helpful assistant", llm=model_id, base_url="https://api.novita.ai/openai", api_key="test-key", ) assert agent is not None assert expected_substring in agent.llm.lower()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/praisonai-agents/tests/unit/test_novita_provider.py` around lines 47 - 84, The three nearly identical tests (test_agent_novita_kimi_model, test_agent_novita_deepseek_model, test_agent_novita_glm_model) should be consolidated into a parameterized pytest to reduce duplication; replace them with a single parametrized test that iterates over model identifiers and expected substrings, calls Agent(...) with llm set to the parameter, and asserts the Agent is created (and optionally that agent.llm contains the expected substring) — update the test function name (e.g., test_agent_accepts_novita_models) and reference the Agent class and llm parameter when making the assertions.
86-97: Weak assertion usingormay mask failures.The assertion
assert "kimi-k2.5" in agent.llm or "moonshotai" in agent.llmwill pass if either condition is true, which makes it unclear what the expected behavior is and could mask subtle bugs. Consider asserting on the exact expected value.💡 Proposed stronger assertion
- assert "kimi-k2.5" in agent.llm or "moonshotai" in agent.llm + # Assert exact expected value or the full model string + assert agent.llm == "openai/moonshotai/kimi-k2.5"If the
Agentclass normalizes the model string, verify the expected normalized format instead.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/praisonai-agents/tests/unit/test_novita_provider.py` around lines 86 - 97, The test test_agent_novita_model_stored uses a weak boolean assertion; replace it with a single exact-value assertion against the expected normalized model string for the Agent (reference Agent and agent.llm) — e.g. assert agent.llm == "openai/moonshotai/kimi-k2.5" (or if Agent normalizes to a shorter form, assert the exact normalized value like "moonshotai/kimi-k2.5"); ensure the test checks equality to the single expected string rather than using an or condition.
33-45: Strengthen assertion to verify API key was actually configured.The test patches the environment and passes the value to
Agent, but only assertsagent is not None. This doesn't verify the API key was correctly read from the environment and stored. The pattern is already established intest_agent_accepts_novita_base_url(line 31), which asserts both agent creation and the attribute value. Consider asserting onagent.api_keyto match that pattern:with patch.dict(os.environ, {"NOVITA_API_KEY": "env-test-key"}): agent = Agent( name="NovitaEnvTest", instructions="You are a helpful assistant", llm="openai/moonshotai/kimi-k2.5", base_url="https://api.novita.ai/openai", api_key=os.environ.get("NOVITA_API_KEY"), ) assert agent is not None + assert agent.api_key == "env-test-key"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/praisonai-agents/tests/unit/test_novita_provider.py` around lines 33 - 45, Update the test_agent_novita_api_key_from_env test to assert the Agent actually stored the API key: after creating the Agent instance in test_agent_novita_api_key_from_env, add an assertion that agent.api_key equals the expected "env-test-key" (or the value from os.environ.get("NOVITA_API_KEY")), similar to the pattern used in test_agent_accepts_novita_base_url; reference the Agent constructor and the agent.api_key attribute to locate where to add the assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/praisonai-agents/novita-basic.py`:
- Around line 17-22: The Agent instantiation uses
os.environ.get("NOVITA_API_KEY") which can be None; add an early validation
before creating Agent: read the env var into a variable (e.g., novita_api_key),
check if it's falsy, and if so raise a clear error or exit with a message like
"NOVITA_API_KEY environment variable is required", otherwise pass that variable
into the Agent constructor's api_key parameter; update references around
Agent(...) to use this validated novita_api_key.
In `@src/praisonai-agents/tests/unit/test_novita_provider.py`:
- Around line 47-84: The three nearly identical tests
(test_agent_novita_kimi_model, test_agent_novita_deepseek_model,
test_agent_novita_glm_model) should be consolidated into a parameterized pytest
to reduce duplication; replace them with a single parametrized test that
iterates over model identifiers and expected substrings, calls Agent(...) with
llm set to the parameter, and asserts the Agent is created (and optionally that
agent.llm contains the expected substring) — update the test function name
(e.g., test_agent_accepts_novita_models) and reference the Agent class and llm
parameter when making the assertions.
- Around line 86-97: The test test_agent_novita_model_stored uses a weak boolean
assertion; replace it with a single exact-value assertion against the expected
normalized model string for the Agent (reference Agent and agent.llm) — e.g.
assert agent.llm == "openai/moonshotai/kimi-k2.5" (or if Agent normalizes to a
shorter form, assert the exact normalized value like "moonshotai/kimi-k2.5");
ensure the test checks equality to the single expected string rather than using
an or condition.
- Around line 33-45: Update the test_agent_novita_api_key_from_env test to
assert the Agent actually stored the API key: after creating the Agent instance
in test_agent_novita_api_key_from_env, add an assertion that agent.api_key
equals the expected "env-test-key" (or the value from
os.environ.get("NOVITA_API_KEY")), similar to the pattern used in
test_agent_accepts_novita_base_url; reference the Agent constructor and the
agent.api_key attribute to locate where to add the assertion.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: bd0ce45f-9e87-4e68-9f10-7c7661276aa5
📒 Files selected for processing (2)
src/praisonai-agents/novita-basic.pysrc/praisonai-agents/tests/unit/test_novita_provider.py
- Add API key validation in example before Agent construction - Consolidate duplicate model tests into parametrized test - Use exact equality assertion for model name storage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
novita-basic.pyexample showing how to use Novita AI's OpenAI-compatible endpoint (https://api.novita.ai/openai) with PraisonAI agentstests/unit/test_novita_provider.pywith unit tests covering Novita provider configuration (base URL, API key, Kimi/DeepSeek/GLM model names)Usage
Set
NOVITA_API_KEYto your Novita AI API key. Novita AI offers fast inference for Kimi K2.5, DeepSeek V3.2, GLM-5, and other open-source models.Test plan
pytest src/praisonai-agents/tests/unit/test_novita_provider.pypasses without real API callspython src/praisonai-agents/novita-basic.pywith a validNOVITA_API_KEYfor end-to-end verificationGenerated with Claude Code
Summary by CodeRabbit
New Features
Tests