darkc0de commited on
Commit
afeaf74
·
verified ·
1 Parent(s): 8ccde8c

Update chat_template.jinja

Browse files
Files changed (1) hide show
  1. chat_template.jinja +285 -452
chat_template.jinja CHANGED
@@ -1,44 +1,10 @@
1
- {%- set template_version = "qwen3.8-safe-v3.1" %}
2
- {#- -------------------------------------------------------------------------
3
- Whitespace contract: every tag opener in this file carries a leading minus,
4
- so it strips the whitespace and newlines that precede it. All emitted text
5
- comes from string literals, which makes the rendered prompt byte-exact and
6
- free of incidental newlines. Comment tags need the minus just as much as
7
- block tags do; a plain comment tag breaks the strip chain and leaks the
8
- surrounding indentation into the prompt.
9
- ------------------------------------------------------------------------- -#}
10
- {#- The message list has to exist before anything else can inspect it. -#}
11
- {%- if not messages %}
12
- {{- raise_exception('No messages provided.') }}
13
- {%- endif %}
14
- {#- -------------------------------------------------------------------------
15
- Configuration
16
- ------------------------------------------------------------------------- -#}
17
- {%- set _requested_tool_format =
18
- tool_call_format if tool_call_format is defined else 'xml'
19
- %}
20
- {%- if _requested_tool_format not in ('auto', 'xml', 'json') %}
21
- {{- raise_exception(
22
- 'Unexpected tool_call_format ' ~ _requested_tool_format ~
23
- '. Supported values are xml (default), auto, and json.'
24
- ) }}
25
- {%- endif %}
26
  {%- set add_vision_id = add_vision_id if add_vision_id is defined else false %}
27
  {%- set enable_thinking = enable_thinking if enable_thinking is defined else true %}
28
- {%- set auto_disable_thinking_with_tools =
29
- auto_disable_thinking_with_tools
30
- if auto_disable_thinking_with_tools is defined
31
- else false
32
- %}
33
- {%- if preserve_reasoning is defined
34
- and preserve_reasoning is not none
35
- and preserve_thinking is defined
36
- and preserve_thinking is not none
37
- and preserve_reasoning != preserve_thinking %}
38
- {{- raise_exception(
39
- 'preserve_reasoning and preserve_thinking were both provided with conflicting values.'
40
- ) }}
41
- {%- endif %}
42
  {%- if preserve_reasoning is defined and preserve_reasoning is not none %}
43
  {%- set _preserve_thinking = preserve_reasoning %}
44
  {%- elif preserve_thinking is defined and preserve_thinking is not none %}
@@ -46,200 +12,115 @@
46
  {%- else %}
47
  {%- set _preserve_thinking = true %}
48
  {%- endif %}
49
- {%- set max_tool_arg_chars =
50
- max_tool_arg_chars if max_tool_arg_chars is defined else 0
51
- %}
52
- {%- set max_tool_response_chars =
53
- max_tool_response_chars if max_tool_response_chars is defined else 0
54
- %}
55
- {%- if max_tool_arg_chars is not number or max_tool_arg_chars < 0 %}
56
- {{- raise_exception('max_tool_arg_chars must be a non-negative number.') }}
57
- {%- endif %}
58
- {%- if max_tool_response_chars is not number or max_tool_response_chars < 0 %}
59
- {{- raise_exception('max_tool_response_chars must be a non-negative number.') }}
60
- {%- endif %}
61
- {%- if tools is defined and tools is not none and tools %}
62
- {%- if tools is string or tools is mapping or tools is not iterable %}
63
- {{- raise_exception('tools must be an iterable list of tool definitions.') }}
64
- {%- endif %}
65
- {%- set _has_tools = true %}
66
  {%- else %}
67
- {%- set _has_tools = false %}
68
  {%- endif %}
69
- {#- -------------------------------------------------------------------------
70
- Resolve the tool-call wire format.
71
-
72
- OpenAI-compatible servers hand assistant tool calls back with
73
- `function.arguments` as a JSON *string*, not a mapping. The XML parameter
74
- form needs the individual key/value pairs, and a chat template cannot
75
- decode a JSON string: the standard chat-template environment provides
76
- `tojson` but no inverse, and no codepoint-to-character primitive, so a
77
- hand-rolled scanner could not decode \uXXXX escapes correctly. Guessing
78
- would silently corrupt tool arguments, which is worse than any error.
79
-
80
- The deployment-safe default is XML, matching Qwen's native tool-call wire
81
- format and the qwen3_coder tool parser. A caller can explicitly request
82
- tool_call_format='auto' to render the whole prompt in JSON form whenever a
83
- historical tool call carries string arguments. That path is lossless,
84
- needs no decoding, and keeps the system-prompt instructions and rendered
85
- history in one consistent format. Histories whose arguments are all
86
- mappings still render as XML, byte-identically to tool_call_format='xml'.
87
-
88
- A caller that uses the default XML mode (or explicitly pins 'xml') still
89
- gets a hard error for non-empty string arguments, because that request
90
- cannot be honoured faithfully in the native XML parameter representation.
91
- ------------------------------------------------------------------------- -#}
92
- {%- set format_scan = namespace(has_json_string_arguments=false) %}
93
- {%- for message in messages %}
94
- {%- if message.role == 'assistant'
95
- and message.tool_calls is defined
96
- and message.tool_calls is not none
97
- and message.tool_calls
98
- and message.tool_calls is not string
99
- and message.tool_calls is not mapping
100
- and message.tool_calls is iterable %}
101
- {%- for tool_call in message.tool_calls %}
102
- {%- if tool_call.function is defined
103
- and tool_call.function is not none %}
104
- {%- set _tc = tool_call.function %}
105
- {%- else %}
106
- {%- set _tc = tool_call %}
107
- {%- endif %}
108
- {%- if _tc.arguments is defined
109
- and _tc.arguments is not none
110
- and _tc.arguments is string
111
- and _tc.arguments | trim
112
- and _tc.arguments | trim != '{}' %}
113
- {%- set format_scan.has_json_string_arguments = true %}
114
  {%- endif %}
115
- {%- endfor %}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  {%- endif %}
117
  {%- endfor %}
118
- {%- if _requested_tool_format == 'auto' %}
119
- {%- if format_scan.has_json_string_arguments %}
120
- {%- set _tool_format = 'json' %}
121
- {%- else %}
122
- {%- set _tool_format = 'xml' %}
123
- {%- endif %}
124
- {%- else %}
125
- {%- set _tool_format = _requested_tool_format %}
126
- {%- endif %}
127
- {%- set _thinking_enabled = enable_thinking %}
128
- {%- if auto_disable_thinking_with_tools and _has_tools %}
129
- {%- set _thinking_enabled = false %}
130
- {%- endif %}
131
- {#- Normalize and validate reasoning effort even when thinking is disabled.
132
- Explicit null follows the template default; OpenAI-style `minimal` maps to
133
- low, while `none` disables thinking for this render. -#}
134
- {%- if reasoning_effort is undefined or reasoning_effort is none %}
135
- {%- set _effort_raw = 'medium' %}
136
- {%- else %}
137
- {%- set _effort_raw = reasoning_effort %}
138
- {%- endif %}
139
- {%- if _effort_raw == 'none' %}
140
- {%- set _thinking_enabled = false %}
141
- {%- set _reasoning_effort = 'xhigh' %}
142
- {%- elif _effort_raw == 'high' or _effort_raw == 'xhigh' %}
143
- {%- set _reasoning_effort = 'xhigh' %}
144
- {%- elif _effort_raw == 'medium' %}
145
- {%- set _reasoning_effort = 'medium' %}
146
- {%- elif _effort_raw == 'minimal' or _effort_raw == 'low' %}
147
- {%- set _reasoning_effort = 'low' %}
148
- {%- else %}
149
- {{- raise_exception(
150
- 'Unexpected reasoning effort ' ~ _effort_raw ~
151
- '. Supported values are none, minimal/low, medium, and high/xhigh; null uses the medium default.'
152
- ) }}
153
- {%- endif %}
154
  {%- set reasoning_instructions = '' %}
155
- {%- if _thinking_enabled %}
156
- {%- if _reasoning_effort == 'xhigh' %}
157
- {%- set reasoning_instructions =
158
- 'Reasoning effort is set to xhigh. Please think carefully through the task, validate key assumptions, consider plausible alternatives, and prioritize correctness, consistency, and clarity in the final answer.'
159
- %}
160
- {%- elif _reasoning_effort == 'low' %}
161
- {%- set reasoning_instructions =
162
- 'Reasoning effort is set to low. Keep your thinking brief and focused, moving directly to the conclusion without unnecessary elaboration.'
163
- %}
164
  {%- endif %}
165
  {%- endif %}
166
- {#- -------------------------------------------------------------------------
167
- Content rendering
168
- ------------------------------------------------------------------------- -#}
169
- {%- set image_count = namespace(value=0) %}
170
- {%- set video_count = namespace(value=0) %}
171
  {%- macro render_content(content, do_vision_count, is_system_content=false) %}
172
  {%- if content is string %}
173
  {{- content }}
174
  {%- elif content is iterable and content is not mapping %}
175
  {%- for item in content %}
176
- {%- if item is not mapping %}
177
- {{- raise_exception(
178
- 'Content-list items must be mappings with a supported text, image, or video type.'
179
- ) }}
180
- {%- endif %}
181
- {%- set _item_type = item.type if 'type' in item else none %}
182
- {%- if _item_type is not none
183
- and _item_type not in ('text', 'image', 'image_url', 'video') %}
184
- {{- raise_exception(
185
- 'Unexpected content item type ' ~ _item_type ~ '.'
186
- ) }}
187
- {%- endif %}
188
- {%- set _is_image =
189
- _item_type == 'image'
190
- or _item_type == 'image_url'
191
- or 'image' in item
192
- or 'image_url' in item
193
- %}
194
- {%- set _is_video =
195
- _item_type == 'video'
196
- or 'video' in item
197
- %}
198
- {%- if _is_image and _is_video %}
199
- {{- raise_exception(
200
- 'A content item cannot contain both image and video data.'
201
- ) }}
202
- {%- elif _item_type == 'text' and (_is_image or _is_video) %}
203
- {{- raise_exception(
204
- 'A text content item cannot also contain image or video data.'
205
- ) }}
206
- {%- elif _is_image %}
207
- {%- if is_system_content %}
208
- {{- raise_exception(
209
- 'System and developer messages cannot contain images.'
210
- ) }}
211
- {%- endif %}
212
- {%- if do_vision_count %}
213
- {%- set image_count.value = image_count.value + 1 %}
214
- {%- endif %}
215
- {%- if add_vision_id %}
216
- {{- 'Picture ' ~ image_count.value ~ ': ' }}
217
- {%- endif %}
218
- {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
219
- {%- elif _is_video %}
220
- {%- if is_system_content %}
221
- {{- raise_exception(
222
- 'System and developer messages cannot contain videos.'
223
- ) }}
224
- {%- endif %}
225
- {%- if do_vision_count %}
226
- {%- set video_count.value = video_count.value + 1 %}
227
- {%- endif %}
228
- {%- if add_vision_id %}
229
- {{- 'Video ' ~ video_count.value ~ ': ' }}
230
- {%- endif %}
231
- {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
232
- {%- elif _item_type == 'text' or 'text' in item %}
233
- {%- if 'text' not in item or item.text is not string %}
234
- {{- raise_exception(
235
- 'Text content items must contain a string text field.'
236
- ) }}
237
  {%- endif %}
238
- {{- item.text }}
239
  {%- else %}
240
- {{- raise_exception(
241
- 'Unexpected item in content list. Expected text, image, or video content.'
242
- ) }}
243
  {%- endif %}
244
  {%- endfor %}
245
  {%- elif content is none or content is undefined %}
@@ -248,49 +129,45 @@
248
  {{- raise_exception('Unexpected content type.') }}
249
  {%- endif %}
250
  {%- endmacro %}
251
- {#- -------------------------------------------------------------------------
252
- Validate and merge leading system/developer messages
253
- ------------------------------------------------------------------------- -#}
254
  {%- set head = namespace(count=0, seen_non_system=false) %}
255
  {%- for message in messages %}
256
- {%- set _is_system =
257
- message.role == 'system' or message.role == 'developer'
258
- %}
259
- {%- if _is_system %}
260
- {%- if head.seen_non_system %}
261
- {{- raise_exception(
262
- 'System and developer messages must appear before all user, assistant, and tool messages.'
263
- ) }}
264
- {%- endif %}
265
  {%- set head.count = head.count + 1 %}
266
  {%- else %}
267
  {%- set head.seen_non_system = true %}
268
  {%- endif %}
269
  {%- endfor %}
270
- {%- set system_state = namespace(content='') %}
271
  {%- for message in messages[:head.count] %}
272
- {%- set _part =
273
- render_content(message.content, false, true) | trim
274
- %}
 
 
 
 
 
 
 
 
275
  {%- if _part %}
276
- {%- if system_state.content %}
277
- {%- set system_state.content =
278
- system_state.content ~ '\n\n' ~ _part
279
- %}
280
  {%- else %}
281
- {%- set system_state.content = _part %}
282
  {%- endif %}
283
  {%- endif %}
284
  {%- endfor %}
285
- {%- set _system_content = system_state.content %}
286
  {%- set _msgs = messages[head.count:] %}
287
- {#- -------------------------------------------------------------------------
288
- System prompt and tool instructions
289
- ------------------------------------------------------------------------- -#}
290
  {%- if _has_tools %}
291
  {{- '<|im_start|>system\n' }}
292
  {%- if reasoning_instructions %}
293
- {{- reasoning_instructions ~ '\n\n' }}
294
  {%- endif %}
295
  {{- '# Tools\n\nYou have access to the following functions:\n\n<tools>' }}
296
  {%- for tool in tools %}
@@ -299,252 +176,204 @@
299
  {%- endfor %}
300
  {{- '\n</tools>' }}
301
  {%- if _tool_format == 'json' %}
302
- {{- '\n\nIf you choose to call a function ONLY reply in the following format with NO suffix:\n\n<tool_call>\n{"name": "example_function_name", "arguments": {"example_parameter_1": "value_1", "example_parameter_2": "This is the value for the second parameter"}}\n</tool_call>\n\n<IMPORTANT>\nReminder:\n- Function calls MUST follow the specified format: a single JSON object with "name" and "arguments" keys must be nested within <tool_call></tool_call> XML tags\n- Required parameters MUST be specified\n- You may provide optional reasoning for your function call in natural language BEFORE the function call, but NOT after\n- If there is no function call available, answer the question like normal with your current knowledge and do not tell the user about function calls\n</IMPORTANT>' }}
303
  {%- else %}
304
- {{- '\n\nIf you choose to call a function ONLY reply in the following format with NO suffix:\n\n<tool_call>\n<function=example_function_name>\n<parameter=example_parameter_1>\nvalue_1\n</parameter>\n<parameter=example_parameter_2>\nThis is the value for the second parameter\nthat can span\nmultiple lines\n</parameter>\n</function>\n</tool_call>\n\n<IMPORTANT>\nReminder:\n- Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags\n- Required parameters MUST be specified\n- You may provide optional reasoning for your function call in natural language BEFORE the function call, but NOT after\n- If there is no function call available, answer the question like normal with your current knowledge and do not tell the user about function calls\n</IMPORTANT>' }}
305
  {%- endif %}
306
- {%- if _system_content %}
307
- {{- '\n\n' ~ _system_content }}
308
  {%- endif %}
309
  {{- '<|im_end|>\n' }}
310
  {%- else %}
311
- {%- if _system_content %}
312
- {{- '<|im_start|>system\n'
313
- ~ (reasoning_instructions ~ '\n\n' if reasoning_instructions else '')
314
- ~ _system_content
315
- ~ '<|im_end|>\n'
316
- }}
317
  {%- elif reasoning_instructions %}
318
- {{- '<|im_start|>system\n'
319
- ~ reasoning_instructions
320
- ~ '<|im_end|>\n'
321
- }}
322
  {%- endif %}
323
  {%- endif %}
324
- {#- -------------------------------------------------------------------------
325
- Find the last real user query
326
- ------------------------------------------------------------------------- -#}
327
- {%- set ns = namespace(
328
- multi_step_tool=true,
329
- last_query_index=(_msgs | length) - 1
330
- ) %}
331
  {%- for message in _msgs[::-1] %}
332
  {%- set index = (_msgs | length - 1) - loop.index0 %}
333
  {%- if ns.multi_step_tool and message.role == 'user' %}
334
- {%- set _rendered_user =
335
- render_content(message.content, false) | trim
336
- %}
337
- {%- if not (
338
- _rendered_user.startswith('<tool_response>')
339
- and _rendered_user.endswith('</tool_response>')
340
- ) %}
341
  {%- set ns.multi_step_tool = false %}
342
  {%- set ns.last_query_index = index %}
343
  {%- endif %}
344
  {%- endif %}
345
  {%- endfor %}
346
  {%- if ns.multi_step_tool %}
347
- {{- raise_exception('No user query found in messages.') }}
 
 
 
 
348
  {%- endif %}
349
- {#- -------------------------------------------------------------------------
350
- Conversation rendering
351
- ------------------------------------------------------------------------- -#}
352
- {%- set history_state = namespace(previous_role='') %}
353
  {%- for message in _msgs %}
354
- {%- set content =
355
- render_content(message.content, true) | trim
356
- %}
357
- {%- if message.role == 'user' %}
358
- {{- '<|im_start|>user\n'
359
- ~ content
360
- ~ '<|im_end|>\n'
361
- }}
 
 
 
 
 
 
 
 
 
 
 
362
  {%- elif message.role == 'assistant' %}
363
  {%- set reasoning_content = '' %}
364
- {#- Prefer current vLLM's `reasoning` field, then retain compatibility
365
- with older `reasoning_content` and other servers' `thinking`. -#}
366
- {%- if message.reasoning is defined
367
- and message.reasoning is not none %}
368
- {%- if message.reasoning is string %}
369
- {%- set reasoning_content = message.reasoning %}
370
- {%- else %}
371
- {%- set reasoning_content =
372
- message.reasoning | string
373
- %}
374
- {%- endif %}
375
- {%- elif message.reasoning_content is defined
376
- and message.reasoning_content is not none %}
377
  {%- if message.reasoning_content is string %}
378
- {%- set reasoning_content = message.reasoning_content %}
379
  {%- else %}
380
- {%- set reasoning_content =
381
- message.reasoning_content | string
382
- %}
383
  {%- endif %}
384
- {%- elif message.thinking is defined
385
- and message.thinking is not none %}
386
  {%- if message.thinking is string %}
387
- {%- set reasoning_content = message.thinking %}
388
  {%- else %}
389
- {%- set reasoning_content =
390
- message.thinking | string
391
- %}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
392
  {%- endif %}
393
  {%- endif %}
394
  {%- set reasoning_content = reasoning_content | trim %}
395
- {#- Preserve the original invariant: when thinking is preserved,
396
- always reconstruct the thinking block, even when it is empty. -#}
397
- {%- if _preserve_thinking
398
- or loop.index0 > ns.last_query_index %}
399
- {{- '<|im_start|>assistant\n<think>\n'
400
- ~ reasoning_content
401
- ~ '\n</think>\n\n'
402
- ~ content
403
- }}
404
  {%- else %}
405
- {{- '<|im_start|>assistant\n' ~ content }}
406
  {%- endif %}
407
- {%- if message.tool_calls is defined
408
- and message.tool_calls is not none
409
- and message.tool_calls %}
410
- {%- if message.tool_calls is string
411
- or message.tool_calls is mapping
412
- or message.tool_calls is not iterable %}
413
- {{- raise_exception(
414
- 'assistant.tool_calls must be an iterable list of tool calls.'
415
- ) }}
416
- {%- endif %}
417
  {%- for tool_call in message.tool_calls %}
418
- {%- if tool_call.function is defined
419
- and tool_call.function is not none %}
420
  {%- set tc = tool_call.function %}
421
  {%- else %}
422
  {%- set tc = tool_call %}
423
  {%- endif %}
424
- {%- if tc.name is not defined
425
- or tc.name is none
426
- or tc.name is not string
427
- or not tc.name %}
428
- {{- raise_exception(
429
- 'Every tool call must have a non-empty string name.'
430
- ) }}
431
- {%- endif %}
432
- {%- set tc_name = tc.name %}
433
  {%- if _tool_format == 'json' %}
434
  {%- if loop.first %}
435
  {%- if content | trim %}
436
- {{- '\n\n<tool_call>\n' }}
437
- {%- else %}
438
- {{- '<tool_call>\n' }}
439
  {%- endif %}
440
  {%- else %}
441
- {{- '\n<tool_call>\n' }}
442
  {%- endif %}
443
- {%- set _json_arguments = '{}' %}
444
- {%- if tc.arguments is defined
445
- and tc.arguments is not none %}
446
  {%- if tc.arguments is mapping %}
447
- {%- set _json_arguments =
448
- tc.arguments | tojson
449
- %}
450
  {%- elif tc.arguments is string %}
451
- {%- set _raw_arguments =
452
- tc.arguments | trim
453
- %}
454
- {%- if _raw_arguments %}
455
- {%- if not (
456
- _raw_arguments.startswith('{')
457
- and _raw_arguments.endswith('}')
458
- ) %}
459
- {{- raise_exception(
460
- 'JSON tool-call arguments must be a JSON object string.'
461
- ) }}
462
- {%- endif %}
463
- {%- set _json_arguments =
464
- _raw_arguments
465
- %}
466
  {%- endif %}
467
  {%- else %}
468
- {{- raise_exception(
469
- 'JSON tool-call arguments must be a mapping or a JSON object string.'
470
- ) }}
471
  {%- endif %}
472
  {%- endif %}
473
- {{- '{"name": ' }}
474
- {{- tc_name | tojson }}
475
- {{- ', "arguments": ' }}
476
- {{- _json_arguments }}
477
- {{- '}\n</tool_call>' }}
478
  {%- else %}
479
  {%- if loop.first %}
480
  {%- if content | trim %}
481
- {{- '\n\n<tool_call>\n<function='
482
- ~ tc_name
483
- ~ '>\n'
484
- }}
485
  {%- else %}
486
- {{- '<tool_call>\n<function='
487
- ~ tc_name
488
- ~ '>\n'
489
- }}
490
  {%- endif %}
491
  {%- else %}
492
- {{- '\n<tool_call>\n<function='
493
- ~ tc_name
494
- ~ '>\n'
495
- }}
496
  {%- endif %}
497
- {%- if tc.arguments is defined
498
- and tc.arguments is not none %}
499
  {%- if tc.arguments is mapping %}
500
- {%- for args_name, args_value
501
- in tc.arguments | items %}
502
- {%- set _argument_name =
503
- args_name | string
504
- %}
505
- {{- '<parameter='
506
- ~ _argument_name
507
- ~ '>\n'
508
- }}
509
- {#- Preserve strings verbatim. Serialize every
510
- other type as JSON so booleans and null stay
511
- true/false/null instead of True/False/None. -#}
512
  {%- if args_value is string %}
513
- {%- set _argument_value =
514
- args_value
515
- %}
516
  {%- else %}
517
- {%- set _argument_value =
518
- args_value | tojson
519
- %}
520
  {%- endif %}
521
- {%- if max_tool_arg_chars > 0
522
- and _argument_value | length
523
- > max_tool_arg_chars %}
524
- {{- _argument_value[:max_tool_arg_chars] }}
525
- {{- '\n[TRUNCATED — original length '
526
- ~ (_argument_value | length | string)
527
- ~ ' chars]'
528
- }}
529
  {%- else %}
530
- {{- _argument_value }}
531
  {%- endif %}
532
  {{- '\n</parameter>\n' }}
533
  {%- endfor %}
534
- {%- elif tc.arguments is string %}
535
- {%- set _raw_arguments =
536
- tc.arguments | trim
537
- %}
538
- {%- if _raw_arguments
539
- and _raw_arguments != '{}' %}
540
- {{- raise_exception(
541
- 'tool_call_format="xml" requires tool-call arguments to be mappings, but received a JSON string. Parse the JSON string into a mapping before applying the template, or set tool_call_format="auto" (or "json") to use the lossless JSON tool-call representation.'
542
- ) }}
543
- {%- endif %}
544
  {%- else %}
545
- {{- raise_exception(
546
- 'XML tool-call arguments must be a mapping. Parse JSON-string arguments before applying the template.'
547
- ) }}
 
 
 
 
 
 
 
 
 
548
  {%- endif %}
549
  {%- endif %}
550
  {{- '</function>\n</tool_call>' }}
@@ -553,44 +382,48 @@
553
  {%- endif %}
554
  {{- '<|im_end|>\n' }}
555
  {%- elif message.role == 'tool' %}
556
- {%- if history_state.previous_role != 'tool' %}
 
 
 
 
 
 
 
 
 
 
 
 
 
557
  {{- '<|im_start|>user' }}
558
  {%- endif %}
559
- {%- if max_tool_response_chars > 0
560
- and content | length > max_tool_response_chars %}
561
- {%- set content =
562
- content[:max_tool_response_chars]
563
- ~ '\n[TRUNCATED original length '
564
- ~ (content | length | string)
565
- ~ ' chars]'
566
- %}
567
  {%- endif %}
568
- {{- '\n<tool_response>\n' }}
569
- {{- content }}
570
  {{- '\n</tool_response>' }}
571
  {%- if loop.last %}
572
  {{- '<|im_end|>\n' }}
573
- {%- elif _msgs[loop.index0 + 1].role != 'tool' %}
574
- {{- '<|im_end|>\n' }}
 
 
 
575
  {%- endif %}
576
- {%- elif message.role == 'system'
577
- or message.role == 'developer' %}
578
- {{- raise_exception(
579
- 'System and developer messages must appear only at the beginning of the conversation.'
580
- ) }}
581
  {%- else %}
582
- {{- raise_exception(
583
- 'Unexpected message role ' ~ message.role ~ '.'
584
- ) }}
585
  {%- endif %}
586
- {%- set history_state.previous_role = message.role %}
587
  {%- endfor %}
588
- {#- -------------------------------------------------------------------------
589
- Generation prompt
590
- ------------------------------------------------------------------------- -#}
591
  {%- if add_generation_prompt %}
592
  {{- '<|im_start|>assistant\n' }}
593
- {%- if not _thinking_enabled %}
594
  {{- '<think>\n\n</think>\n\n' }}
595
  {%- else %}
596
  {{- '<think>\n' }}
 
1
+ {%- set template_version = "darkc0de_xortron_JAX_testing.v14" %}
2
+ {%- set _tool_format = tool_call_format if tool_call_format is defined else 'xml' %}
3
+ {%- set image_count = namespace(value=0) %}
4
+ {%- set video_count = namespace(value=0) %}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  {%- set add_vision_id = add_vision_id if add_vision_id is defined else false %}
6
  {%- set enable_thinking = enable_thinking if enable_thinking is defined else true %}
7
+ {%- set auto_disable_thinking_with_tools = auto_disable_thinking_with_tools if auto_disable_thinking_with_tools is defined else false %}
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  {%- if preserve_reasoning is defined and preserve_reasoning is not none %}
9
  {%- set _preserve_thinking = preserve_reasoning %}
10
  {%- elif preserve_thinking is defined and preserve_thinking is not none %}
 
12
  {%- else %}
13
  {%- set _preserve_thinking = true %}
14
  {%- endif %}
15
+ {%- set max_tool_arg_chars = max_tool_arg_chars if max_tool_arg_chars is defined else 0 %}
16
+ {%- set max_tool_response_chars = max_tool_response_chars if max_tool_response_chars is defined else 0 %}
17
+ {%- set _default_reasoning_effort = 'medium' %}
18
+ {%- set _has_tools = (tools is defined and tools and tools is iterable and tools is not mapping) %}
19
+ {%- set _effort_raw = (reasoning_effort | string | lower) if reasoning_effort is defined and reasoning_effort is not none else _default_reasoning_effort %}
20
+ {%- set _initial_thinking = enable_thinking %}
21
+ {%- if _effort_raw in ('none', 'off') %}
22
+ {%- set _initial_thinking = false %}
23
+ {%- set _initial_effort = 'medium' %}
24
+ {%- elif _effort_raw in ('minimal', 'low') %}
25
+ {%- set _initial_effort = 'low' %}
26
+ {%- elif _effort_raw in ('high', 'xhigh', 'max', 'ultracode', 'extreme') %}
27
+ {%- set _initial_effort = 'xhigh' %}
 
 
 
 
28
  {%- else %}
29
+ {%- set _initial_effort = 'medium' %}
30
  {%- endif %}
31
+ {%- set ns_state = namespace(thinking=_initial_thinking, effort=_initial_effort) %}
32
+ {%- if auto_disable_thinking_with_tools and _has_tools %}
33
+ {%- set ns_state.thinking = false %}
34
+ {%- endif %}
35
+ {%- for msg in messages %}
36
+ {%- if msg.role == 'system' or msg.role == 'developer' or msg.role == 'user' %}
37
+ {%- if msg.content is string %}
38
+ {%- if '<|think_off|>' in msg.content %}
39
+ {%- set ns_state.thinking = false %}
40
+ {%- elif '<|think_on|>' in msg.content %}
41
+ {%- set ns_state.thinking = true %}
42
+ {%- elif '<|think_xhigh|>' in msg.content or '<|think_high|>' in msg.content or '<|think_ultracode|>' in msg.content or '<|think_extreme|>' in msg.content or '<|think_max|>' in msg.content %}
43
+ {%- set ns_state.thinking = true %}
44
+ {%- set ns_state.effort = 'xhigh' %}
45
+ {%- elif '<|think_low|>' in msg.content or '<|think_minimal|>' in msg.content %}
46
+ {%- set ns_state.thinking = true %}
47
+ {%- set ns_state.effort = 'low' %}
48
+ {%- elif '<|think_medium|>' in msg.content %}
49
+ {%- set ns_state.thinking = true %}
50
+ {%- set ns_state.effort = 'medium' %}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  {%- endif %}
52
+ {%- elif msg.content is iterable and msg.content is not mapping %}
53
+ {%- for item in msg.content %}
54
+ {%- if item is string %}
55
+ {%- set _item_text = item %}
56
+ {%- elif item is mapping and 'text' in item and item.text is string %}
57
+ {%- set _item_text = item.text %}
58
+ {%- else %}
59
+ {%- set _item_text = '' %}
60
+ {%- endif %}
61
+ {%- if _item_text %}
62
+ {%- if '<|think_off|>' in _item_text %}
63
+ {%- set ns_state.thinking = false %}
64
+ {%- elif '<|think_on|>' in _item_text %}
65
+ {%- set ns_state.thinking = true %}
66
+ {%- elif '<|think_xhigh|>' in _item_text or '<|think_high|>' in _item_text or '<|think_ultracode|>' in _item_text or '<|think_extreme|>' in _item_text or '<|think_max|>' in _item_text %}
67
+ {%- set ns_state.thinking = true %}
68
+ {%- set ns_state.effort = 'xhigh' %}
69
+ {%- elif '<|think_low|>' in _item_text or '<|think_minimal|>' in _item_text %}
70
+ {%- set ns_state.thinking = true %}
71
+ {%- set ns_state.effort = 'low' %}
72
+ {%- elif '<|think_medium|>' in _item_text %}
73
+ {%- set ns_state.thinking = true %}
74
+ {%- set ns_state.effort = 'medium' %}
75
+ {%- endif %}
76
+ {%- endif %}
77
+ {%- endfor %}
78
+ {%- endif %}
79
  {%- endif %}
80
  {%- endfor %}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  {%- set reasoning_instructions = '' %}
82
+ {%- if ns_state.thinking %}
83
+ {%- if ns_state.effort == 'xhigh' %}
84
+ {%- set reasoning_instructions = 'Reasoning effort is set to xhigh. Please think carefully through the task, validate key assumptions, consider plausible alternatives, and prioritize correctness, consistency, and clarity in the final answer.' %}
85
+ {%- elif ns_state.effort == 'low' %}
86
+ {%- set reasoning_instructions = 'Reasoning effort is set to low. Keep your thinking brief and focused, moving directly to the conclusion without unnecessary elaboration.' %}
 
 
 
 
87
  {%- endif %}
88
  {%- endif %}
 
 
 
 
 
89
  {%- macro render_content(content, do_vision_count, is_system_content=false) %}
90
  {%- if content is string %}
91
  {{- content }}
92
  {%- elif content is iterable and content is not mapping %}
93
  {%- for item in content %}
94
+ {%- if item is mapping %}
95
+ {%- if item.type == 'image' or 'image' in item or 'image_url' in item %}
96
+ {%- if is_system_content %}
97
+ {{- raise_exception('System message cannot contain images.') }}
98
+ {%- endif %}
99
+ {%- if do_vision_count %}
100
+ {%- set image_count.value = image_count.value + 1 %}
101
+ {%- endif %}
102
+ {%- if add_vision_id %}
103
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
104
+ {%- endif %}
105
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
106
+ {%- elif item.type == 'video' or 'video' in item %}
107
+ {%- if is_system_content %}
108
+ {{- raise_exception('System message cannot contain videos.') }}
109
+ {%- endif %}
110
+ {%- if do_vision_count %}
111
+ {%- set video_count.value = video_count.value + 1 %}
112
+ {%- endif %}
113
+ {%- if add_vision_id %}
114
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
115
+ {%- endif %}
116
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
117
+ {%- elif 'text' in item %}
118
+ {{- item.text }}
119
+ {%- else %}
120
+ {{- raise_exception('Unexpected item type in content.') }}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  {%- endif %}
 
122
  {%- else %}
123
+ {{- item | string }}
 
 
124
  {%- endif %}
125
  {%- endfor %}
126
  {%- elif content is none or content is undefined %}
 
129
  {{- raise_exception('Unexpected content type.') }}
130
  {%- endif %}
131
  {%- endmacro %}
132
+ {%- if not messages %}
133
+ {{- raise_exception('No messages provided.') }}
134
+ {%- endif %}
135
  {%- set head = namespace(count=0, seen_non_system=false) %}
136
  {%- for message in messages %}
137
+ {%- set _is_sys = (message.role == 'system' or message.role == 'developer') %}
138
+ {%- if _is_sys and not head.seen_non_system %}
 
 
 
 
 
 
 
139
  {%- set head.count = head.count + 1 %}
140
  {%- else %}
141
  {%- set head.seen_non_system = true %}
142
  {%- endif %}
143
  {%- endfor %}
144
+ {%- set sys_state = namespace(content='') %}
145
  {%- for message in messages[:head.count] %}
146
+ {%- set _part = render_content(message.content, false, true) | trim %}
147
+ {%- if '<|think_off|>' in _part %}{%- set _part = _part.split('<|think_off|>') | join('') | trim %}{%- endif %}
148
+ {%- if '<|think_on|>' in _part %}{%- set _part = _part.split('<|think_on|>') | join('') | trim %}{%- endif %}
149
+ {%- if '<|think_xhigh|>' in _part %}{%- set _part = _part.split('<|think_xhigh|>') | join('') | trim %}{%- endif %}
150
+ {%- if '<|think_high|>' in _part %}{%- set _part = _part.split('<|think_high|>') | join('') | trim %}{%- endif %}
151
+ {%- if '<|think_ultracode|>' in _part %}{%- set _part = _part.split('<|think_ultracode|>') | join('') | trim %}{%- endif %}
152
+ {%- if '<|think_extreme|>' in _part %}{%- set _part = _part.split('<|think_extreme|>') | join('') | trim %}{%- endif %}
153
+ {%- if '<|think_max|>' in _part %}{%- set _part = _part.split('<|think_max|>') | join('') | trim %}{%- endif %}
154
+ {%- if '<|think_medium|>' in _part %}{%- set _part = _part.split('<|think_medium|>') | join('') | trim %}{%- endif %}
155
+ {%- if '<|think_low|>' in _part %}{%- set _part = _part.split('<|think_low|>') | join('') | trim %}{%- endif %}
156
+ {%- if '<|think_minimal|>' in _part %}{%- set _part = _part.split('<|think_minimal|>') | join('') | trim %}{%- endif %}
157
  {%- if _part %}
158
+ {%- if sys_state.content %}
159
+ {%- set sys_state.content = sys_state.content ~ '\n\n' ~ _part %}
 
 
160
  {%- else %}
161
+ {%- set sys_state.content = _part %}
162
  {%- endif %}
163
  {%- endif %}
164
  {%- endfor %}
165
+ {%- set _sc = sys_state.content %}
166
  {%- set _msgs = messages[head.count:] %}
 
 
 
167
  {%- if _has_tools %}
168
  {{- '<|im_start|>system\n' }}
169
  {%- if reasoning_instructions %}
170
+ {{- reasoning_instructions + '\n\n' }}
171
  {%- endif %}
172
  {{- '# Tools\n\nYou have access to the following functions:\n\n<tools>' }}
173
  {%- for tool in tools %}
 
176
  {%- endfor %}
177
  {{- '\n</tools>' }}
178
  {%- if _tool_format == 'json' %}
179
+ {{- '\n\nIf you choose to call a function ONLY reply in the following format with NO suffix:\n\n<think>\nBrief explanation of tool call\n</think>\n<tool_call>\n{"name": "example_function_name", "arguments": {"example_parameter_1": "value_1", "example_parameter_2": "This is the value for the second parameter"}}\n</tool_call>\n\n<IMPORTANT>\nReminder:\n- You can use the <think></think> block to plan your next tool call OR to synthesize data and formulate your final response to the user.\n- ALL explanation and reasoning MUST be placed strictly inside the <think></think> block.\n- Function calls MUST follow the specified format: a single JSON object with "name" and "arguments" keys inside <tool_call></tool_call> XML tags.\n- If you choose to call a tool, you MUST output the <tool_call> block IMMEDIATELY after thinking, with NO conversational text before it.\n- The <tool_call> tag MUST be at the very beginning of a new line, with NO spaces or indentation before it.\n- To call multiple functions, output a separate, completely closed <tool_call></tool_call> block for EACH function. Do NOT nest <tool_call> blocks.\n- If you have all necessary data, provide your final answer directly to the user without any tool call.\n</IMPORTANT>' }}
180
  {%- else %}
181
+ {{- '\n\nIf you choose to call a function ONLY reply in the following format with NO suffix:\n\n<think>\nBrief explanation of tool call\n</think>\n<tool_call>\n<function=example_function_name>\n<parameter=example_parameter_1>\nvalue_1\n</parameter>\n<parameter=example_parameter_2>\nThis is the value for the second parameter\nthat can span\nmultiple lines\n</parameter>\n</function>\n</tool_call>\n\n<IMPORTANT>\nReminder:\n- You can use the <think></think> block to plan your next tool call OR to synthesize data and formulate your final response to the user.\n- ALL explanation and reasoning MUST be placed strictly inside the <think></think> block.\n- Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags.\n- If you choose to call a tool, you MUST output the <tool_call> block IMMEDIATELY after thinking, with NO conversational text before it.\n- The <tool_call> and <function> tags MUST be at the very beginning of a new line, with NO spaces or indentation before them.\n- To call multiple functions, output a separate, completely closed <tool_call></tool_call> block for EACH function. Do NOT nest <tool_call> blocks.\n- If you have all necessary data, provide your final answer directly to the user without any tool call.\n</IMPORTANT>' }}
182
  {%- endif %}
183
+ {%- if _sc %}
184
+ {{- '\n\n' + _sc }}
185
  {%- endif %}
186
  {{- '<|im_end|>\n' }}
187
  {%- else %}
188
+ {%- if _sc %}
189
+ {{- '<|im_start|>system\n' + (reasoning_instructions + '\n\n' if reasoning_instructions else '') + _sc + '<|im_end|>\n' }}
 
 
 
 
190
  {%- elif reasoning_instructions %}
191
+ {{- '<|im_start|>system\n' + reasoning_instructions + '<|im_end|>\n' }}
 
 
 
192
  {%- endif %}
193
  {%- endif %}
194
+ {%- set _last_idx = _msgs | length - 1 %}
195
+ {%- set ns = namespace(multi_step_tool=true, last_query_index=_last_idx) %}
 
 
 
 
 
196
  {%- for message in _msgs[::-1] %}
197
  {%- set index = (_msgs | length - 1) - loop.index0 %}
198
  {%- if ns.multi_step_tool and message.role == 'user' %}
199
+ {%- set _rc = render_content(message.content, false) | trim %}
200
+ {%- if not (_rc.startswith('<tool_response>') and _rc.endswith('</tool_response>')) %}
 
 
 
 
 
201
  {%- set ns.multi_step_tool = false %}
202
  {%- set ns.last_query_index = index %}
203
  {%- endif %}
204
  {%- endif %}
205
  {%- endfor %}
206
  {%- if ns.multi_step_tool %}
207
+ {%- if _last_idx > 50 %}
208
+ {%- set ns.last_query_index = _last_idx %}
209
+ {%- else %}
210
+ {%- set ns.last_query_index = 0 %}
211
+ {%- endif %}
212
  {%- endif %}
213
+ {%- set ns2 = namespace(prev_role='', consecutive_failures=0) %}
 
 
 
214
  {%- for message in _msgs %}
215
+ {%- set is_system = (message.role == "system" or message.role == "developer") %}
216
+ {%- set content = render_content(message.content, true, is_system) | trim %}
217
+ {%- if is_system or message.role == 'user' %}
218
+ {%- if '<|think_off|>' in content %}{%- set content = content.split('<|think_off|>') | join('') | trim %}{%- endif %}
219
+ {%- if '<|think_on|>' in content %}{%- set content = content.split('<|think_on|>') | join('') | trim %}{%- endif %}
220
+ {%- if '<|think_xhigh|>' in content %}{%- set content = content.split('<|think_xhigh|>') | join('') | trim %}{%- endif %}
221
+ {%- if '<|think_high|>' in content %}{%- set content = content.split('<|think_high|>') | join('') | trim %}{%- endif %}
222
+ {%- if '<|think_ultracode|>' in content %}{%- set content = content.split('<|think_ultracode|>') | join('') | trim %}{%- endif %}
223
+ {%- if '<|think_extreme|>' in content %}{%- set content = content.split('<|think_extreme|>') | join('') | trim %}{%- endif %}
224
+ {%- if '<|think_max|>' in content %}{%- set content = content.split('<|think_max|>') | join('') | trim %}{%- endif %}
225
+ {%- if '<|think_medium|>' in content %}{%- set content = content.split('<|think_medium|>') | join('') | trim %}{%- endif %}
226
+ {%- if '<|think_low|>' in content %}{%- set content = content.split('<|think_low|>') | join('') | trim %}{%- endif %}
227
+ {%- if '<|think_minimal|>' in content %}{%- set content = content.split('<|think_minimal|>') | join('') | trim %}{%- endif %}
228
+ {%- endif %}
229
+ {%- if is_system %}
230
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
231
+ {%- elif message.role == 'user' %}
232
+ {%- set ns2.consecutive_failures = 0 %}
233
+ {{- '<|im_start|>user\n' + content + '<|im_end|>\n' }}
234
  {%- elif message.role == 'assistant' %}
235
  {%- set reasoning_content = '' %}
236
+ {%- set _explicit_reasoning = '' %}
237
+ {%- if message.reasoning_content is defined and message.reasoning_content is not none %}
 
 
 
 
 
 
 
 
 
 
 
238
  {%- if message.reasoning_content is string %}
239
+ {%- set _explicit_reasoning = message.reasoning_content %}
240
  {%- else %}
241
+ {%- set _explicit_reasoning = message.reasoning_content | string %}
 
 
242
  {%- endif %}
243
+ {%- elif message.thinking is defined and message.thinking is not none %}
 
244
  {%- if message.thinking is string %}
245
+ {%- set _explicit_reasoning = message.thinking %}
246
  {%- else %}
247
+ {%- set _explicit_reasoning = message.thinking | string %}
248
+ {%- endif %}
249
+ {%- elif message.reasoning is defined and message.reasoning is not none %}
250
+ {%- if message.reasoning is string %}
251
+ {%- set _explicit_reasoning = message.reasoning %}
252
+ {%- else %}
253
+ {%- set _explicit_reasoning = message.reasoning | string %}
254
+ {%- endif %}
255
+ {%- endif %}
256
+ {%- if _explicit_reasoning %}
257
+ {%- set _lead_end = '' %}
258
+ {%- if content.startswith('<think>') and '</think>' in content %}
259
+ {%- set _lead_end = '</think>' %}
260
+ {%- elif content.startswith('<thinking>') and '</thinking>' in content %}
261
+ {%- set _lead_end = '</thinking>' %}
262
+ {%- elif content.startswith('</think>') %}
263
+ {%- set _lead_end = '</think>' %}
264
+ {%- elif content.startswith('</thinking>') %}
265
+ {%- set _lead_end = '</thinking>' %}
266
+ {%- endif %}
267
+ {%- if _lead_end %}
268
+ {%- set content = content.split(_lead_end)[-1].lstrip('\n') %}
269
+ {%- endif %}
270
+ {%- set reasoning_content = _explicit_reasoning %}
271
+ {%- else %}
272
+ {%- set _think_end = '' %}
273
+ {%- if content.startswith('</think>') %}
274
+ {%- set _think_end = '</think>' %}
275
+ {%- elif content.startswith('</thinking>') %}
276
+ {%- set _think_end = '</thinking>' %}
277
+ {%- elif '\n</think>' in content %}
278
+ {%- set _think_end = '\n</think>' %}
279
+ {%- elif '\n</thinking>' in content %}
280
+ {%- set _think_end = '\n</thinking>' %}
281
+ {%- elif '\n</ think>' in content %}
282
+ {%- set _think_end = '\n</ think>' %}
283
+ {%- elif '\n</think >' in content %}
284
+ {%- set _think_end = '\n</think >' %}
285
+ {%- elif content.startswith('<think>') and '</think>' in content %}
286
+ {%- set _think_end = '</think>' %}
287
+ {%- elif content.startswith('<thinking>') and '</thinking>' in content %}
288
+ {%- set _think_end = '</thinking>' %}
289
+ {%- endif %}
290
+ {%- if _think_end %}
291
+ {%- if 'thinking' in _think_end %}
292
+ {%- set _think_start = '<thinking>' %}
293
+ {%- else %}
294
+ {%- set _think_start = '<think>' %}
295
+ {%- endif %}
296
+ {%- set reasoning_content = content.split(_think_end)[0].rstrip('\n') %}
297
+ {%- if _think_start in reasoning_content %}
298
+ {%- set reasoning_content = reasoning_content.split(_think_start)[-1].lstrip('\n') %}
299
+ {%- endif %}
300
+ {%- set content = content.split(_think_end)[-1].lstrip('\n') %}
301
  {%- endif %}
302
  {%- endif %}
303
  {%- set reasoning_content = reasoning_content | trim %}
304
+ {%- if (_preserve_thinking or loop.index0 > ns.last_query_index) %}
305
+ {{- '<|im_start|>assistant\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
 
 
 
 
 
 
 
306
  {%- else %}
307
+ {{- '<|im_start|>assistant\n' + content }}
308
  {%- endif %}
309
+ {%- if message.tool_calls is defined and message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
 
 
 
 
 
 
 
 
 
310
  {%- for tool_call in message.tool_calls %}
311
+ {%- if tool_call.function is defined and tool_call.function is not none %}
 
312
  {%- set tc = tool_call.function %}
313
  {%- else %}
314
  {%- set tc = tool_call %}
315
  {%- endif %}
316
+ {%- set tc_name = tc.name if (tc.name is defined and tc.name is not none) else '' %}
 
 
 
 
 
 
 
 
317
  {%- if _tool_format == 'json' %}
318
  {%- if loop.first %}
319
  {%- if content | trim %}
320
+ {{- '\n\n' }}
 
 
321
  {%- endif %}
322
  {%- else %}
323
+ {{- '\n' }}
324
  {%- endif %}
325
+ {%- set _args = '{}' %}
326
+ {%- if tc.arguments is defined and tc.arguments is not none %}
 
327
  {%- if tc.arguments is mapping %}
328
+ {%- set _args = tc.arguments | tojson %}
 
 
329
  {%- elif tc.arguments is string %}
330
+ {%- if tc.arguments %}
331
+ {%- set _args = tc.arguments %}
 
 
 
 
 
 
 
 
 
 
 
 
 
332
  {%- endif %}
333
  {%- else %}
334
+ {%- set _args = tc.arguments | tojson %}
 
 
335
  {%- endif %}
336
  {%- endif %}
337
+ {{- '<tool_call>\n{"name": ' }}{{- tc_name | tojson }}{{- ', "arguments": ' }}{{- _args }}{{- '}\n</tool_call>' }}
 
 
 
 
338
  {%- else %}
339
  {%- if loop.first %}
340
  {%- if content | trim %}
341
+ {{- '\n\n<tool_call>\n<function=' + tc_name + '>\n' }}
 
 
 
342
  {%- else %}
343
+ {{- '<tool_call>\n<function=' + tc_name + '>\n' }}
 
 
 
344
  {%- endif %}
345
  {%- else %}
346
+ {{- '\n<tool_call>\n<function=' + tc_name + '>\n' }}
 
 
 
347
  {%- endif %}
348
+ {%- if tc.arguments is defined and tc.arguments is not none %}
 
349
  {%- if tc.arguments is mapping %}
350
+ {%- for args_name, args_value in tc.arguments.items() %}
351
+ {{- '<parameter=' + args_name + '>\n' }}
 
 
 
 
 
 
 
 
 
 
352
  {%- if args_value is string %}
353
+ {%- set _av = args_value %}
 
 
354
  {%- else %}
355
+ {%- set _av = args_value | tojson %}
 
 
356
  {%- endif %}
357
+ {%- if max_tool_arg_chars > 0 and _av | length > max_tool_arg_chars %}
358
+ {{- _av[:max_tool_arg_chars] + '\n[TRUNCATED - original length ' ~ (_av | length | string) ~ ' chars]' }}
 
 
 
 
 
 
359
  {%- else %}
360
+ {{- _av }}
361
  {%- endif %}
362
  {{- '\n</parameter>\n' }}
363
  {%- endfor %}
 
 
 
 
 
 
 
 
 
 
364
  {%- else %}
365
+ {%- if tc.arguments is string %}
366
+ {%- set _raw_args = tc.arguments %}
367
+ {%- else %}
368
+ {%- set _raw_args = tc.arguments | tojson %}
369
+ {%- endif %}
370
+ {%- if _raw_args %}
371
+ {%- if max_tool_arg_chars > 0 and _raw_args | length > max_tool_arg_chars %}
372
+ {{- _raw_args[:max_tool_arg_chars] + '\n[TRUNCATED - original length ' ~ (_raw_args | length | string) ~ ' chars]' }}
373
+ {%- else %}
374
+ {{- _raw_args }}
375
+ {%- endif %}
376
+ {%- endif %}
377
  {%- endif %}
378
  {%- endif %}
379
  {{- '</function>\n</tool_call>' }}
 
382
  {%- endif %}
383
  {{- '<|im_end|>\n' }}
384
  {%- elif message.role == 'tool' %}
385
+ {%- set _content_lower = content | lower %}
386
+ {%- set _content_head = _content_lower[:120] %}
387
+ {%- set _is_code_or_grep = ('throw new ' in _content_lower or 'throw error' in _content_lower or 'console.error' in _content_lower or 'logger.error' in _content_lower or 'logging.error' in _content_lower or 'import ' in _content_head or 'def ' in _content_head or 'function ' in _content_head) %}
388
+ {%- set _exit_code_zero = ('exit code: 0' in _content_head or 'process exited with code 0' in _content_head) %}
389
+ {%- set _error_field_ok = ('"error": null' in _content_head or '"error":null' in _content_head or '"error": false' in _content_head or '"error":false' in _content_head or '"error": ""' in _content_head or '"error":""' in _content_head) %}
390
+ {%- set _strong_error = (('"error":' in _content_head and not _error_field_ok) or '"status": "error"' in _content_head or '"status":"error"' in _content_head or 'traceback (most recent call last):' in _content_head or 'command not found' in _content_head or 'invalid syntax' in _content_head or 'fatal:' in _content_head or (('exit code: ' in _content_head or 'process exited with code' in _content_head) and not _exit_code_zero) or _content_head.startswith('exception:') or _content_head.startswith('failed to ')) %}
391
+ {%- set _weak_error = ('error:' in _content_head or 'err!' in _content_head) %}
392
+ {%- set _weak_suppressed = ('$ ' in _content_head or 'took ' in _content_head or content | length >= 600) %}
393
+ {%- if not _is_code_or_grep and (_strong_error or (_weak_error and not _weak_suppressed)) %}
394
+ {%- set ns2.consecutive_failures = ns2.consecutive_failures + 1 %}
395
+ {%- else %}
396
+ {%- set ns2.consecutive_failures = 0 %}
397
+ {%- endif %}
398
+ {%- if ns2.prev_role != 'tool' %}
399
  {{- '<|im_start|>user' }}
400
  {%- endif %}
401
+ {%- if _tool_format != 'json' and max_tool_response_chars > 0 and content | length > max_tool_response_chars %}
402
+ {%- set content = content[:max_tool_response_chars] + '\n[TRUNCATED - original length ' ~ (content | length | string) ~ ' chars]' %}
403
+ {%- endif %}
404
+ {{- '\n<tool_response>\n' + content }}
405
+ {%- if ns2.consecutive_failures >= 2 %}
406
+ {{- '\n\n⚠️ SYSTEM WARNING: ' ~ ns2.consecutive_failures ~ ' consecutive tool errors detected. Your previous approach is incorrect. You MUST use a fundamentally different approach or corrected arguments.' }}
407
+ {%- elif ns2.consecutive_failures == 1 %}
408
+ {{- '\n\n⚠️ SYSTEM WARNING: The previous tool call returned an error. Diagnose the failure and retry with completely corrected arguments.' }}
409
  {%- endif %}
 
 
410
  {{- '\n</tool_response>' }}
411
  {%- if loop.last %}
412
  {{- '<|im_end|>\n' }}
413
+ {%- else %}
414
+ {%- set _next_role = _msgs[loop.index0 + 1].role %}
415
+ {%- if _next_role != 'tool' %}
416
+ {{- '<|im_end|>\n' }}
417
+ {%- endif %}
418
  {%- endif %}
 
 
 
 
 
419
  {%- else %}
420
+ {{- '<|im_start|>user\n[' + message.role + ']: ' + content + '<|im_end|>\n' }}
 
 
421
  {%- endif %}
422
+ {%- set ns2.prev_role = message.role %}
423
  {%- endfor %}
 
 
 
424
  {%- if add_generation_prompt %}
425
  {{- '<|im_start|>assistant\n' }}
426
+ {%- if not ns_state.thinking %}
427
  {{- '<think>\n\n</think>\n\n' }}
428
  {%- else %}
429
  {{- '<think>\n' }}