Skip to content
Merged
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
12 changes: 10 additions & 2 deletions nemoguardrails/server/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,9 @@ async def _process_message(
if role == "user":
return None, _create_check_options(run_input=True)

if role == "system":
return None, _create_check_options(run_input=True)

if role == "assistant":
if "tool_calls" in msg:
# Tool output rails - validate tool calls before execution
Expand All @@ -1038,7 +1041,7 @@ async def _process_message(
return None, _create_check_options(run_tool_input=True)

# Unsupported role
raise ValueError(f"Unsupported message role: '{role}'. Supported roles are: 'user', 'assistant', 'tool'.")
raise ValueError(f"Unsupported message role: '{role}'. Supported roles are: 'user', 'system', 'assistant', 'tool'.")


def _build_check_messages(role: str, content: str, msg: dict) -> List[dict]:
Expand All @@ -1058,6 +1061,9 @@ def _build_check_messages(role: str, content: str, msg: dict) -> List[dict]:
if role == "user":
return [{"role": "user", "content": content}]

if role == "system":
return [{"role": "user", "content": content}]

if role == "assistant":
return [
{"role": "user", "content": ""},
Expand All @@ -1070,7 +1076,7 @@ def _build_check_messages(role: str, content: str, msg: dict) -> List[dict]:
return [tool_msg]

# This should never be reached since _process_message validates the role first
raise ValueError(f"Unsupported message role: '{role}'. Supported roles are: 'user', 'assistant', 'tool'.")
raise ValueError(f"Unsupported message role: '{role}'. Supported roles are: 'user', 'system', 'assistant', 'tool'.")


@app.post(
Expand All @@ -1082,6 +1088,7 @@ async def guardrail_checks(body: GuardrailsChatCompletionRequest, request: Reque

This endpoint validates messages against configured guardrails using role-based routing:
- user messages: evaluated by input rails
- system messages: evaluated by input rails
- assistant messages: evaluated by output rails
- tool messages: evaluated by tool_input rails

Expand Down Expand Up @@ -1110,6 +1117,7 @@ async def process_checks():

Messages are checked independently based on role:
- user messages: input rails
- system messages: input rails
- assistant messages: output rails
- tool messages: tool_input rails
"""
Expand Down
20 changes: 19 additions & 1 deletion tests/test_guardrail_checks_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,13 +338,31 @@
api.app.default_config_id = "simple_rails"


def test_system_message_passes():
"""System message triggers input rails and passes."""
response = client.post(
"/v1/guardrail/checks",
json={
"model": "test",
"messages": [{"role": "system", "content": "You are a helpful assistant"}],
"guardrails": {"config_id": "simple_rails"},
},
)

result = response.json()
assert result["status"] == "success"

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
assert len(result["messages"]) == 1

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
assert result["messages"][0]["role"] == "system"

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
assert result["messages"][0]["index"] == 0

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.


def test_unsupported_message_role():
"""Unsupported message role returns error."""
response = client.post(
"/v1/guardrail/checks",
json={
"model": "test",
"messages": [{"role": "system", "content": "You are a helpful assistant"}],
"messages": [{"role": "developer", "content": "some content"}],
"guardrails": {"config_id": "simple_rails"},
},
)
Expand Down
Loading