@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/react/index.mjs
CHANGED
|
@@ -1813,6 +1813,35 @@ function decodeChunkVector(vector, onMalformed) {
|
|
|
1813
1813
|
}
|
|
1814
1814
|
}
|
|
1815
1815
|
|
|
1816
|
+
// src/lib/scheduling.ts
|
|
1817
|
+
function nowMs() {
|
|
1818
|
+
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
1819
|
+
}
|
|
1820
|
+
function yieldToEventLoop() {
|
|
1821
|
+
const scheduler = globalThis.scheduler;
|
|
1822
|
+
if (typeof scheduler?.yield === "function") return scheduler.yield();
|
|
1823
|
+
if (typeof MessageChannel === "function") {
|
|
1824
|
+
return new Promise((resolve) => {
|
|
1825
|
+
const channel = new MessageChannel();
|
|
1826
|
+
channel.port1.onmessage = () => {
|
|
1827
|
+
channel.port1.close();
|
|
1828
|
+
channel.port2.close();
|
|
1829
|
+
resolve();
|
|
1830
|
+
};
|
|
1831
|
+
channel.port2.postMessage(null);
|
|
1832
|
+
});
|
|
1833
|
+
}
|
|
1834
|
+
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
1835
|
+
}
|
|
1836
|
+
function createTimeSliceYielder(budgetMs) {
|
|
1837
|
+
let sliceStart = nowMs();
|
|
1838
|
+
return async () => {
|
|
1839
|
+
if (nowMs() - sliceStart < budgetMs) return;
|
|
1840
|
+
await yieldToEventLoop();
|
|
1841
|
+
sliceStart = nowMs();
|
|
1842
|
+
};
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1816
1845
|
// src/lib/db/encryption-utils.ts
|
|
1817
1846
|
var ENCRYPTION_PREFIX = "enc:v3:";
|
|
1818
1847
|
function isEncrypted(value) {
|
|
@@ -3193,6 +3222,95 @@ async function searchMessagesOp(ctx, queryVector, options) {
|
|
|
3193
3222
|
})
|
|
3194
3223
|
);
|
|
3195
3224
|
}
|
|
3225
|
+
var CHUNK_VECTOR_BATCH_SIZE = 50;
|
|
3226
|
+
var CHUNK_SCAN_YIELD_BUDGET_MS = 12;
|
|
3227
|
+
var hasEmbeddingSql = `(coalesce("chunks", '') != '' or coalesce("vector", '') != '')`;
|
|
3228
|
+
function toChunkCandidateKey(raw) {
|
|
3229
|
+
return {
|
|
3230
|
+
id: raw.id,
|
|
3231
|
+
conversationId: String(raw.conversation_id),
|
|
3232
|
+
version: Number(raw.updated_at) || 0,
|
|
3233
|
+
embeddingModel: raw.embedding_model ?? null
|
|
3234
|
+
};
|
|
3235
|
+
}
|
|
3236
|
+
async function fetchRowsByIds(ctx, ids) {
|
|
3237
|
+
if (ids.length === 0) return [];
|
|
3238
|
+
return await ctx.messagesCollection.query(Q.where("id", Q.oneOf(ids))).unsafeFetchRaw();
|
|
3239
|
+
}
|
|
3240
|
+
async function projectedChunkRowSource(ctx, filter) {
|
|
3241
|
+
const clauses = [
|
|
3242
|
+
`"history"."_status" is not 'deleted'`,
|
|
3243
|
+
hasEmbeddingSql,
|
|
3244
|
+
`exists (select 1 from "conversations" where "conversations"."conversation_id" = "history"."conversation_id" and "conversations"."is_deleted" = 0 and "conversations"."_status" is not 'deleted')`
|
|
3245
|
+
];
|
|
3246
|
+
const args = [];
|
|
3247
|
+
if (filter.conversationId !== void 0) {
|
|
3248
|
+
clauses.push(`"history"."conversation_id" = ?`);
|
|
3249
|
+
args.push(filter.conversationId);
|
|
3250
|
+
}
|
|
3251
|
+
if (filter.excludeConversationId !== void 0) {
|
|
3252
|
+
clauses.push(`"history"."conversation_id" != ?`);
|
|
3253
|
+
args.push(filter.excludeConversationId);
|
|
3254
|
+
}
|
|
3255
|
+
const keyRows = await ctx.messagesCollection.query(
|
|
3256
|
+
Q.unsafeSqlQuery(
|
|
3257
|
+
`select "id", "conversation_id", "updated_at", "embedding_model" from "history" where ${clauses.join(" and ")}`,
|
|
3258
|
+
args
|
|
3259
|
+
)
|
|
3260
|
+
).unsafeFetchRaw();
|
|
3261
|
+
return {
|
|
3262
|
+
keys: keyRows.map(toChunkCandidateKey),
|
|
3263
|
+
loadVectorRows: async (ids) => {
|
|
3264
|
+
if (ids.length === 0) return [];
|
|
3265
|
+
return await ctx.messagesCollection.query(
|
|
3266
|
+
Q.unsafeSqlQuery(
|
|
3267
|
+
`select "id", "updated_at", "chunks", "vector" from "history" where "_status" is not 'deleted' and "id" in (${ids.map(() => "?").join(",")})`,
|
|
3268
|
+
ids
|
|
3269
|
+
)
|
|
3270
|
+
).unsafeFetchRaw();
|
|
3271
|
+
},
|
|
3272
|
+
loadFullRows: (ids) => fetchRowsByIds(ctx, ids)
|
|
3273
|
+
};
|
|
3274
|
+
}
|
|
3275
|
+
async function fullScanChunkRowSource(ctx, filter) {
|
|
3276
|
+
const activeConversations = await ctx.conversationsCollection.query(Q.where("is_deleted", false)).fetch();
|
|
3277
|
+
const activeConversationIds = new Set(
|
|
3278
|
+
activeConversations.map((c) => String(c._getRaw("conversation_id")))
|
|
3279
|
+
);
|
|
3280
|
+
const queryConditions = filter.conversationId !== void 0 ? [Q.where("conversation_id", filter.conversationId)] : [];
|
|
3281
|
+
const rows = await ctx.messagesCollection.query(...queryConditions).unsafeFetchRaw();
|
|
3282
|
+
const rowsById = /* @__PURE__ */ new Map();
|
|
3283
|
+
for (const row of rows) {
|
|
3284
|
+
const conversationId = String(row.conversation_id);
|
|
3285
|
+
if (!activeConversationIds.has(conversationId)) continue;
|
|
3286
|
+
if (filter.excludeConversationId !== void 0 && conversationId === filter.excludeConversationId) {
|
|
3287
|
+
continue;
|
|
3288
|
+
}
|
|
3289
|
+
if (!row.chunks && !row.vector) continue;
|
|
3290
|
+
rowsById.set(row.id, row);
|
|
3291
|
+
}
|
|
3292
|
+
const pick = (ids) => Promise.resolve(
|
|
3293
|
+
ids.flatMap((id) => {
|
|
3294
|
+
const row = rowsById.get(id);
|
|
3295
|
+
return row ? [row] : [];
|
|
3296
|
+
})
|
|
3297
|
+
);
|
|
3298
|
+
return {
|
|
3299
|
+
keys: Array.from(rowsById.values(), toChunkCandidateKey),
|
|
3300
|
+
loadVectorRows: pick,
|
|
3301
|
+
loadFullRows: pick
|
|
3302
|
+
};
|
|
3303
|
+
}
|
|
3304
|
+
async function chunkRowSource(ctx, filter) {
|
|
3305
|
+
try {
|
|
3306
|
+
return await projectedChunkRowSource(ctx, filter);
|
|
3307
|
+
} catch (err) {
|
|
3308
|
+
getLogger().debug(
|
|
3309
|
+
"searchChunksOp: projected SQL unavailable, using full-load fallback: " + (err instanceof Error ? err.message : String(err))
|
|
3310
|
+
);
|
|
3311
|
+
return fullScanChunkRowSource(ctx, filter);
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3196
3314
|
async function searchChunksOp(ctx, queryVector, options) {
|
|
3197
3315
|
const {
|
|
3198
3316
|
limit = 10,
|
|
@@ -3200,83 +3318,111 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
3200
3318
|
conversationId,
|
|
3201
3319
|
excludeConversationId,
|
|
3202
3320
|
embeddingModel,
|
|
3203
|
-
chunkCache
|
|
3321
|
+
chunkCache,
|
|
3322
|
+
onStats
|
|
3204
3323
|
} = options || {};
|
|
3205
|
-
const
|
|
3206
|
-
const
|
|
3207
|
-
activeConversations.map((c) => String(c._getRaw("conversation_id")))
|
|
3208
|
-
);
|
|
3209
|
-
const queryConditions = conversationId ? [Q.where("conversation_id", conversationId)] : [];
|
|
3210
|
-
const messages = await ctx.messagesCollection.query(...queryConditions).unsafeFetchRaw();
|
|
3324
|
+
const source = await chunkRowSource(ctx, { conversationId, excludeConversationId });
|
|
3325
|
+
const yieldIfDue = createTimeSliceYielder(CHUNK_SCAN_YIELD_BUDGET_MS);
|
|
3211
3326
|
const candidates = [];
|
|
3212
3327
|
let staleSkipped = 0;
|
|
3213
3328
|
let unreadableVectors = 0;
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
}
|
|
3329
|
+
let cacheHits = 0;
|
|
3330
|
+
const missIds = [];
|
|
3331
|
+
const orderById = /* @__PURE__ */ new Map();
|
|
3332
|
+
for (const [order, key] of source.keys.entries()) {
|
|
3333
|
+
await yieldIfDue();
|
|
3334
|
+
orderById.set(key.id, order);
|
|
3335
|
+
if (embeddingModel && key.embeddingModel !== null && key.embeddingModel !== embeddingModel) {
|
|
3336
|
+
staleSkipped++;
|
|
3337
|
+
continue;
|
|
3224
3338
|
}
|
|
3225
|
-
const
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
if (cached.chunks.length > 0) {
|
|
3229
|
-
for (let ci = 0; ci < cached.chunks.length; ci++) {
|
|
3230
|
-
const vec = cached.chunks[ci];
|
|
3231
|
-
if (vec.length === 0) continue;
|
|
3232
|
-
const similarity = cosineSimilarity(queryVector, vec);
|
|
3233
|
-
if (similarity >= minSimilarity) {
|
|
3234
|
-
candidates.push({
|
|
3235
|
-
message,
|
|
3236
|
-
similarity,
|
|
3237
|
-
chunkTextSource: { kind: "chunk-cached", chunkIndex: ci, version }
|
|
3238
|
-
});
|
|
3239
|
-
}
|
|
3240
|
-
}
|
|
3241
|
-
} else if (cached.fallback) {
|
|
3242
|
-
const similarity = cosineSimilarity(queryVector, cached.fallback);
|
|
3243
|
-
if (similarity >= minSimilarity) {
|
|
3244
|
-
candidates.push({ message, similarity, chunkTextSource: { kind: "message" } });
|
|
3245
|
-
}
|
|
3246
|
-
}
|
|
3339
|
+
const cached = chunkCache?.get(key.id);
|
|
3340
|
+
if (!cached || cached.version !== key.version) {
|
|
3341
|
+
missIds.push(key.id);
|
|
3247
3342
|
continue;
|
|
3248
3343
|
}
|
|
3249
|
-
|
|
3250
|
-
if (
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
unreadableVectors++;
|
|
3254
|
-
})
|
|
3255
|
-
);
|
|
3256
|
-
chunkCache?.set(message.id, { version, chunks: vectors });
|
|
3257
|
-
for (let ci = 0; ci < chunks3.length; ci++) {
|
|
3258
|
-
const vec = vectors[ci];
|
|
3344
|
+
cacheHits++;
|
|
3345
|
+
if (cached.chunks.length > 0) {
|
|
3346
|
+
for (let ci = 0; ci < cached.chunks.length; ci++) {
|
|
3347
|
+
const vec = cached.chunks[ci];
|
|
3259
3348
|
if (vec.length === 0) continue;
|
|
3260
3349
|
const similarity = cosineSimilarity(queryVector, vec);
|
|
3261
3350
|
if (similarity >= minSimilarity) {
|
|
3262
3351
|
candidates.push({
|
|
3263
|
-
|
|
3352
|
+
id: key.id,
|
|
3353
|
+
version: key.version,
|
|
3354
|
+
order,
|
|
3264
3355
|
similarity,
|
|
3265
|
-
chunkTextSource: { kind: "chunk",
|
|
3356
|
+
chunkTextSource: { kind: "chunk-cached", chunkIndex: ci, version: key.version }
|
|
3266
3357
|
});
|
|
3267
3358
|
}
|
|
3268
3359
|
}
|
|
3269
|
-
} else {
|
|
3270
|
-
const
|
|
3271
|
-
if (!messageVector || messageVector.length === 0) continue;
|
|
3272
|
-
const fallback = Float32Array.from(messageVector);
|
|
3273
|
-
chunkCache?.set(message.id, { version, chunks: [], fallback });
|
|
3274
|
-
const similarity = cosineSimilarity(queryVector, fallback);
|
|
3360
|
+
} else if (cached.fallback) {
|
|
3361
|
+
const similarity = cosineSimilarity(queryVector, cached.fallback);
|
|
3275
3362
|
if (similarity >= minSimilarity) {
|
|
3276
|
-
candidates.push({
|
|
3363
|
+
candidates.push({
|
|
3364
|
+
id: key.id,
|
|
3365
|
+
version: key.version,
|
|
3366
|
+
order,
|
|
3367
|
+
similarity,
|
|
3368
|
+
chunkTextSource: { kind: "message" }
|
|
3369
|
+
});
|
|
3370
|
+
}
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
let rowsFetched = 0;
|
|
3374
|
+
for (let offset = 0; offset < missIds.length; offset += CHUNK_VECTOR_BATCH_SIZE) {
|
|
3375
|
+
const rows = await source.loadVectorRows(
|
|
3376
|
+
missIds.slice(offset, offset + CHUNK_VECTOR_BATCH_SIZE)
|
|
3377
|
+
);
|
|
3378
|
+
rowsFetched += rows.length;
|
|
3379
|
+
for (const row of rows) {
|
|
3380
|
+
await yieldIfDue();
|
|
3381
|
+
const id = row.id;
|
|
3382
|
+
const version = Number(row.updated_at) || 0;
|
|
3383
|
+
const order = orderById.get(id) ?? Number.MAX_SAFE_INTEGER;
|
|
3384
|
+
const chunks3 = await readRawJsonField(row, "chunks", ctx.walletAddress);
|
|
3385
|
+
if (chunks3 && chunks3.length > 0) {
|
|
3386
|
+
const vectors = chunks3.map(
|
|
3387
|
+
(chunk) => decodeChunkVector(chunk.vector, () => {
|
|
3388
|
+
unreadableVectors++;
|
|
3389
|
+
})
|
|
3390
|
+
);
|
|
3391
|
+
chunkCache?.set(id, { version, chunks: vectors });
|
|
3392
|
+
for (let ci = 0; ci < chunks3.length; ci++) {
|
|
3393
|
+
const vec = vectors[ci];
|
|
3394
|
+
if (vec.length === 0) continue;
|
|
3395
|
+
const similarity = cosineSimilarity(queryVector, vec);
|
|
3396
|
+
if (similarity >= minSimilarity) {
|
|
3397
|
+
candidates.push({
|
|
3398
|
+
id,
|
|
3399
|
+
version,
|
|
3400
|
+
order,
|
|
3401
|
+
similarity,
|
|
3402
|
+
chunkTextSource: { kind: "chunk", chunk: chunks3[ci], siblings: chunks3 }
|
|
3403
|
+
});
|
|
3404
|
+
}
|
|
3405
|
+
}
|
|
3406
|
+
} else {
|
|
3407
|
+
const messageVector = await readRawJsonField(row, "vector", ctx.walletAddress);
|
|
3408
|
+
if (messageVector && messageVector.length > 0) {
|
|
3409
|
+
const fallback = Float32Array.from(messageVector);
|
|
3410
|
+
chunkCache?.set(id, { version, chunks: [], fallback });
|
|
3411
|
+
const similarity = cosineSimilarity(queryVector, fallback);
|
|
3412
|
+
if (similarity >= minSimilarity) {
|
|
3413
|
+
candidates.push({
|
|
3414
|
+
id,
|
|
3415
|
+
version,
|
|
3416
|
+
order,
|
|
3417
|
+
similarity,
|
|
3418
|
+
chunkTextSource: { kind: "message" }
|
|
3419
|
+
});
|
|
3420
|
+
}
|
|
3421
|
+
}
|
|
3277
3422
|
}
|
|
3278
3423
|
}
|
|
3279
3424
|
}
|
|
3425
|
+
onStats?.({ rowsScanned: source.keys.length, rowsFetched, cacheHits });
|
|
3280
3426
|
if (staleSkipped > 0) {
|
|
3281
3427
|
getLogger().warn(
|
|
3282
3428
|
`searchChunksOp: skipped ${staleSkipped} messages whose embedding model differs from the current model (${embeddingModel}) \u2014 re-embed via chunkAndEmbedAllMessages`
|
|
@@ -3287,12 +3433,17 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
3287
3433
|
`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`
|
|
3288
3434
|
);
|
|
3289
3435
|
}
|
|
3290
|
-
const topK = candidates.sort((a, b) => b.similarity - a.similarity).slice(0, limit);
|
|
3291
|
-
const
|
|
3292
|
-
|
|
3436
|
+
const topK = candidates.sort((a, b) => b.similarity - a.similarity || a.order - b.order).slice(0, limit);
|
|
3437
|
+
const topIds = Array.from(new Set(topK.map((c) => c.id)));
|
|
3438
|
+
const fullRows = await source.loadFullRows(topIds);
|
|
3439
|
+
const rowById = new Map(fullRows.map((row) => [row.id, row]));
|
|
3440
|
+
const liveTopK = topK.filter((c) => {
|
|
3441
|
+
const row = rowById.get(c.id);
|
|
3442
|
+
return row !== void 0 && (Number(row.updated_at) || 0) === c.version;
|
|
3443
|
+
});
|
|
3293
3444
|
const storedById = new Map(
|
|
3294
3445
|
await Promise.all(
|
|
3295
|
-
Array.from(
|
|
3446
|
+
Array.from(rowById, async ([id, m]) => {
|
|
3296
3447
|
const stored2 = await messageRawToStored(
|
|
3297
3448
|
m,
|
|
3298
3449
|
ctx.walletAddress,
|
|
@@ -3305,24 +3456,24 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
3305
3456
|
);
|
|
3306
3457
|
const chunkStateByMsgId = /* @__PURE__ */ new Map();
|
|
3307
3458
|
const needsChunkText = /* @__PURE__ */ new Set();
|
|
3308
|
-
for (const c of
|
|
3309
|
-
if (c.chunkTextSource.kind === "chunk-cached") needsChunkText.add(c.
|
|
3459
|
+
for (const c of liveTopK) {
|
|
3460
|
+
if (c.chunkTextSource.kind === "chunk-cached") needsChunkText.add(c.id);
|
|
3310
3461
|
}
|
|
3311
3462
|
await Promise.all(
|
|
3312
3463
|
Array.from(needsChunkText, async (id) => {
|
|
3313
|
-
const m =
|
|
3464
|
+
const m = rowById.get(id);
|
|
3314
3465
|
const parsed = await readRawJsonField(m, "chunks", ctx.walletAddress);
|
|
3315
3466
|
const version = Number(m.updated_at) || 0;
|
|
3316
3467
|
if (parsed) chunkStateByMsgId.set(id, { version, chunks: parsed });
|
|
3317
3468
|
})
|
|
3318
3469
|
);
|
|
3319
|
-
return
|
|
3320
|
-
const stored2 = { ...storedById.get(
|
|
3470
|
+
return liveTopK.map(({ id, similarity, chunkTextSource }) => {
|
|
3471
|
+
const stored2 = { ...storedById.get(id) };
|
|
3321
3472
|
let chunkText2;
|
|
3322
3473
|
if (chunkTextSource.kind === "chunk") {
|
|
3323
3474
|
chunkText2 = resolveChunkText(stored2.content, chunkTextSource.chunk, chunkTextSource.siblings);
|
|
3324
3475
|
} else if (chunkTextSource.kind === "chunk-cached") {
|
|
3325
|
-
const state = chunkStateByMsgId.get(
|
|
3476
|
+
const state = chunkStateByMsgId.get(id);
|
|
3326
3477
|
const chunk = state && state.version === chunkTextSource.version ? state.chunks[chunkTextSource.chunkIndex] : void 0;
|
|
3327
3478
|
chunkText2 = resolveChunkText(stored2.content, chunk, state?.chunks);
|
|
3328
3479
|
} else {
|
|
@@ -4476,13 +4627,35 @@ async function generateEmbedding(text14, options) {
|
|
|
4476
4627
|
if (total === void 0) return embedOne(text14, options, void 0);
|
|
4477
4628
|
return withDeadline((signal) => embedOne(text14, options, signal), total, "embedding");
|
|
4478
4629
|
}
|
|
4630
|
+
var inFlightByCache = /* @__PURE__ */ new WeakMap();
|
|
4479
4631
|
async function embedOne(text14, options, outer) {
|
|
4480
|
-
const {
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4632
|
+
const { cache } = options;
|
|
4633
|
+
if (!cache) return Array.from(await requestEmbedding(text14, options, outer));
|
|
4634
|
+
const cached = cache.get(text14);
|
|
4635
|
+
if (cached) return Array.from(cached);
|
|
4636
|
+
const inFlight = inFlightByCache.get(cache) ?? /* @__PURE__ */ new Map();
|
|
4637
|
+
inFlightByCache.set(cache, inFlight);
|
|
4638
|
+
const pending = inFlight.get(text14);
|
|
4639
|
+
if (pending) {
|
|
4640
|
+
try {
|
|
4641
|
+
return Array.from(await pending);
|
|
4642
|
+
} catch (err) {
|
|
4643
|
+
if (outer?.aborted) throw err;
|
|
4644
|
+
}
|
|
4645
|
+
}
|
|
4646
|
+
const request = requestEmbedding(text14, options, outer);
|
|
4647
|
+
inFlight.set(text14, request);
|
|
4648
|
+
try {
|
|
4649
|
+
const embedding2 = await request;
|
|
4650
|
+
cache.set(text14, embedding2);
|
|
4651
|
+
return Array.from(embedding2);
|
|
4652
|
+
} finally {
|
|
4653
|
+
if (inFlight.get(text14) === request) inFlight.delete(text14);
|
|
4485
4654
|
}
|
|
4655
|
+
}
|
|
4656
|
+
async function requestEmbedding(text14, options, outer) {
|
|
4657
|
+
const { baseUrl = BASE_URL, model } = options;
|
|
4658
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_EMBEDDING_REQUEST_TIMEOUT_MS;
|
|
4486
4659
|
const headers = {
|
|
4487
4660
|
...await resolveAuthHeaders(options, outer),
|
|
4488
4661
|
...taskTypeHeader(options.taskType)
|
|
@@ -4517,11 +4690,7 @@ async function embedOne(text14, options, outer) {
|
|
|
4517
4690
|
totalTokens: response.data.usage.total_tokens ?? 0
|
|
4518
4691
|
});
|
|
4519
4692
|
}
|
|
4520
|
-
|
|
4521
|
-
if (cache) {
|
|
4522
|
-
cache.set(text14, f32Embedding);
|
|
4523
|
-
}
|
|
4524
|
-
return Array.from(f32Embedding);
|
|
4693
|
+
return Float32Array.from(embedding2);
|
|
4525
4694
|
}
|
|
4526
4695
|
var DEFAULT_EMBEDDING_BATCH_SIZE = 100;
|
|
4527
4696
|
var DEFAULT_EMBEDDING_BATCH_CONCURRENCY = 3;
|
|
@@ -15801,9 +15970,9 @@ function recencyMultiplier(updatedAt, opts = {}) {
|
|
|
15801
15970
|
const updatedMs = updatedAt.getTime();
|
|
15802
15971
|
if (!Number.isFinite(updatedMs)) return noDate;
|
|
15803
15972
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
15804
|
-
const
|
|
15805
|
-
if (!Number.isFinite(
|
|
15806
|
-
const ageDays2 = Math.max(0, (
|
|
15973
|
+
const nowMs2 = now.getTime();
|
|
15974
|
+
if (!Number.isFinite(nowMs2)) return noDate;
|
|
15975
|
+
const ageDays2 = Math.max(0, (nowMs2 - updatedMs) / DAY_MS2);
|
|
15807
15976
|
const perYearDecay = opts.perYearDecay ?? DEFAULT_PER_YEAR_DECAY;
|
|
15808
15977
|
const floor = opts.floor ?? DEFAULT_FLOOR;
|
|
15809
15978
|
const decay = perYearDecay * (ageDays2 / 365);
|
|
@@ -16312,9 +16481,6 @@ function createVaultEmbeddingCache(maxSize = DEFAULT_VAULT_CACHE_SIZE) {
|
|
|
16312
16481
|
|
|
16313
16482
|
// src/lib/memoryVault/searchTool.ts
|
|
16314
16483
|
var DEFAULT_RERANK_TOP_N = 5;
|
|
16315
|
-
function nowMs() {
|
|
16316
|
-
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
16317
|
-
}
|
|
16318
16484
|
var warnedProgrammaticDecomposeIgnored = false;
|
|
16319
16485
|
function normalizeEventTimeKind(kind) {
|
|
16320
16486
|
return kind === "point" || kind === "range" || kind === "ongoing" ? kind : null;
|
|
@@ -19205,6 +19371,32 @@ function rankProfileCandidates(inputs, now = Date.now(), options = {}) {
|
|
|
19205
19371
|
return ranked;
|
|
19206
19372
|
}
|
|
19207
19373
|
|
|
19374
|
+
// src/lib/db/chat/embeddingCache.ts
|
|
19375
|
+
var MaskScopedEmbeddingCache = class extends Map {
|
|
19376
|
+
constructor(inner, masked) {
|
|
19377
|
+
super();
|
|
19378
|
+
this.inner = inner;
|
|
19379
|
+
this.masked = masked;
|
|
19380
|
+
}
|
|
19381
|
+
key(text14) {
|
|
19382
|
+
return `${this.masked ? "m" : "r"}:${text14}`;
|
|
19383
|
+
}
|
|
19384
|
+
get(text14) {
|
|
19385
|
+
return this.inner.get(this.key(text14));
|
|
19386
|
+
}
|
|
19387
|
+
set(text14, value) {
|
|
19388
|
+
this.inner.set(this.key(text14), value);
|
|
19389
|
+
return this;
|
|
19390
|
+
}
|
|
19391
|
+
};
|
|
19392
|
+
var scopedViews = /* @__PURE__ */ new WeakMap();
|
|
19393
|
+
function maskScopedEmbeddingCache(cache, masked) {
|
|
19394
|
+
const views = scopedViews.get(cache) ?? {};
|
|
19395
|
+
scopedViews.set(cache, views);
|
|
19396
|
+
const slot = masked ? "masked" : "raw";
|
|
19397
|
+
return views[slot] ?? (views[slot] = new MaskScopedEmbeddingCache(cache, masked));
|
|
19398
|
+
}
|
|
19399
|
+
|
|
19208
19400
|
// src/lib/memory/queryTemporal.ts
|
|
19209
19401
|
var RELATIVE_DAY_ENTRIES = [
|
|
19210
19402
|
[/\btoday\b/, "today", 0],
|
|
@@ -19412,9 +19604,6 @@ function scoreEventTimeOverlap(memoryStart, memoryEnd, memoryKind, window2) {
|
|
|
19412
19604
|
var DEFAULT_LIMIT = 8;
|
|
19413
19605
|
var DEFAULT_BUDGET = "low";
|
|
19414
19606
|
var DEFAULT_FACT_MIN_SCORE = 0.1;
|
|
19415
|
-
function nowMs2() {
|
|
19416
|
-
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
19417
|
-
}
|
|
19418
19607
|
var DEFAULT_CHUNK_MIN_SCORE = 0.5;
|
|
19419
19608
|
var DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS = 8e3;
|
|
19420
19609
|
function flagsForBudget(budget) {
|
|
@@ -19452,12 +19641,19 @@ async function recall(query, ctx, options = {}) {
|
|
|
19452
19641
|
const subQueries = normalizedFacets.length >= 2 ? normalizedFacets : void 0;
|
|
19453
19642
|
const embeddingOptions = {
|
|
19454
19643
|
...ctx.embeddingOptions,
|
|
19455
|
-
taskType: "memory_recall_embed"
|
|
19644
|
+
taskType: "memory_recall_embed",
|
|
19645
|
+
...options.embeddingCache && !ctx.embeddingOptions.cache && {
|
|
19646
|
+
cache: maskScopedEmbeddingCache(
|
|
19647
|
+
options.embeddingCache,
|
|
19648
|
+
Boolean(ctx.embeddingOptions.maskInput)
|
|
19649
|
+
)
|
|
19650
|
+
}
|
|
19456
19651
|
};
|
|
19457
|
-
const t0 =
|
|
19652
|
+
const t0 = nowMs();
|
|
19458
19653
|
let prepMs = 0;
|
|
19459
19654
|
let factLaneMs = 0;
|
|
19460
19655
|
let chunkLaneMs = 0;
|
|
19656
|
+
let chunkStats;
|
|
19461
19657
|
let fuseMs = 0;
|
|
19462
19658
|
const factResults = [];
|
|
19463
19659
|
const chunkResults = [];
|
|
@@ -19512,6 +19708,11 @@ async function recall(query, ctx, options = {}) {
|
|
|
19512
19708
|
...decryptLastRan !== void 0 && { decryptLast: decryptLastRan },
|
|
19513
19709
|
...vaultRowsDecrypted !== void 0 && { vaultRowsDecrypted },
|
|
19514
19710
|
...vaultRowsEmbedded !== void 0 && { vaultRowsEmbedded },
|
|
19711
|
+
...chunkStats && {
|
|
19712
|
+
chunkRowsScanned: chunkStats.rowsScanned,
|
|
19713
|
+
chunkRowsFetched: chunkStats.rowsFetched,
|
|
19714
|
+
chunkCacheHits: chunkStats.cacheHits
|
|
19715
|
+
},
|
|
19515
19716
|
factCount: factResults.length,
|
|
19516
19717
|
chunkCount: chunkResults.length,
|
|
19517
19718
|
admittedCount: admitted.length,
|
|
@@ -19523,7 +19724,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
19523
19724
|
temporalLaneCount,
|
|
19524
19725
|
emptyReason: emptyReasonFor(admitted.length, laneRan),
|
|
19525
19726
|
timings: {
|
|
19526
|
-
total:
|
|
19727
|
+
total: nowMs() - t0,
|
|
19527
19728
|
prep: prepMs,
|
|
19528
19729
|
factLane: factLaneMs,
|
|
19529
19730
|
rerank: rerankMs,
|
|
@@ -19545,14 +19746,14 @@ async function recall(query, ctx, options = {}) {
|
|
|
19545
19746
|
const needsChunkEmbedding = types.includes("chunk") && ctx.storageCtx;
|
|
19546
19747
|
const wantsTemporal = types.includes("fact") && (ctx.factSource || ctx.vaultCtx);
|
|
19547
19748
|
const queryEmbedTotalTimeoutMs = options.queryEmbedTotalTimeoutMs ?? DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS;
|
|
19548
|
-
const prepStart =
|
|
19749
|
+
const prepStart = nowMs();
|
|
19549
19750
|
let sharedEmbedMs = 0;
|
|
19550
19751
|
const [queryEmbedding, entityRanking, temporalRanking] = await Promise.all([
|
|
19551
19752
|
needsChunkEmbedding ? generateEmbedding(query, {
|
|
19552
19753
|
...embeddingOptions,
|
|
19553
19754
|
totalTimeoutMs: queryEmbedTotalTimeoutMs
|
|
19554
19755
|
}).finally(() => {
|
|
19555
|
-
sharedEmbedMs =
|
|
19756
|
+
sharedEmbedMs = nowMs() - prepStart;
|
|
19556
19757
|
}).then((vec) => {
|
|
19557
19758
|
if (vec.length === 0) {
|
|
19558
19759
|
getLogger().warn(
|
|
@@ -19585,11 +19786,11 @@ async function recall(query, ctx, options = {}) {
|
|
|
19585
19786
|
() => ctx.factSource ? ctx.factSource.temporalRanking(query, options.now) : buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)
|
|
19586
19787
|
) : Promise.resolve([])
|
|
19587
19788
|
]);
|
|
19588
|
-
prepMs =
|
|
19789
|
+
prepMs = nowMs() - prepStart;
|
|
19589
19790
|
graphLaneCount = entityRanking.length;
|
|
19590
19791
|
temporalLaneCount = temporalRanking.length;
|
|
19591
19792
|
if (types.includes("fact") && (ctx.factSource || ctx.vaultCtx && ctx.vaultCache)) {
|
|
19592
|
-
const factStart =
|
|
19793
|
+
const factStart = nowMs();
|
|
19593
19794
|
const vaultMinScore = options.minScore ?? DEFAULT_FACT_MIN_SCORE;
|
|
19594
19795
|
factFloor = vaultMinScore;
|
|
19595
19796
|
const {
|
|
@@ -19665,11 +19866,11 @@ async function recall(query, ctx, options = {}) {
|
|
|
19665
19866
|
factLaneRankedOnCosine = factRankedOnCosine;
|
|
19666
19867
|
decryptLastRan = factDecryptLast;
|
|
19667
19868
|
vaultRowsDecrypted = factRowsDecrypted;
|
|
19668
|
-
factLaneMs =
|
|
19869
|
+
factLaneMs = nowMs() - factStart;
|
|
19669
19870
|
}
|
|
19670
19871
|
if (chunkEmbedFailed && !factLaneRankedOnCosine) embeddingsUnavailable = true;
|
|
19671
19872
|
if (types.includes("chunk") && ctx.storageCtx && queryEmbedding) {
|
|
19672
|
-
const chunkStart =
|
|
19873
|
+
const chunkStart = nowMs();
|
|
19673
19874
|
const chunkMinScore = options.minScore ?? DEFAULT_CHUNK_MIN_SCORE;
|
|
19674
19875
|
chunkFloor = chunkMinScore;
|
|
19675
19876
|
const results = await searchChunksOp(ctx.storageCtx, queryEmbedding, {
|
|
@@ -19680,12 +19881,15 @@ async function recall(query, ctx, options = {}) {
|
|
|
19680
19881
|
...options.excludeConversationId && {
|
|
19681
19882
|
excludeConversationId: options.excludeConversationId
|
|
19682
19883
|
},
|
|
19683
|
-
...ctx.chunkCache && { chunkCache: ctx.chunkCache }
|
|
19884
|
+
...ctx.chunkCache && { chunkCache: ctx.chunkCache },
|
|
19885
|
+
onStats: (stats) => {
|
|
19886
|
+
chunkStats = stats;
|
|
19887
|
+
}
|
|
19684
19888
|
});
|
|
19685
19889
|
chunkResults.push(...dedupeBy(results, (r) => r.chunkText.trim()));
|
|
19686
|
-
chunkLaneMs =
|
|
19890
|
+
chunkLaneMs = nowMs() - chunkStart;
|
|
19687
19891
|
}
|
|
19688
|
-
const fuseStart =
|
|
19892
|
+
const fuseStart = nowMs();
|
|
19689
19893
|
if (types.length === 1 || factResults.length === 0 || chunkResults.length === 0) {
|
|
19690
19894
|
const memories2 = [
|
|
19691
19895
|
...factResults.map((r) => toFactMemory(r, options.now)),
|
|
@@ -19693,7 +19897,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
19693
19897
|
];
|
|
19694
19898
|
memories2.sort((a, b) => b.score - a.score);
|
|
19695
19899
|
const candidateCount = factResults.length + chunkResults.length;
|
|
19696
|
-
fuseMs =
|
|
19900
|
+
fuseMs = nowMs() - fuseStart;
|
|
19697
19901
|
const admitted = memories2.slice(0, limit);
|
|
19698
19902
|
hitLimit = memories2.length > limit;
|
|
19699
19903
|
emitDiagnostics(candidateCount, admitted);
|
|
@@ -19757,7 +19961,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
19757
19961
|
memories = selection.out;
|
|
19758
19962
|
}
|
|
19759
19963
|
hitLimit = selection.cut;
|
|
19760
|
-
fuseMs =
|
|
19964
|
+
fuseMs = nowMs() - fuseStart;
|
|
19761
19965
|
emitDiagnostics(byId.size, memories);
|
|
19762
19966
|
return {
|
|
19763
19967
|
memories,
|
|
@@ -29760,28 +29964,6 @@ async function cleanupConversationSummary(database, conversationId) {
|
|
|
29760
29964
|
}
|
|
29761
29965
|
}
|
|
29762
29966
|
|
|
29763
|
-
// src/lib/db/chat/embeddingCache.ts
|
|
29764
|
-
var MaskScopedEmbeddingCache = class extends Map {
|
|
29765
|
-
constructor(inner, masked) {
|
|
29766
|
-
super();
|
|
29767
|
-
this.inner = inner;
|
|
29768
|
-
this.masked = masked;
|
|
29769
|
-
}
|
|
29770
|
-
key(text14) {
|
|
29771
|
-
return `${this.masked ? "m" : "r"}:${text14}`;
|
|
29772
|
-
}
|
|
29773
|
-
get(text14) {
|
|
29774
|
-
return this.inner.get(this.key(text14));
|
|
29775
|
-
}
|
|
29776
|
-
set(text14, value) {
|
|
29777
|
-
this.inner.set(this.key(text14), value);
|
|
29778
|
-
return this;
|
|
29779
|
-
}
|
|
29780
|
-
};
|
|
29781
|
-
function maskScopedEmbeddingCache(cache, masked) {
|
|
29782
|
-
return new MaskScopedEmbeddingCache(cache, masked);
|
|
29783
|
-
}
|
|
29784
|
-
|
|
29785
29967
|
// src/lib/tools/selection/activeToolSets.ts
|
|
29786
29968
|
function mergeActiveToolSets(current, derived) {
|
|
29787
29969
|
if (derived.length === 0) return current;
|