Skip to content

Commit fba8078

Browse files
committed
feat(validation): enforce reasoning traces with dialog rails
Added a root validator in `RailsConfig` to ensure that reasoning traces cannot be enabled when dialog rails are present, either explicitly or implicitly. This includes checks for user messages, bot messages, and flows. Also added comprehensive test cases to validate this behavior: - Explicit dialog rails - Implicit dialog rails via user/bot messages or flows - Scenarios without dialog rails to ensure reasoning traces work as expected.
1 parent 8639f37 commit fba8078

File tree

2 files changed

+210
-0
lines changed

2 files changed

+210
-0
lines changed

nemoguardrails/rails/llm/config.py

+41
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,47 @@ class RailsConfig(BaseModel):
11331133
description="Configuration for tracing.",
11341134
)
11351135

1136+
@root_validator(pre=True, allow_reuse=True)
1137+
def check_reasoning_traces_with_dialog_rails(cls, values):
1138+
"""Check that reasoning traces are not enabled when dialog rails are present."""
1139+
1140+
models = values.get("models", [])
1141+
rails = values.get("rails", {})
1142+
dialog_rails = rails.get("dialog", {})
1143+
1144+
# check if any model has reasoning traces enabled
1145+
# TODO: we must check for models that are used in a specific dialog task
1146+
has_reasoning_traces = False
1147+
for model in models:
1148+
if isinstance(model, dict):
1149+
reasoning_config = model.get("reasoning_config", {})
1150+
if not reasoning_config.get("remove_thinking_traces", True):
1151+
has_reasoning_traces = True
1152+
break
1153+
elif hasattr(model, "reasoning_config"):
1154+
if not model.reasoning_config.remove_thinking_traces:
1155+
has_reasoning_traces = True
1156+
break
1157+
1158+
# check if dialog rails are present (explicitly or implicitly)
1159+
has_dialog_rails = bool(dialog_rails)
1160+
1161+
# check implicit dialog rails through user messages, bot messages, or flows
1162+
if not has_dialog_rails:
1163+
has_dialog_rails = (
1164+
bool(values.get("user_messages"))
1165+
or bool(values.get("bot_messages"))
1166+
or bool(values.get("flows"))
1167+
)
1168+
1169+
if has_reasoning_traces and has_dialog_rails:
1170+
raise ValueError(
1171+
"Reasoning traces cannot be enabled when dialog rails are present. "
1172+
"Please either disable reasoning traces or remove dialog rails."
1173+
)
1174+
1175+
return values
1176+
11361177
@root_validator(pre=True, allow_reuse=True)
11371178
def check_prompt_exist_for_self_check_rails(cls, values):
11381179
rails = values.get("rails", {})

tests/test_config_validation.py

