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