@anuma/sdk 4.2.0 → 5.0.0
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/{chunk-VBO6KSNQ.mjs → chunk-SIMGZQ4P.mjs} +480 -196
- package/dist/expo/index.cjs +417 -120
- package/dist/expo/index.d.mts +161 -26
- package/dist/expo/index.d.ts +161 -26
- package/dist/expo/index.mjs +22 -6
- package/dist/expo/{recall-OCQOA7M3.mjs → recall-PIDYDFIQ.mjs} +1 -1
- package/dist/index.cjs +31 -17
- package/dist/index.mjs +31 -17
- package/dist/react/{chunk-BS7C4CUW.mjs → chunk-KTBOHRRE.mjs} +480 -196
- package/dist/react/index.cjs +417 -120
- package/dist/react/index.d.mts +155 -26
- package/dist/react/index.d.ts +155 -26
- package/dist/react/index.mjs +22 -6
- package/dist/react/{recall-WXCZHXHZ.mjs → recall-DVX4W2UD.mjs} +1 -1
- package/dist/server/{chunk-WADHFDMA.mjs → chunk-FKVYUOSD.mjs} +480 -196
- package/dist/server/index.cjs +417 -120
- package/dist/server/index.d.mts +154 -25
- package/dist/server/index.d.ts +154 -25
- package/dist/server/index.mjs +22 -6
- package/dist/server/{recall-QTVT7HCZ.mjs → recall-74L75BJ3.mjs} +1 -1
- package/package.json +1 -1
package/dist/expo/index.cjs
CHANGED
|
@@ -112,14 +112,11 @@ function notifyKeyAvailable(address) {
|
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
-
function getStoredKey(address) {
|
|
116
|
-
const keys = encryptionKeyStore.get(address);
|
|
117
|
-
return keys?.current ?? null;
|
|
118
|
-
}
|
|
119
115
|
function getStoredKeyByVersion(address, version) {
|
|
120
116
|
const keys = encryptionKeyStore.get(address);
|
|
121
117
|
if (!keys) return null;
|
|
122
|
-
|
|
118
|
+
const value = version === "v2" ? keys.legacy : keys.current;
|
|
119
|
+
return value ?? null;
|
|
123
120
|
}
|
|
124
121
|
function setStoredKey(address, keys) {
|
|
125
122
|
encryptionKeyStore.set(address, keys);
|
|
@@ -128,6 +125,8 @@ function clearEncryptionKey(address) {
|
|
|
128
125
|
encryptionKeyStore.delete(address);
|
|
129
126
|
cryptoKeyCache.delete(`${address}:v2`);
|
|
130
127
|
cryptoKeyCache.delete(`${address}:v3`);
|
|
128
|
+
refreshCandidatesByAddress.delete(address);
|
|
129
|
+
divergentDeriveAddresses.delete(address);
|
|
131
130
|
}
|
|
132
131
|
function clearAllEncryptionState() {
|
|
133
132
|
sessionEpoch += 1;
|
|
@@ -135,6 +134,9 @@ function clearAllEncryptionState() {
|
|
|
135
134
|
cryptoKeyCache.clear();
|
|
136
135
|
keyAvailableCallbacks.clear();
|
|
137
136
|
pendingKeyRequests.clear();
|
|
137
|
+
pendingCandidateDerives.clear();
|
|
138
|
+
refreshCandidatesByAddress.clear();
|
|
139
|
+
divergentDeriveAddresses.clear();
|
|
138
140
|
clearAllKeyPairs();
|
|
139
141
|
for (const cb of clearAllEncryptionStateCallbacks) {
|
|
140
142
|
try {
|
|
@@ -318,9 +320,7 @@ async function getEncryptionKey(address, version = "v3") {
|
|
|
318
320
|
}
|
|
319
321
|
const keyHex = getStoredKeyByVersion(address, version);
|
|
320
322
|
if (!keyHex) {
|
|
321
|
-
throw new
|
|
322
|
-
"Encryption key not found. Please sign a message to generate your encryption key."
|
|
323
|
-
);
|
|
323
|
+
throw new EncryptionKeyMissingError(address, version);
|
|
324
324
|
}
|
|
325
325
|
const keyBytes = hexToBytes(keyHex);
|
|
326
326
|
const cryptoKey = await crypto.subtle.importKey(
|
|
@@ -346,8 +346,42 @@ async function decryptData(encryptedHex, address, version = "v3") {
|
|
|
346
346
|
const key = await getEncryptionKey(address, version);
|
|
347
347
|
return decryptDataWithKey(encryptedHex, key);
|
|
348
348
|
}
|
|
349
|
-
function hasEncryptionKey(address) {
|
|
350
|
-
return
|
|
349
|
+
function hasEncryptionKey(address, version) {
|
|
350
|
+
return getStoredKeyByVersion(address, version ?? "v3") !== null;
|
|
351
|
+
}
|
|
352
|
+
function seedEncryptionKeys(address, keys) {
|
|
353
|
+
if (!isValidWalletAddress(address)) {
|
|
354
|
+
throw new Error(
|
|
355
|
+
`Invalid wallet address: ${address}. Address must start with 0x and be 42 characters (0x + 40 hex characters).`
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
if (!keys.legacy && !keys.current) {
|
|
359
|
+
throw new Error("seedEncryptionKeys: at least one of legacy or current is required");
|
|
360
|
+
}
|
|
361
|
+
if (keys.legacy !== void 0) {
|
|
362
|
+
assertAes256KeyHex("legacy", keys.legacy);
|
|
363
|
+
}
|
|
364
|
+
if (keys.current !== void 0) {
|
|
365
|
+
assertAes256KeyHex("current", keys.current);
|
|
366
|
+
}
|
|
367
|
+
const existing = encryptionKeyStore.get(address);
|
|
368
|
+
const next = {
|
|
369
|
+
legacy: keys.legacy ?? existing?.legacy,
|
|
370
|
+
current: keys.current ?? existing?.current
|
|
371
|
+
};
|
|
372
|
+
setStoredKey(address, next);
|
|
373
|
+
if (keys.legacy !== void 0) cryptoKeyCache.delete(`${address}:v2`);
|
|
374
|
+
if (keys.current !== void 0) cryptoKeyCache.delete(`${address}:v3`);
|
|
375
|
+
refreshCandidatesByAddress.delete(address);
|
|
376
|
+
divergentDeriveAddresses.delete(address);
|
|
377
|
+
notifyKeyAvailable(address);
|
|
378
|
+
}
|
|
379
|
+
function assertAes256KeyHex(field10, value) {
|
|
380
|
+
if (!AES_256_KEY_HEX.test(value)) {
|
|
381
|
+
throw new Error(
|
|
382
|
+
`seedEncryptionKeys: ${field10} must be 64 hex characters (32-byte AES key), got length ${value.length}`
|
|
383
|
+
);
|
|
384
|
+
}
|
|
351
385
|
}
|
|
352
386
|
async function encryptBytesWithKey(plaintext, key) {
|
|
353
387
|
const plaintextBytes = typeof plaintext === "string" ? SHARED_TEXT_ENCODER.encode(plaintext) : plaintext;
|
|
@@ -383,20 +417,23 @@ async function decryptDataWithKey(encryptedHex, key) {
|
|
|
383
417
|
);
|
|
384
418
|
return SHARED_TEXT_DECODER.decode(decryptedData);
|
|
385
419
|
}
|
|
386
|
-
async function requestEncryptionKey(walletAddress, signMessage, embeddedWalletSigner) {
|
|
420
|
+
async function requestEncryptionKey(walletAddress, signMessage, embeddedWalletSigner, options) {
|
|
387
421
|
if (!isValidWalletAddress(walletAddress)) {
|
|
388
422
|
throw new Error(
|
|
389
423
|
`Invalid wallet address: ${walletAddress}. Address must start with 0x and be 42 characters (0x + 40 hex characters).`
|
|
390
424
|
);
|
|
391
425
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
return;
|
|
426
|
+
if (!options?.force && getStoredKeyByVersion(walletAddress, "v3") && getStoredKeyByVersion(walletAddress, "v2")) {
|
|
427
|
+
return true;
|
|
395
428
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
429
|
+
if (!options?.force && divergentDeriveAddresses.has(walletAddress)) {
|
|
430
|
+
return false;
|
|
431
|
+
}
|
|
432
|
+
if (!options?.force) {
|
|
433
|
+
const pending = pendingKeyRequests.get(walletAddress);
|
|
434
|
+
if (pending) {
|
|
435
|
+
return pending;
|
|
436
|
+
}
|
|
400
437
|
}
|
|
401
438
|
const startEpoch = sessionEpoch;
|
|
402
439
|
const promise = (async () => {
|
|
@@ -424,20 +461,143 @@ async function requestEncryptionKey(walletAddress, signMessage, embeddedWalletSi
|
|
|
424
461
|
deriveKeyFromSignatureV3(signature)
|
|
425
462
|
]);
|
|
426
463
|
if (sessionEpoch !== startEpoch) {
|
|
427
|
-
return;
|
|
464
|
+
return false;
|
|
428
465
|
}
|
|
429
|
-
|
|
466
|
+
const existing = encryptionKeyStore.get(walletAddress);
|
|
467
|
+
if (!options?.force && existing && (existing.legacy || existing.current)) {
|
|
468
|
+
const matchesCurrent = Boolean(existing.current && existing.current === currentKey);
|
|
469
|
+
const matchesLegacy = Boolean(existing.legacy && existing.legacy === legacyKey);
|
|
470
|
+
if (!matchesCurrent && !matchesLegacy) {
|
|
471
|
+
getLogger().warn(
|
|
472
|
+
"requestEncryptionKey: derived keys do not match existing store; leaving unchanged"
|
|
473
|
+
);
|
|
474
|
+
divergentDeriveAddresses.add(walletAddress);
|
|
475
|
+
return false;
|
|
476
|
+
}
|
|
477
|
+
setStoredKey(walletAddress, {
|
|
478
|
+
legacy: existing.legacy ?? legacyKey,
|
|
479
|
+
current: existing.current ?? currentKey
|
|
480
|
+
});
|
|
481
|
+
} else {
|
|
482
|
+
setStoredKey(walletAddress, { legacy: legacyKey, current: currentKey });
|
|
483
|
+
}
|
|
484
|
+
cryptoKeyCache.delete(`${walletAddress}:v2`);
|
|
485
|
+
cryptoKeyCache.delete(`${walletAddress}:v3`);
|
|
486
|
+
refreshCandidatesByAddress.delete(walletAddress);
|
|
487
|
+
divergentDeriveAddresses.delete(walletAddress);
|
|
430
488
|
notifyKeyAvailable(walletAddress);
|
|
489
|
+
return true;
|
|
431
490
|
})();
|
|
432
491
|
pendingKeyRequests.set(walletAddress, promise);
|
|
433
492
|
try {
|
|
434
|
-
await promise;
|
|
493
|
+
return await promise;
|
|
435
494
|
} finally {
|
|
436
495
|
if (pendingKeyRequests.get(walletAddress) === promise) {
|
|
437
496
|
pendingKeyRequests.delete(walletAddress);
|
|
438
497
|
}
|
|
439
498
|
}
|
|
440
499
|
}
|
|
500
|
+
async function refreshEncryptionKeyIfMatches(walletAddress, probeCiphertext, signMessage, embeddedWalletSigner) {
|
|
501
|
+
if (!isValidWalletAddress(walletAddress)) {
|
|
502
|
+
throw new Error(
|
|
503
|
+
`Invalid wallet address: ${walletAddress}. Address must start with 0x and be 42 characters (0x + 40 hex characters).`
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
const parsed = parsePrefixedCiphertext(probeCiphertext);
|
|
507
|
+
if (!parsed) {
|
|
508
|
+
return false;
|
|
509
|
+
}
|
|
510
|
+
const cached = refreshCandidatesByAddress.get(walletAddress);
|
|
511
|
+
if (cached) {
|
|
512
|
+
return tryCommitCandidatesIfProbeMatches(walletAddress, parsed, cached);
|
|
513
|
+
}
|
|
514
|
+
let derivePromise = pendingCandidateDerives.get(walletAddress);
|
|
515
|
+
if (!derivePromise) {
|
|
516
|
+
derivePromise = (async () => {
|
|
517
|
+
const candidates2 = await deriveRefreshCandidates(signMessage, embeddedWalletSigner);
|
|
518
|
+
if (candidates2) {
|
|
519
|
+
refreshCandidatesByAddress.set(walletAddress, candidates2);
|
|
520
|
+
}
|
|
521
|
+
return candidates2;
|
|
522
|
+
})().finally(() => {
|
|
523
|
+
if (pendingCandidateDerives.get(walletAddress) === derivePromise) {
|
|
524
|
+
pendingCandidateDerives.delete(walletAddress);
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
pendingCandidateDerives.set(walletAddress, derivePromise);
|
|
528
|
+
}
|
|
529
|
+
const candidates = await derivePromise;
|
|
530
|
+
if (!candidates) {
|
|
531
|
+
return false;
|
|
532
|
+
}
|
|
533
|
+
return tryCommitCandidatesIfProbeMatches(walletAddress, parsed, candidates);
|
|
534
|
+
}
|
|
535
|
+
function parsePrefixedCiphertext(probeCiphertext) {
|
|
536
|
+
const version = probeCiphertext.startsWith("enc:v3:") ? "v3" : probeCiphertext.startsWith("enc:v2:") ? "v2" : null;
|
|
537
|
+
if (!version) return null;
|
|
538
|
+
const encryptedData = probeCiphertext.slice(
|
|
539
|
+
version === "v3" ? "enc:v3:".length : "enc:v2:".length
|
|
540
|
+
);
|
|
541
|
+
if (encryptedData.length < 56 || !/^[0-9a-f]+$/i.test(encryptedData)) {
|
|
542
|
+
return null;
|
|
543
|
+
}
|
|
544
|
+
return { version, encryptedData };
|
|
545
|
+
}
|
|
546
|
+
async function deriveRefreshCandidates(signMessage, embeddedWalletSigner) {
|
|
547
|
+
const startEpoch = sessionEpoch;
|
|
548
|
+
const signOptions = { showWalletUIs: false };
|
|
549
|
+
let signature;
|
|
550
|
+
try {
|
|
551
|
+
if (embeddedWalletSigner) {
|
|
552
|
+
signature = await embeddedWalletSigner(SIGN_MESSAGE, signOptions);
|
|
553
|
+
} else {
|
|
554
|
+
signature = await signMessage(SIGN_MESSAGE, signOptions);
|
|
555
|
+
}
|
|
556
|
+
} catch (error) {
|
|
557
|
+
if (embeddedWalletSigner && error instanceof Error) {
|
|
558
|
+
getLogger().warn(
|
|
559
|
+
"Embedded wallet signing failed during key refresh, falling back to standard signMessage:",
|
|
560
|
+
error.message
|
|
561
|
+
);
|
|
562
|
+
signature = await signMessage(SIGN_MESSAGE, signOptions);
|
|
563
|
+
} else {
|
|
564
|
+
throw error;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
const [legacyKey, currentKey] = await Promise.all([
|
|
568
|
+
deriveKeyFromSignature(signature),
|
|
569
|
+
deriveKeyFromSignatureV3(signature)
|
|
570
|
+
]);
|
|
571
|
+
if (sessionEpoch !== startEpoch) {
|
|
572
|
+
return null;
|
|
573
|
+
}
|
|
574
|
+
return { legacy: legacyKey, current: currentKey };
|
|
575
|
+
}
|
|
576
|
+
async function tryCommitCandidatesIfProbeMatches(walletAddress, parsed, candidates) {
|
|
577
|
+
const candidateHex = parsed.version === "v2" ? candidates.legacy : candidates.current;
|
|
578
|
+
const keyBytes = hexToBytes(candidateHex);
|
|
579
|
+
const candidateCryptoKey = await crypto.subtle.importKey(
|
|
580
|
+
"raw",
|
|
581
|
+
keyBytes.buffer,
|
|
582
|
+
{ name: "AES-GCM" },
|
|
583
|
+
false,
|
|
584
|
+
["encrypt", "decrypt"]
|
|
585
|
+
);
|
|
586
|
+
try {
|
|
587
|
+
await decryptDataWithKey(parsed.encryptedData, candidateCryptoKey);
|
|
588
|
+
} catch {
|
|
589
|
+
getLogger().warn(
|
|
590
|
+
"refreshEncryptionKeyIfMatches: candidate keys failed to decrypt probe; leaving store unchanged"
|
|
591
|
+
);
|
|
592
|
+
return false;
|
|
593
|
+
}
|
|
594
|
+
setStoredKey(walletAddress, { legacy: candidates.legacy, current: candidates.current });
|
|
595
|
+
cryptoKeyCache.delete(`${walletAddress}:v2`);
|
|
596
|
+
cryptoKeyCache.delete(`${walletAddress}:v3`);
|
|
597
|
+
divergentDeriveAddresses.delete(walletAddress);
|
|
598
|
+
notifyKeyAvailable(walletAddress);
|
|
599
|
+
return true;
|
|
600
|
+
}
|
|
441
601
|
async function persistKeyPair(address, startEpoch) {
|
|
442
602
|
if (typeof window === "undefined") {
|
|
443
603
|
return;
|
|
@@ -671,15 +831,28 @@ function useEncryption(signMessage, embeddedWalletSigner) {
|
|
|
671
831
|
clearKeyPair: (walletAddress) => clearKeyPair(walletAddress)
|
|
672
832
|
};
|
|
673
833
|
}
|
|
674
|
-
var SIGN_MESSAGE, encryptionKeyStore, pendingKeyRequests, sessionEpoch, cryptoKeyCache, keyAvailableCallbacks, clearAllEncryptionStateCallbacks, keyPairStore, SHARED_TEXT_ENCODER, SHARED_TEXT_DECODER, KEYPAIR_STORAGE_PREFIX;
|
|
834
|
+
var SIGN_MESSAGE, EncryptionKeyMissingError, encryptionKeyStore, pendingKeyRequests, pendingCandidateDerives, refreshCandidatesByAddress, divergentDeriveAddresses, sessionEpoch, cryptoKeyCache, keyAvailableCallbacks, clearAllEncryptionStateCallbacks, keyPairStore, SHARED_TEXT_ENCODER, SHARED_TEXT_DECODER, AES_256_KEY_HEX, KEYPAIR_STORAGE_PREFIX;
|
|
675
835
|
var init_useEncryption = __esm({
|
|
676
836
|
"src/react/useEncryption.ts"() {
|
|
677
837
|
"use strict";
|
|
678
838
|
"use client";
|
|
679
839
|
init_logger();
|
|
680
840
|
SIGN_MESSAGE = "The app is asking you to sign this message to generate a key, which will be used to encrypt data.";
|
|
841
|
+
EncryptionKeyMissingError = class extends Error {
|
|
842
|
+
constructor(address, version) {
|
|
843
|
+
super(
|
|
844
|
+
`Encryption key (${version}) not found for ${address}. Please sign a message to generate your encryption key.`
|
|
845
|
+
);
|
|
846
|
+
this.name = "EncryptionKeyMissingError";
|
|
847
|
+
this.address = address;
|
|
848
|
+
this.version = version;
|
|
849
|
+
}
|
|
850
|
+
};
|
|
681
851
|
encryptionKeyStore = /* @__PURE__ */ new Map();
|
|
682
852
|
pendingKeyRequests = /* @__PURE__ */ new Map();
|
|
853
|
+
pendingCandidateDerives = /* @__PURE__ */ new Map();
|
|
854
|
+
refreshCandidatesByAddress = /* @__PURE__ */ new Map();
|
|
855
|
+
divergentDeriveAddresses = /* @__PURE__ */ new Set();
|
|
683
856
|
sessionEpoch = 0;
|
|
684
857
|
cryptoKeyCache = /* @__PURE__ */ new Map();
|
|
685
858
|
keyAvailableCallbacks = /* @__PURE__ */ new Map();
|
|
@@ -687,6 +860,7 @@ var init_useEncryption = __esm({
|
|
|
687
860
|
keyPairStore = /* @__PURE__ */ new Map();
|
|
688
861
|
SHARED_TEXT_ENCODER = new TextEncoder();
|
|
689
862
|
SHARED_TEXT_DECODER = new TextDecoder();
|
|
863
|
+
AES_256_KEY_HEX = /^[0-9a-fA-F]{64}$/;
|
|
690
864
|
KEYPAIR_STORAGE_PREFIX = "ecdh_keypair_";
|
|
691
865
|
}
|
|
692
866
|
});
|
|
@@ -739,20 +913,29 @@ async function encryptField(value, address, signMessage, embeddedWalletSigner, s
|
|
|
739
913
|
const encrypted = await encryptData(value, address);
|
|
740
914
|
return `${ENCRYPTION_PREFIX}${encrypted}`;
|
|
741
915
|
}
|
|
742
|
-
async function
|
|
743
|
-
if (!value) return value;
|
|
916
|
+
async function decryptFieldDetailed(value, address) {
|
|
917
|
+
if (!value) return { status: "plaintext", value };
|
|
744
918
|
const detected = detectEncryptionVersion(value);
|
|
745
|
-
if (!detected) return value;
|
|
919
|
+
if (!detected) return { status: "plaintext", value };
|
|
746
920
|
if (detected.encryptedData.length < 56 || !/^[0-9a-f]+$/i.test(detected.encryptedData)) {
|
|
747
|
-
return value;
|
|
921
|
+
return { status: "invalid_payload", value, version: detected.version };
|
|
748
922
|
}
|
|
749
923
|
try {
|
|
750
|
-
|
|
924
|
+
const plaintext = await decryptData(detected.encryptedData, address, detected.version);
|
|
925
|
+
return { status: "ok", value: plaintext, version: detected.version };
|
|
751
926
|
} catch (error) {
|
|
752
|
-
|
|
753
|
-
|
|
927
|
+
if (error instanceof EncryptionKeyMissingError) {
|
|
928
|
+
getLogger().warn("Failed to decrypt field (key missing for version):", error.message);
|
|
929
|
+
return { status: "key_missing", value, version: detected.version };
|
|
930
|
+
}
|
|
931
|
+
getLogger().warn("Failed to decrypt field (auth mismatch or crypto error):", error);
|
|
932
|
+
return { status: "auth_mismatch", value, version: detected.version };
|
|
754
933
|
}
|
|
755
934
|
}
|
|
935
|
+
async function decryptField(value, address) {
|
|
936
|
+
const result = await decryptFieldDetailed(value, address);
|
|
937
|
+
return result.value;
|
|
938
|
+
}
|
|
756
939
|
async function encryptJsonField(value, address, signMessage, embeddedWalletSigner, skipKeyRequest) {
|
|
757
940
|
if (!value) return void 0;
|
|
758
941
|
const jsonString = JSON.stringify(value);
|
|
@@ -869,20 +1052,40 @@ async function encryptMessageFields(message, address, signMessage, embeddedWalle
|
|
|
869
1052
|
throw error;
|
|
870
1053
|
}
|
|
871
1054
|
}
|
|
872
|
-
async function
|
|
873
|
-
if (value === void 0) return void 0;
|
|
874
|
-
if (value === null) return value;
|
|
1055
|
+
async function decryptMaybeJsonFieldDetailed(value, address) {
|
|
1056
|
+
if (value === void 0) return { value: void 0, status: "plaintext" };
|
|
1057
|
+
if (value === null) return { value, status: "plaintext" };
|
|
875
1058
|
if (typeof value === "string") {
|
|
876
1059
|
if (isEncrypted(value)) {
|
|
877
|
-
|
|
1060
|
+
const detailed = await decryptFieldDetailed(value, address);
|
|
1061
|
+
if (detailed.status !== "ok") {
|
|
1062
|
+
return { value: void 0, status: detailed.status, probe: value };
|
|
1063
|
+
}
|
|
1064
|
+
try {
|
|
1065
|
+
return { value: JSON.parse(detailed.value), status: "ok" };
|
|
1066
|
+
} catch (error) {
|
|
1067
|
+
getLogger().warn("Failed to parse decrypted JSON field:", error);
|
|
1068
|
+
return { value: void 0, status: "invalid_payload", probe: value };
|
|
1069
|
+
}
|
|
878
1070
|
}
|
|
879
1071
|
try {
|
|
880
|
-
return JSON.parse(value);
|
|
1072
|
+
return { value: JSON.parse(value), status: "plaintext" };
|
|
881
1073
|
} catch {
|
|
882
|
-
return void 0;
|
|
1074
|
+
return { value: void 0, status: "plaintext" };
|
|
883
1075
|
}
|
|
884
1076
|
}
|
|
885
|
-
return value;
|
|
1077
|
+
return { value, status: "plaintext" };
|
|
1078
|
+
}
|
|
1079
|
+
function worseDecryptStatus(a, b) {
|
|
1080
|
+
if (b === "ok" || b === "plaintext") return a;
|
|
1081
|
+
if (!a || a === "ok" || a === "plaintext") return b;
|
|
1082
|
+
const rank = (s) => {
|
|
1083
|
+
if (s === "auth_mismatch") return 3;
|
|
1084
|
+
if (s === "key_missing") return 2;
|
|
1085
|
+
if (s === "invalid_payload") return 1;
|
|
1086
|
+
return 0;
|
|
1087
|
+
};
|
|
1088
|
+
return rank(b) >= rank(a) ? b : a;
|
|
886
1089
|
}
|
|
887
1090
|
async function decryptMessageFields(message, address, signMessage, embeddedWalletSigner) {
|
|
888
1091
|
if (!address) {
|
|
@@ -895,33 +1098,82 @@ async function decryptMessageFields(message, address, signMessage, embeddedWalle
|
|
|
895
1098
|
getLogger().warn("Failed to request encryption key for decryption:", error);
|
|
896
1099
|
}
|
|
897
1100
|
}
|
|
898
|
-
|
|
899
|
-
const
|
|
900
|
-
|
|
1101
|
+
let assembled = await assembleDecryptedMessage(message, address);
|
|
1102
|
+
const needsRefresh = assembled.decryptionStatus === "auth_mismatch" || assembled.decryptionStatus === "key_missing";
|
|
1103
|
+
if (needsRefresh && signMessage && assembled.refreshProbe) {
|
|
1104
|
+
try {
|
|
1105
|
+
const refreshed = await refreshEncryptionKeyIfMatches(
|
|
1106
|
+
address,
|
|
1107
|
+
assembled.refreshProbe,
|
|
1108
|
+
signMessage,
|
|
1109
|
+
embeddedWalletSigner
|
|
1110
|
+
);
|
|
1111
|
+
if (refreshed) {
|
|
1112
|
+
assembled = await assembleDecryptedMessage(message, address);
|
|
1113
|
+
}
|
|
1114
|
+
} catch (error) {
|
|
1115
|
+
getLogger().warn("Failed to refresh encryption key after decrypt failure:", error);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
const { refreshProbe: _probe, ...result } = assembled;
|
|
1119
|
+
return result;
|
|
1120
|
+
}
|
|
1121
|
+
async function assembleDecryptedMessage(message, address) {
|
|
1122
|
+
const contentResult = await decryptFieldDetailed(message.content, address);
|
|
1123
|
+
const thinkingResult = message.thinking ? await decryptFieldDetailed(message.thinking, address) : null;
|
|
1124
|
+
const vectorResult = await decryptMaybeJsonFieldDetailed(
|
|
901
1125
|
message.vector,
|
|
902
1126
|
address
|
|
903
1127
|
);
|
|
904
|
-
const
|
|
1128
|
+
const chunksResult = await decryptMaybeJsonFieldDetailed(
|
|
905
1129
|
message.chunks,
|
|
906
1130
|
address
|
|
907
1131
|
);
|
|
908
|
-
const
|
|
1132
|
+
const sourcesResult = await decryptMaybeJsonFieldDetailed(
|
|
909
1133
|
message.sources,
|
|
910
1134
|
address
|
|
911
1135
|
);
|
|
912
|
-
const
|
|
1136
|
+
const thoughtProcessResult = await decryptMaybeJsonFieldDetailed(
|
|
913
1137
|
message.thoughtProcess,
|
|
914
1138
|
address
|
|
915
1139
|
);
|
|
916
|
-
|
|
1140
|
+
let decryptionStatus;
|
|
1141
|
+
let refreshProbe;
|
|
1142
|
+
const consider = (status, probe) => {
|
|
1143
|
+
decryptionStatus = worseDecryptStatus(decryptionStatus, status);
|
|
1144
|
+
if (!refreshProbe && probe && (status === "auth_mismatch" || status === "key_missing")) {
|
|
1145
|
+
refreshProbe = probe;
|
|
1146
|
+
}
|
|
1147
|
+
};
|
|
1148
|
+
consider(contentResult.status, isEncrypted(message.content) ? message.content : void 0);
|
|
1149
|
+
if (thinkingResult && message.thinking && typeof message.thinking === "string") {
|
|
1150
|
+
consider(thinkingResult.status, isEncrypted(message.thinking) ? message.thinking : void 0);
|
|
1151
|
+
}
|
|
1152
|
+
if (vectorResult.probe) consider(vectorResult.status, vectorResult.probe);
|
|
1153
|
+
if (chunksResult.probe) consider(chunksResult.status, chunksResult.probe);
|
|
1154
|
+
if (sourcesResult.probe) consider(sourcesResult.status, sourcesResult.probe);
|
|
1155
|
+
if (thoughtProcessResult.probe) {
|
|
1156
|
+
consider(thoughtProcessResult.status, thoughtProcessResult.probe);
|
|
1157
|
+
}
|
|
1158
|
+
const statusForConsumer = decryptionStatus === "ok" || decryptionStatus === "plaintext" || !decryptionStatus ? void 0 : decryptionStatus;
|
|
1159
|
+
const result = {
|
|
917
1160
|
...message,
|
|
918
|
-
content:
|
|
919
|
-
thinking:
|
|
920
|
-
vector:
|
|
921
|
-
chunks:
|
|
922
|
-
sources:
|
|
923
|
-
thoughtProcess:
|
|
1161
|
+
content: contentResult.value,
|
|
1162
|
+
thinking: thinkingResult ? thinkingResult.value : message.thinking,
|
|
1163
|
+
vector: vectorResult.value,
|
|
1164
|
+
chunks: chunksResult.value,
|
|
1165
|
+
sources: sourcesResult.value,
|
|
1166
|
+
thoughtProcess: thoughtProcessResult.value
|
|
924
1167
|
};
|
|
1168
|
+
if (statusForConsumer) {
|
|
1169
|
+
result.decryptionStatus = statusForConsumer;
|
|
1170
|
+
} else {
|
|
1171
|
+
delete result.decryptionStatus;
|
|
1172
|
+
}
|
|
1173
|
+
if (refreshProbe) {
|
|
1174
|
+
result.refreshProbe = refreshProbe;
|
|
1175
|
+
}
|
|
1176
|
+
return result;
|
|
925
1177
|
}
|
|
926
1178
|
var init_encryption = __esm({
|
|
927
1179
|
"src/lib/db/chat/encryption.ts"() {
|
|
@@ -6149,11 +6401,11 @@ async function decomposeQuery(query, options) {
|
|
|
6149
6401
|
userMessage: `Classify the following memory query and decompose if composite. Respond with JSON only \u2014 do not answer the question, do not ask for clarification.
|
|
6150
6402
|
|
|
6151
6403
|
Query: ${trimmed}`,
|
|
6152
|
-
// Decompose runs
|
|
6404
|
+
// Decompose runs ahead of recall in the tool layer — tighter than the
|
|
6153
6405
|
// portalLlm default (consolidate/extract can wait longer).
|
|
6154
6406
|
timeoutMs: 2e4,
|
|
6155
6407
|
// No internal retry: a failure degrades to the safe `{specific,[query]}`
|
|
6156
|
-
// fallback below
|
|
6408
|
+
// fallback below. The agent/tool loop is the retry surface (719/B4).
|
|
6157
6409
|
maxAttempts: 1,
|
|
6158
6410
|
tag: "memory/decompose",
|
|
6159
6411
|
...options.fetchFn && { fetchFn: options.fetchFn }
|
|
@@ -6165,12 +6417,28 @@ Query: ${trimmed}`,
|
|
|
6165
6417
|
if (parsed === null) return fallback;
|
|
6166
6418
|
return validate(parsed, trimmed) ?? fallback;
|
|
6167
6419
|
}
|
|
6420
|
+
function normalizeSubQueries(raw) {
|
|
6421
|
+
if (!raw || raw.length === 0) return [];
|
|
6422
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6423
|
+
const out = [];
|
|
6424
|
+
for (const s of raw) {
|
|
6425
|
+
if (typeof s !== "string") continue;
|
|
6426
|
+
const t = s.trim();
|
|
6427
|
+
if (t.length === 0) continue;
|
|
6428
|
+
const key = t.toLowerCase();
|
|
6429
|
+
if (seen.has(key)) continue;
|
|
6430
|
+
seen.add(key);
|
|
6431
|
+
out.push(t);
|
|
6432
|
+
if (out.length >= MAX_SUB_QUERIES) break;
|
|
6433
|
+
}
|
|
6434
|
+
return out;
|
|
6435
|
+
}
|
|
6168
6436
|
function validate(parsed, originalQuery) {
|
|
6169
6437
|
if (typeof parsed !== "object" || parsed === null) return null;
|
|
6170
6438
|
const obj = parsed;
|
|
6171
6439
|
const mode = obj.mode === "composite" ? "composite" : "specific";
|
|
6172
6440
|
if (!Array.isArray(obj.subQueries)) return null;
|
|
6173
|
-
const subQueries = obj.subQueries
|
|
6441
|
+
const subQueries = normalizeSubQueries(obj.subQueries);
|
|
6174
6442
|
if (subQueries.length === 0) return null;
|
|
6175
6443
|
if (mode === "specific") {
|
|
6176
6444
|
return { mode: "specific", subQueries: [originalQuery] };
|
|
@@ -6787,12 +7055,12 @@ __export(recall_exports, {
|
|
|
6787
7055
|
function flagsForBudget(budget) {
|
|
6788
7056
|
switch (budget) {
|
|
6789
7057
|
case "high":
|
|
6790
|
-
return { rerank: true,
|
|
7058
|
+
return { rerank: true, traverse: true };
|
|
6791
7059
|
case "mid":
|
|
6792
|
-
return { rerank: true,
|
|
7060
|
+
return { rerank: true, traverse: false };
|
|
6793
7061
|
case "low":
|
|
6794
7062
|
default:
|
|
6795
|
-
return { rerank: false,
|
|
7063
|
+
return { rerank: false, traverse: false };
|
|
6796
7064
|
}
|
|
6797
7065
|
}
|
|
6798
7066
|
function dedupeBy(items, ...keys) {
|
|
@@ -6811,10 +7079,10 @@ function dedupeBy(items, ...keys) {
|
|
|
6811
7079
|
async function recall(query, ctx, options = {}) {
|
|
6812
7080
|
const types = options.types ?? ["fact"];
|
|
6813
7081
|
const limit = options.limit ?? DEFAULT_LIMIT;
|
|
6814
|
-
const
|
|
6815
|
-
const flags = flagsForBudget(
|
|
6816
|
-
const
|
|
6817
|
-
const
|
|
7082
|
+
const usedBudget = options.budget ?? DEFAULT_BUDGET;
|
|
7083
|
+
const flags = flagsForBudget(usedBudget);
|
|
7084
|
+
const normalizedFacets = normalizeSubQueries(options.subQueries);
|
|
7085
|
+
const subQueries = normalizedFacets.length >= 2 ? normalizedFacets : void 0;
|
|
6818
7086
|
const t0 = nowMs();
|
|
6819
7087
|
let prepMs = 0;
|
|
6820
7088
|
let factLaneMs = 0;
|
|
@@ -6835,7 +7103,9 @@ async function recall(query, ctx, options = {}) {
|
|
|
6835
7103
|
if (flags.rerank && factResults.length > 0 && hadV2Head && !didRerank) {
|
|
6836
7104
|
degraded.push("rerank-unavailable");
|
|
6837
7105
|
}
|
|
6838
|
-
if (
|
|
7106
|
+
if (usedBudget === "high" && options.decomposeOptions && !subQueries && !options.graphRefine) {
|
|
7107
|
+
degraded.push("decompose-moved");
|
|
7108
|
+
}
|
|
6839
7109
|
if (embeddingsUnavailable) degraded.push("embeddings-unavailable");
|
|
6840
7110
|
const diagnostics = {
|
|
6841
7111
|
usedBudget,
|
|
@@ -6948,10 +7218,8 @@ async function recall(query, ctx, options = {}) {
|
|
|
6948
7218
|
},
|
|
6949
7219
|
...options.rrfK !== void 0 && { rrfK: options.rrfK },
|
|
6950
7220
|
...options.decryptLast !== void 0 && { decryptLast: options.decryptLast },
|
|
6951
|
-
|
|
6952
|
-
|
|
6953
|
-
decomposeOptions: options.decomposeOptions
|
|
6954
|
-
},
|
|
7221
|
+
// 719/B4 — composite facets arrive pre-built; no LLM call here.
|
|
7222
|
+
...subQueries && { subQueries },
|
|
6955
7223
|
...options.scopes && { scopes: options.scopes },
|
|
6956
7224
|
...options.folderId !== void 0 && { folderId: options.folderId },
|
|
6957
7225
|
...options.factTypes?.length && { factTypes: options.factTypes },
|
|
@@ -7188,6 +7456,7 @@ var init_recall = __esm({
|
|
|
7188
7456
|
init_logger();
|
|
7189
7457
|
init_constants();
|
|
7190
7458
|
init_embeddings();
|
|
7459
|
+
init_decomposeQuery();
|
|
7191
7460
|
init_searchTool();
|
|
7192
7461
|
init_graphTraversal();
|
|
7193
7462
|
init_observationTrend();
|
|
@@ -8133,52 +8402,51 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
|
|
|
8133
8402
|
...searchOptions?.rrfK !== void 0 && { rrfK: searchOptions.rrfK },
|
|
8134
8403
|
...searchOptions?.factTypeWeights && { factTypeWeights: searchOptions.factTypeWeights }
|
|
8135
8404
|
};
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8153
|
-
|
|
8154
|
-
|
|
8155
|
-
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
|
-
|
|
8159
|
-
|
|
8160
|
-
|
|
8161
|
-
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
|
|
8176
|
-
|
|
8177
|
-
|
|
8178
|
-
|
|
8179
|
-
|
|
8180
|
-
|
|
8181
|
-
}
|
|
8405
|
+
const normalizedFacets = normalizeSubQueries(searchOptions?.subQueries);
|
|
8406
|
+
const facetQueries = normalizedFacets.length >= 2 ? normalizedFacets : void 0;
|
|
8407
|
+
if (useFusion && !embeddingsUnavailable && facetQueries) {
|
|
8408
|
+
let subEmbeddings;
|
|
8409
|
+
try {
|
|
8410
|
+
subEmbeddings = await generateEmbeddings(facetQueries, embeddingOptions);
|
|
8411
|
+
} catch (err) {
|
|
8412
|
+
getLogger().warn(
|
|
8413
|
+
"memoryVault: sub-query embedding failed \u2014 falling back to single-query ranking: " + (err instanceof Error ? err.message : String(err))
|
|
8414
|
+
);
|
|
8415
|
+
subEmbeddings = [];
|
|
8416
|
+
}
|
|
8417
|
+
const subEmbeddingsUsable = facetQueries.length > 0 && subEmbeddings.length === facetQueries.length && subEmbeddings.every((v) => v.length > 0 && v.length === queryEmbedding.length);
|
|
8418
|
+
if (subEmbeddings.length > 0 && !subEmbeddingsUsable) {
|
|
8419
|
+
getLogger().warn(
|
|
8420
|
+
`memoryVault: sub-query embedding returned ${subEmbeddings.length} vectors (dims ${subEmbeddings.map((v) => v.length).join(",")}) for ${facetQueries.length} sub-queries against a ${queryEmbedding.length}-dim query \u2014 falling back to single-query ranking`
|
|
8421
|
+
);
|
|
8422
|
+
}
|
|
8423
|
+
if (subEmbeddingsUsable) {
|
|
8424
|
+
const subQueries = facetQueries.map((sq, i) => ({
|
|
8425
|
+
query: sq,
|
|
8426
|
+
embedding: subEmbeddings[i]
|
|
8427
|
+
}));
|
|
8428
|
+
const v2HeadStats = { hadResults: false };
|
|
8429
|
+
const composite = await rankComposite(query, queryEmbedding, subQueries, embeddedItems, {
|
|
8430
|
+
limit,
|
|
8431
|
+
minSimilarity,
|
|
8432
|
+
rerank: !!searchOptions?.rerank,
|
|
8433
|
+
...searchOptions?.rerankTopN !== void 0 && {
|
|
8434
|
+
rerankTopN: searchOptions.rerankTopN
|
|
8435
|
+
},
|
|
8436
|
+
...searchOptions?.ceWeight !== void 0 && { ceWeight: searchOptions.ceWeight },
|
|
8437
|
+
...searchOptions?.mmr !== void 0 && { mmr: searchOptions.mmr },
|
|
8438
|
+
...tuning,
|
|
8439
|
+
...searchOptions?.entityRanking && { entityRanking: searchOptions.entityRanking },
|
|
8440
|
+
...searchOptions?.temporalRanking && { temporalRanking: searchOptions.temporalRanking },
|
|
8441
|
+
rerankStats,
|
|
8442
|
+
v2HeadStats
|
|
8443
|
+
});
|
|
8444
|
+
return stampTimestamps({
|
|
8445
|
+
results: composite,
|
|
8446
|
+
vaultSize,
|
|
8447
|
+
reranked: rerankStats.applied,
|
|
8448
|
+
hadV2Head: v2HeadStats.hadResults
|
|
8449
|
+
});
|
|
8182
8450
|
}
|
|
8183
8451
|
}
|
|
8184
8452
|
if (useFusion && searchOptions?.rerank) {
|
|
@@ -8238,6 +8506,12 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
|
|
|
8238
8506
|
rankedOnCosine: false
|
|
8239
8507
|
};
|
|
8240
8508
|
}
|
|
8509
|
+
if (searchOptions?.decompose === "llm" && normalizeSubQueries(searchOptions.subQueries).length < 2 && !warnedProgrammaticDecomposeIgnored) {
|
|
8510
|
+
warnedProgrammaticDecomposeIgnored = true;
|
|
8511
|
+
getLogger().warn(
|
|
8512
|
+
'memoryVault: decompose:"llm" is ignored by searchVaultMemories \u2014 pass subQueries or use createMemoryVaultSearchTool / createRecallTool (719/B4)'
|
|
8513
|
+
);
|
|
8514
|
+
}
|
|
8241
8515
|
const prepared = await prepareVaultCandidates(
|
|
8242
8516
|
query,
|
|
8243
8517
|
vaultCtx,
|
|
@@ -8342,7 +8616,8 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
8342
8616
|
return "Error: A search query is required.";
|
|
8343
8617
|
}
|
|
8344
8618
|
try {
|
|
8345
|
-
const
|
|
8619
|
+
const wantsDecompose = searchOptions?.decompose === "llm" && !!searchOptions.decomposeOptions;
|
|
8620
|
+
const budget = wantsDecompose ? "high" : searchOptions?.rerank ? "mid" : "low";
|
|
8346
8621
|
const folderId = searchOptions?.folderId ?? argFolderId;
|
|
8347
8622
|
if (searchOptions?.useFusion === false) {
|
|
8348
8623
|
const { results: legacy, embeddingsUnavailable } = await searchVaultMemoriesWithSize(
|
|
@@ -8366,6 +8641,13 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
8366
8641
|
legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
|
|
8367
8642
|
);
|
|
8368
8643
|
}
|
|
8644
|
+
let subQueries;
|
|
8645
|
+
if (wantsDecompose && searchOptions?.decomposeOptions) {
|
|
8646
|
+
const decomp = await decomposeQuery(query, searchOptions.decomposeOptions);
|
|
8647
|
+
if (decomp.mode === "composite" && decomp.subQueries.length >= 2) {
|
|
8648
|
+
subQueries = decomp.subQueries;
|
|
8649
|
+
}
|
|
8650
|
+
}
|
|
8369
8651
|
const { recall: recall2 } = await Promise.resolve().then(() => (init_recall(), recall_exports));
|
|
8370
8652
|
let recallDegraded = [];
|
|
8371
8653
|
const result = await recall2(
|
|
@@ -8382,9 +8664,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
8382
8664
|
...tuningForward,
|
|
8383
8665
|
...folderId !== void 0 && { folderId },
|
|
8384
8666
|
...searchOptions?.scopes && { scopes: searchOptions.scopes },
|
|
8385
|
-
...
|
|
8386
|
-
decomposeOptions: searchOptions.decomposeOptions
|
|
8387
|
-
}
|
|
8667
|
+
...subQueries && { subQueries }
|
|
8388
8668
|
}
|
|
8389
8669
|
);
|
|
8390
8670
|
if (result.vaultSize === 0) {
|
|
@@ -8414,7 +8694,7 @@ ${formatted}`;
|
|
|
8414
8694
|
}
|
|
8415
8695
|
};
|
|
8416
8696
|
}
|
|
8417
|
-
var SUPERSESSION_SIMILARITY_THRESHOLD, SUPERSESSION_MIN_AGE_GAP_MS, SUPERSESSION_BOOST_FACTOR, SUPERSESSION_MAX_WINDOW, EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL;
|
|
8697
|
+
var warnedProgrammaticDecomposeIgnored, SUPERSESSION_SIMILARITY_THRESHOLD, SUPERSESSION_MIN_AGE_GAP_MS, SUPERSESSION_BOOST_FACTOR, SUPERSESSION_MAX_WINDOW, EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL;
|
|
8418
8698
|
var init_searchTool = __esm({
|
|
8419
8699
|
"src/lib/memoryVault/searchTool.ts"() {
|
|
8420
8700
|
"use strict";
|
|
@@ -8432,6 +8712,7 @@ var init_searchTool = __esm({
|
|
|
8432
8712
|
init_bm25();
|
|
8433
8713
|
init_decomposeQuery();
|
|
8434
8714
|
init_lruCache();
|
|
8715
|
+
warnedProgrammaticDecomposeIgnored = false;
|
|
8435
8716
|
SUPERSESSION_SIMILARITY_THRESHOLD = 0.7;
|
|
8436
8717
|
SUPERSESSION_MIN_AGE_GAP_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
8437
8718
|
SUPERSESSION_BOOST_FACTOR = 0.8;
|
|
@@ -8627,6 +8908,7 @@ __export(index_exports, {
|
|
|
8627
8908
|
DEFAULT_VAULT_CACHE_SIZE: () => DEFAULT_VAULT_CACHE_SIZE,
|
|
8628
8909
|
DatabaseManager: () => DatabaseManager,
|
|
8629
8910
|
ENTITY_FANOUT: () => ENTITY_FANOUT,
|
|
8911
|
+
EncryptionKeyMissingError: () => EncryptionKeyMissingError,
|
|
8630
8912
|
HARD_DELETE_WINDOW_MS: () => HARD_DELETE_WINDOW_MS,
|
|
8631
8913
|
INFERENCE_ID_HEADER: () => INFERENCE_ID_HEADER,
|
|
8632
8914
|
LoggerProvider: () => LoggerProvider,
|
|
@@ -8753,6 +9035,7 @@ __export(index_exports, {
|
|
|
8753
9035
|
rankProfileCandidates: () => rankProfileCandidates,
|
|
8754
9036
|
recall: () => recall,
|
|
8755
9037
|
reflect: () => reflect,
|
|
9038
|
+
refreshEncryptionKeyIfMatches: () => refreshEncryptionKeyIfMatches,
|
|
8756
9039
|
refreshNotionAccessToken: () => refreshNotionAccessToken,
|
|
8757
9040
|
registerNotionClient: () => registerNotionClient,
|
|
8758
9041
|
relinkMemoryTopicsOp: () => relinkMemoryTopicsOp,
|
|
@@ -8767,6 +9050,7 @@ __export(index_exports, {
|
|
|
8767
9050
|
sdkModelClasses: () => sdkModelClasses,
|
|
8768
9051
|
sdkSchema: () => sdkSchema,
|
|
8769
9052
|
searchVaultMemories: () => searchVaultMemories,
|
|
9053
|
+
seedEncryptionKeys: () => seedEncryptionKeys,
|
|
8770
9054
|
setLogger: () => setLogger,
|
|
8771
9055
|
setMemoryVisibilityOp: () => setMemoryVisibilityOp,
|
|
8772
9056
|
shouldChunkMessage: () => shouldChunkMessage,
|
|
@@ -16460,6 +16744,7 @@ function rankProfileCandidates(inputs, now = Date.now(), options = {}) {
|
|
|
16460
16744
|
init_recall();
|
|
16461
16745
|
|
|
16462
16746
|
// src/lib/memory/recallTool.ts
|
|
16747
|
+
init_decomposeQuery();
|
|
16463
16748
|
init_recall();
|
|
16464
16749
|
init_recallConstants();
|
|
16465
16750
|
var DEFAULT_LIMIT2 = 8;
|
|
@@ -16557,7 +16842,7 @@ function createRecallTool(ctx, toolOptions, callbacks) {
|
|
|
16557
16842
|
type: "function",
|
|
16558
16843
|
function: {
|
|
16559
16844
|
name: RECALL_TOOL_NAME,
|
|
16560
|
-
description:
|
|
16845
|
+
description: `Search the user's memory across stored facts/preferences and past conversation excerpts. Returns a unified ranked list \u2014 facts carry an \`id\` you can reference; conversation excerpts carry a date and role. Use this whenever the user's question may relate to anything previously discussed or saved (preferences, prior decisions, past topics). Phrase the query naturally. For multi-faceted / overview questions ("tell me about the user", "what's my tech stack"), prefer several targeted searches \u2014 one facet each (e.g. name, work, hobbies) \u2014 over a single broad query; fuse the results yourself.`,
|
|
16561
16846
|
arguments: {
|
|
16562
16847
|
type: "object",
|
|
16563
16848
|
properties: {
|
|
@@ -16612,6 +16897,13 @@ function createRecallTool(ctx, toolOptions, callbacks) {
|
|
|
16612
16897
|
let surfaced = 0;
|
|
16613
16898
|
try {
|
|
16614
16899
|
let recallDegraded = [];
|
|
16900
|
+
let subQueries;
|
|
16901
|
+
if (defaultBudget === "high" && toolOptions?.decomposeOptions) {
|
|
16902
|
+
const decomp = await decomposeQuery(query, toolOptions.decomposeOptions);
|
|
16903
|
+
if (decomp.mode === "composite" && decomp.subQueries.length >= 2) {
|
|
16904
|
+
subQueries = decomp.subQueries;
|
|
16905
|
+
}
|
|
16906
|
+
}
|
|
16615
16907
|
const recallOpts = {
|
|
16616
16908
|
onDiagnostics: (d) => {
|
|
16617
16909
|
recallDegraded = d.degraded;
|
|
@@ -16625,10 +16917,12 @@ function createRecallTool(ctx, toolOptions, callbacks) {
|
|
|
16625
16917
|
...toolOptions?.excludeConversationId && {
|
|
16626
16918
|
excludeConversationId: toolOptions.excludeConversationId
|
|
16627
16919
|
},
|
|
16628
|
-
|
|
16629
|
-
|
|
16630
|
-
|
|
16631
|
-
|
|
16920
|
+
// Do NOT forward decomposeOptions into recall() — rewrite already
|
|
16921
|
+
// ran above, and forwarding would falsely trip `decompose-moved`
|
|
16922
|
+
// on every specific-mode high-budget call. graphRefine auth can
|
|
16923
|
+
// be threaded later when the tool opts into that path.
|
|
16924
|
+
...toolOptions?.now !== void 0 && { now: toolOptions.now },
|
|
16925
|
+
...subQueries && { subQueries }
|
|
16632
16926
|
};
|
|
16633
16927
|
const result = await recall(query, ctx, recallOpts);
|
|
16634
16928
|
if (callbacks?.onChunksRetrieved) {
|
|
@@ -23032,6 +23326,7 @@ function createNotionTools(getAccessToken, requestNotionAccess) {
|
|
|
23032
23326
|
DEFAULT_VAULT_CACHE_SIZE,
|
|
23033
23327
|
DatabaseManager,
|
|
23034
23328
|
ENTITY_FANOUT,
|
|
23329
|
+
EncryptionKeyMissingError,
|
|
23035
23330
|
HARD_DELETE_WINDOW_MS,
|
|
23036
23331
|
INFERENCE_ID_HEADER,
|
|
23037
23332
|
LoggerProvider,
|
|
@@ -23158,6 +23453,7 @@ function createNotionTools(getAccessToken, requestNotionAccess) {
|
|
|
23158
23453
|
rankProfileCandidates,
|
|
23159
23454
|
recall,
|
|
23160
23455
|
reflect,
|
|
23456
|
+
refreshEncryptionKeyIfMatches,
|
|
23161
23457
|
refreshNotionAccessToken,
|
|
23162
23458
|
registerNotionClient,
|
|
23163
23459
|
relinkMemoryTopicsOp,
|
|
@@ -23172,6 +23468,7 @@ function createNotionTools(getAccessToken, requestNotionAccess) {
|
|
|
23172
23468
|
sdkModelClasses,
|
|
23173
23469
|
sdkSchema,
|
|
23174
23470
|
searchVaultMemories,
|
|
23471
|
+
seedEncryptionKeys,
|
|
23175
23472
|
setLogger,
|
|
23176
23473
|
setMemoryVisibilityOp,
|
|
23177
23474
|
shouldChunkMessage,
|