Skip to content

Commit 5f471d7

Browse files
feat(api): Support input guardrail checks when role: 'system'
1 parent 15e9757 commit 5f471d7

2 files changed

Lines changed: 29 additions & 3 deletions

File tree

nemoguardrails/server/api.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,9 @@ async def _process_message(
10261026
if role == "user":
10271027
return None, _create_check_options(run_input=True)
10281028

1029+
if role == "system":
1030+
return None, _create_check_options(run_input=True)
1031+
10291032
if role == "assistant":
10301033
if "tool_calls" in msg:
10311034
# Tool output rails - validate tool calls before execution
@@ -1039,7 +1042,7 @@ async def _process_message(
10391042
return None, _create_check_options(run_tool_input=True)
10401043

10411044
# Unsupported role
1042-
raise ValueError(f"Unsupported message role: '{role}'. Supported roles are: 'user', 'assistant', 'tool'.")
1045+
raise ValueError(f"Unsupported message role: '{role}'. Supported roles are: 'user', 'system', 'assistant', 'tool'.")
10431046

10441047

10451048
def _build_check_messages(role: str, content: str, msg: dict) -> List[dict]:
@@ -1059,6 +1062,9 @@ def _build_check_messages(role: str, content: str, msg: dict) -> List[dict]:
10591062
if role == "user":
10601063
return [{"role": "user", "content": content}]
10611064

1065+
if role == "system":
1066+
return [{"role": "user", "content": content}]
1067+
10621068
if role == "assistant":
10631069
return [
10641070
{"role": "user", "content": ""},
@@ -1071,7 +1077,7 @@ def _build_check_messages(role: str, content: str, msg: dict) -> List[dict]:
10711077
return [tool_msg]
10721078

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

10761082

10771083
@app.post(
@@ -1083,6 +1089,7 @@ async def guardrail_checks(body: GuardrailsChatCompletionRequest, request: Reque
10831089
10841090
This endpoint validates messages against configured guardrails using role-based routing:
10851091
- user messages: evaluated by input rails
1092+
- system messages: evaluated by input rails
10861093
- assistant messages: evaluated by output rails
10871094
- tool messages: evaluated by tool_input rails
10881095
@@ -1111,6 +1118,7 @@ async def process_checks():
11111118
11121119
Messages are checked independently based on role:
11131120
- user messages: input rails
1121+
- system messages: input rails
11141122
- assistant messages: output rails
11151123
- tool messages: tool_input rails
11161124
"""

tests/test_guardrail_checks_api.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,13 +338,31 @@ def test_no_config_and_no_default():
338338
api.app.default_config_id = "simple_rails"
339339

340340

341+
def test_system_message_passes():
342+
"""System message triggers input rails and passes."""
343+
response = client.post(
344+
"/v1/guardrail/checks",
345+
json={
346+
"model": "test",
347+
"messages": [{"role": "system", "content": "You are a helpful assistant"}],
348+
"guardrails": {"config_id": "simple_rails"},
349+
},
350+
)
351+
352+
result = response.json()
353+
assert result["status"] == "success"
354+
assert len(result["messages"]) == 1
355+
assert result["messages"][0]["role"] == "system"
356+
assert result["messages"][0]["index"] == 0
357+
358+
341359
def test_unsupported_message_role():
342360
"""Unsupported message role returns error."""
343361
response = client.post(
344362
"/v1/guardrail/checks",
345363
json={
346364
"model": "test",
347-
"messages": [{"role": "system", "content": "You are a helpful assistant"}],
365+
"messages": [{"role": "developer", "content": "some content"}],
348366
"guardrails": {"config_id": "simple_rails"},
349367
},
350368
)

0 commit comments

Comments
 (0)