File size: 3,652 Bytes
a0b676c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// 简单内存缓存:按 sessionId + model 维度缓存思维链签名和工具签名
// 同时集成内存管理器,在压力较高时自动收缩/清空缓存

import memoryManager, { MemoryPressure } from './memoryManager.js';

const reasoningSignatureCache = new Map();
const toolSignatureCache = new Map();

// 正常情况下允许的最大条目数(低压力时)
const MAX_REASONING_ENTRIES = 256;
const MAX_TOOL_ENTRIES = 256;

// 过期时间与定时清理间隔(毫秒)
const ENTRY_TTL_MS = 30 * 60 * 1000;      // 30 分钟
const CLEAN_INTERVAL_MS = 10 * 60 * 1000; // 每 10 分钟扫一遍

function makeKey(sessionId, model) {
  return `${sessionId || ''}::${model || ''}`;
}

function pruneMap(map, targetSize) {
  if (map.size <= targetSize) return;
  const removeCount = map.size - targetSize;
  let removed = 0;
  for (const key of map.keys()) {
    map.delete(key);
    removed++;
    if (removed >= removeCount) break;
  }
}

function pruneExpired(map, now) {
  for (const [key, entry] of map.entries()) {
    if (!entry || typeof entry.ts !== 'number') continue;
    if (now - entry.ts > ENTRY_TTL_MS) {
      map.delete(key);
    }
  }
}

// 注册到内存管理器,在不同压力级别下自动清理缓存
memoryManager.registerCleanup((pressure) => {
  if (pressure === MemoryPressure.MEDIUM) {
    // 中等压力:收缩到一半容量
    pruneMap(reasoningSignatureCache, Math.floor(MAX_REASONING_ENTRIES / 2));
    pruneMap(toolSignatureCache, Math.floor(MAX_TOOL_ENTRIES / 2));
  } else if (pressure === MemoryPressure.HIGH) {
    // 高压力:大幅收缩
    pruneMap(reasoningSignatureCache, Math.floor(MAX_REASONING_ENTRIES / 4));
    pruneMap(toolSignatureCache, Math.floor(MAX_TOOL_ENTRIES / 4));
  } else if (pressure === MemoryPressure.CRITICAL) {
    // 紧急压力:直接清空,优先保活
    reasoningSignatureCache.clear();
    toolSignatureCache.clear();
  }
});

// 定时清理:不依赖压力等级,按 TTL 移除过期签名
setInterval(() => {
  const now = Date.now();
  pruneExpired(reasoningSignatureCache, now);
  pruneExpired(toolSignatureCache, now);
}, CLEAN_INTERVAL_MS).unref?.();

export function setReasoningSignature(sessionId, model, signature) {
  if (!signature) return;
  const key = makeKey(sessionId, model);
  reasoningSignatureCache.set(key, { signature, ts: Date.now() });
  // 防止在低压力下无限增长
  pruneMap(reasoningSignatureCache, MAX_REASONING_ENTRIES);
}

export function getReasoningSignature(sessionId, model) {
  const key = makeKey(sessionId, model);
  const entry = reasoningSignatureCache.get(key);
  if (!entry) return null;
  const now = Date.now();
  if (typeof entry.ts === 'number' && now - entry.ts > ENTRY_TTL_MS) {
    reasoningSignatureCache.delete(key);
    return null;
  }
  return entry.signature || null;
}

export function setToolSignature(sessionId, model, signature) {
  if (!signature) return;
  const key = makeKey(sessionId, model);
  toolSignatureCache.set(key, { signature, ts: Date.now() });
  pruneMap(toolSignatureCache, MAX_TOOL_ENTRIES);
}

export function getToolSignature(sessionId, model) {
  const key = makeKey(sessionId, model);
  const entry = toolSignatureCache.get(key);
  if (!entry) return null;
  const now = Date.now();
  if (typeof entry.ts === 'number' && now - entry.ts > ENTRY_TTL_MS) {
    toolSignatureCache.delete(key);
    return null;
  }
  return entry.signature || null;
}

// 预留:手动清理接口(目前未在外部使用,但方便将来扩展)
export function clearThoughtSignatureCaches() {
  reasoningSignatureCache.clear();
  toolSignatureCache.clear();
}