1
0

messageKey.ts 1.4 KB

123456789101112131415161718192021222324252627282930
  1. // lib/messageKey.ts:由 lib/utils.ts 按职责拆分(实现未改)
  2. let messageSeq = 0;
  3. // 极端情况兜底(对象被冻结/密封等无法挂属性时),用 WeakMap 记录
  4. const messageKeyFallback = new WeakMap<object, string>();
  5. /**
  6. * 消息的稳定标识:同一条消息在整个生命周期内返回同一个 key,供列表渲染与「按消息」存储的局部状态
  7. * (思考折叠、引用折叠、复制态、编辑态、回答切换位置)使用。
  8. *
  9. * 不能用下标:消息被截断重发或重新生成后下标会整体前移,这些状态就会跟错消息。
  10. * 也不能用后端 id:那是流式结束后才回填的,key 变化会导致节点重建、状态丢失。
  11. * uid 挂在消息对象上且不可枚举,不会进入请求体或序列化结果。
  12. */
  13. export const getMessageKey = (message: unknown): string => {
  14. const target = message as Record<string, unknown> | null | undefined;
  15. if (!target || typeof target !== 'object') return 'unknown';
  16. if (typeof target.__uid !== 'string') {
  17. const uid = `msg-${++messageSeq}`;
  18. try {
  19. Object.defineProperty(target, '__uid', { value: uid, enumerable: false, configurable: true, writable: true });
  20. } catch {
  21. const existing = messageKeyFallback.get(target);
  22. if (existing) return existing;
  23. messageKeyFallback.set(target, uid);
  24. return uid;
  25. }
  26. }
  27. return target.__uid as string;
  28. };