package renderers

import (
	"os"
	"testing"

	"github.com/google/go-cmp/cmp"
)

// Expectations for the extra cases, captured from
// testdata/nemotron3nano_chat_template.jinja2 itself, so they are the
// template's output and not the renderer's. The default run compares the
// renderer against them; VERIFY_JINJA2=1 re-checks them against the template.
var nemotronExtraExpected = map[string]string{
	"tool without description":                  "<|im_start|>system\n# Tools\n\nYou have access to the following functions:\n\n<tools>\n<function>\n<name>ping</name>\n<parameters>\n<parameter>\n<name>host</name>\n<type>string</type>\n<description>Host</description>\n</parameter>\n<required>[\"host\"]</required>\n</parameters>\n</function>\n</tools>\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><|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool without parameters":                   "<|im_start|>system\n# Tools\n\nYou have access to the following functions:\n\n<tools>\n<function>\n<name>now</name>\n<description>Current time</description>\n<parameters>\n</parameters>\n</function>\n</tools>\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><|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool param without type":                   "<|im_start|>system\n# Tools\n\nYou have access to the following functions:\n\n<tools>\n<function>\n<name>q</name>\n<description>Query</description>\n<parameters>\n<parameter>\n<name>x</name>\n<description>no type</description>\n</parameter>\n</parameters>\n</function>\n</tools>\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><|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool param with unhandled keys":            "<|im_start|>system\n# Tools\n\nYou have access to the following functions:\n\n<tools>\n<function>\n<name>q</name>\n<description>Query</description>\n<parameters>\n<parameter>\n<name>x</name>\n<type>string</type>\n<description>X</description>\n<items>[\"a\", \"b\"]</items>\n</parameter>\n</parameters>\n</function>\n</tools>\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><|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool without required list":                "<|im_start|>system\n# Tools\n\nYou have access to the following functions:\n\n<tools>\n<function>\n<name>q</name>\n<description>Query</description>\n<parameters>\n<parameter>\n<name>x</name>\n<type>string</type>\n</parameter>\n</parameters>\n</function>\n</tools>\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><|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"system message after first turn":           "<|im_start|>system\nFirst system<|im_end|>\n<|im_start|>user\nHi<|im_end|>\n<|im_start|>system\nSecond system<|im_end|>\n<|im_start|>user\nAgain<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool message last":                         "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=f>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>user\n<tool_response>\nresult\n</tool_response>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool run then assistant":                   "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=f>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>user\n<tool_response>\none\n</tool_response>\n<tool_response>\ntwo\n</tool_response>\n<|im_end|>\n<|im_start|>assistant\n<think></think>done<|im_end|>\n<|im_start|>user\nnext<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"two user turns truncates earlier thinking": "<|im_start|>system\n<|im_end|>\n<|im_start|>user\nfirst<|im_end|>\n<|im_start|>assistant\n<think></think>\nanswer one<|im_end|>\n<|im_start|>user\nsecond<|im_end|>\n<|im_start|>assistant\n<think>\nlate reasoning\n</think>\nanswer two<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"assistant reasoning with tool call":        "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think>\ndecide\n</think>\ncalling\n<tool_call>\n<function=f>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"system only no user":                       "<|im_start|>system\nOnly system<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"assistant first no user":                   "<|im_start|>system\n<|im_end|>\n<|im_start|>assistant\n<think></think>unprompted<|im_end|>\n<|im_start|>user\nnow ask<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool message first":                        "<|im_start|>system\n<|im_end|>\n<tool_response>\norphan result\n</tool_response>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"multiple tools":                            "<|im_start|>system\n# Tools\n\nYou have access to the following functions:\n\n<tools>\n<function>\n<name>alpha</name>\n<description>First</description>\n<parameters>\n<parameter>\n<name>a</name>\n<type>string</type>\n</parameter>\n</parameters>\n</function>\n<function>\n<name>beta</name>\n<description>Second</description>\n<parameters>\n</parameters>\n</function>\n</tools>\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><|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool call multiple arguments":              "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=f>\n<parameter=one>\n1\n</parameter>\n<parameter=two>\n2\n</parameter>\n<parameter=three>\nTrue\n</parameter>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"assistant fully empty":                     "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think><|im_end|>\n<|im_start|>user\nagain<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"deep multi turn truncation":                "<|im_start|>system\n<|im_end|>\n<|im_start|>user\nu1<|im_end|>\n<|im_start|>assistant\n<think></think>\na1<|im_end|>\n<|im_start|>user\nu2<|im_end|>\n<|im_start|>assistant\n<think></think>\na2<|im_end|>\n<|im_start|>user\nu3<|im_end|>\n<|im_start|>assistant\n<think>\nt3\n</think>\na3<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"content think tags with tool call":         "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think>inline</think>after\n<tool_call>\n<function=f>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool response json":                        "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=f>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>user\n<tool_response>\n{\"temp\": 14, \"unit\": \"c\"}\n</tool_response>\n<|im_end|>\n<|im_start|>user\nand?<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"assistant closing tag only":                "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\nstray </think> tail<|im_end|>\n<|im_start|>user\nagain<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool call scalar arg types":                "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=f>\n<parameter=int>\n7\n</parameter>\n<parameter=float>\n2.5\n</parameter>\n<parameter=wholefloat>\n2\n</parameter>\n<parameter=boolfalse>\nFalse\n</parameter>\n<parameter=empty>\n\n</parameter>\n<parameter=zero>\n0\n</parameter>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool call container arg":                   "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=f>\n<parameter=obj>\n{\"k\": true}\n</parameter>\n<parameter=arr>\n[1, \"two\", false]\n</parameter>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"assistant two tool calls":                  "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=first>\n<parameter=a>\n1\n</parameter>\n</function>\n</tool_call>\n<tool_call>\n<function=second>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool call no arguments":                    "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=bare>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"multiline content":                         "<|im_start|>system\n<|im_end|>\n<|im_start|>user\nline one\nline two<|im_end|>\n<|im_start|>assistant\n<think></think>reply one\nreply two<|im_end|>\n<|im_start|>user\nagain<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"unicode content":                           "<|im_start|>system\n<|im_end|>\n<|im_start|>user\nhéllo <b>&amp;</b> 日本語 é<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"empty user content":                        "<|im_start|>system\n<|im_end|>\n<|im_start|>user\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"system with markup":                        "<|im_start|>system\n<tool_call>not real</tool_call><|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tools registered with history call":        "<|im_start|>system\n# Tools\n\nYou have access to the following functions:\n\n<tools>\n<function>\n<name>search_docs</name>\n<description>Search docs</description>\n<parameters>\n<parameter>\n<name>query</name>\n<type>string</type>\n<description>Search query</description>\n<enum>[\"api\", \"cli\"]</enum>\n</parameter>\n<parameter>\n<name>mode</name>\n<type>['string', 'null']</type>\n<description>Mode</description>\n<anyOf>[{\"type\": \"string\"}, {\"type\": \"number\"}]</anyOf>\n</parameter>\n<parameter>\n<name>payload</name>\n<type>object</type>\n<description>Payload</description>\n<properties>{\"enabled\": {\"type\": \"boolean\"}}</properties>\n<required>[\"enabled\"]</required>\n</parameter>\n<parameter>\n<name>tags</name>\n<type>array</type>\n<description>Tags</description>\n<items>{\"type\": \"string\"}</items>\n</parameter>\n<$defs>{\"shared\": {\"type\": \"string\"}}</$defs>\n<required>[\"query\"]</required>\n</parameters>\n</function>\n</tools>\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><|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=search_docs>\n<parameter=query>\napi\n</parameter>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>user\n<tool_response>\nfound\n</tool_response>\n<|im_end|>\n<|im_start|>user\nthanks<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"think unset with history":                  "<|im_start|>system\n<|im_end|>\n<|im_start|>user\nu1<|im_end|>\n<|im_start|>assistant\n<think></think>\na1<|im_end|>\n<|im_start|>user\nu2<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"consecutive assistant messages":            "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>first<|im_end|>\n<|im_start|>assistant\n<think></think>second<|im_end|>\n<|im_start|>user\nagain<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"user directly after tool":                  "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=f>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>user\n<tool_response>\nres\n</tool_response>\n<|im_end|>\n<|im_start|>user\nnext<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"assistant thinking empty content":          "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think><|im_end|>\n<|im_start|>user\nagain<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool response empty":                       "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=f>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>user\n<tool_response>\n\n</tool_response>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"assistant whitespace content":              "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think><|im_end|>\n<|im_start|>user\nagain<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"empty system message":                      "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"agentic multi round tool loop":             "<|im_start|>system\n# Tools\n\nYou have access to the following functions:\n\n<tools>\n<function>\n<name>search_docs</name>\n<description>Search docs</description>\n<parameters>\n<parameter>\n<name>query</name>\n<type>string</type>\n<description>Search query</description>\n<enum>[\"api\", \"cli\"]</enum>\n</parameter>\n<parameter>\n<name>mode</name>\n<type>['string', 'null']</type>\n<description>Mode</description>\n<anyOf>[{\"type\": \"string\"}, {\"type\": \"number\"}]</anyOf>\n</parameter>\n<parameter>\n<name>payload</name>\n<type>object</type>\n<description>Payload</description>\n<properties>{\"enabled\": {\"type\": \"boolean\"}}</properties>\n<required>[\"enabled\"]</required>\n</parameter>\n<parameter>\n<name>tags</name>\n<type>array</type>\n<description>Tags</description>\n<items>{\"type\": \"string\"}</items>\n</parameter>\n<$defs>{\"shared\": {\"type\": \"string\"}}</$defs>\n<required>[\"query\"]</required>\n</parameters>\n</function>\n</tools>\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><|im_end|>\n<|im_start|>user\nplan it<|im_end|>\n<|im_start|>assistant\n<think></think>checking\n<tool_call>\n<function=lookup>\n<parameter=q>\na\n</parameter>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>user\n<tool_response>\nres one\n</tool_response>\n<|im_end|>\n<|im_start|>assistant\n<think></think>again\n<tool_call>\n<function=lookup>\n<parameter=q>\nb\n</parameter>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>user\n<tool_response>\nres two\n</tool_response>\n<|im_end|>\n<|im_start|>assistant\n<think></think>final answer<|im_end|>\n<|im_start|>user\nthanks<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool call punctuated name":                 "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=ns.sub_tool-v2>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool call empty containers":                "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=f>\n<parameter=obj>\n{}\n</parameter>\n<parameter=arr>\n[]\n</parameter>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"explicit think true with tools":            "<|im_start|>system\n# Tools\n\nYou have access to the following functions:\n\n<tools>\n<function>\n<name>search_docs</name>\n<description>Search docs</description>\n<parameters>\n<parameter>\n<name>query</name>\n<type>string</type>\n<description>Search query</description>\n<enum>[\"api\", \"cli\"]</enum>\n</parameter>\n<parameter>\n<name>mode</name>\n<type>['string', 'null']</type>\n<description>Mode</description>\n<anyOf>[{\"type\": \"string\"}, {\"type\": \"number\"}]</anyOf>\n</parameter>\n<parameter>\n<name>payload</name>\n<type>object</type>\n<description>Payload</description>\n<properties>{\"enabled\": {\"type\": \"boolean\"}}</properties>\n<required>[\"enabled\"]</required>\n</parameter>\n<parameter>\n<name>tags</name>\n<type>array</type>\n<description>Tags</description>\n<items>{\"type\": \"string\"}</items>\n</parameter>\n<$defs>{\"shared\": {\"type\": \"string\"}}</$defs>\n<required>[\"query\"]</required>\n</parameters>\n</function>\n</tools>\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><|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\nok<|im_end|>\n<|im_start|>user\nmore<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"history content with think pair":           "<|im_start|>system\n<|im_end|>\n<|im_start|>user\nu1<|im_end|>\n<|im_start|>assistant\n<think></think>visible<|im_end|>\n<|im_start|>user\nu2<|im_end|>\n<|im_start|>assistant\n<think>kept</think>tail<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"assistant open think only":                 "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think>unclosed reasoning<|im_end|>\n<|im_start|>user\nagain<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"assistant multiple think pairs":            "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>end<|im_end|>\n<|im_start|>user\nagain<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool response with think markers":          "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=f>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>user\n<tool_response>\n<think>from tool</think>result\n</tool_response>\n<|im_end|>\n<|im_start|>user\nnext<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"user content with think markers":           "<|im_start|>system\n<|im_end|>\n<|im_start|>user\n<think>user wrote this</think>question<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"content with im_start markers":             "<|im_start|>system\n<|im_end|>\n<|im_start|>user\n<|im_start|>fake<|im_end|><|im_end|>\n<|im_start|>assistant\n<think></think><|im_end|>odd<|im_end|>\n<|im_start|>user\nagain<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"thinking field and content tags":           "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>body<|im_end|>\n<|im_start|>user\nagain<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"ends with assistant turn":                  "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>partial<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool call content closing tag only":        "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n</think>after\n<tool_call>\n<function=f>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"system tools think off round trip":         "<|im_start|>system\nSys\n\n# Tools\n\nYou have access to the following functions:\n\n<tools>\n<function>\n<name>search_docs</name>\n<description>Search docs</description>\n<parameters>\n<parameter>\n<name>query</name>\n<type>string</type>\n<description>Search query</description>\n<enum>[\"api\", \"cli\"]</enum>\n</parameter>\n<parameter>\n<name>mode</name>\n<type>['string', 'null']</type>\n<description>Mode</description>\n<anyOf>[{\"type\": \"string\"}, {\"type\": \"number\"}]</anyOf>\n</parameter>\n<parameter>\n<name>payload</name>\n<type>object</type>\n<description>Payload</description>\n<properties>{\"enabled\": {\"type\": \"boolean\"}}</properties>\n<required>[\"enabled\"]</required>\n</parameter>\n<parameter>\n<name>tags</name>\n<type>array</type>\n<description>Tags</description>\n<items>{\"type\": \"string\"}</items>\n</parameter>\n<$defs>{\"shared\": {\"type\": \"string\"}}</$defs>\n<required>[\"query\"]</required>\n</parameters>\n</function>\n</tools>\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><|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=search_docs>\n<parameter=query>\ncli\n</parameter>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>user\n<tool_response>\nhit\n</tool_response>\n<|im_end|>\n<|im_start|>user\nsummarize<|im_end|>\n<|im_start|>assistant\n<think></think>",
	"tool call null and numeric args":           "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=f>\n<parameter=nothing>\nNone\n</parameter>\n<parameter=negative>\n-12\n</parameter>\n<parameter=big>\n9007199254740993\n</parameter>\n<parameter=fraction>\n0.125\n</parameter>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool call nested mixed container":          "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=f>\n<parameter=deep>\n{\"b\": false, \"f\": 1.5, \"i\": 3, \"inner\": [1, {\"z\": true}], \"n\": null, \"s\": \"q\\\"uote\"}\n</parameter>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool param many unhandled keys":            "<|im_start|>system\n# Tools\n\nYou have access to the following functions:\n\n<tools>\n<function>\n<name>q</name>\n<description>Query</description>\n<parameters>\n<parameter>\n<name>x</name>\n<type>string</type>\n<description>X</description>\n<anyOf>[{\"type\": \"null\"}]</anyOf>\n<items>{\"minimum\": 0, \"type\": \"number\"}</items>\n</parameter>\n</parameters>\n</function>\n</tools>\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><|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool call content think pair only":         "<|im_start|>system\n<|im_end|>\n<|im_start|>user\nu1<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=f>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>user\nu2<|im_end|>\n<|im_start|>assistant\n<think>y</think>z\n<tool_call>\n<function=g>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool call quoted string arg":               "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=f>\n<parameter=s>\nline\nbreak \"quoted\"\n</parameter>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool schema nested and items":              "<|im_start|>system\n# Tools\n\nYou have access to the following functions:\n\n<tools>\n<function>\n<name>deep</name>\n<description>Nested schema</description>\n<parameters>\n<parameter>\n<name>outer</name>\n<type>object</type>\n<description>Outer object</description>\n<enum>[\"a\", \"b\"]</enum>\n<items>{\"type\": \"integer\"}</items>\n<properties>{\"inner\": {\"type\": \"string\", \"description\": \"Inner\"}, \"flag\": {\"type\": [\"boolean\", \"null\"]}}</properties>\n<required>[\"inner\"]</required>\n</parameter>\n<items>{\"type\": \"string\"}</items>\n<required>[\"outer\"]</required>\n</parameters>\n</function>\n</tools>\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><|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool call unsigned numeric container":      "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=f>\n<parameter=nums>\n{\"f32\": 1.5, \"i64\": -9, \"u\": 7, \"u8\": 255}\n</parameter>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool call whitespace content":              "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=f>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool schema defs property map":             "<|im_start|>system\n# Tools\n\nYou have access to the following functions:\n\n<tools>\n<function>\n<name>defs</name>\n<parameters>\n<parameter>\n<name>x</name>\n<type>string</type>\n</parameter>\n<$defs>{\"shared\": {\"type\": \"string\", \"description\": \"Shared\"}}</$defs>\n</parameters>\n</function>\n</tools>\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><|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool schema defs rich property":            "<|im_start|>system\n# Tools\n\nYou have access to the following functions:\n\n<tools>\n<function>\n<name>rich</name>\n<parameters>\n<parameter>\n<name>p</name>\n<type>string</type>\n</parameter>\n<$defs>{\"node\": {\"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}], \"type\": \"object\", \"items\": {\"type\": \"integer\"}, \"description\": \"Node\", \"enum\": [\"x\", \"y\"], \"properties\": {\"child\": {\"type\": \"string\"}}, \"required\": [\"child\"]}}</$defs>\n</parameters>\n</function>\n</tools>\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><|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool schema items property type":           "<|im_start|>system\n# Tools\n\nYou have access to the following functions:\n\n<tools>\n<function>\n<name>pt</name>\n<parameters>\n<parameter>\n<name>p</name>\n<type>string</type>\n</parameter>\n<items>[\"string\", \"null\"]</items>\n</parameters>\n</function>\n</tools>\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><|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool schema nil defs map":                  "<|im_start|>system\n# Tools\n\nYou have access to the following functions:\n\n<tools>\n<function>\n<name>niltest</name>\n<parameters>\n<parameter>\n<name>p</name>\n<type>string</type>\n</parameter>\n<$defs>None</$defs>\n</parameters>\n</function>\n</tools>\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><|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool call struct argument":                 "<|im_start|>system\n<|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think></think>\n<tool_call>\n<function=f>\n<parameter=custom>\n{\"a\": \"x\", \"b\": 2}\n</parameter>\n<parameter=list>\n[1, 2, 3]\n</parameter>\n</function>\n</tool_call>\n<|im_end|>\n<|im_start|>assistant\n<think>\n",
	"tool schema nested nil properties":         "<|im_start|>system\n# Tools\n\nYou have access to the following functions:\n\n<tools>\n<function>\n<name>nested</name>\n<parameters>\n<parameter>\n<name>p</name>\n<type>string</type>\n</parameter>\n<$defs>{\"node\": {\"type\": \"object\", \"required\": [\"q\"]}}</$defs>\n</parameters>\n</function>\n</tools>\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><|im_end|>\n<|im_start|>user\ngo<|im_end|>\n<|im_start|>assistant\n<think>\n",
}

func TestNemotron3NanoRendererMatchesReferenceExtra(t *testing.T) {
	verifyJinja2 := os.Getenv("VERIFY_JINJA2") != ""

	renderer := &Nemotron3NanoRenderer{}
	for _, tc := range nemotronExtraCases() {
		t.Run(tc.name, func(t *testing.T) {
			want, ok := nemotronExtraExpected[tc.name]
			if !ok {
				t.Fatalf("no expectation for %q: every case must be covered", tc.name)
			}

			got, err := renderer.Render(tc.messages, tc.tools, tc.think)
			if err != nil {
				t.Fatalf("Render() error = %v", err)
			}
			if diff := cmp.Diff(want, got); diff != "" {
				t.Fatalf("renderer mismatch (-want +got):\n%s", diff)
			}

			if verifyJinja2 {
				jinja2Output := renderNemotronWithJinja2(t, nemotron3NanoTemplate, tc.messages, tc.tools, tc.think)
				if diff := cmp.Diff(want, jinja2Output); diff != "" {
					t.Fatalf("template mismatch (-want +got):\n%s", diff)
				}
			}
		})
	}
}
