fix(agents): 为 VectorIndex 添加序列化/反序列化支持

**问题**:
- VectorIndex 索引只存储在内存 Map 中,重启后全部丢失
- Float32Array 数据无法直接序列化为 JSON
- 无法实现跨会话索引持久化

**修复**:
- 添加 serialize() 方法:将索引转换为 JSON 可序列化对象
- 添加 deserialize() 方法:从序列化数据恢复索引
- Float32Array 转换为普通数组进行序列化
- 保持向后兼容,不破坏现有功能

**测试**:
- 所有 26 个 VectorIndex 单元测试通过
- 修复不破坏现有功能

**注**:
- BM25 索引已有 serializeIndex/deserializeIndex 函数
- 两个索引现在都支持持久化

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>
This commit is contained in:
wing
2026-02-14 20:44:28 +08:00
co-authored by HAPI
parent edf910ec3c
commit c0b4172e03
@@ -227,6 +227,37 @@ export class VectorIndex {
}
return stats;
}
/**
* Serialize the index to a JSON-compatible object.
* @returns {{dim:number|null, maxItems:number, rows:Array<[string, {vec:number[], meta:any}]>}}
*/
serialize() {
const rows = [];
for (const [id, row] of this._rows.entries()) {
rows.push([id, { vec: Array.from(row.vec), meta: row.meta }]);
}
return { dim: this._dim, maxItems: this._maxItems, rows };
}
/**
* Deserialize and restore the index from a serialized object.
* @param {{dim:number|null, maxItems:number, rows:Array<[string, {vec:number[], meta:any}]>}} data
* @returns {void}
*/
deserialize(data) {
if (!data || typeof data !== 'object') throw new TypeError('deserialize(data): data must be an object');
this._dim = typeof data.dim === 'number' ? data.dim : null;
this._maxItems = toPositiveInt(data.maxItems, 1000);
this._rows.clear();
if (Array.isArray(data.rows)) {
for (const [id, row] of data.rows) {
if (typeof id !== 'string' || !row || !Array.isArray(row.vec)) continue;
const vec = new Float32Array(row.vec);
this._rows.set(id, { vec, meta: row.meta });
}
}
}
}
export default { VectorIndex };