Skip to main content

prepend_bos

Function prepend_bos 

Source
pub fn prepend_bos<T: Copy + PartialEq>(tokens: &mut Vec<T>, bos: Option<T>)
Expand description

Prepends the checkpoint’s BOS id to an already-encoded prompt, unless the prompt already starts with it.

§The rule, stated once

The chat template owns BOS when it prints one; the loader owns it otherwise. Which of the two happens is a property of the individual checkpoint, not of the family:

  • Many upstream templates open with {{ bos_token }} — gemma-2/3 (<bos>), Mistral-Instruct and TinyLlama (<s>), Llama-3 (<|begin_of_text|>). Rendering one of those already puts BOS in the text, and both GgufBpeTokenizer::encode and GgufSpmTokenizer::encode split on special-token text first, so it comes back as the BOS id in position 0.
  • Unsloth deliberately strips {{ bos_token }} out of the templates it bakes into its GGUF exports, precisely so that a runtime which adds BOS itself does not double it. On those checkpoints the render carries no BOS and the loader must add it.

So neither “always add” nor “never add” is right, and a renderer cannot be sniffed for which case it is. This function implements the only rule that is correct for both: add the id, idempotently. bos is already the gated value — pass None when should_add_bos_token says this vocabulary does not take one (BPE/qwen2 ship a bos_token_id they never prepend).

Note this is stricter than llama.cpp, whose add_special path pushes BOS unconditionally and leaves the duplicate to a warning. Ferrox has no user-visible “you asked for two BOS tokens” surface, so it dedupes instead of warning. Generic over the id width because the CLI and server carry prompts as Vec<usize> and the tokenizers emit Vec<u32>.