@@ -5413,6 +5413,98 @@ def __call__(self, **kwargs):
54135413 # Use parent implementation
54145414 return super ().__call__ (** kwargs )
54155415
5416+ class LFM25VLChatHandler (MTMDChatHandler ):
5417+ # Aligned with LFM2.5-VL tokenizer_config
5418+ LFM25VL_BOS_TOKEN = "<|startoftext|>"
5419+ LFM25VL_EOS_TOKEN = "<|im_end|>"
5420+ LFM25VL_PAD_TOKEN = "<|pad|>"
5421+
5422+ # Image specific tokens
5423+ LFM25VL_IMAGE_TOKEN = "<image>"
5424+ LFM25VL_IMAGE_START_TOKEN = "<|image_start|>"
5425+ LFM25VL_IMAGE_END_TOKEN = "<|image_end|>"
5426+ LFM25VL_IMAGE_THUMBNAIL = "<|img_thumbnail|>"
5427+
5428+ CHAT_FORMAT = (
5429+ "{{- bos_token -}}\n "
5430+ "{%- set keep_past_thinking = keep_past_thinking | default(false) -%}\n "
5431+ "{%- set ns = namespace(system_prompt='', content='') -%}\n "
5432+ "{%- if messages[0]['role'] == 'system' -%}\n "
5433+ " {%- set ns.system_prompt = messages[0]['content'] -%}\n "
5434+ " {%- set messages = messages[1:] -%}\n "
5435+ "{%- endif -%}\n "
5436+ "{%- if tools -%}\n "
5437+ " {%- set ns.system_prompt = ns.system_prompt + ('\\ n' if ns.system_prompt else '') + 'List of tools: [' -%}\n "
5438+ " {%- for tool in tools -%}\n "
5439+ " {%- if tool is not string -%}\n "
5440+ " {%- set tool = tool | tojson -%}\n "
5441+ " {%- endif -%}\n "
5442+ " {%- set ns.system_prompt = ns.system_prompt + tool -%}\n "
5443+ " {%- if not loop.last -%}\n "
5444+ " {%- set ns.system_prompt = ns.system_prompt + ', ' -%}\n "
5445+ " {%- endif -%}\n "
5446+ " {%- endfor -%}\n "
5447+ " {%- set ns.system_prompt = ns.system_prompt + ']' -%}\n "
5448+ "{%- endif -%}\n "
5449+ "{%- if ns.system_prompt -%}\n "
5450+ " {{- '<|im_start|>system\\ n' + ns.system_prompt + '<|im_end|>\\ n' -}}\n "
5451+ "{%- endif -%}\n "
5452+ "{%- set ns.last_assistant_index = -1 -%}\n "
5453+ "{%- for message in messages -%}\n "
5454+ " {%- if message['role'] == 'assistant' -%}\n "
5455+ " {%- set ns.last_assistant_index = loop.index0 -%}\n "
5456+ " {%- endif -%}\n "
5457+ "{%- endfor -%}\n "
5458+ "{%- for message in messages -%}\n "
5459+ " {{- '<|im_start|>' + message['role'] + '\\ n' -}}\n "
5460+ " {%- set content = message['content'] -%}\n "
5461+ " {%- if content is not string -%}\n "
5462+ " {%- set ns.content = '' -%}\n "
5463+ " {#- MTMD-style Multimodal Injection (Audio stripped for VL model) -#}\n "
5464+ " {%- for item in content -%}\n "
5465+ " {%- if item['type'] == 'image_url' -%}\n "
5466+ " {%- set img_val = item['image_url'] if item['image_url'] is string else item['image_url']['url'] -%}\n "
5467+ " {%- set ns.content = ns.content + img_val -%}\n "
5468+ " {%- elif item['type'] == 'text' -%}\n "
5469+ " {%- set ns.content = ns.content + item['text'] -%}\n "
5470+ " {%- else -%}\n "
5471+ " {%- set ns.content = ns.content + (item | tojson) -%}\n "
5472+ " {%- endif -%}\n "
5473+ " {%- endfor -%}\n "
5474+ " {%- set content = ns.content -%}\n "
5475+ " {%- endif -%}\n "
5476+ " {%- if message['role'] == 'assistant' and not keep_past_thinking and loop.index0 != ns.last_assistant_index -%}\n "
5477+ " {%- if '</think>' in content -%}\n "
5478+ " {%- set content = content.split('</think>')[-1] | trim -%}\n "
5479+ " {%- endif -%}\n "
5480+ " {%- endif -%}\n "
5481+ " {{- content + '<|im_end|>\\ n' -}}\n "
5482+ "{%- endfor -%}\n "
5483+ "{%- if add_generation_prompt -%}\n "
5484+ " {{- '<|im_start|>assistant\\ n' -}}\n "
5485+ "{%- endif -%}\n "
5486+ )
5487+
5488+ def __init__ (self , keep_past_thinking : bool = False , ** kwargs ):
5489+ self .keep_past_thinking = keep_past_thinking
5490+ super ().__init__ (** kwargs )
5491+
5492+
5493+ def __call__ (self , ** kwargs ):
5494+ if self .image_min_tokens > 256 :
5495+ if self .verbose :
5496+ print (f"For LFM2.5-VL, using values higher than 256 for `image_min_tokens` could cause errors. Setting to **256**." )
5497+
5498+ self .image_min_tokens = 256
5499+
5500+ self .extra_template_arguments ["keep_past_thinking" ] = self .keep_past_thinking
5501+
5502+ kwargs ['stop' ] = [self .LFM25VL_EOS_TOKEN ]
5503+
5504+ if self .verbose :
5505+ print (f"{ self .log_prefix } (keep_past_thinking={ self .keep_past_thinking } ) - Start processing" )
5506+ return super ().__call__ (** kwargs )
5507+
54165508@register_chat_completion_handler ("chatml-function-calling" )
54175509def chatml_function_calling (
54185510 llama : llama_core .Llama ,
0 commit comments