From b3d28bcdf1beeea470c7771b9f07d54f12f05093 Mon Sep 17 00:00:00 2001 From: cepvor Date: Thu, 14 May 2026 16:05:16 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=B8=BA=20cacheWarningStateBySource=20?= =?UTF-8?q?Map=20=E8=AE=BE=E7=BD=AE=E4=B8=8A=E9=99=90=E9=98=B2=E6=AD=A2?= =?UTF-8?q?=E5=86=85=E5=AD=98=E6=B3=84=E6=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Map 以 querySource 为 key 存储每个来源的缓存命中率历史状态, 但 querySource 类型为 `any`,长时间会话中可能产生大量唯一值, Map 持续增长永不清理。 新增 MAX_SOURCE_ENTRIES = 50 上限,新增条目时若达到上限则 逐出最早插入的条目(Map 按插入顺序迭代)。 同时也新增 _resetCacheWarningStateForTest() 用于测试隔离。 Co-Authored-By: deepseek-v4-pro[1m] --- src/utils/cacheWarning.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/utils/cacheWarning.ts b/src/utils/cacheWarning.ts index 39ba5a599..2e193f9a4 100644 --- a/src/utils/cacheWarning.ts +++ b/src/utils/cacheWarning.ts @@ -24,6 +24,12 @@ interface CacheWarningState { // 模块级状态,每个 querySource 独立跟踪 const cacheWarningStateBySource = new Map() +// Limit the number of tracked sources to prevent unbounded Map growth. +// querySource strings are effectively unbounded (typed as `any`), so a +// long-running session that spawns many subagents could leak memory. +// Evict the oldest entry (by insertion order) when the limit is exceeded. +const MAX_SOURCE_ENTRIES = 50 + const DEFAULT_CACHE_THRESHOLD = 80 /** @@ -81,6 +87,13 @@ export function shouldShowCacheWarning( let state = cacheWarningStateBySource.get(querySource) if (!state) { state = { lastHitRate: null, lastTimestamp: null } + // Evict oldest entry when at capacity so the Map stays bounded + if (cacheWarningStateBySource.size >= MAX_SOURCE_ENTRIES) { + const oldestKey = cacheWarningStateBySource.keys().next().value + if (oldestKey !== undefined) { + cacheWarningStateBySource.delete(oldestKey) + } + } cacheWarningStateBySource.set(querySource, state) } @@ -132,3 +145,10 @@ export function createCacheWarningMessage(info: CacheHitRateInfo): Message { isMeta: false, } as Message } + +/** + * Reset the per-source tracking state — only used in tests. + */ +export function _resetCacheWarningStateForTest(): void { + cacheWarningStateBySource.clear() +}