Skip to content

Comments

Add Mistral moderation#424

Merged
KaQuMiQ merged 1 commit intomainfrom
feature/mistral_moderation
Sep 18, 2025
Merged

Add Mistral moderation#424
KaQuMiQ merged 1 commit intomainfrom
feature/mistral_moderation

Conversation

@KaQuMiQ
Copy link
Collaborator

@KaQuMiQ KaQuMiQ commented Sep 18, 2025

No description provided.

@coderabbitai
Copy link

coderabbitai bot commented Sep 18, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Bumps package version and adds Mistral moderation support: new MistralModerationConfig, a draive.mistral.moderation module with MistralContentModeration, and re-exports in draive.mistral. Mistral client now includes GuardrailsModeration in its feature set and wiring. OpenAI moderation APIs renamed and reworked (content_guardrails → moderation_guardrails, content_verification → content_moderation) and client import updated. Guardrails moderation payloads and exceptions change from Sequence[str] to Mapping[str, float] across guardrails types, Bedrock guardrails, and provider implementations to carry per-category scores.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning No pull request description was provided; because the description is absent it does not describe or contextualize the changeset and therefore fails this check. The raw changes show substantive additions (new moderation class, config, exports) that would benefit from an explanatory summary. Please add a brief PR description summarizing what was changed and why, note any public API or configuration impacts (e.g., MistralModerationConfig and MistralContentModeration), and state how the change was tested or validated, including links to related issues or tests and any migration notes.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title "Add Mistral moderation" is concise and accurately reflects the primary change in the diff — adding Mistral moderation support (new moderation module, config, and exports). It is specific enough for a reviewer scanning PR history to understand the main intent.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b31c9a8 and 3009a26.

📒 Files selected for processing (9)
  • pyproject.toml (1 hunks)
  • src/draive/bedrock/guardrails.py (2 hunks)
  • src/draive/guardrails/moderation/types.py (4 hunks)
  • src/draive/mistral/__init__.py (1 hunks)
  • src/draive/mistral/client.py (5 hunks)
  • src/draive/mistral/config.py (2 hunks)
  • src/draive/mistral/moderation.py (1 hunks)
  • src/draive/openai/client.py (2 hunks)
  • src/draive/openai/moderation.py (4 hunks)

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9791fb6 and b31c9a8.

