pub use axon_csys::tokens::{count_tokens, estimate, CountKind, TokenCount};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_text_is_zero_tokens() {
let r = count_tokens("gpt-4o-mini", "");
assert_eq!(r.count, 0);
}
#[test]
fn empty_text_estimate_is_zero() {
let r = estimate("");
assert_eq!(r.count, 0);
assert_eq!(r.kind, CountKind::Estimate);
}
#[test]
fn estimate_rounds_up() {
assert_eq!(estimate("hello").count, 2);
assert_eq!(estimate("ABCD").count, 1);
assert_eq!(estimate("ABCDEFGH").count, 2);
assert_eq!(estimate("ABCDEFGHI").count, 3);
}
#[test]
fn anthropic_uses_estimate() {
let r = count_tokens("claude-sonnet-4-5", "hello world this is a test");
assert_eq!(r.kind, CountKind::Estimate);
}
#[test]
fn gemini_uses_estimate() {
let r = count_tokens("gemini-2.5-pro", "hello world this is a test");
assert_eq!(r.kind, CountKind::Estimate);
}
#[test]
fn unknown_model_uses_estimate() {
let r = count_tokens("totally-fake-model-7b", "hello world");
assert_eq!(r.kind, CountKind::Estimate);
}
#[test]
fn ollama_local_models_use_estimate() {
for model in &["llama-3.1-70b", "mistral-7b", "qwen-2.5-7b", "phi-4"] {
let r = count_tokens(model, "hello world");
assert_eq!(
r.kind,
CountKind::Estimate,
"model {model} unexpected kind {r:?}"
);
}
}
#[test]
fn gpt_4o_uses_o200k_exact() {
let r = count_tokens("gpt-4o-mini", "hello world");
assert_eq!(r.kind, CountKind::Exact);
assert!(r.count >= 1);
assert!(r.count <= 5);
}
#[test]
fn gpt_3_5_turbo_uses_cl100k_exact() {
let r = count_tokens("gpt-3.5-turbo", "hello world");
assert_eq!(r.kind, CountKind::Exact);
}
#[test]
fn o1_and_o3_use_o200k_exact() {
let a = count_tokens("o1-mini", "hello world");
let b = count_tokens("o3-mini", "hello world");
assert_eq!(a.kind, CountKind::Exact);
assert_eq!(b.kind, CountKind::Exact);
assert_eq!(a.count, b.count);
}
#[test]
fn kimi_and_glm_use_cl100k_exact() {
let a = count_tokens("kimi-k2.6", "hello world");
let b = count_tokens("glm-4-plus", "hello world");
assert_eq!(a.kind, CountKind::Exact);
assert_eq!(b.kind, CountKind::Exact);
}
#[test]
fn moonshot_alias_uses_cl100k_exact() {
let r = count_tokens("moonshot-v1-8k", "hello world");
assert_eq!(r.kind, CountKind::Exact);
}
#[test]
fn openrouter_strips_prefix_and_recurses() {
let r = count_tokens("openrouter:openai/gpt-4o-mini", "hello world");
assert_eq!(r.kind, CountKind::Exact);
}
#[test]
fn openrouter_to_anthropic_falls_back_to_estimate() {
let r = count_tokens("openrouter:anthropic/claude-sonnet-4-5", "hello world");
assert_eq!(r.kind, CountKind::Estimate);
}
#[test]
fn case_insensitive_model_matching() {
let r = count_tokens("GPT-4o-mini", "hello");
assert_eq!(r.kind, CountKind::Exact);
}
#[test]
fn unicode_text_counts_chars_not_bytes() {
let r = estimate("héllo");
assert_eq!(r.count, 2);
}
}