@juspay/neurolink
Version:
The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002
104 lines (103 loc) • 4.43 kB
TypeScript
/**
* Token Estimation Utilities
*
* Provides character-based token estimation with per-provider adjustment
* multipliers. Uses the same approach as Continue (gpt-tokenizer baseline
* + provider multipliers) but without requiring a tokenizer dependency.
*
* Multiplier sources: Continue project's getAdjustedTokenCount.ts
* - Anthropic: 1.23x (Anthropic tokenizer produces ~23% more tokens)
* - Google (AI Studio / Vertex): 1.18x
* - Mistral/Codestral: 1.26x
* - OpenAI/GPT: 1.0x (baseline)
*/
import type { ChatMessage } from "../types/index.js";
/** Characters per token for English text */
export declare const CHARS_PER_TOKEN = 4;
/** Characters per token for code */
export declare const CODE_CHARS_PER_TOKEN = 3;
/**
* Safety margin: additive fraction of baseTokens added to the provider-adjusted estimate.
* Using additive margin prevents compounding with provider multipliers.
*
* Old behavior: baseTokens * providerMultiplier * 1.15 (compounding)
* e.g. Anthropic: baseTokens * 1.23 * 1.15 = baseTokens * 1.4145
* New behavior: baseTokens * providerMultiplier + baseTokens * 0.05 (additive)
* e.g. Anthropic: baseTokens * 1.23 + baseTokens * 0.05 = baseTokens * 1.28
*/
export declare const TOKEN_SAFETY_MARGIN_ADDITIVE = 0.05;
/** @deprecated Use TOKEN_SAFETY_MARGIN_ADDITIVE instead. Kept for backward compatibility. */
export declare const TOKEN_SAFETY_MARGIN = 1.15;
/** Message framing overhead in tokens (role + delimiters) */
export declare const TOKENS_PER_MESSAGE = 4;
/** Conversation-level overhead in tokens */
export declare const TOKENS_PER_CONVERSATION = 24;
/** Image token estimate (flat) */
export declare const IMAGE_TOKEN_ESTIMATE = 1024;
/**
* Get the token multiplier for a given provider.
*/
export declare function getProviderMultiplier(provider?: string): number;
/**
* Estimate token count for a string.
*
* @param text - Input text
* @param provider - Optional provider for multiplier adjustment
* @param isCode - Whether the text is code (uses CODE_CHARS_PER_TOKEN)
* @returns Estimated token count
*/
export declare function estimateTokens(text: string, provider?: string, isCode?: boolean): number;
/**
* Serialize an arbitrary value for estimation. Never throws: `JSON.stringify`
* raises RangeError once a value exceeds V8's max string length, and a tool
* argument blob is exactly the shape that gets there. A payload that large is
* charged at the fallback size rather than aborting the estimate (and with it
* the whole turn).
*/
/**
* Serialize a value for token estimation. The fallback is deliberately huge:
* an estimator that cannot measure a value must over-report, so a budget guard
* fires rather than waving through content it failed to size.
*/
export declare function serializeForEstimate(value: unknown): string;
/**
* Estimate token count for a single ChatMessage.
* Includes message framing overhead.
*
* Counts `content` AND `args`. A `tool_call` is persisted with an EMPTY
* `content` and its entire payload in `args` (see flushPendingToolData),
* so a content-only estimate scored a 39 KB Write call at ~28 tokens against a
* real cost near 9,750 — the budget checker, the compaction trigger and the
* summarization threshold were all blind to the single largest source of
* context growth in an agentic session.
*
* `result` is deliberately NOT counted: `result.result` is re-hydrated FROM
* `content` at read time (redisConversationMemoryManager), so counting both
* double-bills the same bytes. Only `result.error`, which has no counterpart in
* `content`, is included.
*/
export declare function estimateMessageTokens(message: ChatMessage | {
role: string;
content: unknown;
}, provider?: string): number;
/**
* Estimate total token count for an array of messages.
* Includes conversation-level overhead.
*/
export declare function estimateMessagesTokens(messages: Array<ChatMessage | {
role: string;
content: unknown;
}>, provider?: string): number;
/**
* Truncate text to fit within a token budget.
* Tries to cut at sentence or word boundaries.
*
* @param text - Input text
* @param maxTokens - Maximum tokens allowed
* @param provider - Optional provider for multiplier
* @returns Truncated text with "..." suffix if truncated
*/
export declare function truncateToTokenBudget(text: string, maxTokens: number, provider?: string): {
text: string;
truncated: boolean;
};