@@ -378,6 +378,131 @@ def test_ray_infer_fn_max_tokens_edge_cases(self, mock_model, mock_tokenizer, mo
378378 assert "sentences" in output
379379
380380
381+ class TestHFDeployableApplyChatTemplate :
382+ """Tests for apply_chat_template functionality added to HuggingFaceLLMDeploy."""
383+
384+ @pytest .fixture
385+ def mock_tokenizer_with_chat_template (self ):
386+ """Create a mock tokenizer with chat template support."""
387+ tokenizer = MagicMock (spec = AutoTokenizer )
388+ tokenizer .pad_token = "[PAD]"
389+ tokenizer .eos_token = "[EOS]"
390+ tokenizer .chat_template = "{% for message in messages %}{{ message.role }}: {{ message.content }}\n {% endfor %}"
391+ tokenizer .apply_chat_template = MagicMock (return_value = "<|begin_of_text|>user: Hello\n assistant:" )
392+ return tokenizer
393+
394+ @pytest .fixture
395+ def mock_tokenizer_without_chat_template (self ):
396+ """Create a mock tokenizer without chat template support."""
397+ tokenizer = MagicMock (spec = AutoTokenizer )
398+ tokenizer .pad_token = "[PAD]"
399+ tokenizer .eos_token = "[EOS]"
400+ tokenizer .chat_template = None
401+ return tokenizer
402+
403+ @pytest .fixture
404+ def hf_deployable_with_chat_template (self , mock_model , mock_tokenizer_with_chat_template ):
405+ """Create HuggingFaceLLMDeploy instance with chat template support."""
406+ deployer = HuggingFaceLLMDeploy (
407+ model = mock_model , tokenizer = mock_tokenizer_with_chat_template , task = "text-generation"
408+ )
409+ return deployer
410+
411+ @pytest .fixture
412+ def hf_deployable_without_chat_template (self , mock_model , mock_tokenizer_without_chat_template ):
413+ """Create HuggingFaceLLMDeploy instance without chat template support."""
414+ deployer = HuggingFaceLLMDeploy (
415+ model = mock_model , tokenizer = mock_tokenizer_without_chat_template , task = "text-generation"
416+ )
417+ return deployer
418+
419+ def test_apply_chat_template_with_messages_list (self , hf_deployable_with_chat_template ):
420+ """Test apply_chat_template with a list of message dictionaries."""
421+ messages = [{"role" : "user" , "content" : "Hello, how are you?" }]
422+
423+ result = hf_deployable_with_chat_template .apply_chat_template (messages )
424+
425+ assert result == "<|begin_of_text|>user: Hello\n assistant:"
426+ hf_deployable_with_chat_template .tokenizer .apply_chat_template .assert_called_once_with (
427+ messages ,
428+ tokenize = False ,
429+ add_generation_prompt = True ,
430+ )
431+
432+ def test_apply_chat_template_with_json_string (self , hf_deployable_with_chat_template ):
433+ """Test apply_chat_template with JSON string input."""
434+ import json
435+
436+ messages = [{"role" : "user" , "content" : "Hello" }]
437+ messages_json = json .dumps (messages )
438+
439+ result = hf_deployable_with_chat_template .apply_chat_template (messages_json )
440+
441+ assert result == "<|begin_of_text|>user: Hello\n assistant:"
442+ # Verify it was called with the parsed list
443+ hf_deployable_with_chat_template .tokenizer .apply_chat_template .assert_called_once ()
444+
445+ def test_apply_chat_template_without_generation_prompt (self , hf_deployable_with_chat_template ):
446+ """Test apply_chat_template with add_generation_prompt=False."""
447+ messages = [{"role" : "user" , "content" : "Hello" }]
448+
449+ hf_deployable_with_chat_template .apply_chat_template (messages , add_generation_prompt = False )
450+
451+ hf_deployable_with_chat_template .tokenizer .apply_chat_template .assert_called_once_with (
452+ messages ,
453+ tokenize = False ,
454+ add_generation_prompt = False ,
455+ )
456+
457+ def test_apply_chat_template_raises_error_when_no_template (self , hf_deployable_without_chat_template ):
458+ """Test apply_chat_template raises ValueError when tokenizer has no chat template."""
459+ messages = [{"role" : "user" , "content" : "Hello" }]
460+
461+ with pytest .raises (ValueError , match = "The tokenizer does not have a chat template defined" ):
462+ hf_deployable_without_chat_template .apply_chat_template (messages )
463+
464+ def test_ray_infer_fn_with_apply_chat_template (
465+ self , mock_model , mock_tokenizer_with_chat_template , mock_torch_cuda
466+ ):
467+ """Test ray_infer_fn correctly applies chat template when requested."""
468+ deployer = HuggingFaceLLMDeploy (
469+ model = mock_model , tokenizer = mock_tokenizer_with_chat_template , task = "text-generation"
470+ )
471+
472+ messages = [{"role" : "user" , "content" : "Hello" }]
473+ inputs = {
474+ "prompts" : [messages ],
475+ "max_tokens" : 100 ,
476+ "apply_chat_template" : True ,
477+ }
478+
479+ result = deployer .ray_infer_fn (inputs )
480+
481+ assert "sentences" in result
482+ # Verify apply_chat_template was called
483+ mock_tokenizer_with_chat_template .apply_chat_template .assert_called ()
484+
485+ def test_ray_infer_fn_without_apply_chat_template (
486+ self , mock_model , mock_tokenizer_with_chat_template , mock_torch_cuda
487+ ):
488+ """Test ray_infer_fn does not apply chat template when not requested."""
489+ deployer = HuggingFaceLLMDeploy (
490+ model = mock_model , tokenizer = mock_tokenizer_with_chat_template , task = "text-generation"
491+ )
492+
493+ inputs = {
494+ "prompts" : ["plain text prompt" ],
495+ "max_tokens" : 100 ,
496+ "apply_chat_template" : False ,
497+ }
498+
499+ result = deployer .ray_infer_fn (inputs )
500+
501+ assert "sentences" in result
502+ # Verify apply_chat_template was NOT called
503+ mock_tokenizer_with_chat_template .apply_chat_template .assert_not_called ()
504+
505+
381506class TestHFDeployableEchoAndLogprobs :
382507 """Tests for echo parameter and logprobs functionality added to HuggingFaceLLMDeploy."""
383508
0 commit comments