fix(responses-bridge): expand namespace tools instead of dropping them - #36253
fix(responses-bridge): expand namespace tools instead of dropping them#36253devin-ai-integration[bot] wants to merge 2 commits into
Conversation
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
Greptile SummaryThis PR fixes the Responses-to-Chat-Completions bridge so namespace containers are recursively expanded rather than discarded.
Confidence Score: 5/5The PR appears safe to merge, with namespace tools now flowing through the bridge’s existing conversion behavior without an identified regression. The flattening helper preserves the order and content of non-namespace tools, recursively exposes nested tools to the established conversion loop, and the added tests cover the primary fixed behavior and mixed-tool case.
|
| Filename | Overview |
|---|---|
| litellm/responses/litellm_completion_transformation/namespace_tools.py | Adds a focused, non-mutating recursive helper that preserves tool order while replacing namespace containers with their nested tools. |
| litellm/responses/litellm_completion_transformation/transformation.py | Applies namespace expansion before the existing conversion loop and removes namespace from the unsupported-tool drop list. |
| tests/test_litellm/responses/litellm_completion_transformation/test_litellm_completion_responses.py | Adds meaningful regression tests covering nested function conversion, ordering alongside top-level tools, parameter defaults, and dropping unsupported nested built-ins. |
Reviews (1): Last reviewed commit: "fix(responses-bridge): expand namespace ..." | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
TLDR
Problem this solves:
How it solves it:
User Flow
Before: a developer using a client that groups its tools in a namespace, against a model routed through the chat completions bridge, watches the model act as if it has no tools
"tool_choice": "required"and one tool of"type": "namespace"holding aget_weatherfunction tooloutputholds a single message with empty text, nofunction_callitemAfter: the same request produces the tool call the client asked for
outputnow holds afunction_callitem namedget_weatherwith{"city":"Tokyo"}Relevant issues
Issue 2 of #35878. Issue 1 of it was fixed separately in #35885, so #35878 is reopened for this half
Linear ticket
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaito re-request a review after pushing changes)Screenshots / Proof of Fix
A namespace is a grouping container: it has no callable schema of its own, and its
toolsarray holds ordinary function tools. The bridge treated it as an unsupported built-in next tocomputer_useandimage_generationand dropped it, taking the nested tools with it, so a bridged client silently lost themConfig used for both runs, a real OpenAI model forced onto the bridge:
Request body used for both runs, saved as
request.json:{ "model": "bridged-model", "input": "Call the get_weather tool for Tokyo. Do not answer in text.", "tool_choice": "required", "reasoning": {"effort": "none"}, "tools": [ { "type": "namespace", "name": "collaboration", "description": "sub-agent tools", "tools": [ { "type": "function", "name": "get_weather", "description": "Get the weather for a city", "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]} } ] } ] }Before, at
0a606cb258(this branch's base, with the fix not applied), the namespace and its nested tool are gone and the model answers with empty text:{"id":"resp_IgIOoTcP_Yh74rI4g71pGHiyjTMiTyGSF...","created_at":1786159520,"model":"bridged-model","object":"response","output":[{"type":"message","id":"chatcmpl-EARySoR9kgGZISjvuz8ENhVPgLPWZ","status":"completed","role":"assistant","content":[{"type":"output_text","text":"","annotations":[]}],"phase":null}],"parallel_tool_calls":false,"temperature":0.0,"tool_choice":"auto","tools":[]}and the proxy log for that request says so outright:
After, same curl at
82df8a9489, the nested tool survives and the model calls it:{"id":"resp_yHqPRxKGKlEGJTd8kDGrEg4tqOVjzYJEqNL8...","created_at":1786160325,"model":"bridged-model","object":"response","output":[{"type":"message","id":"chatcmpl-EASBXPb2DkLGzFPpjBWX8PaWycLgD","status":"completed","role":"assistant","content":[{"type":"output_text","text":null,"annotations":[]}],"phase":null},{"arguments":"{\"city\":\"Tokyo\"}","call_id":"call_TrzCsyrJhvCHcF5ut2gb0yyj","name":"get_weather","type":"function_call","id":"call_TrzCsyrJhvCHcF5ut2gb0yyj","namespace":null,"status":"completed"}],"parallel_tool_calls":false,"temperature":0.0,"tool_choice":"auto","tools":[]}No
Dropping Responses API toolline appears in the log for the after runThe two new regression tests fail on the unfixed tree and pass with the fix, and
tests/test_litellm/responses/stays greenType
🐛 Bug Fix
Changes
litellm/responses/litellm_completion_transformation/namespace_tools.pyis new and holdsflatten_namespace_tools, which walks the requested tools and swaps each namespace for the tools it containslitellm/responses/litellm_completion_transformation/transformation.pyruns the requested tools through that helper before its conversion loop. Flattening up front rather than adding a branch inside the loop keeps that already long function from growing another path, and it avoids the recursion the code-quality check bans. Nested tools then go through the samefunction,custom,mcp, andweb_searchhandling as top level ones, so an unsupported built-in nested inside a namespace is still dropped, andnamespacestays in the drop list so a namespace nested inside a namespace never reaches the providerThis matches what the Anthropic chat transformation already does with namespaces, which flattens them rather than dropping
Not included: #35878 also asks for
tool_searchto be converted into a function tool. That one is a server side Responses tool, so turning it into a client facing function tool would have the model emittool_searchcalls the client never intended to answer. #33783 already drops it, which is the right handling for chat only providers, so this PR leaves that path aloneFinal Attestation
Link to Devin session: https://app.devin.ai/sessions/f4699e222aab44d5a016abc259d9f19b
Requested by: @yucheng-berri