Remove crashing extra_params.append in NeMoGuardrailsServer.__init__#1947
Remove crashing extra_params.append in NeMoGuardrailsServer.__init__#1947chuenchen309 wants to merge 2 commits into
Conversation
__init__ ran:
if self.extra_params and not self.extra_params.get("extra_body"):
self.extra_params.append("extra_body")
but extra_params is a dict (OpenAICompatible default {}, consumed via
.items()), so .append raises AttributeError. Any user who sets a non-empty
extra_params without an 'extra_body' key crashes generator construction.
The block is also vestigial: guardrails config is delivered through the
self.extra_body attribute (set just below and passed to the client by the
base class). And a naive 'fix' of setting extra_params["extra_body"] = {}
would be worse -- OpenAICompatible._call_model spreads extra_params into the
request after applying self.extra_body, so it would overwrite the real
guardrails config with an empty dict. Since the block only ever crashes or
is skipped (it never completed successfully), removing it changes no working
behaviour. Existing rail-selection tests still pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Andrew Chen <48723787+chuenchen309@users.noreply.github.com>
| if self.extra_params and not self.extra_params.get("extra_body"): | ||
| self.extra_params.append("extra_body") |
There was a problem hiding this comment.
Great catch, there is definitely a logic bug here. The approach taken though does not look to align with the intent as the original guard logic was flawed and does not have a clear comment on what it was meant to change after the call to super.__init__() completed.
The fix to this should not be to remove support for an existing extra_body found in the extra_params dict, a fix should properly handle when one does exist. The changes here actually would result in the user provided extra_body overriding what this generator is attempting to support as self.extra_body would shadowed by self.extra_params["extra_body"] in the current OpenAICompatible._call_model().
This suggests the the guard clause is checking the wrong condition and should be improved so the action taken will preform the correct addition. This guard exists augment the existing expectations for extra_params in OpenAICompatible to pass thru any keys in the extra_params provided via config as parameters to the OpenAI client method used for the inference request by merging the guardrails specific extra_body values.
if self.extra_params and "extra_body" in self.extra_params:
user_extra_body = self.extra_params.pop("extra_body", None)
if user_extra_body:
self.extra_body = user_extra_body
This would align with the rest of the initialization here by setting self.extra_body to the configured value and allowing the guardrails specific injections to be added to a configuration provided extra_body.
Note the suggestion above is still somewhat naive and should probably be extended with type checking to ensure self.extra_params["extra_body"] is a dict to avoid a type mis-match and raise an early exception about invalid configuration values.
Consider exploring adding more unit tests that evaluate how self.extra_body and self.extra_params will behave in the various combinations. Also consider looking at what happens if you were to mock the call to the underlying OpenAI client object in _call_model to see how these values end up mapping into that methods arguments.
Addresses review feedback from @jmartin-tech: the prior commit removed the crashing `self.extra_params.append("extra_body")` guard outright, but that left a separate, pre-existing bug in place -- a user-provided `extra_body` arriving nested inside `extra_params` was never merged into `self.extra_body`. Since `OpenAICompatible._call_model()` applies `self.extra_params` *after* the instance's own attributes, a lingering `extra_params["extra_body"]` would silently overwrite the guardrails config injected into `self.extra_body`, with the user's own extra_body also never actually reaching the request in combination with it. Pop `extra_body` out of `extra_params` (if present) and fold it into `self.extra_body` before the existing guardrails-merge logic runs, so the two sources combine instead of one shadowing the other. Also raise a clear ValueError if the popped value isn't a dict, per review suggestion, rather than failing confusingly later. Added two tests: one confirms a user extra_body and the guardrails config both end up in the actual outgoing request body (verified via the existing respx-mocked OpenAI client, per review suggestion to check how these map into the client call); the other confirms a non-dict extra_body raises ValueError at construction time. Confirmed both fail against the pre-fix code and pass after. Ran the full generators/test_guardrails.py + test_openai.py suites (no regressions) and black --check clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Andrew Chen <48723787+chuenchen309@users.noreply.github.com>
2271cc2 to
814f5cc
Compare
|
Thanks for the detailed review, @jmartin-tech — you're right, removing the guard outright just traded the crash for a silent shadowing bug. Pushed a fix that pops Added a test that verifies this end-to-end through the mocked OpenAI client (checking the actual outgoing request body has both the user's custom key and the guardrails config merged), plus a test for the ValueError on a non-dict |
What
NeMoGuardrailsServer.__init__runs:extra_paramsis a dict (inherited fromOpenAICompatible, default{}, consumed via.items()), so.appendraisesAttributeError: 'dict' object has no attribute 'append'. Any user who sets a non-emptyextra_paramswithout anextra_bodykey crashes generator construction:Why remove rather than fix the
.appendself.extra_bodyattribute set just below (and passed to the client by the base class), not via anextra_params["extra_body"]key.self.extra_params["extra_body"] = {}would be worse:OpenAICompatible._call_modelspreadsextra_paramsinto the request after applyingself.extra_body, so it would overwrite the real guardrails config with an empty dict.Test
Added
test_nonempty_extra_params_does_not_crash_init: constructingNeMoGuardrailsServerwithextra_params={"foo": 1}must not raise and must leaveextra_paramsintact. Fails before the change (AttributeError), passes after. The existing rail-selection tests still pass, confirming the block was vestigial.black --checkclean.Disclosure: this contribution was prepared with the assistance of an AI agent (Claude Code). The analysis, fix, and test were reviewed by me before submission.