Issue description
JinjaTemplateChatWrapper (and therefore resolveChatWrapper/"auto" when it falls back to it) does not reproduce the part of the chat template's generation prompt that comes after the assistant role header. Any static text the template emits between the role header and the model's content -- most importantly a pre-filled reasoning tag like <think> is silently dropped.
Expected Behavior
If a model's jinja template explicitly emits <think>, the JinjaTemplateChatWrapper class should respect that.
Actual Behavior
The <think> tag is stripped out, inadvertently breaking the expected reasoning behavior of the model.
Steps to reproduce
The bug can be reproduced like this:
import { JinjaTemplateChatWrapper } from "node-llama-cpp";
// A chat template that pre-fills "<think>\n" in its generation prompt,
// as several reasoning-model GGUF templates do:
const template =
"{%- for m in messages %}{{- '<|im_start|>' + m.role + '\\n' + m.content + '<|im_end|>\\n' }}{%- endfor %}" +
"{%- if add_generation_prompt %}{{- '<|im_start|>assistant\\n<think>\\n' }}{%- endif %}";
const wrapper = new JinjaTemplateChatWrapper({ template });
const { contextText } = wrapper.generateContextState({
chatHistory: [
{ type: "user", text: "Hi" },
{ type: "model", response: [] }, // i.e. generating the assistant turn now
],
availableFunctions: {},
});
console.log(JSON.stringify(contextText.toString()));
Expected: "<|im_start|>user\nHi<|im_end|>\n<|im_start|>assistant\n<think>\n"
Actual: "<|im_start|>user\nHi<|im_end|>\n<|im_start|>assistant\n"
My Environment
| Dependency |
Version |
| Operating System |
macOS 24.5.0 (arm64) |
| CPU |
M4 |
| Node.js version |
24.18.0 |
| Typescript version |
5.9.3 |
node-llama-cpp version |
3.19.1 |
npx --yes node-llama-cpp inspect gpu output:
OS: macOS 24.5.0 (arm64)
Node: 24.18.0 (arm64)
TypeScript: 5.9.3
node-llama-cpp: 3.19.1
Prebuilt binaries: b10068
Cloned source: b10068
Metal: available
Metal device: Apple M4 Max
Metal used VRAM: 0% (464KB/96GB)
Metal free VRAM: 99.99% (96GB/96GB)
Metal unified memory: 96GB (100%)
CPU model: Apple M4 Max
Math cores: 12
Used RAM: 81.49% (104.32GB/128GB)
Free RAM: 18.5% (23.68GB/128GB)
Wired RAM: 2.91% (3.74GB/128GB)
Used swap: 0% (0B/0B)
Max swap size: dynamic
mmap: supported
Additional Context
Many reasoning GGUFs (various Qwen3 fine-tunes/merges) pre-fill <think> in their add_generation_prompt block and rely on it to start reasoning. Under JinjaTemplateChatWrapper they never receive the prefill and so never reason, even though the wrapper is meant to faithfully use the model's own template. The result is that these models, which are supposed to be reasoning models, can't do reasoning in node-llama-cpp. A good example of one is Qwen3.6-27B-Fable-Fusion which is currently #3 on HuggingFace.
Relevant Features Used
Are you willing to resolve this issue by submitting a Pull Request?
Yes, I have the time, and I know how to start.
Issue description
JinjaTemplateChatWrapper (and therefore resolveChatWrapper/"auto" when it falls back to it) does not reproduce the part of the chat template's generation prompt that comes after the assistant role header. Any static text the template emits between the role header and the model's content -- most importantly a pre-filled reasoning tag like
<think>is silently dropped.Expected Behavior
If a model's jinja template explicitly emits
<think>, theJinjaTemplateChatWrapperclass should respect that.Actual Behavior
The
<think>tag is stripped out, inadvertently breaking the expected reasoning behavior of the model.Steps to reproduce
The bug can be reproduced like this:
Expected:
"<|im_start|>user\nHi<|im_end|>\n<|im_start|>assistant\n<think>\n"Actual:
"<|im_start|>user\nHi<|im_end|>\n<|im_start|>assistant\n"My Environment
node-llama-cppversionnpx --yes node-llama-cpp inspect gpuoutput:Additional Context
Many reasoning GGUFs (various Qwen3 fine-tunes/merges) pre-fill
<think>in theiradd_generation_promptblock and rely on it to start reasoning. UnderJinjaTemplateChatWrapperthey never receive the prefill and so never reason, even though the wrapper is meant to faithfully use the model's own template. The result is that these models, which are supposed to be reasoning models, can't do reasoning innode-llama-cpp. A good example of one is Qwen3.6-27B-Fable-Fusion which is currently #3 on HuggingFace.Relevant Features Used
Are you willing to resolve this issue by submitting a Pull Request?
Yes, I have the time, and I know how to start.