litellm/tests/unit/llms/openai
Kerry Lu 8207a57d84
fix(responses): keep the namespace == name shape for deferred top-level tools (#50602)
* fix(responses): keep the namespace == name shape for deferred top-level tools

The OpenAI Agents SDK matches a call to a deferred top-level function
(defer_loading=True) only when the function_call carries namespace == name,
the shape it reserves for deferred top-level tools. The Responses bridge
returned no namespace, so after a native tool search the SDK failed with
"Tool <name> not found". A client that adds namespace == name then hit the
echo path, which joined it into "<name>__<name>" for the provider.

- namespace_tool_name_map maps deferred top-level functions to (name, name),
  so non-streaming and streaming replies carry namespace == name
- the function_call echo does not qualify a name whose namespace equals it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(responses): keep the qualified name for a namespace member that shares its namespace's name

A namespace "search" with a member "search" is advertised as the chat tool
"search__search" and comes back as name == namespace == "search". The echo
rule from the previous commit skipped the join for every namespace == name,
so that replay reached the provider as "search", a tool it was never given.

The bare-name echo now applies only to the request's deferred top-level
tools (deferred_top_level_names), and the reply map uses the same set. A
deferred top-level name that a self-named namespace member also uses is left
out of both directions, so the namespace member keeps its round trip.

The lookup reads defer_loading is True instead of validating it, so
callers that only read the input (token counting under drop_params) do not
raise on a malformed flag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(responses): keep the bare name for a namespace == name echo replayed without request tools

Stored history (previous_response_id) is rebuilt with no request tools, so the echo of a deferred
call carrying namespace == name used to join to name__name. Only a namespace that holds a member of
its own name still joins. The lookup also tolerates a tools value that is not a list, and the
comprehensions stay within one for and one if clause.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(responses): read request tools through one validated accessor

The deferred-name lookup and the response-side tool maps take the request's tools from one
TypeAdapter-backed accessor, so a tools value that is not a list of objects reads as no tools and
the type gate does not grow.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(responses): type the request mapping handed to the input transformer

transform_responses_api_input_to_messages takes dict[str, object] instead of a bare dict, so the
tools accessor's argument is known to the type gate and the instructions value is narrowed to str.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(responses): build the namespace tool map from the validated member names

namespace_tool_name_map reads each namespace's members through the same validated accessor as the
self-named check, which keeps the type gate's per-rule counts at their merge-base values.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(responses): replay stored turns with the tools they were sent with

Stored previous_response_id history is rebuilt with each turn's own tools, so a namespace member
that shares its namespace's name keeps the joined name__name form on replay, while a deferred
top-level call keeps the bare name. Adds the session handler regression.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(responses): keep the object entries of a tools list and read them on the streaming path too

One accessor hands the request's tools to the request path and the streaming iterator, dropping only
the entries that are not objects instead of the whole list, so both paths see the same custom, namespace
and deferred tools. Trims the explanatory comments.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(responses): count input tokens with the request's tools in hand

/v1/responses/input_tokens hands the request params, tools included, to the input transformer, so an
echoed call for a namespace member named after its namespace counts as name__name there too.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(responses): hand the request tools to every input conversion that reads an echoed call

The guardrail provenance pass, the prompt caching pre-call check and the Rust precall token count convert
Responses input with the request's tools, so a namespace member named after its namespace keeps name__name
there as it does on the request path.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(responses): keep namespace == name for deferred tools loaded by a client-side tool search

A tool the client's own tool search loaded is still a deferred top-level tool to the Agents SDK, so the bridge keeps its deferral for the response-side name map and the route strips it again before the provider sees the request.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Homen Shum <317650355+homenshum-cheiron@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-11-10 14:24:15 -08:00
..
chat fix(openai): download PDF URLs off the event loop and transform async chat messages once (#49176) 2026-11-10 16:37:00 +00:00
completion fix(openai): keep the upstream error body on e.response for OpenAI and Azure errors (#49079) 2026-10-29 23:30:02 -07:00
decisions feat(decisions): add Parallel AI web-grounded decisions (#49188) 2026-11-03 04:47:02 +00:00
embeddings test: add package initializers to migrated unit test directories 2026-09-20 11:52:07 +00:00
evals fix(llms): join api_base and route with one shared helper (#47535) 2026-10-21 06:59:32 +00:00
image_generation refactor(images): remove dall-e-2 and dall-e-3 code paths (#48703) 2026-10-28 17:48:09 -07:00
image_variations fix(openai): keep the upstream error body on e.response for OpenAI and Azure errors (#49079) 2026-10-29 23:30:02 -07:00
live refactor(router): delete the python router core, the rust core is the only core (#50178) 2026-11-05 10:40:46 -08:00
realtime feat(realtime)!: support latest OpenAI audio models (#35600) 2026-11-03 07:27:52 +00:00
responses fix(responses): keep the namespace == name shape for deferred top-level tools (#50602) 2026-11-10 14:24:15 -08:00
speech test: add package initializers to migrated unit test directories 2026-09-20 11:52:07 +00:00
transcriptions fix(cost)!: bill transcriptions by the seconds the provider reports (#50727) 2026-11-09 13:37:55 -08:00
vector_store_files fix(proxy)!: return provider-matching 4xx for the LIT-8062 status code follow-ups (#45537) 2026-10-13 11:42:39 -07:00
vector_stores test: add package initializers to migrated unit test directories 2026-09-20 11:52:07 +00:00
videos feat(videos): add first-class OpenRouter video request fields (#50319) 2026-11-06 16:50:48 -08:00
__init__.py test(unit): make every tests/unit directory a package so pytest collection is unique 2026-09-20 11:50:59 +00:00
test_cost_calculation.py test: move tests/test_litellm/llms into tests/unit/llms (#43191) 2026-09-25 12:43:23 -07:00
test_data_residency.py feat(openai): bill gov.api.openai.com FedRAMP endpoint with 1.1x uplift (#49951) 2026-11-04 08:57:42 -08:00
test_gpt_reasoning_transformation.py refactor(router): route the router family through RoutingContext and close the outside surface (#49118) 2026-10-30 19:18:54 -07:00
test_is_model_gpt_5_model.py refactor(llms): rename model-version transformation files to family names (#48509) 2026-10-26 18:53:16 -07:00
test_o_series_transformation.py fix(openai): stop stripping cache_control from the caller's own messages and tools (#35602) 2026-10-31 00:29:10 -07:00
test_openai.py refactor(model-cost): move the cost map inputs, fetch and register_model overlay into Rust (#50501) 2026-11-10 02:37:35 +00:00
test_openai_authentication_error.py test: migrate local_testing SDK and provider tests out of build_and_test (#45760) 2026-10-10 23:14:25 +00:00
test_openai_common_utils.py fix(logging): warn when drop_params drops a requested reasoning level on the remaining paths (#48933) 2026-10-30 08:48:43 -07:00
test_openai_empty_response.py fix(openai): send chat completions through client.post so the SDK's per-message param transform stops holding the event loop (#46967) 2026-10-16 18:06:01 -07:00
test_openai_file_content_streaming.py test: move tests/test_litellm/llms into tests/unit/llms (#43191) 2026-09-25 12:43:23 -07:00
test_openai_image_edit_transformation.py test: move tests/test_litellm/llms into tests/unit/llms (#43191) 2026-09-25 12:43:23 -07:00
test_openai_workload_identity.py refactor(router): route the router family through RoutingContext and close the outside surface (#49118) 2026-10-30 19:18:54 -07:00
test_organization_costs.py test: move tests/test_litellm/llms into tests/unit/llms (#43191) 2026-09-25 12:43:23 -07:00
test_use_chat_completions_api_no_leak.py fix(openai): send chat completions through client.post so the SDK's per-message param transform stops holding the event loop (#46967) 2026-10-16 18:06:01 -07:00