Skip to content

Commit d8e90cd

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 d8e90cd

File tree

2 files changed

+203
-0
lines changed

2 files changed

+203
-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

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

0 commit comments

Comments
 (0)