Skip to content

Commit 9203a83

Browse files
committed
chore(types): annotate text_length is upper-bound estimate (char ≈ 4 tokens)
`MessageContent::text_length` is sometimes used as a proxy for LLM token count, but it returns UTF-8 byte length — not Unicode chars and not real tokens. Document the upper-bound semantics, the ~4 bytes ≈ 1 token rule of thumb, and that exact counts should swap to a real tokenizer rather than mutate this function.
1 parent b64a24c commit 9203a83

1 file changed

Lines changed: 21 additions & 1 deletion

File tree

crates/librefang-types/src/message.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,27 @@ impl MessageContent {
169169
MessageContent::Text(content.into())
170170
}
171171

172-
/// Get the total character length of text in this content.
172+
/// Total UTF-8 byte length of textual payload across all blocks.
173+
///
174+
/// **Upper-bound token estimate, not an exact count.**
175+
///
176+
/// Callers that use this to estimate LLM token usage should treat the
177+
/// returned value as a rough cap, not a real tokenization. The current
178+
/// implementation returns `String::len()` which is the **byte** length
179+
/// (per Rust semantics, not the user-facing "char count"). For
180+
/// most modern LLM tokenizers (BPE/tiktoken-style), 1 token ≈ 4 bytes
181+
/// of English-prose UTF-8 and somewhat less for CJK / source code, so
182+
/// `text_length / 4` is a conservative ceiling.
183+
///
184+
/// `ToolUse` blocks include the tool name plus the JSON-serialised
185+
/// arguments — also counted in bytes — to keep tool-heavy turns from
186+
/// looking artificially small. Images / image-files are skipped: they
187+
/// have their own provider-specific token cost models.
188+
///
189+
/// If exact token counts ever become necessary, swap callers to a real
190+
/// tokenizer (tiktoken-rs, anthropic count-tokens API) rather than
191+
/// changing this function — its current callers rely on it being
192+
/// cheap, infallible, and offline.
173193
pub fn text_length(&self) -> usize {
174194
match self {
175195
MessageContent::Text(s) => s.len(),

0 commit comments

Comments
 (0)