+169
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,172 @@ def test_passthrough_and_single_call_incompatibility():
122122
# LLMRails(config=config)
123123
#
124124
# assert "You must provide a `self_check_facts` prompt" in str(exc_info.value)
125+
126+
127+
def test_reasoning_traces_with_explicit_dialog_rails():
128+
"""Test that reasoning traces cannot be enabled when dialog rails are explicitly configured."""
129+
130+
with pytest.raises(ValueError) as exc_info:
131+
config = RailsConfig.from_content(
132+
yaml_content="""
133+
models:
134+
- type: main
135+
engine: openai
136+
model: gpt-3.5-turbo-instruct
137+
reasoning_config:
138+
remove_thinking_traces: false
139+
rails:
140+
dialog:
141+
single_call:
142+
enabled: true
143+
""",
144+
)
145+
LLMRails(config=config)
146+
147+
assert "Reasoning traces cannot be enabled when dialog rails are present" in str(
148+
exc_info.value
149+
)
150+
151+
152+
def test_reasoning_traces_without_dialog_rails():
153+
"""Test that reasoning traces can be enabled when no dialog rails are present."""
154+
155+
config = RailsConfig.from_content(
156+
yaml_content="""
157+
models:
158+
- type: main
159+
engine: openai
160+
model: gpt-3.5-turbo-instruct
161+
reasoning_config:
162+
remove_thinking_traces: false
163+
""",
164+
)
165+
LLMRails(config=config)
166+
167+
168+
def test_dialog_rails_without_reasoning_traces():
169+
"""Test that dialog rails can be enabled when reasoning traces are not enabled."""
170+
171+
config = RailsConfig.from_content(
172+
yaml_content="""
173+
models:
174+
- type: main
175+
engine: openai
176+
model: gpt-3.5-turbo-instruct
177+
rails:
178+
dialog:
179+
single_call:
180+
enabled: true
181+
""",
182+
)
183+
LLMRails(config=config)
184+
185+
186+
def test_reasoning_traces_with_implicit_dialog_rails_user_bot_messages():
187+
"""Test that reasoning traces cannot be enabled when dialog rails are implicitly enabled thru user/bot messages."""
188+
189+
with pytest.raises(ValueError) as exc_info:
190+
config = RailsConfig.from_content(
191+
yaml_content="""
192+
models:
193+
- type: main
194+
engine: openai
195+
model: gpt-3.5-turbo-instruct
196+
reasoning_config:
197+
remove_thinking_traces: false
198+
""",
199+
colang_content="""
200+
define user express greeting
201+
"hello"
202+
"hi"
203+
204+
define bot express greeting
205+
"Hello there!"
206+
207+
define flow
208+
user express greeting
209+
bot express greeting
210+
""",
211+
)
212+
LLMRails(config=config)
213+
214+
assert "Reasoning traces cannot be enabled when dialog rails are present" in str(
215+
exc_info.value
216+
)
217+
218+
219+
def test_reasoning_traces_with_implicit_dialog_rails_flows_only():
220+
"""Test that reasoning traces cannot be enabled when dialog rails are implicitly enabled thru flows only."""
221+
222+
with pytest.raises(ValueError) as exc_info:
223+
config = RailsConfig.from_content(
224+
yaml_content="""
225+
models:
226+
- type: main
227+
engine: openai
228+
model: gpt-3.5-turbo-instruct
229+
reasoning_config:
230+
remove_thinking_traces: false
231+
""",
232+
colang_content="""
233+
define flow
234+
user express greeting
235+
bot express greeting
236+
""",
237+
)
238+
LLMRails(config=config)
239+
240+
assert "Reasoning traces cannot be enabled when dialog rails are present" in str(
241+
exc_info.value
242+
)
243+
244+
245+
def test_reasoning_traces_with_implicit_dialog_rails_user_messages_only():
246+
"""Test that reasoning traces cannot be enabled when dialog rails are implicitly enabled thru user messages only."""
247+
248+
with pytest.raises(ValueError) as exc_info:
249+
config = RailsConfig.from_content(
250+
yaml_content="""
251+
models:
252+
- type: main
253+
engine: openai
254+
model: gpt-3.5-turbo-instruct
255+
reasoning_config:
256+
remove_thinking_traces: false
257+
""",
258+
colang_content="""
259+
define user express greeting
260+
"hello"
261+
"hi"
262+
""",
263+
)
264+
LLMRails(config=config)
265+
266+
assert "Reasoning traces cannot be enabled when dialog rails are present" in str(
267+
exc_info.value
268+
)
269+
270+
271+
def test_reasoning_traces_with_implicit_dialog_rails_bot_messages_only():
272+
"""Test that reasoning traces cannot be enabled when dialog rails are implicitly enabled thru bot messages only."""
273+
274+
with pytest.raises(ValueError) as exc_info:
275+
config = RailsConfig.from_content(
276+
yaml_content="""
277+
models:
278+
- type: main
279+
engine: openai
280+
model: gpt-3.5-turbo-instruct
281+
reasoning_config:
282+
remove_thinking_traces: false
283+
""",
284+
colang_content="""
285+
define bot express greeting
286+
"Hello there!"
287+
""",
288+
)
289+
LLMRails(config=config)
290+
291+
assert "Reasoning traces cannot be enabled when dialog rails are present" in str(
292+
exc_info.value
293+
)

0 commit comments

Comments
 (0)