📒 Files selected for processing (6)
  • pyproject.toml (1 hunks)
  • src/draive/mistral/__init__.py (1 hunks)
  • src/draive/mistral/config.py (2 hunks)
  • src/draive/mistral/moderation.py (1 hunks)
  • src/draive/openai/client.py (2 hunks)
  • src/draive/openai/moderation.py (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Use absolute imports from the draive package (e.g., from draive import ...), not relative imports
Follow Ruff import ordering: standard library, third-party, then local imports
Use Python 3.12+ typing features (e.g., | unions, PEP 695 generics)
Prefer abstract/base collection types (Sequence, Mapping, Set, Iterable) over concrete list, dict, set in type hints
Define and raise custom exception types for specific error cases
Use NumPy docstring convention for all functions, classes, and methods
Skip module-level docstrings unless explicitly requested
Docstrings should include Parameters, Returns, Raises, and Notes (if needed) sections

Format all Python code with Ruff formatter (run via make format); do not use any other formatter

Files:

  • src/draive/mistral/config.py
  • src/draive/openai/client.py
  • src/draive/mistral/__init__.py
  • src/draive/mistral/moderation.py
  • src/draive/openai/moderation.py
src/draive/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/draive/**/*.py: Import Haiway symbols directly as from haiway import State, ctx
Use ctx.scope(...) to bind active State instances; avoid global state
Route all logging through ctx.log_* and never use print
Enforce strict typing on public APIs; avoid untyped definitions and Any except at verified third‑party boundaries
Prefer explicit attribute access with static types; avoid dynamic getattr except at narrow boundaries
Use abstract immutable protocols (Mapping, Sequence, Iterable) instead of concrete dict/list/set in public types
Use final where applicable; prefer composition over complex inheritance
Use precise unions (|), narrow with match/isinstance, and avoid cast unless provably safe and localized
Model immutable configuration/data as haiway.State; avoid in‑place mutation and prefer State.updated(...)/functional builders
Access active state via haiway.ctx within async scopes (ctx.scope(...))
Public state methods that dispatch on the active instance must use @statemethod
Add structured, concise logs around generation calls, tool dispatch, and provider requests/responses (without secrets); add metrics via ctx.record where applicable
All I/O is async; keep boundaries async, use ctx.spawn for detached tasks, and avoid custom threading
Translate provider/SDK errors into typed exceptions; never raise bare Exception; preserve context
Compose multimodal content with MultimodalContent.of(...); use ResourceContent/Reference for blobs; wrap custom data in ArtifactContent (use hidden when needed)
Public symbols require NumPy-style docstrings with Parameters/Returns/Raises and rationale when non-obvious
Avoid docstrings for internal helpers; prefer self-explanatory names; skip module-level docstrings
Never log secrets or full request bodies containing keys/tokens
Read credentials from environment variables; resolve via helpers like getenv_str

Files:

  • src/draive/mistral/config.py
  • src/draive/openai/client.py
  • src/draive/mistral/__init__.py
  • src/draive/mistral/moderation.py
  • src/draive/openai/moderation.py
src/draive/{openai,anthropic,mistral,gemini,vllm,ollama,bedrock,cohere}/{config,client,api}.py

📄 CodeRabbit inference engine (AGENTS.md)

Provider adapters must include config.py, client.py, and api.py within each provider package

Files:

  • src/draive/mistral/config.py
  • src/draive/openai/client.py
🧠 Learnings (1)
📚 Learning: 2025-09-11T15:22:15.967Z
Learnt from: CR
PR: miquido/draive#0
File: AGENTS.md:0-0
Timestamp: 2025-09-11T15:22:15.967Z
Learning: Applies to src/draive/__init__.py : Centralize and update all public exports in `src/draive/__init__.py` when API surface changes

Applied to files:

  • src/draive/mistral/__init__.py
🧬 Code graph analysis (4)
src/draive/openai/client.py (1)
src/draive/openai/moderation.py (2)
  • OpenAIContentModeration (15-246)
  • moderation_guardrails (16-20)
src/draive/mistral/__init__.py (1)
src/draive/mistral/config.py (3)
  • MistralChatConfig (12-18)
  • MistralEmbeddingConfig (21-23)
  • MistralModerationConfig (26-27)
src/draive/mistral/moderation.py (8)
src/draive/guardrails/moderation/state.py (1)
  • GuardrailsModeration (24-102)
src/draive/guardrails/moderation/types.py (1)
  • GuardrailsModerationException (16-29)
src/draive/mistral/api.py (1)
  • MistralAPI (9-51)
src/draive/mistral/config.py (1)
  • MistralModerationConfig (26-27)
src/draive/multimodal/content.py (2)
  • MultimodalContent (25-592)
  • resources (95-125)
src/draive/multimodal/artifact.py (1)
  • ArtifactContent (11-96)
src/draive/multimodal/text.py (1)
  • TextContent (11-82)
src/draive/resources/types.py (2)
  • ResourceContent (126-212)
  • ResourceReference (74-97)
src/draive/openai/moderation.py (1)
src/draive/guardrails/moderation/state.py (1)
  • GuardrailsModeration (24-102)
🔇 Additional comments (5)
pyproject.toml (1)

8-8: Version bump looks good.

The version increment from 0.85.4 to 0.85.5 appropriately reflects the addition of new Mistral moderation features.

src/draive/mistral/config.py (1)

26-27: LGTM! Configuration follows established patterns.

The MistralModerationConfig class properly extends Configuration and provides a sensible default model name.

src/draive/openai/moderation.py (1)

16-20: Good API alignment with dual checking.

The rename to moderation_guardrails better describes the functionality, and applying moderation to both input and output is a security best practice.

src/draive/openai/client.py (1)

14-14: Import and method call correctly updated.

The changes properly reflect the new moderation module structure and API naming.

Also applies to: 89-89

src/draive/mistral/__init__.py (1)

2-2: Add Mistral moderation exports to the top-level API

src/draive/mistral/init.py exports MistralModerationConfig (alongside Mistral, MistralChatConfig, MistralEmbeddingConfig), but src/draive/init.py does not re-export them — add the appropriate imports and all entries in src/draive/init.py if these should be exposed at package top-level.

moderated_content.append(media_ref.to_str())

case ArtifactContent() as artifact:
moderated_content.append(artifact.artifact.to_str())
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure hidden artifacts are handled correctly.

The artifact.artifact.to_str() bypasses the ArtifactContent.to_str() method which respects the hidden flag. Hidden artifacts should return empty strings as per the ArtifactContent implementation.

-                        moderated_content.append(artifact.artifact.to_str())
+                        moderated_content.append(artifact.to_str())
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
moderated_content.append(artifact.artifact.to_str())
moderated_content.append(artifact.to_str())
🤖 Prompt for AI Agents
In src/draive/mistral/moderation.py around line 62, the code appends
artifact.artifact.to_str() which bypasses the Artifact's public to_str() that
enforces the hidden flag; replace that direct inner conversion with a call to
the Artifact object's to_str() (the method that delegates to
ArtifactContent.to_str() and returns an empty string for hidden artifacts) so
hidden artifacts are handled correctly.

