feat: Add token usage indicator to chat input

Add TokenUsageIndicator component with circular progress ring
Create useTokenUsage hook with Jotai atom for state
Add model context window lookups to data-provider
Consolidate token utilities (output limits, TOKEN_DEFAULTS)
Display input/output tokens and percentage of context used
This commit is contained in:
Marco Beretta 2025-12-14 00:36:45 +01:00
parent dc489e7b25
commit af2958fcba
No known key found for this signature in database
GPG key ID: D918033D8E74CC11
11 changed files with 710 additions and 32 deletions

View file

@ -8,6 +8,7 @@ import {
isAgentsEndpoint,
replaceSpecialVars,
providerEndpointMap,
TOKEN_DEFAULTS,
} from 'librechat-data-provider';
import type {
AgentToolResources,
@ -337,7 +338,7 @@ export async function initializeAgent(
providerEndpointMap[provider as keyof typeof providerEndpointMap],
options.endpointTokenConfig,
),
18000,
TOKEN_DEFAULTS.AGENT_CONTEXT_FALLBACK,
);
if (
@ -394,7 +395,7 @@ export async function initializeAgent(
agent.additional_instructions = artifactsPromptResult ?? undefined;
}
const agentMaxContextNum = Number(agentMaxContextTokens) || 18000;
const agentMaxContextNum = Number(agentMaxContextTokens) || TOKEN_DEFAULTS.AGENT_CONTEXT_FALLBACK;
const maxOutputTokensNum = Number(maxOutputTokens) || 0;
const finalAttachments: IMongoFile[] = (primedAttachments ?? [])
@ -413,7 +414,9 @@ export async function initializeAgent(
toolContextMap: toolContextMap ?? {},
useLegacyContent: !!options.useLegacyContent,
tools: (tools ?? []) as GenericTool[] & string[],
maxContextTokens: Math.round((agentMaxContextNum - maxOutputTokensNum) * 0.9),
maxContextTokens: Math.round(
(agentMaxContextNum - maxOutputTokensNum) * TOKEN_DEFAULTS.CONTEXT_SAFETY_MARGIN,
),
};
return initializedAgent;

View file

@ -1,34 +1,16 @@
import z from 'zod';
import { EModelEndpoint } from 'librechat-data-provider';
import {
EModelEndpoint,
TOKEN_DEFAULTS,
findMatchingPattern as findMatchingPatternSimple,
getModelMaxTokens as getModelMaxTokensSimple,
getModelMaxOutputTokens as getModelMaxOutputTokensSimple,
matchModelName as matchModelNameSimple,
} from 'librechat-data-provider';
import type { EndpointTokenConfig, TokenConfig } from '~/types';
/**
* Model Token Configuration Maps
*
* IMPORTANT: Key Ordering for Pattern Matching
* ============================================
* The `findMatchingPattern` function iterates through object keys in REVERSE order
* (last-defined keys are checked first) and uses `modelName.includes(key)` for matching.
*
* This means:
* 1. BASE PATTERNS must be defined FIRST (e.g., "kimi", "moonshot")
* 2. SPECIFIC PATTERNS must be defined AFTER their base patterns (e.g., "kimi-k2", "kimi-k2.5")
*
* Example ordering for Kimi models:
* kimi: 262144, // Base pattern - checked last
* 'kimi-k2': 262144, // More specific - checked before "kimi"
* 'kimi-k2.5': 262144, // Most specific - checked first
*
* Why this matters:
* - Model name "kimi-k2.5" contains both "kimi" and "kimi-k2" as substrings
* - If "kimi" were checked first, it would incorrectly match "kimi-k2.5"
* - By defining specific patterns AFTER base patterns, they're checked first in reverse iteration
*
* When adding new model families:
* 1. Define the base/generic pattern first
* 2. Define increasingly specific patterns after
* 3. Ensure no pattern is a substring of another that should match differently
*/
// Re-export from data-provider for backwards compatibility
export { TOKEN_DEFAULTS };
const openAIModels = {
'o4-mini': 200000,
@ -421,6 +403,14 @@ export const maxOutputTokensMap = {
[EModelEndpoint.custom]: { ...modelMaxOutputs, ...deepseekMaxOutputs },
};
// Re-export simple versions (for use without EndpointTokenConfig)
export {
findMatchingPatternSimple,
getModelMaxTokensSimple,
getModelMaxOutputTokensSimple,
matchModelNameSimple,
};
/**
* Finds the first matching pattern in the tokens map.
* @param {string} modelName