/** * Token estimation. * * Today this is a chars/4 heuristic (same as pi's `estimateTokens`). Keeping * every estimate behind this module is the seam for a future real tokenizer — * swap the implementation here and every collector picks it up. */ /** Estimate tokens for arbitrary text (chars/4, same heuristic as pi's estimateTokens). */ export const textTokens = (s: string | undefined | null): number => s && s.trim().length > 0 ? Math.max(1, Math.ceil(s.trim().length / 4)) : 0; /** * Skills appear in the prompt as name/description/location blocks; full * SKILL.md content is loaded on demand, not inlined. The flat pad keeps the * estimate above zero. */ const SKILL_PROMPT_PAD = 30; export const skillPromptTokens = ( name: string, description: string, filePath: string, ): number => textTokens(`${name} ${description} ${filePath}`) + SKILL_PROMPT_PAD; /** * Interface for message estimators — pi's `estimateTokens` conforms to it; * tests inject a fake. Keeps `messagesSection` free of pi runtime imports so * it runs under any TS runner. */ export type MessageEstimator = (message: unknown) => number;