Comment on lines +71 to +78
response: ModerationResponse = await self._client.classifiers.moderate_async(
model=moderation_config.model,
inputs=moderated_content,
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

Verify the Mistral client has required async moderation methods.

Let me verify that the Mistral client's classifiers module has the moderate_async method as used here.


🏁 Script executed:

#!/bin/bash
# Verify the Mistral SDK has the moderate_async method

# Check if mistralai package documentation or usage exists
echo "Searching for Mistral moderation API usage patterns:"
rg -A5 -B5 "classifiers.moderate" --type py

# Check for any Mistral client initialization or documentation
echo -e "\nChecking Mistral API client structure:"
rg -A10 "from mistralai import" --type py

# Look for any test files that might show usage
echo -e "\nChecking test files for Mistral moderation usage:"
fd -e py -x grep -l "moderate_async\|ModerationResponse" {} \;

Length of output: 4289


🌐 Web query:

Does the mistralai Python SDK support classifiers.moderate_async method for content moderation?

💡 Result:

Short answer: No — the official Mistral Python SDK exposes classifiers.moderate and classifiers.moderate_chat (not a classifiers.moderate_async method). See the SDK classifiers docs and package reference. [1][2]

Sources:

  • Mistral client-python classifiers README (shows moderate, moderate_chat). [1]
  • mistralai Python package details / API listing (shows classifiers: moderate, moderate_chat). [2]

Replace classifiers.moderate_async with supported Mistral moderation API

src/draive/mistral/moderation.py (lines 71–74) calls self._client.classifiers.moderate_async, but the mistralai Python SDK exposes classifiers.moderate and classifiers.moderate_chat (no moderate_async); update the call to use one of the supported methods and reconcile the sync/async boundary and related imports/typing (ModerationResponse).

🤖 Prompt for AI Agents
In src/draive/mistral/moderation.py around lines 71 to 74, the code currently
awaits self._client.classifiers.moderate_async which does not exist in the
mistralai SDK; replace it with a supported API (classifiers.moderate or
classifiers.moderate_chat) and reconcile the sync/async boundary by calling the
synchronous method inside an executor (e.g., asyncio.to_thread) or removing the
await if you convert the function to synchronous. Also update imports/typing for
ModerationResponse to match the return type of the chosen method and adjust any
downstream code that expects the previous async signature.

Comment on lines 78 to 83
if result.categories is None:
continue # skip empty

for category, flagged in result.categories.items():
if flagged: # add all flagged categories
violations.add(category)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick

Consider defensive handling of categories structure.

While you check for None categories, the iteration assumes categories is a dictionary when not None. Consider adding more defensive checks or documenting the expected structure.

             for result in response.results:
                 if result.categories is None:
                     continue  # skip empty
+                if not isinstance(result.categories, dict):
+                    ctx.log_warning(f"Unexpected categories type: {type(result.categories)}")
+                    continue

                 for category, flagged in result.categories.items():
🤖 Prompt for AI Agents
In src/draive/mistral/moderation.py around lines 78 to 83, the code only checks
for None but then assumes result.categories is a dict and calls .items(); add a
defensive check to ensure result.categories is a mapping/dict before iterating
(e.g., isinstance(result.categories, dict)), and if it's not a dict either
convert/coerce it into the expected shape (or skip and optionally log a warning)
so you never call .items() on an unexpected type; also update the function/type
hint or add a short comment documenting the expected categories structure.

) -> None:
moderation_config: OpenAIModerationConfig = config or ctx.state(OpenAIModerationConfig)
async with ctx.scope("openai_moderation"):
async with ctx.scope("moderation"):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick

