Skip to main content

hf_chat_template/
lib.rs

1//! Render Hugging Face `chat_template` (Jinja2) strings the way Python
2//! `transformers.apply_chat_template` does.
3//!
4//! This crate emits a **prompt string**. Turning it into token IDs is the caller's job
5//! (`tokenizers`, `tiktoken-rs`, …) — keeping that boundary is deliberate.
6//!
7//! ```
8//! use hf_chat_template::ChatTemplate;
9//! use minijinja::context;
10//!
11//! let tmpl = ChatTemplate::from_str(
12//!     "{% for m in messages %}<|{{ m.role }}|>{{ m.content }}\n{% endfor %}\
13//!      {% if add_generation_prompt %}<|assistant|>{% endif %}",
14//! ).unwrap();
15//!
16//! let out = tmpl.render_value(context! {
17//!     messages => vec![
18//!         context!{ role => "user", content => "hi" },
19//!     ],
20//!     add_generation_prompt => true,
21//! }).unwrap();
22//! assert_eq!(out, "<|user|>hi\n<|assistant|>");
23//! ```
24//!
25//! ## Special tokens & BOS doubling
26//! Templates that emit `{{ bos_token }}` expect you to pass `bos_token` in the context, and
27//! to set `add_special_tokens = false` at encode time so the tokenizer does not add BOS a
28//! second time. This crate renders exactly what the template says and never strips silently.
29
30#![forbid(unsafe_code)]
31
32mod clock;
33mod config;
34mod engine;
35mod error;
36#[cfg(feature = "hub")]
37mod hub;
38mod json;
39mod model;
40mod template;
41
42pub use clock::{Clock, FixedClock, SystemClock};
43pub use config::{ChatTemplateField, NamedTemplate, TokenField, TokenizerConfig};
44pub use error::Error;
45pub use model::{Content, Message, RenderInput};
46pub use template::{ChatTemplate, ChatTemplateBuilder};
47
48/// Re-export of the `minijinja` we build against, so downstreams can construct context
49/// [`Value`](minijinja::Value)s without guessing a version. Note: `render_value` ties our
50/// public API to this `minijinja` major version.
51pub use minijinja;