@anuma/sdk 10.5.1 → 10.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19345,6 +19345,28 @@ async function chunkRowSource(ctx, filter) {
19345
19345
  return fullScanChunkRowSource(ctx, filter);
19346
19346
  }
19347
19347
  }
19348
+ async function readChunkVectorRow(ctx, row, onUnreadable) {
19349
+ const version = Number(row.updated_at) || 0;
19350
+ const chunks = await readRawJsonField(row, "chunks", ctx.walletAddress);
19351
+ if (chunks && chunks.length > 0) {
19352
+ return {
19353
+ entry: {
19354
+ version,
19355
+ chunks: chunks.map((chunk) => decodeChunkVector(chunk.vector, onUnreadable))
19356
+ },
19357
+ chunks
19358
+ };
19359
+ }
19360
+ const messageVector = await readRawJsonField(row, "vector", ctx.walletAddress);
19361
+ if (!messageVector || messageVector.length === 0) return null;
19362
+ return { entry: { version, chunks: [], fallback: Float32Array.from(messageVector) }, chunks: [] };
19363
+ }
19364
+ function warnUnreadableChunkVectors(operation, count) {
19365
+ if (count === 0) return;
19366
+ getLogger().warn(
19367
+ `${operation}: could not read ${count} chunk vectors and left them out of ranking \u2014 the stored value is corrupt, so those chunks stay unsearchable until the message is re-embedded via chunkAndEmbedAllMessages`
19368
+ );
19369
+ }
19348
19370
  async function searchChunksOp(ctx, queryVector, options) {
19349
19371
  const {
19350
19372
  limit = 10,
@@ -19413,45 +19435,39 @@ async function searchChunksOp(ctx, queryVector, options) {
19413
19435
  for (const row of rows) {
19414
19436
  await yieldIfDue();
19415
19437
  const id = row.id;
19416
- const version = Number(row.updated_at) || 0;
19417
19438
  const order = orderById.get(id) ?? Number.MAX_SAFE_INTEGER;
19418
- const chunks = await readRawJsonField(row, "chunks", ctx.walletAddress);
19419
- if (chunks && chunks.length > 0) {
19420
- const vectors = chunks.map(
19421
- (chunk) => decodeChunkVector(chunk.vector, () => {
19422
- unreadableVectors++;
19423
- })
19424
- );
19425
- chunkCache?.set(id, { version, chunks: vectors });
19426
- for (let ci = 0; ci < chunks.length; ci++) {
19427
- const vec = vectors[ci];
19428
- if (vec.length === 0) continue;
19429
- const similarity = cosineSimilarity(queryVector, vec);
19430
- if (similarity >= minSimilarity) {
19431
- candidates.push({
19432
- id,
19433
- version,
19434
- order,
19435
- similarity,
19436
- chunkTextSource: { kind: "chunk", chunk: chunks[ci], siblings: chunks }
19437
- });
19438
- }
19439
+ const read = await readChunkVectorRow(ctx, row, () => {
19440
+ unreadableVectors++;
19441
+ });
19442
+ if (!read) continue;
19443
+ const { entry, chunks } = read;
19444
+ const { version } = entry;
19445
+ chunkCache?.set(id, entry);
19446
+ if (entry.fallback) {
19447
+ const similarity = cosineSimilarity(queryVector, entry.fallback);
19448
+ if (similarity >= minSimilarity) {
19449
+ candidates.push({
19450
+ id,
19451
+ version,
19452
+ order,
19453
+ similarity,
19454
+ chunkTextSource: { kind: "message" }
19455
+ });
19439
19456
  }
19440
- } else {
19441
- const messageVector = await readRawJsonField(row, "vector", ctx.walletAddress);
19442
- if (messageVector && messageVector.length > 0) {
19443
- const fallback = Float32Array.from(messageVector);
19444
- chunkCache?.set(id, { version, chunks: [], fallback });
19445
- const similarity = cosineSimilarity(queryVector, fallback);
19446
- if (similarity >= minSimilarity) {
19447
- candidates.push({
19448
- id,
19449
- version,
19450
- order,
19451
- similarity,
19452
- chunkTextSource: { kind: "message" }
19453
- });
19454
- }
19457
+ continue;
19458
+ }
19459
+ for (let ci = 0; ci < chunks.length; ci++) {
19460
+ const vec = entry.chunks[ci];
19461
+ if (vec.length === 0) continue;
19462
+ const similarity = cosineSimilarity(queryVector, vec);
19463
+ if (similarity >= minSimilarity) {
19464
+ candidates.push({
19465
+ id,
19466
+ version,
19467
+ order,
19468
+ similarity,
19469
+ chunkTextSource: { kind: "chunk", chunk: chunks[ci], siblings: chunks }
19470
+ });
19455
19471
  }
19456
19472
  }
19457
19473
  }
@@ -19462,11 +19478,7 @@ async function searchChunksOp(ctx, queryVector, options) {
19462
19478
  `searchChunksOp: skipped ${staleSkipped} messages whose embedding model differs from the current model (${embeddingModel}) \u2014 re-embed via chunkAndEmbedAllMessages`
19463
19479
  );
19464
19480
  }
19465
- if (unreadableVectors > 0) {
19466
- getLogger().warn(
19467
- `searchChunksOp: could not read ${unreadableVectors} chunk vectors and left them out of ranking \u2014 the stored value is corrupt, so those chunks stay unsearchable until the message is re-embedded via chunkAndEmbedAllMessages`
19468
- );
19469
- }
19481
+ warnUnreadableChunkVectors("searchChunksOp", unreadableVectors);
19470
19482
  const topK = candidates.sort((a, b) => b.similarity - a.similarity || a.order - b.order).slice(0, limit);
19471
19483
  const topIds = Array.from(new Set(topK.map((c) => c.id)));
19472
19484
  const fullRows = await source.loadFullRows(topIds);
@@ -33056,12 +33068,16 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
33056
33068
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
33057
33069
  const uncachedTexts = [];
33058
33070
  const uncachedIndices = [];
33071
+ const resolvedVectors = /* @__PURE__ */ new Map();
33059
33072
  let staleReembedCount = 0;
33060
33073
  for (let i = 0; queryEmbedding.length > 0 && i < memories.length; i++) {
33061
33074
  const content = memories[i].content;
33062
33075
  const memoryId = memories[i].uniqueId;
33063
33076
  const cached = cachedRowVector(cache, memoryId, memories[i].updatedAt, content);
33064
- if (cached && cached.length === queryEmbedding.length) continue;
33077
+ if (cached && cached.length === queryEmbedding.length) {
33078
+ resolvedVectors.set(memoryId, cached);
33079
+ continue;
33080
+ }
33065
33081
  if (cached) cache.delete(memoryId);
33066
33082
  const storedModel = memories[i].embeddingModel;
33067
33083
  const modelCompatible = (storedModel ?? currentModel) === currentModel;
@@ -33069,13 +33085,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
33069
33085
  try {
33070
33086
  const parsed = JSON.parse(memories[i].embedding);
33071
33087
  if (Array.isArray(parsed) && parsed.length === queryEmbedding.length) {
33072
- cacheRowVector(
33073
- cache,
33074
- memoryId,
33075
- Float32Array.from(parsed),
33076
- memories[i].updatedAt,
33077
- content
33078
- );
33088
+ const vector = Float32Array.from(parsed);
33089
+ resolvedVectors.set(memoryId, vector);
33090
+ cacheRowVector(cache, memoryId, vector, memories[i].updatedAt, content);
33079
33091
  continue;
33080
33092
  }
33081
33093
  } catch {
@@ -33108,20 +33120,17 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
33108
33120
  }
33109
33121
  if (newEmbeddings) {
33110
33122
  for (let j = 0; j < uncachedTexts.length; j++) {
33111
- cacheRowVector(
33112
- cache,
33113
- memories[uncachedIndices[j]].uniqueId,
33114
- Float32Array.from(newEmbeddings[j]),
33115
- memories[uncachedIndices[j]].updatedAt,
33116
- memories[uncachedIndices[j]].content
33117
- );
33123
+ const memory = memories[uncachedIndices[j]];
33124
+ const vector = Float32Array.from(newEmbeddings[j]);
33125
+ resolvedVectors.set(memory.uniqueId, vector);
33126
+ cacheRowVector(cache, memory.uniqueId, vector, memory.updatedAt, memory.content);
33118
33127
  }
33119
33128
  }
33120
33129
  }
33121
33130
  embeddedItems = memories.map((m) => ({
33122
33131
  id: m.uniqueId,
33123
33132
  content: m.content,
33124
- embedding: cache.get(m.uniqueId) ?? [],
33133
+ embedding: resolvedVectors.get(m.uniqueId) ?? [],
33125
33134
  createdAt: m.createdAt,
33126
33135
  updatedAt: m.updatedAt,
33127
33136
  proofCount: m.proofCount,
@@ -4100,6 +4100,13 @@ interface ChatBackend extends ChatStorageAdapter {
4100
4100
  uniqueId: string;
4101
4101
  }): Promise<StoredMessage>;
4102
4102
  searchChunks(queryVector: number[], options?: ChatChunkSearchOptions): Promise<ChunkSearchResult[]>;
4103
+ /** Fills a chunk vector cache ahead of the first search, for backends that score on the device. */
4104
+ warmChunkCache?(options: {
4105
+ chunkCache: ChunkVectorCache;
4106
+ embeddingModel?: string;
4107
+ limit?: number;
4108
+ signal?: AbortSignal;
4109
+ }): Promise<number>;
4103
4110
  getSummary(conversationId: string): Promise<StoredConversationSummary | null>;
4104
4111
  upsertSummary(conversationId: string, summary: string, summarizedUpTo: string, tokenCount: number): Promise<StoredConversationSummary>;
4105
4112
  deleteSummary(conversationId: string): Promise<void>;
@@ -4100,6 +4100,13 @@ interface ChatBackend extends ChatStorageAdapter {
4100
4100
  uniqueId: string;
4101
4101
  }): Promise<StoredMessage>;
4102
4102
  searchChunks(queryVector: number[], options?: ChatChunkSearchOptions): Promise<ChunkSearchResult[]>;
4103
+ /** Fills a chunk vector cache ahead of the first search, for backends that score on the device. */
4104
+ warmChunkCache?(options: {
4105
+ chunkCache: ChunkVectorCache;
4106
+ embeddingModel?: string;
4107
+ limit?: number;
4108
+ signal?: AbortSignal;
4109
+ }): Promise<number>;
4103
4110
  getSummary(conversationId: string): Promise<StoredConversationSummary | null>;
4104
4111
  upsertSummary(conversationId: string, summary: string, summarizedUpTo: string, tokenCount: number): Promise<StoredConversationSummary>;
4105
4112
  deleteSummary(conversationId: string): Promise<void>;
@@ -17637,6 +17637,28 @@ async function chunkRowSource(ctx, filter) {
17637
17637
  return fullScanChunkRowSource(ctx, filter);
17638
17638
  }
17639
17639
  }
17640
+ async function readChunkVectorRow(ctx, row, onUnreadable) {
17641
+ const version = Number(row.updated_at) || 0;
17642
+ const chunks = await readRawJsonField(row, "chunks", ctx.walletAddress);
17643
+ if (chunks && chunks.length > 0) {
17644
+ return {
17645
+ entry: {
17646
+ version,
17647
+ chunks: chunks.map((chunk) => decodeChunkVector(chunk.vector, onUnreadable))
17648
+ },
17649
+ chunks
17650
+ };
17651
+ }
17652
+ const messageVector = await readRawJsonField(row, "vector", ctx.walletAddress);
17653
+ if (!messageVector || messageVector.length === 0) return null;
17654
+ return { entry: { version, chunks: [], fallback: Float32Array.from(messageVector) }, chunks: [] };
17655
+ }
17656
+ function warnUnreadableChunkVectors(operation, count) {
17657
+ if (count === 0) return;
17658
+ getLogger().warn(
17659
+ `${operation}: could not read ${count} chunk vectors and left them out of ranking \u2014 the stored value is corrupt, so those chunks stay unsearchable until the message is re-embedded via chunkAndEmbedAllMessages`
17660
+ );
17661
+ }
17640
17662
  async function searchChunksOp(ctx, queryVector, options) {
17641
17663
  const {
17642
17664
  limit = 10,
@@ -17705,45 +17727,39 @@ async function searchChunksOp(ctx, queryVector, options) {
17705
17727
  for (const row of rows) {
17706
17728
  await yieldIfDue();
17707
17729
  const id = row.id;
17708
- const version = Number(row.updated_at) || 0;
17709
17730
  const order = orderById.get(id) ?? Number.MAX_SAFE_INTEGER;
17710
- const chunks = await readRawJsonField(row, "chunks", ctx.walletAddress);
17711
- if (chunks && chunks.length > 0) {
17712
- const vectors = chunks.map(
17713
- (chunk) => decodeChunkVector(chunk.vector, () => {
17714
- unreadableVectors++;
17715
- })
17716
- );
17717
- chunkCache?.set(id, { version, chunks: vectors });
17718
- for (let ci = 0; ci < chunks.length; ci++) {
17719
- const vec = vectors[ci];
17720
- if (vec.length === 0) continue;
17721
- const similarity = cosineSimilarity(queryVector, vec);
17722
- if (similarity >= minSimilarity) {
17723
- candidates.push({
17724
- id,
17725
- version,
17726
- order,
17727
- similarity,
17728
- chunkTextSource: { kind: "chunk", chunk: chunks[ci], siblings: chunks }
17729
- });
17730
- }
17731
+ const read = await readChunkVectorRow(ctx, row, () => {
17732
+ unreadableVectors++;
17733
+ });
17734
+ if (!read) continue;
17735
+ const { entry, chunks } = read;
17736
+ const { version } = entry;
17737
+ chunkCache?.set(id, entry);
17738
+ if (entry.fallback) {
17739
+ const similarity = cosineSimilarity(queryVector, entry.fallback);
17740
+ if (similarity >= minSimilarity) {
17741
+ candidates.push({
17742
+ id,
17743
+ version,
17744
+ order,
17745
+ similarity,
17746
+ chunkTextSource: { kind: "message" }
17747
+ });
17731
17748
  }
17732
- } else {
17733
- const messageVector = await readRawJsonField(row, "vector", ctx.walletAddress);
17734
- if (messageVector && messageVector.length > 0) {
17735
- const fallback = Float32Array.from(messageVector);
17736
- chunkCache?.set(id, { version, chunks: [], fallback });
17737
- const similarity = cosineSimilarity(queryVector, fallback);
17738
- if (similarity >= minSimilarity) {
17739
- candidates.push({
17740
- id,
17741
- version,
17742
- order,
17743
- similarity,
17744
- chunkTextSource: { kind: "message" }
17745
- });
17746
- }
17749
+ continue;
17750
+ }
17751
+ for (let ci = 0; ci < chunks.length; ci++) {
17752
+ const vec = entry.chunks[ci];
17753
+ if (vec.length === 0) continue;
17754
+ const similarity = cosineSimilarity(queryVector, vec);
17755
+ if (similarity >= minSimilarity) {
17756
+ candidates.push({
17757
+ id,
17758
+ version,
17759
+ order,
17760
+ similarity,
17761
+ chunkTextSource: { kind: "chunk", chunk: chunks[ci], siblings: chunks }
17762
+ });
17747
17763
  }
17748
17764
  }
17749
17765
  }
@@ -17754,11 +17770,7 @@ async function searchChunksOp(ctx, queryVector, options) {
17754
17770
  `searchChunksOp: skipped ${staleSkipped} messages whose embedding model differs from the current model (${embeddingModel}) \u2014 re-embed via chunkAndEmbedAllMessages`
17755
17771
  );
17756
17772
  }
17757
- if (unreadableVectors > 0) {
17758
- getLogger().warn(
17759
- `searchChunksOp: could not read ${unreadableVectors} chunk vectors and left them out of ranking \u2014 the stored value is corrupt, so those chunks stay unsearchable until the message is re-embedded via chunkAndEmbedAllMessages`
17760
- );
17761
- }
17773
+ warnUnreadableChunkVectors("searchChunksOp", unreadableVectors);
17762
17774
  const topK = candidates.sort((a, b) => b.similarity - a.similarity || a.order - b.order).slice(0, limit);
17763
17775
  const topIds = Array.from(new Set(topK.map((c) => c.id)));
17764
17776
  const fullRows = await source.loadFullRows(topIds);
@@ -31294,12 +31306,16 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
31294
31306
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
31295
31307
  const uncachedTexts = [];
31296
31308
  const uncachedIndices = [];
31309
+ const resolvedVectors = /* @__PURE__ */ new Map();
31297
31310
  let staleReembedCount = 0;
31298
31311
  for (let i = 0; queryEmbedding.length > 0 && i < memories.length; i++) {
31299
31312
  const content = memories[i].content;
31300
31313
  const memoryId = memories[i].uniqueId;
31301
31314
  const cached = cachedRowVector(cache, memoryId, memories[i].updatedAt, content);
31302
- if (cached && cached.length === queryEmbedding.length) continue;
31315
+ if (cached && cached.length === queryEmbedding.length) {
31316
+ resolvedVectors.set(memoryId, cached);
31317
+ continue;
31318
+ }
31303
31319
  if (cached) cache.delete(memoryId);
31304
31320
  const storedModel = memories[i].embeddingModel;
31305
31321
  const modelCompatible = (storedModel ?? currentModel) === currentModel;
@@ -31307,13 +31323,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
31307
31323
  try {
31308
31324
  const parsed = JSON.parse(memories[i].embedding);
31309
31325
  if (Array.isArray(parsed) && parsed.length === queryEmbedding.length) {
31310
- cacheRowVector(
31311
- cache,
31312
- memoryId,
31313
- Float32Array.from(parsed),
31314
- memories[i].updatedAt,
31315
- content
31316
- );
31326
+ const vector = Float32Array.from(parsed);
31327
+ resolvedVectors.set(memoryId, vector);
31328
+ cacheRowVector(cache, memoryId, vector, memories[i].updatedAt, content);
31317
31329
  continue;
31318
31330
  }
31319
31331
  } catch {
@@ -31346,20 +31358,17 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
31346
31358
  }
31347
31359
  if (newEmbeddings) {
31348
31360
  for (let j = 0; j < uncachedTexts.length; j++) {
31349
- cacheRowVector(
31350
- cache,
31351
- memories[uncachedIndices[j]].uniqueId,
31352
- Float32Array.from(newEmbeddings[j]),
31353
- memories[uncachedIndices[j]].updatedAt,
31354
- memories[uncachedIndices[j]].content
31355
- );
31361
+ const memory = memories[uncachedIndices[j]];
31362
+ const vector = Float32Array.from(newEmbeddings[j]);
31363
+ resolvedVectors.set(memory.uniqueId, vector);
31364
+ cacheRowVector(cache, memory.uniqueId, vector, memory.updatedAt, memory.content);
31356
31365
  }
31357
31366
  }
31358
31367
  }
31359
31368
  embeddedItems = memories.map((m) => ({
31360
31369
  id: m.uniqueId,
31361
31370
  content: m.content,
31362
- embedding: cache.get(m.uniqueId) ?? [],
31371
+ embedding: resolvedVectors.get(m.uniqueId) ?? [],
31363
31372
  createdAt: m.createdAt,
31364
31373
  updatedAt: m.updatedAt,
31365
31374
  proofCount: m.proofCount,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anuma/sdk",
3
- "version": "10.5.1",
3
+ "version": "10.5.3",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",