Consider maintaining provider-specific scope naming.

While "moderation" is cleaner, using "openai_moderation" would maintain consistency with other provider-specific scopes and make it easier to distinguish between different moderation providers in observability data.

-        async with ctx.scope("moderation"):
+        async with ctx.scope("openai_moderation"):
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async with ctx.scope("moderation"):
async with ctx.scope("openai_moderation"):
🤖 Prompt for AI Agents
In src/draive/openai/moderation.py around line 31, the scope is currently named
"moderation"; change it to the provider-specific name "openai_moderation" to
match other provider-specific scopes used across the codebase. Update that async
with ctx.scope(...) call to use "openai_moderation" and scan for any related
observability/telemetry code or tests that reference the old "moderation" scope
so they can be adjusted accordingly.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/draive/mistral/moderation.py (1)

17-91: Add NumPy-style docstring for public class.

The public class MistralContentModeration is missing required documentation per coding guidelines.

Add after line 17:

class MistralContentModeration(MistralAPI):
    """
    Mistral API implementation for content moderation.

    Provides content moderation capabilities using Mistral's moderation API,
    supporting multimodal content checking for both input and output guardrails.

    Parameters
    ----------
    server_url : str | None
        Optional Mistral API server URL. Defaults to MISTRAL_SERVER_URL env var
        or "https://api.mistral.ai".
    api_key : str | None
        Optional Mistral API key. Defaults to MISTRAL_API_KEY env var.
    timeout : float | None
        Optional request timeout in seconds.
    **extra : Any
        Additional parameters passed to the base API class.
    """
src/draive/openai/client.py (1)

30-33: Adopt NumPy‑style docstring for the public class.

Project guidelines require NumPy docstrings for public symbols. Replace the brief sentence with a structured docstring.

-    """
-    Access to OpenAI services, can be used to prepare various functionalities like lmm.
-    """
+    """
+    Access to OpenAI services.
+
+    Parameters
+    ----------
+    base_url : str | None, optional
+        Base URL for the OpenAI API (overrides environment/default), by default None.
+    api_key : str | None, optional
+        API key, by default None (resolved from environment).
+    organization : str | None, optional
+        OpenAI organization identifier, by default None.
+    azure_api_endpoint : str | None, optional
+        Azure OpenAI endpoint, by default None.
+    azure_api_version : str | None, optional
+        Azure OpenAI API version, by default None.
+    azure_deployment : str | None, optional
+        Azure OpenAI deployment name, by default None.
+    timeout : float | None, optional
+        Client request timeout in seconds, by default None.
+    features : Collection[type[State]] | None, optional
+        Enabled feature states to bind on enter. Defaults to
+        {GenerativeModel, RealtimeGenerativeModel, TextEmbedding, ImageGeneration, GuardrailsModeration}.
+    **extra : Any
+        Provider‑specific options forwarded to the underlying client.
+
+    Notes
+    -----
+    Use this class as an async context manager and bind the returned states with `haiway.ctx.scope(...)`.
+    """
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9791fb6 and b31c9a8.

