Skip to content

feat(guardian): Mistral provider + auto-select by API key#87

Merged
zaebee merged 4 commits into
mainfrom
feat/mistral-provider
Jun 8, 2026
Merged

feat(guardian): Mistral provider + auto-select by API key#87
zaebee merged 4 commits into
mainfrom
feat/mistral-provider

Conversation

@zaebee

@zaebee zaebee commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Summary

  • MistralProvider using the mistralai SDK (already declared in [dependency-groups] guardian)
  • guardian_review.py auto-selects: if MISTRAL_API_KEY is set → Mistral; otherwise Gemini. Raises clearly if neither is present.
  • GUARDIAN_MODEL env override works for both providers
  • Workflow exposes MISTRAL_API_KEY secret so you can add it in GitHub and switch with no code changes

Test plan

  • Add MISTRAL_API_KEY secret in GitHub repo settings
  • Comment /guardian review on a PR — it should pick Mistral automatically
  • Set GUARDIAN_MODEL=mistral-large-latest as a GitHub variable to override the model
  • Remove MISTRAL_API_KEY and verify Gemini fallback still works

🤖 Generated with Claude Code

zaebee and others added 2 commits June 8, 2026 22:42
2.0-flash drops connections under load; 2.5-flash is stable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- MistralProvider uses mistralai SDK (already in guardian dep-group)
- guardian_review.py picks Mistral if MISTRAL_API_KEY is set, falls back to Gemini
- GUARDIAN_MODEL override works for both providers
- Add MISTRAL_API_KEY to guardian.yml workflow env
- Add mistralai.* mypy override to silence import-untyped

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

Keep _build_provider logic from feat/mistral-provider; main's
_DEFAULT_MODEL = "gemini-2.5-flash" is superseded by the provider
auto-selection constants.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@zaebee

zaebee commented Jun 8, 2026

Copy link
Copy Markdown
Owner Author

/guardian review

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

🛡️ CGIS Guardian Review Report

Status: ⚠️ Conditional Approval
Reviewer: CGIS Guardian
Focus: Correctness, Type Safety, Determinism


📝 Summary

The Pull Request introduces support for the Mistral AI provider within the Guardian review engine. It successfully adheres to the strict type discipline required by CGIS, avoids the use of Any, and implements lazy loading to manage optional dependencies. The refactoring of the provider selection logic is clean, but there are minor concerns regarding Determinism and Semantic Exception Handling that should be addressed to meet our "mission-critical" standards.


🔍 Detailed Findings

1. Determinism & Configuration Ambiguity

Location: scripts/guardian_review.py -> _build_provider()

Issue: The current implementation of _build_provider uses an implicit priority system. If both MISTRAL_API_KEY and GEMINI_API_KEY are present in the environment, the engine will silently default to Mistral. In a mission-critical pipeline, silent configuration shifts can lead to non-deterministic review results if different developers have different keys set.

Reason: This violates our principle of Determinism. The engine's behavior should be explicitly driven by configuration, not by the accidental presence of environment variables.

Suggested Fix:
Introduce an explicit GUARDIAN_PROVIDER environment variable to resolve ambiguity.

def _build_provider() -> tuple[BaseProvider, str]:
    """Return (provider, model_name) based on explicit provider selection."""
    provider_choice = os.environ.get("GUARDIAN_PROVIDER", "gemini").lower()
    model_override = os.environ.get("GUARDIAN_MODEL")

    if provider_choice == "mistral":
        mistral_key = os.environ.get("MISTRAL_API_KEY")
        if not mistral_key:
            raise RuntimeError("MISTRAL_API_KEY must be set when GUARDIAN_PROVIDER is 'mistral'")
        model = model_override or _DEFAULT_MISTRAL_MODEL
        return MistralProvider(api_key=mistral_key, model_name=model), model

    # Default to Gemini
    gemini_key = os.environ.get("GEMINI_API_KEY")
    if not gemini_key:
        raise RuntimeError("GEMINI_API_KEY must be set for the default provider")
    model = model_override or _DEFAULT_GEMINI_MODEL
    return GeminiProvider(api_key=gemini_key, model_name=model), model

2. Semantic Exception Mapping

Location: scripts/guardian_review.py -> _build_provider()

Issue: The function raises OSError when no API keys are found.

Reason: While not technically "incorrect," OSError is semantically intended for system-level errors (like file I/O failures). Configuration errors in a software application are more appropriately categorized as RuntimeError.

Suggested Fix:
Change raise OSError(_msg) to raise RuntimeError(_msg).

3. Type Safety & Robustness (Positive Note)

Location: src/cgis/guardian/providers/mistral.py

Observation: The implementation of generate_content is excellent.

  • The use of a lazy import with noqa: PLC0415 is the correct architectural pattern for optional dependencies.
  • The explicit check for if not response.choices and if content is None ensures that the function adheres to its -> str return type contract without relying on implicit type coercion.
  • The mypy override in pyproject.toml correctly handles the lack of stubs in the mistralai library, maintaining our strict typing standards.

✅ Checklist Compliance

  • Type Discipline: No Any used. All functions are fully annotated.
  • Linting: ruff suppressions are documented and justified.
  • Documentation: Docstrings are present for all new classes and methods.
  • Ontology: No changes to the core graph ontology; changes are confined to the tooling layer.
  • Determinism:Fails (due to implicit provider priority).

🚀 Final Recommendation

Approve after addressing the Determinism issue in _build_provider.

The code quality is high, and the architectural pattern for new providers is well-defined. Once the provider selection is made explicit, this PR will be ready for merge.

…eError

- Add GUARDIAN_PROVIDER env var for explicit provider selection
  (Mistral wins if set, otherwise key-based auto-detection as before)
- OSError → RuntimeError for configuration failures (semantic correctness)
- Expose GUARDIAN_PROVIDER as GitHub Actions variable

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Jun 8, 2026

Copy link
Copy Markdown

@zaebee zaebee merged commit 6d147ad into main Jun 8, 2026
3 checks passed
@zaebee zaebee deleted the feat/mistral-provider branch June 8, 2026 22:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant