Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion docs/devel_doc/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -14639,7 +14639,13 @@
"url": {
"type": "string",
"title": "Base URL",
"description": "The model_id to use for the guard"
"description": "Base URL of the OpenAI-compatible inference endpoint."
},
"model_id": {
"type": "string",
"title": "Model name",
"description": "Model name sent to the inference server. Override when the server registers the model under a different name (e.g. an Ollama tag). The prompt template is built for the 4.1 format.",
"default": "ibm-granite/granite-guardian-4.1-8b"
},
"api_key": {
"anyOf": [
Expand Down Expand Up @@ -14686,6 +14692,21 @@
"description": "SSL certificate verification. Can be:\n - True: Verify using system CA bundle (default, recommended)\n - False: Disable verification (insecure, for dev only)\n - str: Path to custom CA bundle file (for internal PKI)",
"default": true
},
"parallel": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "integer",
"maximum": 10.0,
"minimum": 1.0
}
],
"title": "Parallel execution",
"description": "True to run all risk checks in parallel, False to run sequentially, or an integer 1-10 for explicit batch size.",
"default": 3
},
"risks": {
"items": {
"$ref": "#/components/schemas/RiskDefinition"
Expand Down
48 changes: 45 additions & 3 deletions src/models/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
PositiveInt,
PrivateAttr,
SecretStr,
StrictBool,
field_validator,
model_validator,
)
Expand Down Expand Up @@ -2422,8 +2423,7 @@ def validate_providers_and_default(self) -> Self:

if self.default_provider is None:
raise ValueError(
"vector_store.default_provider is required when providers "
"is non-empty"
"vector_store.default_provider is required when providers is non-empty"
)

ids = [provider.id for provider in self.providers]
Expand Down Expand Up @@ -3217,7 +3217,19 @@ class GraniteGuardianConfig(ConfigurationBase):
"""Configuration for the Granite Guardian moderation guardrail."""

url: str = Field(
..., title="Base URL", description="The model_id to use for the guard"
...,
title="Base URL",
description="Base URL of the OpenAI-compatible inference endpoint.",
)

model_id: str = Field(
"ibm-granite/granite-guardian-4.1-8b",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What happens if this model is not configured?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Also, I noticed that we're not using OGX here. Is this correct way how to reference guardian models? Just asking...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

the goal of this shield is to satisfy ask rhs need. they use models.corp for granite guardian so we are just extending that pattern. I don't think we need to run it through llama stack when we can access it directly.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sure, my question was more like - is this correct way how to reference models? <provider>/<model> (just asking).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@asimurka do you mean that if this can successfully receive 200 from the models.corp endpoints or you concern about the format? 🤔

title="Model name",
description=(
"Model name sent to the inference server. Override when the "
"server registers the model under a different name (e.g. an "
"Ollama tag). The prompt template is built for the 4.1 format."
),
)

api_key: Optional[SecretStr] = Field(
Expand All @@ -3243,12 +3255,42 @@ class GraniteGuardianConfig(ConfigurationBase):
),
)

parallel: StrictBool | Annotated[int, Field(ge=1, le=10)] = Field(
default=3,
title="Parallel execution",
description=(
"True to run all risk checks in parallel, "
"False to run sequentially, "
"or an integer 1-10 for explicit batch size."
),
)

risks: list[RiskDefinition] = Field(
...,
title="Defined risks",
description="Risks to be considered while applying this guradrail",
)

@model_validator(mode="after")
def validate_api_key_requires_https(self) -> Self:
"""Require HTTPS when an API key is configured.

Prevents the API key from being sent to the inference endpoint over
an unencrypted connection.

Raises:
ValueError: If ``api_key`` is set but ``url``'s scheme isn't https.

Returns:
The validated configuration instance.
"""
# pylint: disable=no-member
if self.api_key is not None and not self.url.startswith("https://"):
raise ValueError(
"Granite Guardian endpoints with an API key must use HTTPS"
)
return self


class GraniteGuardianShieldConfiguration(ConfigurationBase):
"""Configuration for a named Granite Guardian guardrail shield.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""Granite Guardian safety capability for risk-based moderation."""

from pydantic_ai_lightspeed.capabilities.granite_guardian._capability import (
GraniteGuardian,
)

__all__ = ["GraniteGuardian"]
Loading
Loading