📒 Files selected for processing (6)
  • pyproject.toml (1 hunks)
  • src/draive/mistral/__init__.py (1 hunks)
  • src/draive/mistral/config.py (2 hunks)
  • src/draive/mistral/moderation.py (1 hunks)
  • src/draive/openai/client.py (2 hunks)
  • src/draive/openai/moderation.py (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Use absolute imports from the draive package (e.g., from draive import ...), not relative imports
Follow Ruff import ordering: standard library, third-party, then local imports
Use Python 3.12+ typing features (e.g., | unions, PEP 695 generics)
Prefer abstract/base collection types (Sequence, Mapping, Set, Iterable) over concrete list, dict, set in type hints
Define and raise custom exception types for specific error cases
Use NumPy docstring convention for all functions, classes, and methods
Skip module-level docstrings unless explicitly requested
Docstrings should include Parameters, Returns, Raises, and Notes (if needed) sections

Format all Python code with Ruff formatter (run via make format); do not use any other formatter

Files:

  • src/draive/mistral/moderation.py
  • src/draive/mistral/__init__.py
  • src/draive/mistral/config.py
  • src/draive/openai/moderation.py
  • src/draive/openai/client.py
src/draive/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/draive/**/*.py: Import Haiway symbols directly as from haiway import State, ctx
Use ctx.scope(...) to bind active State instances; avoid global state
Route all logging through ctx.log_* and never use print
Enforce strict typing on public APIs; avoid untyped definitions and Any except at verified third‑party boundaries
Prefer explicit attribute access with static types; avoid dynamic getattr except at narrow boundaries
Use abstract immutable protocols (Mapping, Sequence, Iterable) instead of concrete dict/list/set in public types
Use final where applicable; prefer composition over complex inheritance
Use precise unions (|), narrow with match/isinstance, and avoid cast unless provably safe and localized
Model immutable configuration/data as haiway.State; avoid in‑place mutation and prefer State.updated(...)/functional builders
Access active state via haiway.ctx within async scopes (ctx.scope(...))
Public state methods that dispatch on the active instance must use @statemethod
Add structured, concise logs around generation calls, tool dispatch, and provider requests/responses (without secrets); add metrics via ctx.record where applicable
All I/O is async; keep boundaries async, use ctx.spawn for detached tasks, and avoid custom threading
Translate provider/SDK errors into typed exceptions; never raise bare Exception; preserve context
Compose multimodal content with MultimodalContent.of(...); use ResourceContent/Reference for blobs; wrap custom data in ArtifactContent (use hidden when needed)
Public symbols require NumPy-style docstrings with Parameters/Returns/Raises and rationale when non-obvious
Avoid docstrings for internal helpers; prefer self-explanatory names; skip module-level docstrings
Never log secrets or full request bodies containing keys/tokens
Read credentials from environment variables; resolve via helpers like getenv_str

Files:

  • src/draive/mistral/moderation.py
  • src/draive/mistral/__init__.py
  • src/draive/mistral/config.py
  • src/draive/openai/moderation.py
  • src/draive/openai/client.py
src/draive/{openai,anthropic,mistral,gemini,vllm,ollama,bedrock,cohere}/{config,client,api}.py

📄 CodeRabbit inference engine (AGENTS.md)

Provider adapters must include config.py, client.py, and api.py within each provider package

Files:

  • src/draive/mistral/config.py
  • src/draive/openai/client.py
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
PR: miquido/draive#0
File: AGENTS.md:0-0
Timestamp: 2025-09-11T15:22:15.967Z
Learning: Applies to src/draive/__init__.py : Centralize and update all public exports in `src/draive/__init__.py` when API surface changes
📚 Learning: 2025-09-11T15:22:15.967Z
Learnt from: CR
PR: miquido/draive#0
File: AGENTS.md:0-0
Timestamp: 2025-09-11T15:22:15.967Z
Learning: Applies to src/draive/__init__.py : Centralize and update all public exports in `src/draive/__init__.py` when API surface changes

Applied to files:

  • src/draive/mistral/__init__.py
📚 Learning: 2025-09-08T10:32:32.520Z
Learnt from: CR
PR: miquido/draive#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T10:32:32.520Z
Learning: Applies to draive/**/__init__.py : Put exported public symbols into package __init__.py files

Applied to files:

  • src/draive/mistral/__init__.py
🧬 Code graph analysis (4)
src/draive/mistral/moderation.py (8)
src/draive/guardrails/moderation/state.py (1)
  • GuardrailsModeration (24-102)
src/draive/guardrails/moderation/types.py (1)
  • GuardrailsModerationException (16-29)
src/draive/mistral/api.py (1)
  • MistralAPI (9-51)
src/draive/mistral/config.py (1)
  • MistralModerationConfig (26-27)
src/draive/multimodal/content.py (2)
  • MultimodalContent (25-592)
  • resources (95-125)
src/draive/multimodal/artifact.py (1)
  • ArtifactContent (11-96)
src/draive/multimodal/text.py (1)
  • TextContent (11-82)
src/draive/resources/types.py (2)
  • ResourceContent (126-212)
  • ResourceReference (74-97)
src/draive/mistral/__init__.py (1)
src/draive/mistral/config.py (3)
  • MistralChatConfig (12-18)
  • MistralEmbeddingConfig (21-23)
  • MistralModerationConfig (26-27)
src/draive/openai/moderation.py (1)
src/draive/guardrails/moderation/state.py (1)
  • GuardrailsModeration (24-102)
src/draive/openai/client.py (1)
src/draive/openai/moderation.py (2)
  • OpenAIContentModeration (15-246)
  • moderation_guardrails (16-20)
🔇 Additional comments (7)
pyproject.toml (1)

8-8: Version bump looks good.

The version increment from 0.85.4 to 0.85.5 is appropriate for this new feature addition.

src/draive/mistral/config.py (1)

26-27: LGTM!

The MistralModerationConfig follows the established pattern and uses the appropriate default model.

src/draive/openai/moderation.py (2)

16-20: LGTM! Consistent naming improvement.

The rename from content_guardrails to moderation_guardrails improves clarity and consistency.


22-31: Good consistency with method naming.

The rename from content_verification to content_moderation and the scope change from "openai_moderation" to "moderation" provide better consistency across the moderation system.

src/draive/mistral/__init__.py (1)

2-9: Export MistralModerationConfig from top-level package

src/draive/mistral/init.py exposes MistralModerationConfig, but src/draive/init.py does not—add from draive.mistral import MistralModerationConfig and include "MistralModerationConfig" in __all__ of src/draive/init.py.

Likely an incorrect or invalid review comment.

src/draive/mistral/moderation.py (1)

14-14: Verify MistralContentModeration export in package root

Search returned no matches for MistralContentModeration in src/draive/init.py or src/draive/mistral/init.py — if the class is intended for public use, import it in src/draive/init.py and add to all (or ensure src/draive/mistral/init.py re-exports it).

src/draive/openai/client.py (1)

88-90: Correct use of the renamed API (moderation_guardrails).

This aligns with the new guardrails entrypoint and the GuardrailsModeration feature gate.

Comment on lines +18 to +23
def content_guardrails(self) -> GuardrailsModeration:
return GuardrailsModeration(
input_checking=self.content_verification,
output_checking=self.content_verification,
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick

Consider renaming method for consistency.

The method name content_guardrails() differs from the OpenAI implementation's moderation_guardrails(). Consider aligning the naming for consistency across providers.

-    def content_guardrails(self) -> GuardrailsModeration:
+    def moderation_guardrails(self) -> GuardrailsModeration:
         return GuardrailsModeration(
             input_checking=self.content_verification,
             output_checking=self.content_verification,
         )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def content_guardrails(self) -> GuardrailsModeration:
return GuardrailsModeration(
input_checking=self.content_verification,
output_checking=self.content_verification,
)
def moderation_guardrails(self) -> GuardrailsModeration:
return GuardrailsModeration(
input_checking=self.content_verification,
output_checking=self.content_verification,
)
🤖 Prompt for AI Agents
In src/draive/mistral/moderation.py around lines 18 to 22, rename the method
content_guardrails() to moderation_guardrails() to match the OpenAI
implementation; update the method definition name and all internal
references/imports/usages across the codebase (including tests) to call
moderation_guardrails(), keep the same return type GuardrailsModeration and
behavior, and optionally add a thin compatibility wrapper named
content_guardrails() that forwards to moderation_guardrails() if you need to
avoid breaking callers during the transition.

Comment on lines 24 to 31
async def content_verification( # noqa: C901
self,
content: Multimodal,
/,
config: MistralModerationConfig,
**extra: Any,
) -> None:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick

Rename method to align with OpenAI pattern.

For consistency with the OpenAI implementation, consider renaming content_verification to content_moderation.

-    async def content_verification(  # noqa: C901
+    async def content_moderation(  # noqa: C901
         self,
         content: Multimodal,
         /,
         config: MistralModerationConfig,
         **extra: Any,
     ) -> None:

And update the guardrails method:

     def moderation_guardrails(self) -> GuardrailsModeration:
         return GuardrailsModeration(
-            input_checking=self.content_verification,
-            output_checking=self.content_verification,
+            input_checking=self.content_moderation,
+            output_checking=self.content_moderation,
         )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async def content_verification( # noqa: C901
self,
content: Multimodal,
/,
config: MistralModerationConfig,
**extra: Any,
) -> None:
async def content_moderation( # noqa: C901
self,
content: Multimodal,
/,
config: MistralModerationConfig,
**extra: Any,
) -> None:
def moderation_guardrails(self) -> GuardrailsModeration:
return GuardrailsModeration(
input_checking=self.content_moderation,
output_checking=self.content_moderation,
)
🤖 Prompt for AI Agents
In src/draive/mistral/moderation.py around lines 24-30, rename the async method
content_verification to content_moderation to match the OpenAI naming pattern;
update the corresponding guardrails method name used inside this module (and any
internal helper names) to the new content_moderation name, then update all call
sites, imports, tests, and documentation to reference content_moderation instead
of content_verification so nothing breaks at runtime; ensure function signature
and behavior remain identical and run the test suite to confirm no remaining
references.

moderated_content.append(media_ref.to_str())

case ArtifactContent() as artifact:
moderated_content.append(artifact.artifact.to_str())
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

Potential attribute access error on ArtifactContent.

The code assumes all artifacts have a to_str() method, which may not be guaranteed for all DataModel types.

Consider adding a safety check or using the existing to_str() method from ArtifactContent:

-                        moderated_content.append(artifact.artifact.to_str())
+                        moderated_content.append(artifact.to_str())

Let's verify the ArtifactContent implementation:


🏁 Script executed:

#!/bin/bash
# Check ArtifactContent's to_str implementation
ast-grep --pattern 'class ArtifactContent {
  $$$
  def to_str($$$) {
    $$$
  }
  $$$
}'

Length of output: 0


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="src/draive/mistral/moderation.py"
if [ -f "$FILE" ]; then
  echo "=== $FILE ==="
  sed -n '1,240p' "$FILE" || true
else
  echo "$FILE not found"
fi

echo
echo "=== rg searches: ArtifactContent / Artifact / to_str / artifact.artifact / artifact.to_str ==="
rg -n -C3 --hidden --no-ignore '\bclass\s+ArtifactContent\b' || true
rg -n -C3 --hidden --no-ignore '\bclass\s+Artifact\b' || true
rg -n -C3 --hidden --no-ignore '\bdef\s+to_str\b' || true
rg -n -C3 --hidden --no-ignore '\bartifact\.artifact\b' || true
rg -n -C3 --hidden --no-ignore '\bartifact\.to_str\b' || true
rg -n -C3 --hidden --no-ignore '\bArtifactContent\b' || true
rg -n -C3 --hidden --no-ignore '\bto_str\s*\(' || true

Length of output: 102991


Replace direct artifact.artifact.to_str() with ArtifactContent.to_str()

ArtifactContent.to_str() already exists and respects the hidden flag (returns "" when hidden); calling artifact.artifact.to_str() bypasses that and can leak hidden payloads — use artifact.to_str() instead.

Location: src/draive/mistral/moderation.py (around lines 61–62). ArtifactContent.to_str is implemented in src/draive/multimodal/artifact.py (def to_str at ~line 82).

Suggested change:

-                        moderated_content.append(artifact.artifact.to_str())
+                        moderated_content.append(artifact.to_str())
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
moderated_content.append(artifact.artifact.to_str())
moderated_content.append(artifact.to_str())
🤖 Prompt for AI Agents
In src/draive/mistral/moderation.py around line 62, the code calls
artifact.artifact.to_str(), bypassing ArtifactContent.to_str() which respects
the hidden flag and can return an empty string for hidden content; replace the
direct attribute call with artifact.to_str() so the hidden logic is honored and
hidden payloads are not leaked.

from draive.openai.embedding import OpenAIEmbedding
from draive.openai.guardrails import OpenAIContentModeration
from draive.openai.images import OpenAIImageGeneration
from draive.openai.moderation import OpenAIContentModeration
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

🧩 Analysis chain

Import relocation to moderation module looks correct.

Good switch to draive.openai.moderation.OpenAIContentModeration; resolves the new API location.

Run to surface any stale references to the old guardrails API:


🏁 Script executed:

#!/bin/bash
# Find legacy imports and symbols renamed in this PR
rg -nP -C2 $'\bfrom\s+draive\.openai\.guardrails\b|content_guardrails\s*\(|content_verification\s*\('

Length of output: 660


Replace remaining guardrails references in src/draive/mistral/moderation.py

Legacy guardrails APIs (content_guardrails, content_verification) are still present — migrate these to the new moderation API or remove the guardrails usage.

  • src/draive/mistral/moderation.py: lines ~16–26 — def content_guardrails(...) and async def content_verification(...).
🤖 Prompt for AI Agents
src/draive/mistral/moderation.py around lines 16–26: remove or migrate the
legacy guardrails functions content_guardrails(...) and async
content_verification(...); replace their internals to call the new moderation
API (e.g., use the OpenAIContentModeration client from
src/draive/openai/client.py), update imports, adapt parameters and return types
to match the new moderation client, ensure async/await usage and error handling
follow the new API contract, and delete any leftover references to
content_guardrails/content_verification throughout the module.

@KaQuMiQ KaQuMiQ force-pushed the feature/mistral_moderation branch 2 times, most recently from e108213 to aa27090 Compare September 18, 2025 08:13
@KaQuMiQ KaQuMiQ force-pushed the feature/mistral_moderation branch from aa27090 to 3009a26 Compare September 18, 2025 08:17
@KaQuMiQ KaQuMiQ merged commit ef93bb1 into main Sep 18, 2025
4 checks passed
@KaQuMiQ KaQuMiQ deleted the feature/mistral_moderation branch September 18, 2025 08:22
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