@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / b41aa264f9
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 6, 18:15 UTC

fix: resolve chat template names before kwargs detection (#36937)

Co-authored-by: giulio-leone <giulio.leone@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Giulio Leone committed Mar 14, 2026 at 01:20 UTC b41aa264f9ec0f3d2d47ec8e0a136305dafbbe4a
2 files changed +59 -1
tests/renderers/test_hf.py
+56
@@ -299,6 +299,62 @@ def test_resolve_chat_template_kwargs(sample_json_schema, model, expected_kwargs
299 assert "unknown_param" not in resolved_mock
300
301
302 +def test_resolve_chat_template_resolves_name():
303 + """When chat_template is a name, resolve_chat_template should return
304 + the actual Jinja content so that kwargs detection works correctly."""
305 + from unittest.mock import MagicMock
306 +
307 + jinja_content = "{{ messages }}{% if tools %}{{ tools }}{% endif %}"
308 + tokenizer = MagicMock()
309 + tokenizer.get_chat_template.return_value = jinja_content
310 +
311 + model_config = MagicMock()
312 +
313 + result = resolve_chat_template(
314 + tokenizer,
315 + chat_template="tool_use",
316 + tools=None,
317 + model_config=model_config,
318 + )
319 +
320 + assert result == jinja_content
321 + tokenizer.get_chat_template.assert_called_once_with("tool_use", tools=None)
322 +
323 +
324 +def test_resolve_chat_template_kwargs_with_template_name():
325 + """Ensures template kwargs are not silently dropped when chat_template
326 + was originally a template name that has been resolved to Jinja content."""
327 + from unittest.mock import MagicMock
328 +
329 + jinja_content = (
330 + "{% for m in messages %}{{ m }}{% endfor %}"
331 + "{% if tools %}{{ tools }}{% endif %}"
332 + "{% if documents %}{{ documents }}{% endif %}"
333 + )
334 +
335 + tokenizer = MagicMock()
336 + tokenizer.apply_chat_template = MagicMock()
337 +
338 + kwargs = {
339 + "tools": [{"type": "function", "function": {"name": "f"}}],
340 + "documents": [{"title": "doc"}],
341 + "unknown_param": "should be dropped",
342 + }
343 +
344 + resolved = resolve_chat_template_kwargs(
345 + tokenizer,
346 + chat_template=jinja_content,
347 + chat_template_kwargs=kwargs,
348 + raise_on_unexpected=False,
349 + )
350 +
351 + # template vars "tools" and "documents" should be preserved
352 + assert "tools" in resolved
353 + assert "documents" in resolved
354 + # unknown param should be filtered
355 + assert "unknown_param" not in resolved
356 +
357 +
358 # NOTE: Qwen2-Audio default chat template is specially defined inside
359 # processor class instead of using `tokenizer_config.json`
360 @pytest.mark.parametrize(
vllm/renderers/hf.py
+3 -1
@@ -108,7 +108,9 @@ def resolve_chat_template(
108 ) -> str | None:
109 # 1st priority: The given chat template
110 if chat_template is not None:
111 - return chat_template
111 + # Resolve template names (e.g. "tool_use") to actual Jinja content
112 + # so that downstream kwargs detection can parse template variables.
113 + return tokenizer.get_chat_template(chat_template, tools=tools)
114
115 # 2nd priority: AutoProcessor chat template, unless tool calling is enabled
116 if tools is None: