Repository navigation
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>
β¦ine dispatch (#2892) ## Summary The openai-2.44 pin rework (65129dd, #2456) stopped popping `strict` from function tool definitions in `responses_to_chat_completion_create_params`. This restores the pre-#2456 strip. `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 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 `strict` support on self-hosted engines is planned, a config flag may be preferable β but unconditional stripping matches pre-#2456 behavior and `strict` has no Chat Completions semantics today. ## Changes - `nemo_gym/responses_converter.py`: pop `strict` from function tool dicts before building `NeMoGymChatCompletionToolParam` - `tests/unit_tests/test_responses_converter.py`: assert `strict` does not reach the engine params π€ Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: Pranav Thombre <pthombre@nvidia.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
β¦ine dispatch (#2892) ## Summary The openai-2.44 pin rework (65129dd, #2456) stopped popping `strict` from function tool definitions in `responses_to_chat_completion_create_params`. This restores the pre-#2456 strip. `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 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 `strict` support on self-hosted engines is planned, a config flag may be preferable β but unconditional stripping matches pre-#2456 behavior and `strict` has no Chat Completions semantics today. ## Changes - `nemo_gym/responses_converter.py`: pop `strict` from function tool dicts before building `NeMoGymChatCompletionToolParam` - `tests/unit_tests/test_responses_converter.py`: assert `strict` does not reach the engine params π€ Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: Pranav Thombre <pthombre@nvidia.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 023b370)
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