fix: preserve extra_body for LiteLLM to avoid UnsupportedParamsError (#409)#412
fix: preserve extra_body for LiteLLM to avoid UnsupportedParamsError (#409)#412
Conversation
…409) TransportKwargs.from_request() flattened extra_body keys into top-level kwargs, causing LiteLLM to reject provider-specific params like reasoning_effort via its per-provider allowlist validation. Add a flatten_extra_body flag (default True for backward compat) so the LiteLLM bridge can opt out and preserve extra_body as a distinct kwarg that LiteLLM forwards without validation. Made-with: Cursor
Greptile SummaryThis PR fixes a bug where Key changes:
|
| Filename | Overview |
|---|---|
| packages/data-designer-engine/src/data_designer/engine/models/clients/types.py | Adds flatten_extra_body boolean parameter to TransportKwargs.from_request(). Default True preserves existing flatten behavior; False preserves extra_body as a nested dict. Logic is correct: _META_FIELDS already excludes extra_body/extra_headers from optional_fields, preventing any key collisions. Edge cases (None, empty dict) handled consistently. |
| packages/data-designer-engine/src/data_designer/engine/models/clients/adapters/litellm_bridge.py | All 6 bridge methods (completion, acompletion, embeddings, aembeddings, generate_image, agenerate_image) updated to pass flatten_extra_body=False. This is a behavioral change: any field previously in extra_body (e.g., n for image generation) is now passed as extra_body={...} to LiteLLM instead of being flattened to a top-level kwarg — which is the intended fix. |
| packages/data-designer-engine/src/data_designer/engine/models/facade.py | Comment-only change updating the inline documentation for TransportKwargs behavior. No functional changes. |
| packages/data-designer-engine/tests/engine/models/clients/test_litellm_bridge.py | Existing assertions updated to reflect extra_body={"foo": "bar"} instead of flattened foo="bar". Two new tests added: one verifying reasoning_effort flows through as a nested extra_body kwarg, and corrected parameter ordering in other assertions. All test logic is sound and accurately validates the new behavior. |
| packages/data-designer-engine/tests/engine/models/clients/test_parsing.py | Two new unit tests added for the flatten_extra_body=False path: one verifying preservation of multi-key extra_body, and one verifying an empty extra_body is not injected. Existing default-path tests are unmodified and remain correct. |
Sequence Diagram
sequenceDiagram
participant Caller
participant LiteLLMBridgeClient
participant TransportKwargs
participant LiteLLMRouter
Caller->>LiteLLMBridgeClient: completion(request)<br/>extra_body={"reasoning_effort": "high"}
LiteLLMBridgeClient->>TransportKwargs: from_request(request, flatten_extra_body=False)
note over TransportKwargs: optional_fields = {temperature, ...}<br/>(extra_body excluded via _META_FIELDS)
note over TransportKwargs: body = {temperature: ...}<br/>body["extra_body"] = {"reasoning_effort": "high"}
TransportKwargs-->>LiteLLMBridgeClient: TransportKwargs(body={..., extra_body={...}}, headers={})
LiteLLMBridgeClient->>LiteLLMRouter: completion(model=..., messages=...,<br/>extra_headers=None, **transport.body)<br/>→ extra_body={"reasoning_effort":"high"} as kwarg
note over LiteLLMRouter: LiteLLM forwards extra_body<br/>to provider WITHOUT allowlist validation
LiteLLMRouter-->>LiteLLMBridgeClient: response
LiteLLMBridgeClient-->>Caller: ChatCompletionResponse
Last reviewed commit: 8cfdce3
andreatgretel
left a comment
There was a problem hiding this comment.
nice fix. maybe worth adding one regression test a bit closer to the original config / health check path too, just to lock this in end to end.
|
|
Update stale docstrings in TransportKwargs and facade.py to reflect the new flatten_extra_body flag, and add an edge-case test for empty extra_body with flatten disabled. Made-with: Cursor
good catch! updated stale docs in 8cfdce3 |
📋 Summary
TransportKwargs.from_request()flattenedextra_bodykeys into top-level kwargs, causing LiteLLM to reject provider-specific params likereasoning_effortvia its per-provider allowlist validation. This adds aflatten_extra_bodyflag so the LiteLLM bridge can preserveextra_bodyas a distinct kwarg that LiteLLM forwards without validation.🔄 Changes
🐛 Fixed
LiteLLMBridgeClientnow passesflatten_extra_body=FalsetoTransportKwargs.from_request()across all 6 methods (completion, embedding, image generation — both sync and async), soextra_bodykeys likereasoning_effortare preserved as a nested dict rather than flattened into top-level kwargs where LiteLLM rejects them🔧 Changed
TransportKwargs.from_request()gained aflatten_extra_bodyparameter —True(default) mergesextra_bodyinto the top-level body dict for future native adapters,Falsepreserves it as a distinctextra_bodykwarg for LiteLLM🧪 Tests
extra_body={"foo": "bar"}instead of flattenedfoo="bar"test_completion_passes_extra_body_as_distinct_kwargto explicitly verifyreasoning_effortflows through asextra_bodytest_extra_body_preserved_when_flatten_disabledfor the newTransportKwargscode path🔍 Attention Areas
types.py—TransportKwargs.from_request()— New branching logic forflatten_extra_body. DefaultTruepreserves existing behavior for future native adapters;Falseis the LiteLLM-specific path.🤖 Generated with AI
Closes #409