@anuma/sdk 7.0.1 → 7.0.2
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.
- package/dist/expo/index.cjs +284 -102
- package/dist/expo/index.d.mts +18 -24
- package/dist/expo/index.d.ts +18 -24
- package/dist/expo/index.mjs +284 -102
- package/dist/index.cjs +28 -10
- package/dist/index.mjs +28 -10
- package/dist/memory/context.d.mts +8 -0
- package/dist/memory/context.d.ts +8 -0
- package/dist/react/index.cjs +305 -123
- package/dist/react/index.d.mts +23 -44
- package/dist/react/index.d.ts +23 -44
- package/dist/react/index.mjs +305 -123
- package/dist/server/index.cjs +305 -101
- package/dist/server/index.d.mts +23 -21
- package/dist/server/index.d.ts +23 -21
- package/dist/server/index.mjs +305 -101
- package/dist/telemetry/index.d.mts +6 -0
- package/dist/telemetry/index.d.ts +6 -0
- package/dist/tools/selection/index.cjs +28 -10
- package/dist/tools/selection/index.mjs +28 -10
- package/package.json +1 -1
package/dist/expo/index.cjs
CHANGED
|
@@ -2884,6 +2884,35 @@ function decodeChunkVector(vector, onMalformed) {
|
|
|
2884
2884
|
}
|
|
2885
2885
|
}
|
|
2886
2886
|
|
|
2887
|
+
// src/lib/scheduling.ts
|
|
2888
|
+
function nowMs() {
|
|
2889
|
+
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
2890
|
+
}
|
|
2891
|
+
function yieldToEventLoop() {
|
|
2892
|
+
const scheduler = globalThis.scheduler;
|
|
2893
|
+
if (typeof scheduler?.yield === "function") return scheduler.yield();
|
|
2894
|
+
if (typeof MessageChannel === "function") {
|
|
2895
|
+
return new Promise((resolve) => {
|
|
2896
|
+
const channel = new MessageChannel();
|
|
2897
|
+
channel.port1.onmessage = () => {
|
|
2898
|
+
channel.port1.close();
|
|
2899
|
+
channel.port2.close();
|
|
2900
|
+
resolve();
|
|
2901
|
+
};
|
|
2902
|
+
channel.port2.postMessage(null);
|
|
2903
|
+
});
|
|
2904
|
+
}
|
|
2905
|
+
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
2906
|
+
}
|
|
2907
|
+
function createTimeSliceYielder(budgetMs) {
|
|
2908
|
+
let sliceStart = nowMs();
|
|
2909
|
+
return async () => {
|
|
2910
|
+
if (nowMs() - sliceStart < budgetMs) return;
|
|
2911
|
+
await yieldToEventLoop();
|
|
2912
|
+
sliceStart = nowMs();
|
|
2913
|
+
};
|
|
2914
|
+
}
|
|
2915
|
+
|
|
2887
2916
|
// src/lib/db/encryption-utils.ts
|
|
2888
2917
|
init_logger();
|
|
2889
2918
|
var ENCRYPTION_PREFIX = "enc:v3:";
|
|
@@ -4220,6 +4249,95 @@ async function readRawJsonField(raw, column, walletAddress) {
|
|
|
4220
4249
|
return void 0;
|
|
4221
4250
|
}
|
|
4222
4251
|
}
|
|
4252
|
+
var CHUNK_VECTOR_BATCH_SIZE = 50;
|
|
4253
|
+
var CHUNK_SCAN_YIELD_BUDGET_MS = 12;
|
|
4254
|
+
var hasEmbeddingSql = `(coalesce("chunks", '') != '' or coalesce("vector", '') != '')`;
|
|
4255
|
+
function toChunkCandidateKey(raw) {
|
|
4256
|
+
return {
|
|
4257
|
+
id: raw.id,
|
|
4258
|
+
conversationId: String(raw.conversation_id),
|
|
4259
|
+
version: Number(raw.updated_at) || 0,
|
|
4260
|
+
embeddingModel: raw.embedding_model ?? null
|
|
4261
|
+
};
|
|
4262
|
+
}
|
|
4263
|
+
async function fetchRowsByIds(ctx, ids) {
|
|
4264
|
+
if (ids.length === 0) return [];
|
|
4265
|
+
return await ctx.messagesCollection.query(import_watermelondb2.Q.where("id", import_watermelondb2.Q.oneOf(ids))).unsafeFetchRaw();
|
|
4266
|
+
}
|
|
4267
|
+
async function projectedChunkRowSource(ctx, filter) {
|
|
4268
|
+
const clauses = [
|
|
4269
|
+
`"history"."_status" is not 'deleted'`,
|
|
4270
|
+
hasEmbeddingSql,
|
|
4271
|
+
`exists (select 1 from "conversations" where "conversations"."conversation_id" = "history"."conversation_id" and "conversations"."is_deleted" = 0 and "conversations"."_status" is not 'deleted')`
|
|
4272
|
+
];
|
|
4273
|
+
const args = [];
|
|
4274
|
+
if (filter.conversationId !== void 0) {
|
|
4275
|
+
clauses.push(`"history"."conversation_id" = ?`);
|
|
4276
|
+
args.push(filter.conversationId);
|
|
4277
|
+
}
|
|
4278
|
+
if (filter.excludeConversationId !== void 0) {
|
|
4279
|
+
clauses.push(`"history"."conversation_id" != ?`);
|
|
4280
|
+
args.push(filter.excludeConversationId);
|
|
4281
|
+
}
|
|
4282
|
+
const keyRows = await ctx.messagesCollection.query(
|
|
4283
|
+
import_watermelondb2.Q.unsafeSqlQuery(
|
|
4284
|
+
`select "id", "conversation_id", "updated_at", "embedding_model" from "history" where ${clauses.join(" and ")}`,
|
|
4285
|
+
args
|
|
4286
|
+
)
|
|
4287
|
+
).unsafeFetchRaw();
|
|
4288
|
+
return {
|
|
4289
|
+
keys: keyRows.map(toChunkCandidateKey),
|
|
4290
|
+
loadVectorRows: async (ids) => {
|
|
4291
|
+
if (ids.length === 0) return [];
|
|
4292
|
+
return await ctx.messagesCollection.query(
|
|
4293
|
+
import_watermelondb2.Q.unsafeSqlQuery(
|
|
4294
|
+
`select "id", "updated_at", "chunks", "vector" from "history" where "_status" is not 'deleted' and "id" in (${ids.map(() => "?").join(",")})`,
|
|
4295
|
+
ids
|
|
4296
|
+
)
|
|
4297
|
+
).unsafeFetchRaw();
|
|
4298
|
+
},
|
|
4299
|
+
loadFullRows: (ids) => fetchRowsByIds(ctx, ids)
|
|
4300
|
+
};
|
|
4301
|
+
}
|
|
4302
|
+
async function fullScanChunkRowSource(ctx, filter) {
|
|
4303
|
+
const activeConversations = await ctx.conversationsCollection.query(import_watermelondb2.Q.where("is_deleted", false)).fetch();
|
|
4304
|
+
const activeConversationIds = new Set(
|
|
4305
|
+
activeConversations.map((c) => String(c._getRaw("conversation_id")))
|
|
4306
|
+
);
|
|
4307
|
+
const queryConditions = filter.conversationId !== void 0 ? [import_watermelondb2.Q.where("conversation_id", filter.conversationId)] : [];
|
|
4308
|
+
const rows = await ctx.messagesCollection.query(...queryConditions).unsafeFetchRaw();
|
|
4309
|
+
const rowsById = /* @__PURE__ */ new Map();
|
|
4310
|
+
for (const row of rows) {
|
|
4311
|
+
const conversationId = String(row.conversation_id);
|
|
4312
|
+
if (!activeConversationIds.has(conversationId)) continue;
|
|
4313
|
+
if (filter.excludeConversationId !== void 0 && conversationId === filter.excludeConversationId) {
|
|
4314
|
+
continue;
|
|
4315
|
+
}
|
|
4316
|
+
if (!row.chunks && !row.vector) continue;
|
|
4317
|
+
rowsById.set(row.id, row);
|
|
4318
|
+
}
|
|
4319
|
+
const pick = (ids) => Promise.resolve(
|
|
4320
|
+
ids.flatMap((id) => {
|
|
4321
|
+
const row = rowsById.get(id);
|
|
4322
|
+
return row ? [row] : [];
|
|
4323
|
+
})
|
|
4324
|
+
);
|
|
4325
|
+
return {
|
|
4326
|
+
keys: Array.from(rowsById.values(), toChunkCandidateKey),
|
|
4327
|
+
loadVectorRows: pick,
|
|
4328
|
+
loadFullRows: pick
|
|
4329
|
+
};
|
|
4330
|
+
}
|
|
4331
|
+
async function chunkRowSource(ctx, filter) {
|
|
4332
|
+
try {
|
|
4333
|
+
return await projectedChunkRowSource(ctx, filter);
|
|
4334
|
+
} catch (err) {
|
|
4335
|
+
getLogger().debug(
|
|
4336
|
+
"searchChunksOp: projected SQL unavailable, using full-load fallback: " + (err instanceof Error ? err.message : String(err))
|
|
4337
|
+
);
|
|
4338
|
+
return fullScanChunkRowSource(ctx, filter);
|
|
4339
|
+
}
|
|
4340
|
+
}
|
|
4223
4341
|
async function searchChunksOp(ctx, queryVector, options) {
|
|
4224
4342
|
const {
|
|
4225
4343
|
limit = 10,
|
|
@@ -4227,83 +4345,111 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
4227
4345
|
conversationId,
|
|
4228
4346
|
excludeConversationId,
|
|
4229
4347
|
embeddingModel,
|
|
4230
|
-
chunkCache
|
|
4348
|
+
chunkCache,
|
|
4349
|
+
onStats
|
|
4231
4350
|
} = options || {};
|
|
4232
|
-
const
|
|
4233
|
-
const
|
|
4234
|
-
activeConversations.map((c) => String(c._getRaw("conversation_id")))
|
|
4235
|
-
);
|
|
4236
|
-
const queryConditions = conversationId ? [import_watermelondb2.Q.where("conversation_id", conversationId)] : [];
|
|
4237
|
-
const messages = await ctx.messagesCollection.query(...queryConditions).unsafeFetchRaw();
|
|
4351
|
+
const source = await chunkRowSource(ctx, { conversationId, excludeConversationId });
|
|
4352
|
+
const yieldIfDue = createTimeSliceYielder(CHUNK_SCAN_YIELD_BUDGET_MS);
|
|
4238
4353
|
const candidates = [];
|
|
4239
4354
|
let staleSkipped = 0;
|
|
4240
4355
|
let unreadableVectors = 0;
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
}
|
|
4356
|
+
let cacheHits = 0;
|
|
4357
|
+
const missIds = [];
|
|
4358
|
+
const orderById = /* @__PURE__ */ new Map();
|
|
4359
|
+
for (const [order, key] of source.keys.entries()) {
|
|
4360
|
+
await yieldIfDue();
|
|
4361
|
+
orderById.set(key.id, order);
|
|
4362
|
+
if (embeddingModel && key.embeddingModel !== null && key.embeddingModel !== embeddingModel) {
|
|
4363
|
+
staleSkipped++;
|
|
4364
|
+
continue;
|
|
4251
4365
|
}
|
|
4252
|
-
const
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
if (cached.chunks.length > 0) {
|
|
4256
|
-
for (let ci = 0; ci < cached.chunks.length; ci++) {
|
|
4257
|
-
const vec = cached.chunks[ci];
|
|
4258
|
-
if (vec.length === 0) continue;
|
|
4259
|
-
const similarity = cosineSimilarity(queryVector, vec);
|
|
4260
|
-
if (similarity >= minSimilarity) {
|
|
4261
|
-
candidates.push({
|
|
4262
|
-
message,
|
|
4263
|
-
similarity,
|
|
4264
|
-
chunkTextSource: { kind: "chunk-cached", chunkIndex: ci, version }
|
|
4265
|
-
});
|
|
4266
|
-
}
|
|
4267
|
-
}
|
|
4268
|
-
} else if (cached.fallback) {
|
|
4269
|
-
const similarity = cosineSimilarity(queryVector, cached.fallback);
|
|
4270
|
-
if (similarity >= minSimilarity) {
|
|
4271
|
-
candidates.push({ message, similarity, chunkTextSource: { kind: "message" } });
|
|
4272
|
-
}
|
|
4273
|
-
}
|
|
4366
|
+
const cached = chunkCache?.get(key.id);
|
|
4367
|
+
if (!cached || cached.version !== key.version) {
|
|
4368
|
+
missIds.push(key.id);
|
|
4274
4369
|
continue;
|
|
4275
4370
|
}
|
|
4276
|
-
|
|
4277
|
-
if (
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
unreadableVectors++;
|
|
4281
|
-
})
|
|
4282
|
-
);
|
|
4283
|
-
chunkCache?.set(message.id, { version, chunks: vectors });
|
|
4284
|
-
for (let ci = 0; ci < chunks3.length; ci++) {
|
|
4285
|
-
const vec = vectors[ci];
|
|
4371
|
+
cacheHits++;
|
|
4372
|
+
if (cached.chunks.length > 0) {
|
|
4373
|
+
for (let ci = 0; ci < cached.chunks.length; ci++) {
|
|
4374
|
+
const vec = cached.chunks[ci];
|
|
4286
4375
|
if (vec.length === 0) continue;
|
|
4287
4376
|
const similarity = cosineSimilarity(queryVector, vec);
|
|
4288
4377
|
if (similarity >= minSimilarity) {
|
|
4289
4378
|
candidates.push({
|
|
4290
|
-
|
|
4379
|
+
id: key.id,
|
|
4380
|
+
version: key.version,
|
|
4381
|
+
order,
|
|
4291
4382
|
similarity,
|
|
4292
|
-
chunkTextSource: { kind: "chunk",
|
|
4383
|
+
chunkTextSource: { kind: "chunk-cached", chunkIndex: ci, version: key.version }
|
|
4293
4384
|
});
|
|
4294
4385
|
}
|
|
4295
4386
|
}
|
|
4296
|
-
} else {
|
|
4297
|
-
const
|
|
4298
|
-
if (!messageVector || messageVector.length === 0) continue;
|
|
4299
|
-
const fallback = Float32Array.from(messageVector);
|
|
4300
|
-
chunkCache?.set(message.id, { version, chunks: [], fallback });
|
|
4301
|
-
const similarity = cosineSimilarity(queryVector, fallback);
|
|
4387
|
+
} else if (cached.fallback) {
|
|
4388
|
+
const similarity = cosineSimilarity(queryVector, cached.fallback);
|
|
4302
4389
|
if (similarity >= minSimilarity) {
|
|
4303
|
-
candidates.push({
|
|
4390
|
+
candidates.push({
|
|
4391
|
+
id: key.id,
|
|
4392
|
+
version: key.version,
|
|
4393
|
+
order,
|
|
4394
|
+
similarity,
|
|
4395
|
+
chunkTextSource: { kind: "message" }
|
|
4396
|
+
});
|
|
4397
|
+
}
|
|
4398
|
+
}
|
|
4399
|
+
}
|
|
4400
|
+
let rowsFetched = 0;
|
|
4401
|
+
for (let offset = 0; offset < missIds.length; offset += CHUNK_VECTOR_BATCH_SIZE) {
|
|
4402
|
+
const rows = await source.loadVectorRows(
|
|
4403
|
+
missIds.slice(offset, offset + CHUNK_VECTOR_BATCH_SIZE)
|
|
4404
|
+
);
|
|
4405
|
+
rowsFetched += rows.length;
|
|
4406
|
+
for (const row of rows) {
|
|
4407
|
+
await yieldIfDue();
|
|
4408
|
+
const id = row.id;
|
|
4409
|
+
const version = Number(row.updated_at) || 0;
|
|
4410
|
+
const order = orderById.get(id) ?? Number.MAX_SAFE_INTEGER;
|
|
4411
|
+
const chunks3 = await readRawJsonField(row, "chunks", ctx.walletAddress);
|
|
4412
|
+
if (chunks3 && chunks3.length > 0) {
|
|
4413
|
+
const vectors = chunks3.map(
|
|
4414
|
+
(chunk) => decodeChunkVector(chunk.vector, () => {
|
|
4415
|
+
unreadableVectors++;
|
|
4416
|
+
})
|
|
4417
|
+
);
|
|
4418
|
+
chunkCache?.set(id, { version, chunks: vectors });
|
|
4419
|
+
for (let ci = 0; ci < chunks3.length; ci++) {
|
|
4420
|
+
const vec = vectors[ci];
|
|
4421
|
+
if (vec.length === 0) continue;
|
|
4422
|
+
const similarity = cosineSimilarity(queryVector, vec);
|
|
4423
|
+
if (similarity >= minSimilarity) {
|
|
4424
|
+
candidates.push({
|
|
4425
|
+
id,
|
|
4426
|
+
version,
|
|
4427
|
+
order,
|
|
4428
|
+
similarity,
|
|
4429
|
+
chunkTextSource: { kind: "chunk", chunk: chunks3[ci], siblings: chunks3 }
|
|
4430
|
+
});
|
|
4431
|
+
}
|
|
4432
|
+
}
|
|
4433
|
+
} else {
|
|
4434
|
+
const messageVector = await readRawJsonField(row, "vector", ctx.walletAddress);
|
|
4435
|
+
if (messageVector && messageVector.length > 0) {
|
|
4436
|
+
const fallback = Float32Array.from(messageVector);
|
|
4437
|
+
chunkCache?.set(id, { version, chunks: [], fallback });
|
|
4438
|
+
const similarity = cosineSimilarity(queryVector, fallback);
|
|
4439
|
+
if (similarity >= minSimilarity) {
|
|
4440
|
+
candidates.push({
|
|
4441
|
+
id,
|
|
4442
|
+
version,
|
|
4443
|
+
order,
|
|
4444
|
+
similarity,
|
|
4445
|
+
chunkTextSource: { kind: "message" }
|
|
4446
|
+
});
|
|
4447
|
+
}
|
|
4448
|
+
}
|
|
4304
4449
|
}
|
|
4305
4450
|
}
|
|
4306
4451
|
}
|
|
4452
|
+
onStats?.({ rowsScanned: source.keys.length, rowsFetched, cacheHits });
|
|
4307
4453
|
if (staleSkipped > 0) {
|
|
4308
4454
|
getLogger().warn(
|
|
4309
4455
|
`searchChunksOp: skipped ${staleSkipped} messages whose embedding model differs from the current model (${embeddingModel}) \u2014 re-embed via chunkAndEmbedAllMessages`
|
|
@@ -4314,12 +4460,17 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
4314
4460
|
`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`
|
|
4315
4461
|
);
|
|
4316
4462
|
}
|
|
4317
|
-
const topK = candidates.sort((a, b) => b.similarity - a.similarity).slice(0, limit);
|
|
4318
|
-
const
|
|
4319
|
-
|
|
4463
|
+
const topK = candidates.sort((a, b) => b.similarity - a.similarity || a.order - b.order).slice(0, limit);
|
|
4464
|
+
const topIds = Array.from(new Set(topK.map((c) => c.id)));
|
|
4465
|
+
const fullRows = await source.loadFullRows(topIds);
|
|
4466
|
+
const rowById = new Map(fullRows.map((row) => [row.id, row]));
|
|
4467
|
+
const liveTopK = topK.filter((c) => {
|
|
4468
|
+
const row = rowById.get(c.id);
|
|
4469
|
+
return row !== void 0 && (Number(row.updated_at) || 0) === c.version;
|
|
4470
|
+
});
|
|
4320
4471
|
const storedById = new Map(
|
|
4321
4472
|
await Promise.all(
|
|
4322
|
-
Array.from(
|
|
4473
|
+
Array.from(rowById, async ([id, m]) => {
|
|
4323
4474
|
const stored2 = await messageRawToStored(
|
|
4324
4475
|
m,
|
|
4325
4476
|
ctx.walletAddress,
|
|
@@ -4332,24 +4483,24 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
4332
4483
|
);
|
|
4333
4484
|
const chunkStateByMsgId = /* @__PURE__ */ new Map();
|
|
4334
4485
|
const needsChunkText = /* @__PURE__ */ new Set();
|
|
4335
|
-
for (const c of
|
|
4336
|
-
if (c.chunkTextSource.kind === "chunk-cached") needsChunkText.add(c.
|
|
4486
|
+
for (const c of liveTopK) {
|
|
4487
|
+
if (c.chunkTextSource.kind === "chunk-cached") needsChunkText.add(c.id);
|
|
4337
4488
|
}
|
|
4338
4489
|
await Promise.all(
|
|
4339
4490
|
Array.from(needsChunkText, async (id) => {
|
|
4340
|
-
const m =
|
|
4491
|
+
const m = rowById.get(id);
|
|
4341
4492
|
const parsed = await readRawJsonField(m, "chunks", ctx.walletAddress);
|
|
4342
4493
|
const version = Number(m.updated_at) || 0;
|
|
4343
4494
|
if (parsed) chunkStateByMsgId.set(id, { version, chunks: parsed });
|
|
4344
4495
|
})
|
|
4345
4496
|
);
|
|
4346
|
-
return
|
|
4347
|
-
const stored2 = { ...storedById.get(
|
|
4497
|
+
return liveTopK.map(({ id, similarity, chunkTextSource }) => {
|
|
4498
|
+
const stored2 = { ...storedById.get(id) };
|
|
4348
4499
|
let chunkText2;
|
|
4349
4500
|
if (chunkTextSource.kind === "chunk") {
|
|
4350
4501
|
chunkText2 = resolveChunkText(stored2.content, chunkTextSource.chunk, chunkTextSource.siblings);
|
|
4351
4502
|
} else if (chunkTextSource.kind === "chunk-cached") {
|
|
4352
|
-
const state = chunkStateByMsgId.get(
|
|
4503
|
+
const state = chunkStateByMsgId.get(id);
|
|
4353
4504
|
const chunk = state && state.version === chunkTextSource.version ? state.chunks[chunkTextSource.chunkIndex] : void 0;
|
|
4354
4505
|
chunkText2 = resolveChunkText(stored2.content, chunk, state?.chunks);
|
|
4355
4506
|
} else {
|
|
@@ -5434,13 +5585,35 @@ async function generateEmbedding(text14, options) {
|
|
|
5434
5585
|
if (total === void 0) return embedOne(text14, options, void 0);
|
|
5435
5586
|
return withDeadline((signal) => embedOne(text14, options, signal), total, "embedding");
|
|
5436
5587
|
}
|
|
5588
|
+
var inFlightByCache = /* @__PURE__ */ new WeakMap();
|
|
5437
5589
|
async function embedOne(text14, options, outer) {
|
|
5438
|
-
const {
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5590
|
+
const { cache } = options;
|
|
5591
|
+
if (!cache) return Array.from(await requestEmbedding(text14, options, outer));
|
|
5592
|
+
const cached = cache.get(text14);
|
|
5593
|
+
if (cached) return Array.from(cached);
|
|
5594
|
+
const inFlight = inFlightByCache.get(cache) ?? /* @__PURE__ */ new Map();
|
|
5595
|
+
inFlightByCache.set(cache, inFlight);
|
|
5596
|
+
const pending = inFlight.get(text14);
|
|
5597
|
+
if (pending) {
|
|
5598
|
+
try {
|
|
5599
|
+
return Array.from(await pending);
|
|
5600
|
+
} catch (err) {
|
|
5601
|
+
if (outer?.aborted) throw err;
|
|
5602
|
+
}
|
|
5443
5603
|
}
|
|
5604
|
+
const request = requestEmbedding(text14, options, outer);
|
|
5605
|
+
inFlight.set(text14, request);
|
|
5606
|
+
try {
|
|
5607
|
+
const embedding2 = await request;
|
|
5608
|
+
cache.set(text14, embedding2);
|
|
5609
|
+
return Array.from(embedding2);
|
|
5610
|
+
} finally {
|
|
5611
|
+
if (inFlight.get(text14) === request) inFlight.delete(text14);
|
|
5612
|
+
}
|
|
5613
|
+
}
|
|
5614
|
+
async function requestEmbedding(text14, options, outer) {
|
|
5615
|
+
const { baseUrl = BASE_URL, model } = options;
|
|
5616
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_EMBEDDING_REQUEST_TIMEOUT_MS;
|
|
5444
5617
|
const headers = {
|
|
5445
5618
|
...await resolveAuthHeaders(options, outer),
|
|
5446
5619
|
...taskTypeHeader(options.taskType)
|
|
@@ -5475,11 +5648,7 @@ async function embedOne(text14, options, outer) {
|
|
|
5475
5648
|
totalTokens: response.data.usage.total_tokens ?? 0
|
|
5476
5649
|
});
|
|
5477
5650
|
}
|
|
5478
|
-
|
|
5479
|
-
if (cache) {
|
|
5480
|
-
cache.set(text14, f32Embedding);
|
|
5481
|
-
}
|
|
5482
|
-
return Array.from(f32Embedding);
|
|
5651
|
+
return Float32Array.from(embedding2);
|
|
5483
5652
|
}
|
|
5484
5653
|
var DEFAULT_EMBEDDING_BATCH_SIZE = 100;
|
|
5485
5654
|
var DEFAULT_EMBEDDING_BATCH_CONCURRENCY = 3;
|
|
@@ -10975,8 +11144,12 @@ var MaskScopedEmbeddingCache = class extends Map {
|
|
|
10975
11144
|
return this;
|
|
10976
11145
|
}
|
|
10977
11146
|
};
|
|
11147
|
+
var scopedViews = /* @__PURE__ */ new WeakMap();
|
|
10978
11148
|
function maskScopedEmbeddingCache(cache, masked) {
|
|
10979
|
-
|
|
11149
|
+
const views = scopedViews.get(cache) ?? {};
|
|
11150
|
+
scopedViews.set(cache, views);
|
|
11151
|
+
const slot = masked ? "masked" : "raw";
|
|
11152
|
+
return views[slot] ?? (views[slot] = new MaskScopedEmbeddingCache(cache, masked));
|
|
10980
11153
|
}
|
|
10981
11154
|
|
|
10982
11155
|
// src/lib/db/conversationMemory/models.ts
|
|
@@ -15337,9 +15510,9 @@ function recencyMultiplier(updatedAt, opts = {}) {
|
|
|
15337
15510
|
const updatedMs = updatedAt.getTime();
|
|
15338
15511
|
if (!Number.isFinite(updatedMs)) return noDate;
|
|
15339
15512
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
15340
|
-
const
|
|
15341
|
-
if (!Number.isFinite(
|
|
15342
|
-
const ageDays2 = Math.max(0, (
|
|
15513
|
+
const nowMs2 = now.getTime();
|
|
15514
|
+
if (!Number.isFinite(nowMs2)) return noDate;
|
|
15515
|
+
const ageDays2 = Math.max(0, (nowMs2 - updatedMs) / DAY_MS2);
|
|
15343
15516
|
const perYearDecay = opts.perYearDecay ?? DEFAULT_PER_YEAR_DECAY;
|
|
15344
15517
|
const floor = opts.floor ?? DEFAULT_FLOOR;
|
|
15345
15518
|
const decay = perYearDecay * (ageDays2 / 365);
|
|
@@ -15851,9 +16024,6 @@ function createVaultEmbeddingCache(maxSize = DEFAULT_VAULT_CACHE_SIZE) {
|
|
|
15851
16024
|
|
|
15852
16025
|
// src/lib/memoryVault/searchTool.ts
|
|
15853
16026
|
var DEFAULT_RERANK_TOP_N = 5;
|
|
15854
|
-
function nowMs() {
|
|
15855
|
-
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
15856
|
-
}
|
|
15857
16027
|
var warnedProgrammaticDecomposeIgnored = false;
|
|
15858
16028
|
function normalizeEventTimeKind(kind) {
|
|
15859
16029
|
return kind === "point" || kind === "range" || kind === "ongoing" ? kind : null;
|
|
@@ -18965,9 +19135,6 @@ function scoreEventTimeOverlap(memoryStart, memoryEnd, memoryKind, window2) {
|
|
|
18965
19135
|
var DEFAULT_LIMIT = 8;
|
|
18966
19136
|
var DEFAULT_BUDGET = "low";
|
|
18967
19137
|
var DEFAULT_FACT_MIN_SCORE = 0.1;
|
|
18968
|
-
function nowMs2() {
|
|
18969
|
-
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
18970
|
-
}
|
|
18971
19138
|
var DEFAULT_CHUNK_MIN_SCORE = 0.5;
|
|
18972
19139
|
var DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS = 8e3;
|
|
18973
19140
|
function flagsForBudget(budget) {
|
|
@@ -19005,12 +19172,19 @@ async function recall(query, ctx, options = {}) {
|
|
|
19005
19172
|
const subQueries = normalizedFacets.length >= 2 ? normalizedFacets : void 0;
|
|
19006
19173
|
const embeddingOptions = {
|
|
19007
19174
|
...ctx.embeddingOptions,
|
|
19008
|
-
taskType: "memory_recall_embed"
|
|
19175
|
+
taskType: "memory_recall_embed",
|
|
19176
|
+
...options.embeddingCache && !ctx.embeddingOptions.cache && {
|
|
19177
|
+
cache: maskScopedEmbeddingCache(
|
|
19178
|
+
options.embeddingCache,
|
|
19179
|
+
Boolean(ctx.embeddingOptions.maskInput)
|
|
19180
|
+
)
|
|
19181
|
+
}
|
|
19009
19182
|
};
|
|
19010
|
-
const t0 =
|
|
19183
|
+
const t0 = nowMs();
|
|
19011
19184
|
let prepMs = 0;
|
|
19012
19185
|
let factLaneMs = 0;
|
|
19013
19186
|
let chunkLaneMs = 0;
|
|
19187
|
+
let chunkStats;
|
|
19014
19188
|
let fuseMs = 0;
|
|
19015
19189
|
const factResults = [];
|
|
19016
19190
|
const chunkResults = [];
|
|
@@ -19065,6 +19239,11 @@ async function recall(query, ctx, options = {}) {
|
|
|
19065
19239
|
...decryptLastRan !== void 0 && { decryptLast: decryptLastRan },
|
|
19066
19240
|
...vaultRowsDecrypted !== void 0 && { vaultRowsDecrypted },
|
|
19067
19241
|
...vaultRowsEmbedded !== void 0 && { vaultRowsEmbedded },
|
|
19242
|
+
...chunkStats && {
|
|
19243
|
+
chunkRowsScanned: chunkStats.rowsScanned,
|
|
19244
|
+
chunkRowsFetched: chunkStats.rowsFetched,
|
|
19245
|
+
chunkCacheHits: chunkStats.cacheHits
|
|
19246
|
+
},
|
|
19068
19247
|
factCount: factResults.length,
|
|
19069
19248
|
chunkCount: chunkResults.length,
|
|
19070
19249
|
admittedCount: admitted.length,
|
|
@@ -19076,7 +19255,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
19076
19255
|
temporalLaneCount,
|
|
19077
19256
|
emptyReason: emptyReasonFor(admitted.length, laneRan),
|
|
19078
19257
|
timings: {
|
|
19079
|
-
total:
|
|
19258
|
+
total: nowMs() - t0,
|
|
19080
19259
|
prep: prepMs,
|
|
19081
19260
|
factLane: factLaneMs,
|
|
19082
19261
|
rerank: rerankMs,
|
|
@@ -19098,14 +19277,14 @@ async function recall(query, ctx, options = {}) {
|
|
|
19098
19277
|
const needsChunkEmbedding = types.includes("chunk") && ctx.storageCtx;
|
|
19099
19278
|
const wantsTemporal = types.includes("fact") && (ctx.factSource || ctx.vaultCtx);
|
|
19100
19279
|
const queryEmbedTotalTimeoutMs = options.queryEmbedTotalTimeoutMs ?? DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS;
|
|
19101
|
-
const prepStart =
|
|
19280
|
+
const prepStart = nowMs();
|
|
19102
19281
|
let sharedEmbedMs = 0;
|
|
19103
19282
|
const [queryEmbedding, entityRanking, temporalRanking] = await Promise.all([
|
|
19104
19283
|
needsChunkEmbedding ? generateEmbedding(query, {
|
|
19105
19284
|
...embeddingOptions,
|
|
19106
19285
|
totalTimeoutMs: queryEmbedTotalTimeoutMs
|
|
19107
19286
|
}).finally(() => {
|
|
19108
|
-
sharedEmbedMs =
|
|
19287
|
+
sharedEmbedMs = nowMs() - prepStart;
|
|
19109
19288
|
}).then((vec) => {
|
|
19110
19289
|
if (vec.length === 0) {
|
|
19111
19290
|
getLogger().warn(
|
|
@@ -19138,11 +19317,11 @@ async function recall(query, ctx, options = {}) {
|
|
|
19138
19317
|
() => ctx.factSource ? ctx.factSource.temporalRanking(query, options.now) : buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)
|
|
19139
19318
|
) : Promise.resolve([])
|
|
19140
19319
|
]);
|
|
19141
|
-
prepMs =
|
|
19320
|
+
prepMs = nowMs() - prepStart;
|
|
19142
19321
|
graphLaneCount = entityRanking.length;
|
|
19143
19322
|
temporalLaneCount = temporalRanking.length;
|
|
19144
19323
|
if (types.includes("fact") && (ctx.factSource || ctx.vaultCtx && ctx.vaultCache)) {
|
|
19145
|
-
const factStart =
|
|
19324
|
+
const factStart = nowMs();
|
|
19146
19325
|
const vaultMinScore = options.minScore ?? DEFAULT_FACT_MIN_SCORE;
|
|
19147
19326
|
factFloor = vaultMinScore;
|
|
19148
19327
|
const {
|
|
@@ -19218,11 +19397,11 @@ async function recall(query, ctx, options = {}) {
|
|
|
19218
19397
|
factLaneRankedOnCosine = factRankedOnCosine;
|
|
19219
19398
|
decryptLastRan = factDecryptLast;
|
|
19220
19399
|
vaultRowsDecrypted = factRowsDecrypted;
|
|
19221
|
-
factLaneMs =
|
|
19400
|
+
factLaneMs = nowMs() - factStart;
|
|
19222
19401
|
}
|
|
19223
19402
|
if (chunkEmbedFailed && !factLaneRankedOnCosine) embeddingsUnavailable = true;
|
|
19224
19403
|
if (types.includes("chunk") && ctx.storageCtx && queryEmbedding) {
|
|
19225
|
-
const chunkStart =
|
|
19404
|
+
const chunkStart = nowMs();
|
|
19226
19405
|
const chunkMinScore = options.minScore ?? DEFAULT_CHUNK_MIN_SCORE;
|
|
19227
19406
|
chunkFloor = chunkMinScore;
|
|
19228
19407
|
const results = await searchChunksOp(ctx.storageCtx, queryEmbedding, {
|
|
@@ -19233,12 +19412,15 @@ async function recall(query, ctx, options = {}) {
|
|
|
19233
19412
|
...options.excludeConversationId && {
|
|
19234
19413
|
excludeConversationId: options.excludeConversationId
|
|
19235
19414
|
},
|
|
19236
|
-
...ctx.chunkCache && { chunkCache: ctx.chunkCache }
|
|
19415
|
+
...ctx.chunkCache && { chunkCache: ctx.chunkCache },
|
|
19416
|
+
onStats: (stats) => {
|
|
19417
|
+
chunkStats = stats;
|
|
19418
|
+
}
|
|
19237
19419
|
});
|
|
19238
19420
|
chunkResults.push(...dedupeBy(results, (r) => r.chunkText.trim()));
|
|
19239
|
-
chunkLaneMs =
|
|
19421
|
+
chunkLaneMs = nowMs() - chunkStart;
|
|
19240
19422
|
}
|
|
19241
|
-
const fuseStart =
|
|
19423
|
+
const fuseStart = nowMs();
|
|
19242
19424
|
if (types.length === 1 || factResults.length === 0 || chunkResults.length === 0) {
|
|
19243
19425
|
const memories2 = [
|
|
19244
19426
|
...factResults.map((r) => toFactMemory(r, options.now)),
|
|
@@ -19246,7 +19428,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
19246
19428
|
];
|
|
19247
19429
|
memories2.sort((a, b) => b.score - a.score);
|
|
19248
19430
|
const candidateCount = factResults.length + chunkResults.length;
|
|
19249
|
-
fuseMs =
|
|
19431
|
+
fuseMs = nowMs() - fuseStart;
|
|
19250
19432
|
const admitted = memories2.slice(0, limit);
|
|
19251
19433
|
hitLimit = memories2.length > limit;
|
|
19252
19434
|
emitDiagnostics(candidateCount, admitted);
|
|
@@ -19310,7 +19492,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
19310
19492
|
memories = selection.out;
|
|
19311
19493
|
}
|
|
19312
19494
|
hitLimit = selection.cut;
|
|
19313
|
-
fuseMs =
|
|
19495
|
+
fuseMs = nowMs() - fuseStart;
|
|
19314
19496
|
emitDiagnostics(byId.size, memories);
|
|
19315
19497
|
return {
|
|
19316
19498
|
memories,
|