feat: add Mistral AI provider + provider registry refactor; Kimi brand update (#413)#455
Conversation
Co-Authored-By: Claude <noreply@anthropic.invalid>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #455 +/- ##
==========================================
- Coverage 90.34% 90.34% -0.01%
==========================================
Files 50 50
Lines 19508 19502 -6
Branches 225 225
==========================================
- Hits 17625 17619 -6
Misses 1879 1879
Partials 4 4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds Mistral AI provider support to Inference.complete and refactors provider dispatch from an if/elif chain to a table-driven registry using a Changes
Sequence Diagram(s)sequenceDiagram
participant Caller
participant Vera as Vera.execute/_call_inference_provider
participant Registry as _PROVIDERS
participant External as Provider API
Caller->>Vera: Inference.complete(prompt, optional provider)
alt explicit provider set
Vera->>Registry: lookup(provider)
Registry-->>Vera: provider config (env_key, url, auth_style, default_model)
Vera->>External: HTTP request (headers/body per auth_style)
External-->>Vera: response
Vera-->>Caller: completion text
else auto-detect
Vera->>Registry: iterate providers (in priority)
Registry-->>Vera: first config with env_key set
Vera->>External: HTTP request (built from config)
External-->>Vera: response
Vera-->>Caller: completion text
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@ROADMAP.md`:
- Around line 88-90: Update the three provider roadmap lines so their endpoints
are fully-qualified HTTPS URLs: replace the scheme-less endpoints for XAI
(`api.x.ai/v1/chat/completions`), DeepSeek
(`api.deepseek.com/v1/chat/completions`), and Gemini (any listed Gemini
endpoint) with explicit `https://` prefixed URLs (e.g.,
`https://api.x.ai/v1/chat/completions`,
`https://api.deepseek.com/v1/chat/completions`, and the correct `https://...`
Gemini endpoint) in the `_PROVIDERS` roadmap entries referencing issues `#425`,
`#450`, and `#451`.
In `@tests/test_codegen.py`:
- Around line 9949-9963: Update the test_mistral_provider to assert that the
request sent by _call_inference_provider uses Bearer auth and OpenAI-compatible
request shape: verify req.get_header("Authorization") or req.headers contains
"Authorization: Bearer sk-mistral", ensure the request body is the OpenAI-style
JSON (e.g., has "messages"/"choices" and "model" == "mistral-small-latest"), and
additionally assert Anthropic-specific headers/fields are not present (e.g., no
"x-api-key" header and no "max_tokens" field in the JSON) so the Mistral branch
cannot be accidentally routed through the Anthropic path.
In `@vera/codegen/api.py`:
- Around line 2100-2106: If the selected provider (from VERA_INFERENCE_PROVIDER)
is set but its credential env var is missing, currently api_key becomes "" and
we still call _call_inference_provider; add an early failure: after resolving
cfg = _PROVIDERS.get(provider) and computing api_key, if provider is truthy and
api_key == "" (or cfg exists but cfg.env_key is missing), immediately return
Err(...) with a clear message about the missing API key rather than proceeding
to _call_inference_provider; place this check just before the try block that
invokes _call_inference_provider to fail fast.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 34e10009-8696-4172-95d6-5550e92978bc
⛔ Files ignored due to path filters (7)
docs/SKILL.mdis excluded by!docs/**docs/index.htmlis excluded by!docs/**docs/index.mdis excluded by!docs/**docs/llms-full.txtis excluded by!docs/**docs/llms.txtis excluded by!docs/**examples/inference.verais excluded by!**/*.verauv.lockis excluded by!**/*.lock,!uv.lock
📒 Files selected for processing (12)
CHANGELOG.mdHISTORY.mdREADME.mdROADMAP.mdSKILL.mdTESTING.mdpyproject.tomlscripts/check_spec_examples.pyspec/09-standard-library.mdtests/test_codegen.pyvera/__init__.pyvera/codegen/api.py
- Add https:// prefix to scheme-less xAI and DeepSeek endpoint URLs in ROADMAP.md - Strengthen test_mistral_provider to assert Bearer auth header, OpenAI body shape (has "messages", no "max_tokens"), and absence of Anthropic x-api-key header - Add early Err return in execute() when provider is explicitly set via VERA_INFERENCE_PROVIDER but its API key env var is missing, with a clear diagnostic message naming the required key - Add test_explicit_provider_missing_key_returns_err covering the new early-fail path Co-Authored-By: Claude <noreply@anthropic.invalid>
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
ROADMAP.md (1)
90-90: 🧹 Nitpick | 🔵 TrivialAdd Gemini endpoint for consistency.
The xAI and DeepSeek entries (lines 88-89) include explicit endpoint URLs, but the Gemini entry omits the endpoint. For consistency and completeness, consider adding the Gemini endpoint URL.
📝 Suggested addition
-- [`#451`](https://github.com/aallan/vera/issues/451) **Add Google Gemini 2.5 Pro provider to the Inference effect** — Gemini uses a distinct API shape requiring a custom request/response path; env var `VERA_GEMINI_API_KEY`; default model `gemini-2.5-pro`. +- [`#451`](https://github.com/aallan/vera/issues/451) **Add Google Gemini 2.5 Pro provider to the Inference effect** — Gemini uses a distinct API shape requiring a custom request/response path; endpoint: `https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent`; env var `VERA_GEMINI_API_KEY`; default model `gemini-2.5-pro`.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ROADMAP.md` at line 90, Update the Gemini entry in the ROADMAP.md Inference effect item [`#451`] to include the explicit Gemini API endpoint URL for consistency with the xAI and DeepSeek entries; locate the bullet that mentions env var VERA_GEMINI_API_KEY and default model gemini-2.5-pro and append the Gemini endpoint (e.g., the public Gemini REST URL) so the entry includes the endpoint, env var, and default model together.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@tests/test_codegen.py`:
- Around line 9984-9992: The test test_explicit_provider_missing_key_returns_err
currently only asserts exec_result.value == 0 which can be satisfied by
unrelated failures; update this test to also verify the provider is never
invoked by instrumenting or mocking the provider entry point used by
TestInferenceCollection._CLASSIFY_SOURCE (e.g., patch the provider invocation
function or client factory so it raises or records calls) and then assert that
no call was made (or that the sentinel was not triggered) after execute(...,
env_vars={"VERA_INFERENCE_PROVIDER":"mistral"}), ensuring the code took the
early-fail path rather than failing later.
---
Duplicate comments:
In `@ROADMAP.md`:
- Line 90: Update the Gemini entry in the ROADMAP.md Inference effect item
[`#451`] to include the explicit Gemini API endpoint URL for consistency with the
xAI and DeepSeek entries; locate the bullet that mentions env var
VERA_GEMINI_API_KEY and default model gemini-2.5-pro and append the Gemini
endpoint (e.g., the public Gemini REST URL) so the entry includes the endpoint,
env var, and default model together.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 256b3bb4-af6d-419c-ba99-3b6f4406df97
📒 Files selected for processing (4)
ROADMAP.mdTESTING.mdtests/test_codegen.pyvera/codegen/api.py
- test_explicit_provider_missing_key_returns_err now patches _call_inference_provider with side_effect=AssertionError so the test distinguishes the early-fail guard from a late network failure; assert_not_called() confirms the provider was never reached - Add Gemini endpoint URL to #451 ROADMAP entry for consistency with xAI and DeepSeek entries Co-Authored-By: Claude <noreply@anthropic.invalid>
…tion Moonshot has migrated their developer portal from platform.moonshot.ai to platform.kimi.ai. The API endpoint (api.moonshot.ai) and env var (VERA_MOONSHOT_API_KEY) are unchanged. - spec/09-standard-library.md: update VERA_MOONSHOT_API_KEY table entry to "Kimi (Moonshot)" with link to new portal at platform.kimi.ai - SKILL.md: note VERA_MOONSHOT_API_KEY as "Kimi" in provider list - AGENTS.md: update Moonshot → "Kimi" brand; add VERA_MISTRAL_API_KEY which was missing from the provider key list - FAQ.md: update "<Inference> dispatches to ... Moonshot" → "Kimi (Moonshot)" and add Mistral to the list - Regenerate docs/ site assets Co-Authored-By: Claude <noreply@anthropic.invalid>
There was a problem hiding this comment.
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)
tests/test_codegen.py (1)
9911-9920:⚠️ Potential issue | 🟠 MajorAssert the Anthropic request shape as well.
This test still passes if the
anthropicregistry entry is accidentally routed through the bearer/OpenAI-compatible builder, because it only checkscontent[0].text. Please also inspect the outbound request and lock in the Anthropic endpoint,x-api-key/anthropic-versionheaders, andmax_tokensin the payload.Suggested test hardening
def test_anthropic_provider(self) -> None: """Anthropic branch extracts content[0].text.""" import json - from unittest.mock import patch + from unittest.mock import MagicMock, patch from vera.codegen.api import _call_inference_provider body = json.dumps({"content": [{"text": "hello"}]}) - with patch("urllib.request.urlopen", return_value=self._make_response(body)): + mock_urlopen = MagicMock(return_value=self._make_response(body)) + with patch("urllib.request.urlopen", mock_urlopen): result = _call_inference_provider("anthropic", "prompt", "", "sk-ant") assert result == "hello" + req = mock_urlopen.call_args[0][0] + assert req.full_url == "https://api.anthropic.com/v1/messages" + headers = {k.lower(): v for k, v in req.header_items()} + assert headers["x-api-key"] == "sk-ant" + assert headers["anthropic-version"] == "2023-06-01" + assert "authorization" not in headers + sent_body = json.loads(req.data.decode()) + assert sent_body["model"] == "claude-haiku-4-5-20251001" + assert sent_body["max_tokens"] == 1024 + assert sent_body["messages"] == [{"role": "user", "content": "prompt"}]🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/test_codegen.py` around lines 9911 - 9920, The test test_anthropic_provider is too weak; augment it to assert the outbound request shape so the Anthropic path isn't accidentally using the OpenAI/bearer builder. In the patched urllib.request.urlopen call inside test_anthropic_provider, capture the request object passed to urlopen and assert the URL matches the Anthropic endpoint, that headers include "x-api-key" with the provided key and "anthropic-version" with the expected version, and that the JSON payload contains "max_tokens" (and other Anthropic-specific fields) before returning the mocked response; keep using _call_inference_provider("anthropic", ...) to drive the code and fail the test if any of those endpoint/header/payload expectations are not met.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@ROADMAP.md`:
- Line 11: Update the test count in README.md by changing the string "3,237
tests" to "3,238 tests" so it matches the canonical TESTING.md count (3,238);
locate the occurrence of "3,237 tests" in README.md and replace it with "3,238
tests" and verify no other outdated test-count occurrences remain.
In `@tests/test_codegen.py`:
- Around line 9971-9983: Add a new test that verifies provider precedence when
multiple API keys are present: create a test (e.g., test_multi_key_auto_detect)
that imports vera.codegen.api._PROVIDERS and patches _call_inference_provider
like test_mistral_auto_detect does, then call execute with env_vars containing
at least two different provider keys set (e.g., VERAs for two providers) and
assert that the first provider string from _PROVIDERS is the one passed to the
patched _call_inference_provider; this ensures the ordered scan across
_PROVIDERS is enforced by the detection logic.
---
Outside diff comments:
In `@tests/test_codegen.py`:
- Around line 9911-9920: The test test_anthropic_provider is too weak; augment
it to assert the outbound request shape so the Anthropic path isn't accidentally
using the OpenAI/bearer builder. In the patched urllib.request.urlopen call
inside test_anthropic_provider, capture the request object passed to urlopen and
assert the URL matches the Anthropic endpoint, that headers include "x-api-key"
with the provided key and "anthropic-version" with the expected version, and
that the JSON payload contains "max_tokens" (and other Anthropic-specific
fields) before returning the mocked response; keep using
_call_inference_provider("anthropic", ...) to drive the code and fail the test
if any of those endpoint/header/payload expectations are not met.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 25a13f1a-2a81-410d-85a4-e5cf4b7b5ba7
📒 Files selected for processing (3)
ROADMAP.mdTESTING.mdtests/test_codegen.py
- test_anthropic_provider now asserts endpoint URL, x-api-key header, anthropic-version header, absence of Authorization, presence of max_tokens=1024 in body — mirrors the Mistral test coverage added in #455 - Add test_multi_key_auto_detect_respects_provider_order: sets two provider keys simultaneously and asserts _PROVIDERS insertion order determines the winner; dynamically reads first/second provider from _PROVIDERS so the test stays correct if the registry order ever changes - Update test counts: 3,239 tests, test_codegen.py 859 tests / 10,454 lines - Fix README.md test count (was stale at 3,237; now 3,239) Co-Authored-By: Claude <noreply@anthropic.invalid>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@tests/test_codegen.py`:
- Around line 9934-9943: The test currently only asserts response parsing but
must also verify the OpenAI provider wiring: update test_openai_provider to
assert that _PROVIDERS["openai"] is used with the expected OpenAI endpoint,
request body model, and Authorization header; do this by patching
urllib.request.urlopen with a side-effect function that captures the outgoing
Request object (or its full URL/body/headers) when
_call_inference_provider("openai", ...) is invoked, then assert the request URL
equals the OpenAI endpoint from _PROVIDERS["openai"], the JSON body includes the
expected model field, and the Authorization header equals "Bearer sk-openai"
(and Content-Type is application/json) so the test fails if the registry row is
wired incorrectly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 7284d12e-02f9-4cd2-97ff-a538c4d584f5
📒 Files selected for processing (4)
README.mdROADMAP.mdTESTING.mdtests/test_codegen.py
Mirrors the coverage added for anthropic and mistral providers: assert endpoint URL from _PROVIDERS registry, Bearer auth header, absence of x-api-key, Content-Type, default model in body, presence of messages, absence of max_tokens. Co-Authored-By: Claude <noreply@anthropic.invalid>
Summary
_call_inference_provider()from a growingelifchain to a table-driven_ProviderConfigdataclass +_PROVIDERSregistry dictVERA_MISTRAL_API_KEY, default modelmistral-small-latest)_PROVIDERS_call_inference_providersignature simplified from 6 parameters to 4 (provider,prompt,model,api_key)execute()loops over_PROVIDERSinstead of a hardcodedelifchainexecute()when a provider is explicitly set viaVERA_INFERENCE_PROVIDERbut its API key env var is missingVERA_MOONSHOT_API_KEYunchanged)Test plan
test_anthropic_provider— endpoint, x-api-key header, anthropic-version, max_tokens in bodytest_openai_provider— endpoint, Bearer auth, OpenAI-compatible body shapetest_moonshot_provider— endpoint, Bearer auth, OpenAI-compatible body shapetest_mistral_provider— endpoint, Bearer auth, OpenAI-compatible body shape, no max_tokenstest_mistral_auto_detect— VERA_MISTRAL_API_KEY triggers auto-detectiontest_multi_key_auto_detect_respects_provider_order— registry insertion order wins when multiple keys settest_explicit_provider_missing_key_returns_err— early-fail guard fires before provider invocationmypy vera/— cleanpython scripts/check_conformance.py— all 73 passCloses #413
Generated with Claude Code