fix(responses-converter): strip strict from function tools before engine dispatch - #2892
Conversation
…ine dispatch The openai-2.44 pin rework (65129dd, #2456) stopped popping strict from function tool definitions in responses_to_chat_completion_create_params. strict is an OpenAI-hosted enforcement flag with no Chat Completions semantics on self-hosted engines: vLLM 0.25.1's FunctionDefinition keeps it, and chat templates that render unknown function keys (e.g. Nemotron's render_extra_keys) inject <strict>True</strict> into every <function> block. That perturbs the prompt of every tool-bearing request off-distribution. Observed in RL training (jobs 6707880/6712632 vs baseline 6682989): ~17% of sequences per step run away to the max-token cap, collect reward-0 truncation penalties, and are masked by sequence logprob error (1e4-1e14). Restoring the pre-2456 strip returns the engine request to byte-parity with the pre-rebase tree. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Pranav Thombre <pthombre@nvidia.com>
|
/ok to test be5128c |
|
/claude review |
|
SHIP — no reliability concerns. Focused fix: drops the One thing worth noting (NOTE, author's call): the drop is unconditional, so it also affects the OpenAI-hosted path via |
The multistep tests asserted the post-#2456 payload in which strict was forwarded to the engine. With the converter strip restored, the input tool definitions still carry strict=True but the dispatched tools must not — update the expectations to verify the strip. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Pranav Thombre <pthombre@nvidia.com>
|
/ok to test 8135c93 |
Per review: strict is valid in both the Responses and Chat Completions APIs and carries real schema-enforcement semantics on OpenAI-hosted providers, so the converter keeps it. vLLM is the component that mishandles it (FunctionDefinition keeps the unknown key and chat templates like Nemotron's render_extra_keys inject it into the prompt), so strip it in the vllm_model server instead: - revert the responses_converter pop and its test to upstream - add VLLMModel._strip_hosted_only_tool_fields, applied in _preprocess_chat_completion_create_params and in the use_completions_api path (which branches before preprocessing and renders tools through apply_chat_template locally) - keep the multistep test expectations asserting strict never reaches the engine; add a direct unit test for the helper Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Pranav Thombre <pthombre@nvidia.com>
|
/claude review |
|
/ok to test 134c3db |
|
HOLD — the production change is sound, but two test edits will break CI. The fix itself ( BLOCKER (inline): The edits to Note: the strip runs only on the real vLLM HTTP boundary. Per CLAUDE.md ("green unit tests alone are not enough"), a real rollout against a Nemotron template would confirm the prompt no longer carries |
The multistep tests monkeypatch VLLMModel.chat_completions itself, so they capture the converter output before _preprocess_chat_completion_create_params runs — with the converter reverted to keep strict, that payload correctly still carries it. Restore the upstream expectations there and verify the strip where it now lives: a direct preprocess-hook test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Pranav Thombre <pthombre@nvidia.com>
|
/ok to test dffac65 |
|
/claude review |
|
SHIP — LGTM, no reliability concerns.
Verified coverage of both tool-forwarding paths:
No third path hands tools to vLLM. The strip mutates the same |
…e engine dispatch (2892)` into `r0.6.0` (#2899) beep boop [🤖]: Hi @pthombre 👋, we've cherry picked #2892 into for you! 🚀 Please review and approve this cherry pick by your convenience! Signed-off-by: Pranav Thombre <pthombre@nvidia.com> Signed-off-by: NeMo Bot <nemo-bot@nvidia.com> Co-authored-by: Pranav Thombre <pthombre@nvidia.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Summary
The openai-2.44 pin rework (65129dd, #2456) stopped popping
strictfrom function tool definitions inresponses_to_chat_completion_create_params. This restores the pre-#2456 strip.strictis an OpenAI-hosted enforcement flag with no Chat Completions semantics on self-hosted engines: vLLM 0.25.1'sFunctionDefinitionkeeps it, and chat templates that render unknown function keys (e.g. Nemotron'srender_extra_keys) inject<strict>True</strict>into every<function>block. That perturbs the prompt of every tool-bearing request off-distribution.Observed impact
In RL training (jobs 6707880/6712632 vs baseline 6682989): ~17% of sequences per step ran away to the max-token cap, collected reward-0 truncation penalties, and were masked by sequence logprob error (1e4–1e14). Restoring the strip returns the engine request to byte-parity with the pre-#2456 tree.
Question for reviewers
Was dropping the strip in #2456 intentional? If
strictsupport on self-hosted engines is planned, a config flag may be preferable — but unconditional stripping matches pre-#2456 behavior andstricthas no Chat Completions semantics today.Changes
nemo_gym/responses_converter.py: popstrictfrom function tool dicts before buildingNeMoGymChatCompletionToolParamtests/unit_tests/test_responses_converter.py: assertstrictdoes not reach the engine params🤖 Generated with Claude Code