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: