@anuma/sdk 7.0.0 → 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 +421 -111
- package/dist/expo/index.d.mts +25 -24
- package/dist/expo/index.d.ts +25 -24
- package/dist/expo/index.mjs +420 -111
- package/dist/index.cjs +216 -192
- package/dist/index.mjs +216 -192
- package/dist/memory/context.d.mts +8 -0
- package/dist/memory/context.d.ts +8 -0
- package/dist/react/index.cjs +442 -132
- package/dist/react/index.d.mts +30 -44
- package/dist/react/index.d.ts +30 -44
- package/dist/react/index.mjs +441 -132
- package/dist/server/index.cjs +431 -106
- package/dist/server/index.d.mts +30 -21
- package/dist/server/index.d.ts +30 -21
- package/dist/server/index.mjs +430 -106
- 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.mjs
CHANGED
|
@@ -1314,6 +1314,35 @@ function decodeChunkVector(vector, onMalformed) {
|
|
|
1314
1314
|
}
|
|
1315
1315
|
}
|
|
1316
1316
|
|
|
1317
|
+
// src/lib/scheduling.ts
|
|
1318
|
+
function nowMs() {
|
|
1319
|
+
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
1320
|
+
}
|
|
1321
|
+
function yieldToEventLoop() {
|
|
1322
|
+
const scheduler = globalThis.scheduler;
|
|
1323
|
+
if (typeof scheduler?.yield === "function") return scheduler.yield();
|
|
1324
|
+
if (typeof MessageChannel === "function") {
|
|
1325
|
+
return new Promise((resolve) => {
|
|
1326
|
+
const channel = new MessageChannel();
|
|
1327
|
+
channel.port1.onmessage = () => {
|
|
1328
|
+
channel.port1.close();
|
|
1329
|
+
channel.port2.close();
|
|
1330
|
+
resolve();
|
|
1331
|
+
};
|
|
1332
|
+
channel.port2.postMessage(null);
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
1336
|
+
}
|
|
1337
|
+
function createTimeSliceYielder(budgetMs) {
|
|
1338
|
+
let sliceStart = nowMs();
|
|
1339
|
+
return async () => {
|
|
1340
|
+
if (nowMs() - sliceStart < budgetMs) return;
|
|
1341
|
+
await yieldToEventLoop();
|
|
1342
|
+
sliceStart = nowMs();
|
|
1343
|
+
};
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1317
1346
|
// src/lib/db/encryption-utils.ts
|
|
1318
1347
|
var ENCRYPTION_PREFIX = "enc:v3:";
|
|
1319
1348
|
function isEncrypted(value) {
|
|
@@ -1322,6 +1351,11 @@ function isEncrypted(value) {
|
|
|
1322
1351
|
const payload = value.slice(prefix.length);
|
|
1323
1352
|
return payload.length >= 56 && /^[0-9a-f]+$/i.test(payload);
|
|
1324
1353
|
}
|
|
1354
|
+
function hasEncryptedToolPayload(event) {
|
|
1355
|
+
return [event.arguments, event.output].some(
|
|
1356
|
+
(value) => typeof value === "string" && isEncrypted(value)
|
|
1357
|
+
);
|
|
1358
|
+
}
|
|
1325
1359
|
function detectEncryptionVersion(value) {
|
|
1326
1360
|
if (value.startsWith("enc:v3:")) {
|
|
1327
1361
|
return { version: "v3", encryptedData: value.slice("enc:v3:".length) };
|
|
@@ -1457,6 +1491,12 @@ async function encryptMessageFields(message, address, signMessage, embeddedWalle
|
|
|
1457
1491
|
const encryptedChunks = msg.chunks ? await encryptJsonField(msg.chunks, address, signMessage, embeddedWalletSigner, true) : void 0;
|
|
1458
1492
|
const encryptedSources = msg.sources ? await encryptJsonField(msg.sources, address, signMessage, embeddedWalletSigner, true) : void 0;
|
|
1459
1493
|
const encryptedThoughtProcess = msg.thoughtProcess ? await encryptJsonField(msg.thoughtProcess, address, signMessage, embeddedWalletSigner, true) : void 0;
|
|
1494
|
+
const encryptedToolCallEvents = Array.isArray(msg.toolCallEvents) ? await encryptToolCallEvents(
|
|
1495
|
+
msg.toolCallEvents,
|
|
1496
|
+
address,
|
|
1497
|
+
signMessage,
|
|
1498
|
+
embeddedWalletSigner
|
|
1499
|
+
) : void 0;
|
|
1460
1500
|
return {
|
|
1461
1501
|
...message,
|
|
1462
1502
|
...encryptedContent !== void 0 && { content: encryptedContent },
|
|
@@ -1464,13 +1504,31 @@ async function encryptMessageFields(message, address, signMessage, embeddedWalle
|
|
|
1464
1504
|
...encryptedVector !== void 0 && { vector: encryptedVector },
|
|
1465
1505
|
...encryptedChunks !== void 0 && { chunks: encryptedChunks },
|
|
1466
1506
|
...encryptedSources !== void 0 && { sources: encryptedSources },
|
|
1467
|
-
...encryptedThoughtProcess !== void 0 && { thoughtProcess: encryptedThoughtProcess }
|
|
1507
|
+
...encryptedThoughtProcess !== void 0 && { thoughtProcess: encryptedThoughtProcess },
|
|
1508
|
+
...encryptedToolCallEvents !== void 0 && { toolCallEvents: encryptedToolCallEvents }
|
|
1468
1509
|
};
|
|
1469
1510
|
} catch (error) {
|
|
1470
1511
|
getLogger().warn("Failed to encrypt message fields:", error);
|
|
1471
1512
|
throw error;
|
|
1472
1513
|
}
|
|
1473
1514
|
}
|
|
1515
|
+
function mapToolCallPayloads(events, transform) {
|
|
1516
|
+
return Promise.all(
|
|
1517
|
+
events.map(async (event) => {
|
|
1518
|
+
if (!event || typeof event !== "object") return event;
|
|
1519
|
+
const mapped = { ...event };
|
|
1520
|
+
if (typeof event.arguments === "string") mapped.arguments = await transform(event.arguments);
|
|
1521
|
+
if (typeof event.output === "string") mapped.output = await transform(event.output);
|
|
1522
|
+
return mapped;
|
|
1523
|
+
})
|
|
1524
|
+
);
|
|
1525
|
+
}
|
|
1526
|
+
function encryptToolCallEvents(events, address, signMessage, embeddedWalletSigner) {
|
|
1527
|
+
return mapToolCallPayloads(
|
|
1528
|
+
events,
|
|
1529
|
+
(value) => encryptField(value, address, signMessage, embeddedWalletSigner, true)
|
|
1530
|
+
);
|
|
1531
|
+
}
|
|
1474
1532
|
async function decryptMaybeJsonFieldDetailed(value, address) {
|
|
1475
1533
|
if (value === void 0) return { value: void 0, status: "plaintext" };
|
|
1476
1534
|
if (value === null) return { value, status: "plaintext" };
|
|
@@ -1556,6 +1614,10 @@ async function assembleDecryptedMessage(message, address) {
|
|
|
1556
1614
|
message.thoughtProcess,
|
|
1557
1615
|
address
|
|
1558
1616
|
);
|
|
1617
|
+
const toolCallEventsResult = await decryptMaybeJsonFieldDetailed(
|
|
1618
|
+
message.toolCallEvents,
|
|
1619
|
+
address
|
|
1620
|
+
);
|
|
1559
1621
|
let decryptionStatus;
|
|
1560
1622
|
let refreshProbe;
|
|
1561
1623
|
const consider = (status, probe) => {
|
|
@@ -1574,6 +1636,14 @@ async function assembleDecryptedMessage(message, address) {
|
|
|
1574
1636
|
if (thoughtProcessResult.probe) {
|
|
1575
1637
|
consider(thoughtProcessResult.status, thoughtProcessResult.probe);
|
|
1576
1638
|
}
|
|
1639
|
+
if (toolCallEventsResult.probe) {
|
|
1640
|
+
consider(toolCallEventsResult.status, toolCallEventsResult.probe);
|
|
1641
|
+
}
|
|
1642
|
+
const toolCallEvents = Array.isArray(toolCallEventsResult.value) ? await mapToolCallPayloads(toolCallEventsResult.value, async (value) => {
|
|
1643
|
+
const detailed = await decryptFieldDetailed(value, address);
|
|
1644
|
+
consider(detailed.status, isEncrypted(value) ? value : void 0);
|
|
1645
|
+
return detailed.value;
|
|
1646
|
+
}) : void 0;
|
|
1577
1647
|
const statusForConsumer = decryptionStatus === "ok" || decryptionStatus === "plaintext" || !decryptionStatus ? void 0 : decryptionStatus;
|
|
1578
1648
|
const result = {
|
|
1579
1649
|
...message,
|
|
@@ -1582,7 +1652,8 @@ async function assembleDecryptedMessage(message, address) {
|
|
|
1582
1652
|
vector: vectorResult.value,
|
|
1583
1653
|
chunks: chunksResult.value,
|
|
1584
1654
|
sources: sourcesResult.value,
|
|
1585
|
-
thoughtProcess: thoughtProcessResult.value
|
|
1655
|
+
thoughtProcess: thoughtProcessResult.value,
|
|
1656
|
+
toolCallEvents
|
|
1586
1657
|
};
|
|
1587
1658
|
if (statusForConsumer) {
|
|
1588
1659
|
result.decryptionStatus = statusForConsumer;
|
|
@@ -2378,7 +2449,7 @@ async function updateMessageChunksOp(ctx, uniqueId, chunks3, embeddingModel) {
|
|
|
2378
2449
|
});
|
|
2379
2450
|
return messageToStored(message, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
2380
2451
|
}
|
|
2381
|
-
var
|
|
2452
|
+
var RAW_REPAIR_PAGE_SIZE = 100;
|
|
2382
2453
|
function chunksWithoutText(raw) {
|
|
2383
2454
|
if (typeof raw !== "string") return null;
|
|
2384
2455
|
let parsed;
|
|
@@ -2401,8 +2472,8 @@ function chunksWithoutText(raw) {
|
|
|
2401
2472
|
async function stripLegacyChunkTextOp(ctx) {
|
|
2402
2473
|
const candidateIds = await ctx.messagesCollection.query(Q.where("chunks", Q.like(`%${Q.sanitizeLikeString('"text":')}%`))).fetchIds();
|
|
2403
2474
|
let stripped = 0;
|
|
2404
|
-
for (let start = 0; start < candidateIds.length; start +=
|
|
2405
|
-
const pageIds = candidateIds.slice(start, start +
|
|
2475
|
+
for (let start = 0; start < candidateIds.length; start += RAW_REPAIR_PAGE_SIZE) {
|
|
2476
|
+
const pageIds = candidateIds.slice(start, start + RAW_REPAIR_PAGE_SIZE);
|
|
2406
2477
|
const rows = await ctx.messagesCollection.query(Q.where("id", Q.oneOf(pageIds))).unsafeFetchRaw();
|
|
2407
2478
|
const changedIds = rows.filter((row) => chunksWithoutText(row.chunks) !== null).map((row) => String(row.id));
|
|
2408
2479
|
if (changedIds.length === 0) continue;
|
|
@@ -2426,6 +2497,88 @@ async function stripLegacyChunkTextOp(ctx) {
|
|
|
2426
2497
|
}
|
|
2427
2498
|
return stripped;
|
|
2428
2499
|
}
|
|
2500
|
+
async function encryptedToolCallEventsColumn(raw, address, signMessage, embeddedWalletSigner) {
|
|
2501
|
+
if (typeof raw !== "string") return null;
|
|
2502
|
+
let parsed;
|
|
2503
|
+
try {
|
|
2504
|
+
parsed = JSON.parse(raw);
|
|
2505
|
+
} catch {
|
|
2506
|
+
return null;
|
|
2507
|
+
}
|
|
2508
|
+
if (!Array.isArray(parsed)) return null;
|
|
2509
|
+
const column = JSON.stringify(
|
|
2510
|
+
await encryptToolCallEvents(
|
|
2511
|
+
parsed,
|
|
2512
|
+
address,
|
|
2513
|
+
signMessage,
|
|
2514
|
+
embeddedWalletSigner
|
|
2515
|
+
)
|
|
2516
|
+
);
|
|
2517
|
+
return column === JSON.stringify(parsed) ? null : column;
|
|
2518
|
+
}
|
|
2519
|
+
async function encryptToolCallEventsOp(ctx) {
|
|
2520
|
+
const { walletAddress: address, signMessage, embeddedWalletSigner } = ctx;
|
|
2521
|
+
if (!address || !signMessage) return 0;
|
|
2522
|
+
if (!await requestEncryptionKey(address, signMessage, embeddedWalletSigner)) return 0;
|
|
2523
|
+
if (!hasEncryptionKey(address)) return 0;
|
|
2524
|
+
if (!await savedKeyOpensExistingData(ctx, address, signMessage, embeddedWalletSigner)) {
|
|
2525
|
+
return 0;
|
|
2526
|
+
}
|
|
2527
|
+
const candidateIds = await ctx.messagesCollection.query(
|
|
2528
|
+
Q.where("tool_call_events", Q.notEq(null)),
|
|
2529
|
+
Q.where("tool_call_events", Q.notIn(["", "[]"]))
|
|
2530
|
+
).fetchIds();
|
|
2531
|
+
let encrypted = 0;
|
|
2532
|
+
for (let start = 0; start < candidateIds.length; start += RAW_REPAIR_PAGE_SIZE) {
|
|
2533
|
+
const pageIds = candidateIds.slice(start, start + RAW_REPAIR_PAGE_SIZE);
|
|
2534
|
+
const rows = await ctx.messagesCollection.query(Q.where("id", Q.oneOf(pageIds))).unsafeFetchRaw();
|
|
2535
|
+
const repairs = /* @__PURE__ */ new Map();
|
|
2536
|
+
for (const row of rows) {
|
|
2537
|
+
const column = await encryptedToolCallEventsColumn(
|
|
2538
|
+
row.tool_call_events,
|
|
2539
|
+
address,
|
|
2540
|
+
signMessage,
|
|
2541
|
+
embeddedWalletSigner
|
|
2542
|
+
);
|
|
2543
|
+
if (column !== null) repairs.set(String(row.id), { raw: row.tool_call_events, column });
|
|
2544
|
+
}
|
|
2545
|
+
if (repairs.size === 0) continue;
|
|
2546
|
+
await ctx.database.write(async () => {
|
|
2547
|
+
const messages = (await ctx.messagesCollection.query(Q.where("id", Q.oneOf([...repairs.keys()]))).fetch()).filter(
|
|
2548
|
+
(message) => message._raw.tool_call_events === repairs.get(message.id)?.raw
|
|
2549
|
+
);
|
|
2550
|
+
if (messages.length === 0) return;
|
|
2551
|
+
const conversationIds = [...new Set(messages.map((message) => message.conversationId))];
|
|
2552
|
+
const conversations = await ctx.conversationsCollection.query(Q.where("conversation_id", Q.oneOf(conversationIds))).fetch();
|
|
2553
|
+
await ctx.database.batch(
|
|
2554
|
+
...messages.map(
|
|
2555
|
+
(message) => message.prepareUpdate((msg) => {
|
|
2556
|
+
msg._setRaw("tool_call_events", repairs.get(message.id).column);
|
|
2557
|
+
})
|
|
2558
|
+
),
|
|
2559
|
+
...conversations.map((conversation) => conversation.prepareUpdate(() => {
|
|
2560
|
+
}))
|
|
2561
|
+
);
|
|
2562
|
+
encrypted += messages.length;
|
|
2563
|
+
});
|
|
2564
|
+
}
|
|
2565
|
+
return encrypted;
|
|
2566
|
+
}
|
|
2567
|
+
async function savedKeyOpensExistingData(ctx, address, signMessage, embeddedWalletSigner) {
|
|
2568
|
+
const v3Probe = await findEncryptedContent(ctx, "enc:v3:%");
|
|
2569
|
+
if (v3Probe) {
|
|
2570
|
+
const { status } = await decryptFieldDetailed(v3Probe, address);
|
|
2571
|
+
if (status !== "auth_mismatch" && status !== "key_missing") return true;
|
|
2572
|
+
return refreshEncryptionKeyIfMatches(address, v3Probe, signMessage, embeddedWalletSigner);
|
|
2573
|
+
}
|
|
2574
|
+
const v2Probe = await findEncryptedContent(ctx, "enc:v2:%");
|
|
2575
|
+
if (!v2Probe) return true;
|
|
2576
|
+
return refreshEncryptionKeyIfMatches(address, v2Probe, signMessage, embeddedWalletSigner);
|
|
2577
|
+
}
|
|
2578
|
+
async function findEncryptedContent(ctx, pattern) {
|
|
2579
|
+
const [row] = await ctx.messagesCollection.query(Q.where("content", Q.like(pattern)), Q.take(1)).unsafeFetchRaw();
|
|
2580
|
+
return row ? String(row.content) : null;
|
|
2581
|
+
}
|
|
2429
2582
|
async function updateMessageErrorOp(ctx, uniqueId, error) {
|
|
2430
2583
|
let message;
|
|
2431
2584
|
try {
|
|
@@ -2523,6 +2676,95 @@ async function readRawJsonField(raw, column, walletAddress) {
|
|
|
2523
2676
|
return void 0;
|
|
2524
2677
|
}
|
|
2525
2678
|
}
|
|
2679
|
+
var CHUNK_VECTOR_BATCH_SIZE = 50;
|
|
2680
|
+
var CHUNK_SCAN_YIELD_BUDGET_MS = 12;
|
|
2681
|
+
var hasEmbeddingSql = `(coalesce("chunks", '') != '' or coalesce("vector", '') != '')`;
|
|
2682
|
+
function toChunkCandidateKey(raw) {
|
|
2683
|
+
return {
|
|
2684
|
+
id: raw.id,
|
|
2685
|
+
conversationId: String(raw.conversation_id),
|
|
2686
|
+
version: Number(raw.updated_at) || 0,
|
|
2687
|
+
embeddingModel: raw.embedding_model ?? null
|
|
2688
|
+
};
|
|
2689
|
+
}
|
|
2690
|
+
async function fetchRowsByIds(ctx, ids) {
|
|
2691
|
+
if (ids.length === 0) return [];
|
|
2692
|
+
return await ctx.messagesCollection.query(Q.where("id", Q.oneOf(ids))).unsafeFetchRaw();
|
|
2693
|
+
}
|
|
2694
|
+
async function projectedChunkRowSource(ctx, filter) {
|
|
2695
|
+
const clauses = [
|
|
2696
|
+
`"history"."_status" is not 'deleted'`,
|
|
2697
|
+
hasEmbeddingSql,
|
|
2698
|
+
`exists (select 1 from "conversations" where "conversations"."conversation_id" = "history"."conversation_id" and "conversations"."is_deleted" = 0 and "conversations"."_status" is not 'deleted')`
|
|
2699
|
+
];
|
|
2700
|
+
const args = [];
|
|
2701
|
+
if (filter.conversationId !== void 0) {
|
|
2702
|
+
clauses.push(`"history"."conversation_id" = ?`);
|
|
2703
|
+
args.push(filter.conversationId);
|
|
2704
|
+
}
|
|
2705
|
+
if (filter.excludeConversationId !== void 0) {
|
|
2706
|
+
clauses.push(`"history"."conversation_id" != ?`);
|
|
2707
|
+
args.push(filter.excludeConversationId);
|
|
2708
|
+
}
|
|
2709
|
+
const keyRows = await ctx.messagesCollection.query(
|
|
2710
|
+
Q.unsafeSqlQuery(
|
|
2711
|
+
`select "id", "conversation_id", "updated_at", "embedding_model" from "history" where ${clauses.join(" and ")}`,
|
|
2712
|
+
args
|
|
2713
|
+
)
|
|
2714
|
+
).unsafeFetchRaw();
|
|
2715
|
+
return {
|
|
2716
|
+
keys: keyRows.map(toChunkCandidateKey),
|
|
2717
|
+
loadVectorRows: async (ids) => {
|
|
2718
|
+
if (ids.length === 0) return [];
|
|
2719
|
+
return await ctx.messagesCollection.query(
|
|
2720
|
+
Q.unsafeSqlQuery(
|
|
2721
|
+
`select "id", "updated_at", "chunks", "vector" from "history" where "_status" is not 'deleted' and "id" in (${ids.map(() => "?").join(",")})`,
|
|
2722
|
+
ids
|
|
2723
|
+
)
|
|
2724
|
+
).unsafeFetchRaw();
|
|
2725
|
+
},
|
|
2726
|
+
loadFullRows: (ids) => fetchRowsByIds(ctx, ids)
|
|
2727
|
+
};
|
|
2728
|
+
}
|
|
2729
|
+
async function fullScanChunkRowSource(ctx, filter) {
|
|
2730
|
+
const activeConversations = await ctx.conversationsCollection.query(Q.where("is_deleted", false)).fetch();
|
|
2731
|
+
const activeConversationIds = new Set(
|
|
2732
|
+
activeConversations.map((c) => String(c._getRaw("conversation_id")))
|
|
2733
|
+
);
|
|
2734
|
+
const queryConditions = filter.conversationId !== void 0 ? [Q.where("conversation_id", filter.conversationId)] : [];
|
|
2735
|
+
const rows = await ctx.messagesCollection.query(...queryConditions).unsafeFetchRaw();
|
|
2736
|
+
const rowsById = /* @__PURE__ */ new Map();
|
|
2737
|
+
for (const row of rows) {
|
|
2738
|
+
const conversationId = String(row.conversation_id);
|
|
2739
|
+
if (!activeConversationIds.has(conversationId)) continue;
|
|
2740
|
+
if (filter.excludeConversationId !== void 0 && conversationId === filter.excludeConversationId) {
|
|
2741
|
+
continue;
|
|
2742
|
+
}
|
|
2743
|
+
if (!row.chunks && !row.vector) continue;
|
|
2744
|
+
rowsById.set(row.id, row);
|
|
2745
|
+
}
|
|
2746
|
+
const pick = (ids) => Promise.resolve(
|
|
2747
|
+
ids.flatMap((id) => {
|
|
2748
|
+
const row = rowsById.get(id);
|
|
2749
|
+
return row ? [row] : [];
|
|
2750
|
+
})
|
|
2751
|
+
);
|
|
2752
|
+
return {
|
|
2753
|
+
keys: Array.from(rowsById.values(), toChunkCandidateKey),
|
|
2754
|
+
loadVectorRows: pick,
|
|
2755
|
+
loadFullRows: pick
|
|
2756
|
+
};
|
|
2757
|
+
}
|
|
2758
|
+
async function chunkRowSource(ctx, filter) {
|
|
2759
|
+
try {
|
|
2760
|
+
return await projectedChunkRowSource(ctx, filter);
|
|
2761
|
+
} catch (err) {
|
|
2762
|
+
getLogger().debug(
|
|
2763
|
+
"searchChunksOp: projected SQL unavailable, using full-load fallback: " + (err instanceof Error ? err.message : String(err))
|
|
2764
|
+
);
|
|
2765
|
+
return fullScanChunkRowSource(ctx, filter);
|
|
2766
|
+
}
|
|
2767
|
+
}
|
|
2526
2768
|
async function searchChunksOp(ctx, queryVector, options) {
|
|
2527
2769
|
const {
|
|
2528
2770
|
limit = 10,
|
|
@@ -2530,83 +2772,111 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
2530
2772
|
conversationId,
|
|
2531
2773
|
excludeConversationId,
|
|
2532
2774
|
embeddingModel,
|
|
2533
|
-
chunkCache
|
|
2775
|
+
chunkCache,
|
|
2776
|
+
onStats
|
|
2534
2777
|
} = options || {};
|
|
2535
|
-
const
|
|
2536
|
-
const
|
|
2537
|
-
activeConversations.map((c) => String(c._getRaw("conversation_id")))
|
|
2538
|
-
);
|
|
2539
|
-
const queryConditions = conversationId ? [Q.where("conversation_id", conversationId)] : [];
|
|
2540
|
-
const messages = await ctx.messagesCollection.query(...queryConditions).unsafeFetchRaw();
|
|
2778
|
+
const source = await chunkRowSource(ctx, { conversationId, excludeConversationId });
|
|
2779
|
+
const yieldIfDue = createTimeSliceYielder(CHUNK_SCAN_YIELD_BUDGET_MS);
|
|
2541
2780
|
const candidates = [];
|
|
2542
2781
|
let staleSkipped = 0;
|
|
2543
2782
|
let unreadableVectors = 0;
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
}
|
|
2783
|
+
let cacheHits = 0;
|
|
2784
|
+
const missIds = [];
|
|
2785
|
+
const orderById = /* @__PURE__ */ new Map();
|
|
2786
|
+
for (const [order, key] of source.keys.entries()) {
|
|
2787
|
+
await yieldIfDue();
|
|
2788
|
+
orderById.set(key.id, order);
|
|
2789
|
+
if (embeddingModel && key.embeddingModel !== null && key.embeddingModel !== embeddingModel) {
|
|
2790
|
+
staleSkipped++;
|
|
2791
|
+
continue;
|
|
2554
2792
|
}
|
|
2555
|
-
const
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
if (cached.chunks.length > 0) {
|
|
2559
|
-
for (let ci = 0; ci < cached.chunks.length; ci++) {
|
|
2560
|
-
const vec = cached.chunks[ci];
|
|
2561
|
-
if (vec.length === 0) continue;
|
|
2562
|
-
const similarity = cosineSimilarity(queryVector, vec);
|
|
2563
|
-
if (similarity >= minSimilarity) {
|
|
2564
|
-
candidates.push({
|
|
2565
|
-
message,
|
|
2566
|
-
similarity,
|
|
2567
|
-
chunkTextSource: { kind: "chunk-cached", chunkIndex: ci, version }
|
|
2568
|
-
});
|
|
2569
|
-
}
|
|
2570
|
-
}
|
|
2571
|
-
} else if (cached.fallback) {
|
|
2572
|
-
const similarity = cosineSimilarity(queryVector, cached.fallback);
|
|
2573
|
-
if (similarity >= minSimilarity) {
|
|
2574
|
-
candidates.push({ message, similarity, chunkTextSource: { kind: "message" } });
|
|
2575
|
-
}
|
|
2576
|
-
}
|
|
2793
|
+
const cached = chunkCache?.get(key.id);
|
|
2794
|
+
if (!cached || cached.version !== key.version) {
|
|
2795
|
+
missIds.push(key.id);
|
|
2577
2796
|
continue;
|
|
2578
2797
|
}
|
|
2579
|
-
|
|
2580
|
-
if (
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
unreadableVectors++;
|
|
2584
|
-
})
|
|
2585
|
-
);
|
|
2586
|
-
chunkCache?.set(message.id, { version, chunks: vectors });
|
|
2587
|
-
for (let ci = 0; ci < chunks3.length; ci++) {
|
|
2588
|
-
const vec = vectors[ci];
|
|
2798
|
+
cacheHits++;
|
|
2799
|
+
if (cached.chunks.length > 0) {
|
|
2800
|
+
for (let ci = 0; ci < cached.chunks.length; ci++) {
|
|
2801
|
+
const vec = cached.chunks[ci];
|
|
2589
2802
|
if (vec.length === 0) continue;
|
|
2590
2803
|
const similarity = cosineSimilarity(queryVector, vec);
|
|
2591
2804
|
if (similarity >= minSimilarity) {
|
|
2592
2805
|
candidates.push({
|
|
2593
|
-
|
|
2806
|
+
id: key.id,
|
|
2807
|
+
version: key.version,
|
|
2808
|
+
order,
|
|
2594
2809
|
similarity,
|
|
2595
|
-
chunkTextSource: { kind: "chunk",
|
|
2810
|
+
chunkTextSource: { kind: "chunk-cached", chunkIndex: ci, version: key.version }
|
|
2596
2811
|
});
|
|
2597
2812
|
}
|
|
2598
2813
|
}
|
|
2599
|
-
} else {
|
|
2600
|
-
const
|
|
2601
|
-
if (!messageVector || messageVector.length === 0) continue;
|
|
2602
|
-
const fallback = Float32Array.from(messageVector);
|
|
2603
|
-
chunkCache?.set(message.id, { version, chunks: [], fallback });
|
|
2604
|
-
const similarity = cosineSimilarity(queryVector, fallback);
|
|
2814
|
+
} else if (cached.fallback) {
|
|
2815
|
+
const similarity = cosineSimilarity(queryVector, cached.fallback);
|
|
2605
2816
|
if (similarity >= minSimilarity) {
|
|
2606
|
-
candidates.push({
|
|
2817
|
+
candidates.push({
|
|
2818
|
+
id: key.id,
|
|
2819
|
+
version: key.version,
|
|
2820
|
+
order,
|
|
2821
|
+
similarity,
|
|
2822
|
+
chunkTextSource: { kind: "message" }
|
|
2823
|
+
});
|
|
2607
2824
|
}
|
|
2608
2825
|
}
|
|
2609
2826
|
}
|
|
2827
|
+
let rowsFetched = 0;
|
|
2828
|
+
for (let offset = 0; offset < missIds.length; offset += CHUNK_VECTOR_BATCH_SIZE) {
|
|
2829
|
+
const rows = await source.loadVectorRows(
|
|
2830
|
+
missIds.slice(offset, offset + CHUNK_VECTOR_BATCH_SIZE)
|
|
2831
|
+
);
|
|
2832
|
+
rowsFetched += rows.length;
|
|
2833
|
+
for (const row of rows) {
|
|
2834
|
+
await yieldIfDue();
|
|
2835
|
+
const id = row.id;
|
|
2836
|
+
const version = Number(row.updated_at) || 0;
|
|
2837
|
+
const order = orderById.get(id) ?? Number.MAX_SAFE_INTEGER;
|
|
2838
|
+
const chunks3 = await readRawJsonField(row, "chunks", ctx.walletAddress);
|
|
2839
|
+
if (chunks3 && chunks3.length > 0) {
|
|
2840
|
+
const vectors = chunks3.map(
|
|
2841
|
+
(chunk) => decodeChunkVector(chunk.vector, () => {
|
|
2842
|
+
unreadableVectors++;
|
|
2843
|
+
})
|
|
2844
|
+
);
|
|
2845
|
+
chunkCache?.set(id, { version, chunks: vectors });
|
|
2846
|
+
for (let ci = 0; ci < chunks3.length; ci++) {
|
|
2847
|
+
const vec = vectors[ci];
|
|
2848
|
+
if (vec.length === 0) continue;
|
|
2849
|
+
const similarity = cosineSimilarity(queryVector, vec);
|
|
2850
|
+
if (similarity >= minSimilarity) {
|
|
2851
|
+
candidates.push({
|
|
2852
|
+
id,
|
|
2853
|
+
version,
|
|
2854
|
+
order,
|
|
2855
|
+
similarity,
|
|
2856
|
+
chunkTextSource: { kind: "chunk", chunk: chunks3[ci], siblings: chunks3 }
|
|
2857
|
+
});
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2860
|
+
} else {
|
|
2861
|
+
const messageVector = await readRawJsonField(row, "vector", ctx.walletAddress);
|
|
2862
|
+
if (messageVector && messageVector.length > 0) {
|
|
2863
|
+
const fallback = Float32Array.from(messageVector);
|
|
2864
|
+
chunkCache?.set(id, { version, chunks: [], fallback });
|
|
2865
|
+
const similarity = cosineSimilarity(queryVector, fallback);
|
|
2866
|
+
if (similarity >= minSimilarity) {
|
|
2867
|
+
candidates.push({
|
|
2868
|
+
id,
|
|
2869
|
+
version,
|
|
2870
|
+
order,
|
|
2871
|
+
similarity,
|
|
2872
|
+
chunkTextSource: { kind: "message" }
|
|
2873
|
+
});
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
2879
|
+
onStats?.({ rowsScanned: source.keys.length, rowsFetched, cacheHits });
|
|
2610
2880
|
if (staleSkipped > 0) {
|
|
2611
2881
|
getLogger().warn(
|
|
2612
2882
|
`searchChunksOp: skipped ${staleSkipped} messages whose embedding model differs from the current model (${embeddingModel}) \u2014 re-embed via chunkAndEmbedAllMessages`
|
|
@@ -2617,12 +2887,17 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
2617
2887
|
`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`
|
|
2618
2888
|
);
|
|
2619
2889
|
}
|
|
2620
|
-
const topK = candidates.sort((a, b) => b.similarity - a.similarity).slice(0, limit);
|
|
2621
|
-
const
|
|
2622
|
-
|
|
2890
|
+
const topK = candidates.sort((a, b) => b.similarity - a.similarity || a.order - b.order).slice(0, limit);
|
|
2891
|
+
const topIds = Array.from(new Set(topK.map((c) => c.id)));
|
|
2892
|
+
const fullRows = await source.loadFullRows(topIds);
|
|
2893
|
+
const rowById = new Map(fullRows.map((row) => [row.id, row]));
|
|
2894
|
+
const liveTopK = topK.filter((c) => {
|
|
2895
|
+
const row = rowById.get(c.id);
|
|
2896
|
+
return row !== void 0 && (Number(row.updated_at) || 0) === c.version;
|
|
2897
|
+
});
|
|
2623
2898
|
const storedById = new Map(
|
|
2624
2899
|
await Promise.all(
|
|
2625
|
-
Array.from(
|
|
2900
|
+
Array.from(rowById, async ([id, m]) => {
|
|
2626
2901
|
const stored2 = await messageRawToStored(
|
|
2627
2902
|
m,
|
|
2628
2903
|
ctx.walletAddress,
|
|
@@ -2635,24 +2910,24 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
2635
2910
|
);
|
|
2636
2911
|
const chunkStateByMsgId = /* @__PURE__ */ new Map();
|
|
2637
2912
|
const needsChunkText = /* @__PURE__ */ new Set();
|
|
2638
|
-
for (const c of
|
|
2639
|
-
if (c.chunkTextSource.kind === "chunk-cached") needsChunkText.add(c.
|
|
2913
|
+
for (const c of liveTopK) {
|
|
2914
|
+
if (c.chunkTextSource.kind === "chunk-cached") needsChunkText.add(c.id);
|
|
2640
2915
|
}
|
|
2641
2916
|
await Promise.all(
|
|
2642
2917
|
Array.from(needsChunkText, async (id) => {
|
|
2643
|
-
const m =
|
|
2918
|
+
const m = rowById.get(id);
|
|
2644
2919
|
const parsed = await readRawJsonField(m, "chunks", ctx.walletAddress);
|
|
2645
2920
|
const version = Number(m.updated_at) || 0;
|
|
2646
2921
|
if (parsed) chunkStateByMsgId.set(id, { version, chunks: parsed });
|
|
2647
2922
|
})
|
|
2648
2923
|
);
|
|
2649
|
-
return
|
|
2650
|
-
const stored2 = { ...storedById.get(
|
|
2924
|
+
return liveTopK.map(({ id, similarity, chunkTextSource }) => {
|
|
2925
|
+
const stored2 = { ...storedById.get(id) };
|
|
2651
2926
|
let chunkText2;
|
|
2652
2927
|
if (chunkTextSource.kind === "chunk") {
|
|
2653
2928
|
chunkText2 = resolveChunkText(stored2.content, chunkTextSource.chunk, chunkTextSource.siblings);
|
|
2654
2929
|
} else if (chunkTextSource.kind === "chunk-cached") {
|
|
2655
|
-
const state = chunkStateByMsgId.get(
|
|
2930
|
+
const state = chunkStateByMsgId.get(id);
|
|
2656
2931
|
const chunk = state && state.version === chunkTextSource.version ? state.chunks[chunkTextSource.chunkIndex] : void 0;
|
|
2657
2932
|
chunkText2 = resolveChunkText(stored2.content, chunk, state?.chunks);
|
|
2658
2933
|
} else {
|
|
@@ -3731,13 +4006,35 @@ async function generateEmbedding(text14, options) {
|
|
|
3731
4006
|
if (total === void 0) return embedOne(text14, options, void 0);
|
|
3732
4007
|
return withDeadline((signal) => embedOne(text14, options, signal), total, "embedding");
|
|
3733
4008
|
}
|
|
4009
|
+
var inFlightByCache = /* @__PURE__ */ new WeakMap();
|
|
3734
4010
|
async function embedOne(text14, options, outer) {
|
|
3735
|
-
const {
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
4011
|
+
const { cache } = options;
|
|
4012
|
+
if (!cache) return Array.from(await requestEmbedding(text14, options, outer));
|
|
4013
|
+
const cached = cache.get(text14);
|
|
4014
|
+
if (cached) return Array.from(cached);
|
|
4015
|
+
const inFlight = inFlightByCache.get(cache) ?? /* @__PURE__ */ new Map();
|
|
4016
|
+
inFlightByCache.set(cache, inFlight);
|
|
4017
|
+
const pending = inFlight.get(text14);
|
|
4018
|
+
if (pending) {
|
|
4019
|
+
try {
|
|
4020
|
+
return Array.from(await pending);
|
|
4021
|
+
} catch (err) {
|
|
4022
|
+
if (outer?.aborted) throw err;
|
|
4023
|
+
}
|
|
4024
|
+
}
|
|
4025
|
+
const request = requestEmbedding(text14, options, outer);
|
|
4026
|
+
inFlight.set(text14, request);
|
|
4027
|
+
try {
|
|
4028
|
+
const embedding2 = await request;
|
|
4029
|
+
cache.set(text14, embedding2);
|
|
4030
|
+
return Array.from(embedding2);
|
|
4031
|
+
} finally {
|
|
4032
|
+
if (inFlight.get(text14) === request) inFlight.delete(text14);
|
|
3740
4033
|
}
|
|
4034
|
+
}
|
|
4035
|
+
async function requestEmbedding(text14, options, outer) {
|
|
4036
|
+
const { baseUrl = BASE_URL, model } = options;
|
|
4037
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_EMBEDDING_REQUEST_TIMEOUT_MS;
|
|
3741
4038
|
const headers = {
|
|
3742
4039
|
...await resolveAuthHeaders(options, outer),
|
|
3743
4040
|
...taskTypeHeader(options.taskType)
|
|
@@ -3772,11 +4069,7 @@ async function embedOne(text14, options, outer) {
|
|
|
3772
4069
|
totalTokens: response.data.usage.total_tokens ?? 0
|
|
3773
4070
|
});
|
|
3774
4071
|
}
|
|
3775
|
-
|
|
3776
|
-
if (cache) {
|
|
3777
|
-
cache.set(text14, f32Embedding);
|
|
3778
|
-
}
|
|
3779
|
-
return Array.from(f32Embedding);
|
|
4072
|
+
return Float32Array.from(embedding2);
|
|
3780
4073
|
}
|
|
3781
4074
|
var DEFAULT_EMBEDDING_BATCH_SIZE = 100;
|
|
3782
4075
|
var DEFAULT_EMBEDDING_BATCH_CONCURRENCY = 3;
|
|
@@ -4174,7 +4467,8 @@ function extractReservationReceipts(toolCallEvents) {
|
|
|
4174
4467
|
for (const event of toolCallEvents ?? []) {
|
|
4175
4468
|
const action = ACTIONS.find((a) => event.name?.endsWith(a.tool));
|
|
4176
4469
|
const output = event.output ?? "";
|
|
4177
|
-
if (!action || !output || NOT_AN_ATTEMPT.test(output))
|
|
4470
|
+
if (!action || !output || hasEncryptedToolPayload(event) || NOT_AN_ATTEMPT.test(output))
|
|
4471
|
+
continue;
|
|
4178
4472
|
const kept = latest.get(action.kind)?.status;
|
|
4179
4473
|
if (kept === "made") continue;
|
|
4180
4474
|
const receipt = toReceipt(action, event.arguments ?? "", output);
|
|
@@ -9257,8 +9551,12 @@ var MaskScopedEmbeddingCache = class extends Map {
|
|
|
9257
9551
|
return this;
|
|
9258
9552
|
}
|
|
9259
9553
|
};
|
|
9554
|
+
var scopedViews = /* @__PURE__ */ new WeakMap();
|
|
9260
9555
|
function maskScopedEmbeddingCache(cache, masked) {
|
|
9261
|
-
|
|
9556
|
+
const views = scopedViews.get(cache) ?? {};
|
|
9557
|
+
scopedViews.set(cache, views);
|
|
9558
|
+
const slot = masked ? "masked" : "raw";
|
|
9559
|
+
return views[slot] ?? (views[slot] = new MaskScopedEmbeddingCache(cache, masked));
|
|
9262
9560
|
}
|
|
9263
9561
|
|
|
9264
9562
|
// src/lib/db/conversationMemory/models.ts
|
|
@@ -13602,9 +13900,9 @@ function recencyMultiplier(updatedAt, opts = {}) {
|
|
|
13602
13900
|
const updatedMs = updatedAt.getTime();
|
|
13603
13901
|
if (!Number.isFinite(updatedMs)) return noDate;
|
|
13604
13902
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
13605
|
-
const
|
|
13606
|
-
if (!Number.isFinite(
|
|
13607
|
-
const ageDays2 = Math.max(0, (
|
|
13903
|
+
const nowMs2 = now.getTime();
|
|
13904
|
+
if (!Number.isFinite(nowMs2)) return noDate;
|
|
13905
|
+
const ageDays2 = Math.max(0, (nowMs2 - updatedMs) / DAY_MS2);
|
|
13608
13906
|
const perYearDecay = opts.perYearDecay ?? DEFAULT_PER_YEAR_DECAY;
|
|
13609
13907
|
const floor = opts.floor ?? DEFAULT_FLOOR;
|
|
13610
13908
|
const decay = perYearDecay * (ageDays2 / 365);
|
|
@@ -14113,9 +14411,6 @@ function createVaultEmbeddingCache(maxSize = DEFAULT_VAULT_CACHE_SIZE) {
|
|
|
14113
14411
|
|
|
14114
14412
|
// src/lib/memoryVault/searchTool.ts
|
|
14115
14413
|
var DEFAULT_RERANK_TOP_N = 5;
|
|
14116
|
-
function nowMs() {
|
|
14117
|
-
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
14118
|
-
}
|
|
14119
14414
|
var warnedProgrammaticDecomposeIgnored = false;
|
|
14120
14415
|
function normalizeEventTimeKind(kind) {
|
|
14121
14416
|
return kind === "point" || kind === "range" || kind === "ongoing" ? kind : null;
|
|
@@ -17213,9 +17508,6 @@ function scoreEventTimeOverlap(memoryStart, memoryEnd, memoryKind, window2) {
|
|
|
17213
17508
|
var DEFAULT_LIMIT = 8;
|
|
17214
17509
|
var DEFAULT_BUDGET = "low";
|
|
17215
17510
|
var DEFAULT_FACT_MIN_SCORE = 0.1;
|
|
17216
|
-
function nowMs2() {
|
|
17217
|
-
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
17218
|
-
}
|
|
17219
17511
|
var DEFAULT_CHUNK_MIN_SCORE = 0.5;
|
|
17220
17512
|
var DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS = 8e3;
|
|
17221
17513
|
function flagsForBudget(budget) {
|
|
@@ -17253,12 +17545,19 @@ async function recall(query, ctx, options = {}) {
|
|
|
17253
17545
|
const subQueries = normalizedFacets.length >= 2 ? normalizedFacets : void 0;
|
|
17254
17546
|
const embeddingOptions = {
|
|
17255
17547
|
...ctx.embeddingOptions,
|
|
17256
|
-
taskType: "memory_recall_embed"
|
|
17548
|
+
taskType: "memory_recall_embed",
|
|
17549
|
+
...options.embeddingCache && !ctx.embeddingOptions.cache && {
|
|
17550
|
+
cache: maskScopedEmbeddingCache(
|
|
17551
|
+
options.embeddingCache,
|
|
17552
|
+
Boolean(ctx.embeddingOptions.maskInput)
|
|
17553
|
+
)
|
|
17554
|
+
}
|
|
17257
17555
|
};
|
|
17258
|
-
const t0 =
|
|
17556
|
+
const t0 = nowMs();
|
|
17259
17557
|
let prepMs = 0;
|
|
17260
17558
|
let factLaneMs = 0;
|
|
17261
17559
|
let chunkLaneMs = 0;
|
|
17560
|
+
let chunkStats;
|
|
17262
17561
|
let fuseMs = 0;
|
|
17263
17562
|
const factResults = [];
|
|
17264
17563
|
const chunkResults = [];
|
|
@@ -17313,6 +17612,11 @@ async function recall(query, ctx, options = {}) {
|
|
|
17313
17612
|
...decryptLastRan !== void 0 && { decryptLast: decryptLastRan },
|
|
17314
17613
|
...vaultRowsDecrypted !== void 0 && { vaultRowsDecrypted },
|
|
17315
17614
|
...vaultRowsEmbedded !== void 0 && { vaultRowsEmbedded },
|
|
17615
|
+
...chunkStats && {
|
|
17616
|
+
chunkRowsScanned: chunkStats.rowsScanned,
|
|
17617
|
+
chunkRowsFetched: chunkStats.rowsFetched,
|
|
17618
|
+
chunkCacheHits: chunkStats.cacheHits
|
|
17619
|
+
},
|
|
17316
17620
|
factCount: factResults.length,
|
|
17317
17621
|
chunkCount: chunkResults.length,
|
|
17318
17622
|
admittedCount: admitted.length,
|
|
@@ -17324,7 +17628,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
17324
17628
|
temporalLaneCount,
|
|
17325
17629
|
emptyReason: emptyReasonFor(admitted.length, laneRan),
|
|
17326
17630
|
timings: {
|
|
17327
|
-
total:
|
|
17631
|
+
total: nowMs() - t0,
|
|
17328
17632
|
prep: prepMs,
|
|
17329
17633
|
factLane: factLaneMs,
|
|
17330
17634
|
rerank: rerankMs,
|
|
@@ -17346,14 +17650,14 @@ async function recall(query, ctx, options = {}) {
|
|
|
17346
17650
|
const needsChunkEmbedding = types.includes("chunk") && ctx.storageCtx;
|
|
17347
17651
|
const wantsTemporal = types.includes("fact") && (ctx.factSource || ctx.vaultCtx);
|
|
17348
17652
|
const queryEmbedTotalTimeoutMs = options.queryEmbedTotalTimeoutMs ?? DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS;
|
|
17349
|
-
const prepStart =
|
|
17653
|
+
const prepStart = nowMs();
|
|
17350
17654
|
let sharedEmbedMs = 0;
|
|
17351
17655
|
const [queryEmbedding, entityRanking, temporalRanking] = await Promise.all([
|
|
17352
17656
|
needsChunkEmbedding ? generateEmbedding(query, {
|
|
17353
17657
|
...embeddingOptions,
|
|
17354
17658
|
totalTimeoutMs: queryEmbedTotalTimeoutMs
|
|
17355
17659
|
}).finally(() => {
|
|
17356
|
-
sharedEmbedMs =
|
|
17660
|
+
sharedEmbedMs = nowMs() - prepStart;
|
|
17357
17661
|
}).then((vec) => {
|
|
17358
17662
|
if (vec.length === 0) {
|
|
17359
17663
|
getLogger().warn(
|
|
@@ -17386,11 +17690,11 @@ async function recall(query, ctx, options = {}) {
|
|
|
17386
17690
|
() => ctx.factSource ? ctx.factSource.temporalRanking(query, options.now) : buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)
|
|
17387
17691
|
) : Promise.resolve([])
|
|
17388
17692
|
]);
|
|
17389
|
-
prepMs =
|
|
17693
|
+
prepMs = nowMs() - prepStart;
|
|
17390
17694
|
graphLaneCount = entityRanking.length;
|
|
17391
17695
|
temporalLaneCount = temporalRanking.length;
|
|
17392
17696
|
if (types.includes("fact") && (ctx.factSource || ctx.vaultCtx && ctx.vaultCache)) {
|
|
17393
|
-
const factStart =
|
|
17697
|
+
const factStart = nowMs();
|
|
17394
17698
|
const vaultMinScore = options.minScore ?? DEFAULT_FACT_MIN_SCORE;
|
|
17395
17699
|
factFloor = vaultMinScore;
|
|
17396
17700
|
const {
|
|
@@ -17466,11 +17770,11 @@ async function recall(query, ctx, options = {}) {
|
|
|
17466
17770
|
factLaneRankedOnCosine = factRankedOnCosine;
|
|
17467
17771
|
decryptLastRan = factDecryptLast;
|
|
17468
17772
|
vaultRowsDecrypted = factRowsDecrypted;
|
|
17469
|
-
factLaneMs =
|
|
17773
|
+
factLaneMs = nowMs() - factStart;
|
|
17470
17774
|
}
|
|
17471
17775
|
if (chunkEmbedFailed && !factLaneRankedOnCosine) embeddingsUnavailable = true;
|
|
17472
17776
|
if (types.includes("chunk") && ctx.storageCtx && queryEmbedding) {
|
|
17473
|
-
const chunkStart =
|
|
17777
|
+
const chunkStart = nowMs();
|
|
17474
17778
|
const chunkMinScore = options.minScore ?? DEFAULT_CHUNK_MIN_SCORE;
|
|
17475
17779
|
chunkFloor = chunkMinScore;
|
|
17476
17780
|
const results = await searchChunksOp(ctx.storageCtx, queryEmbedding, {
|
|
@@ -17481,12 +17785,15 @@ async function recall(query, ctx, options = {}) {
|
|
|
17481
17785
|
...options.excludeConversationId && {
|
|
17482
17786
|
excludeConversationId: options.excludeConversationId
|
|
17483
17787
|
},
|
|
17484
|
-
...ctx.chunkCache && { chunkCache: ctx.chunkCache }
|
|
17788
|
+
...ctx.chunkCache && { chunkCache: ctx.chunkCache },
|
|
17789
|
+
onStats: (stats) => {
|
|
17790
|
+
chunkStats = stats;
|
|
17791
|
+
}
|
|
17485
17792
|
});
|
|
17486
17793
|
chunkResults.push(...dedupeBy(results, (r) => r.chunkText.trim()));
|
|
17487
|
-
chunkLaneMs =
|
|
17794
|
+
chunkLaneMs = nowMs() - chunkStart;
|
|
17488
17795
|
}
|
|
17489
|
-
const fuseStart =
|
|
17796
|
+
const fuseStart = nowMs();
|
|
17490
17797
|
if (types.length === 1 || factResults.length === 0 || chunkResults.length === 0) {
|
|
17491
17798
|
const memories2 = [
|
|
17492
17799
|
...factResults.map((r) => toFactMemory(r, options.now)),
|
|
@@ -17494,7 +17801,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
17494
17801
|
];
|
|
17495
17802
|
memories2.sort((a, b) => b.score - a.score);
|
|
17496
17803
|
const candidateCount = factResults.length + chunkResults.length;
|
|
17497
|
-
fuseMs =
|
|
17804
|
+
fuseMs = nowMs() - fuseStart;
|
|
17498
17805
|
const admitted = memories2.slice(0, limit);
|
|
17499
17806
|
hitLimit = memories2.length > limit;
|
|
17500
17807
|
emitDiagnostics(candidateCount, admitted);
|
|
@@ -17558,7 +17865,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
17558
17865
|
memories = selection.out;
|
|
17559
17866
|
}
|
|
17560
17867
|
hitLimit = selection.cut;
|
|
17561
|
-
fuseMs =
|
|
17868
|
+
fuseMs = nowMs() - fuseStart;
|
|
17562
17869
|
emitDiagnostics(byId.size, memories);
|
|
17563
17870
|
return {
|
|
17564
17871
|
memories,
|
|
@@ -25169,11 +25476,12 @@ function storedToLlmapiMessage(stored2) {
|
|
|
25169
25476
|
}
|
|
25170
25477
|
}
|
|
25171
25478
|
const messages = [];
|
|
25172
|
-
|
|
25479
|
+
const toolCallEvents = Array.isArray(stored2.toolCallEvents) ? stored2.toolCallEvents.filter((event) => !hasEncryptedToolPayload(event)) : [];
|
|
25480
|
+
if (stored2.role === "assistant" && toolCallEvents.length) {
|
|
25173
25481
|
messages.push({
|
|
25174
25482
|
role: stored2.role,
|
|
25175
25483
|
content: void 0,
|
|
25176
|
-
tool_calls:
|
|
25484
|
+
tool_calls: toolCallEvents.map((event) => ({
|
|
25177
25485
|
id: event.id,
|
|
25178
25486
|
type: "function",
|
|
25179
25487
|
function: {
|
|
@@ -25182,7 +25490,7 @@ function storedToLlmapiMessage(stored2) {
|
|
|
25182
25490
|
}
|
|
25183
25491
|
}))
|
|
25184
25492
|
});
|
|
25185
|
-
for (const event of
|
|
25493
|
+
for (const event of toolCallEvents) {
|
|
25186
25494
|
if (event.id && event.output !== void 0 && event.output !== null) {
|
|
25187
25495
|
messages.push({
|
|
25188
25496
|
role: "tool",
|
|
@@ -27185,6 +27493,7 @@ export {
|
|
|
27185
27493
|
embedAllMessages,
|
|
27186
27494
|
embedMessage,
|
|
27187
27495
|
encodeChunkVector,
|
|
27496
|
+
encryptToolCallEventsOp,
|
|
27188
27497
|
ensureDefaultFoldersOp,
|
|
27189
27498
|
exchangeNotionCode,
|
|
27190
27499
|
extractAndLinkEntitiesForMemoriesOp,
|