@reverbia/sdk 1.0.0-next.20251205064608 → 1.0.0-next.20251205183506
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/react/index.cjs +104 -96
- package/dist/react/index.d.mts +28 -5
- package/dist/react/index.d.ts +28 -5
- package/dist/react/index.mjs +83 -77
- package/package.json +1 -1
package/dist/react/index.cjs
CHANGED
|
@@ -47109,6 +47109,8 @@ __export(index_exports, {
|
|
|
47109
47109
|
executeTool: () => executeTool,
|
|
47110
47110
|
extractConversationContext: () => extractConversationContext,
|
|
47111
47111
|
formatMemoriesForChat: () => formatMemoriesForChat,
|
|
47112
|
+
hasEncryptionKey: () => hasEncryptionKey,
|
|
47113
|
+
requestEncryptionKey: () => requestEncryptionKey,
|
|
47112
47114
|
selectTool: () => selectTool,
|
|
47113
47115
|
useChat: () => useChat,
|
|
47114
47116
|
useEncryption: () => useEncryption,
|
|
@@ -48479,10 +48481,11 @@ Please inform the user about this issue and try to help them alternatively.`
|
|
|
48479
48481
|
}
|
|
48480
48482
|
|
|
48481
48483
|
// src/react/useEncryption.ts
|
|
48482
|
-
var import_react2 = require("react");
|
|
48483
|
-
var import_react_auth = require("@privy-io/react-auth");
|
|
48484
48484
|
var SIGN_MESSAGE = "The app is asking you to sign this message to generate a key, which will be used to encrypt data.";
|
|
48485
|
-
var
|
|
48485
|
+
var BASE_SIGNATURE_STORAGE_KEY = "privy_encryption_key";
|
|
48486
|
+
function getStorageKey(address) {
|
|
48487
|
+
return `${BASE_SIGNATURE_STORAGE_KEY}_${address}`;
|
|
48488
|
+
}
|
|
48486
48489
|
function getStorageItem(key) {
|
|
48487
48490
|
if (typeof window === "undefined" || !window.localStorage) {
|
|
48488
48491
|
return null;
|
|
@@ -48524,8 +48527,9 @@ async function deriveKeyFromSignature(signature) {
|
|
|
48524
48527
|
const hashBytes = new Uint8Array(hashBuffer);
|
|
48525
48528
|
return bytesToHex(hashBytes);
|
|
48526
48529
|
}
|
|
48527
|
-
async function getEncryptionKey() {
|
|
48528
|
-
const
|
|
48530
|
+
async function getEncryptionKey(address) {
|
|
48531
|
+
const storageKey = getStorageKey(address);
|
|
48532
|
+
const keyHex = getStorageItem(storageKey);
|
|
48529
48533
|
if (!keyHex) {
|
|
48530
48534
|
throw new Error("Encryption key not found. Please sign in first.");
|
|
48531
48535
|
}
|
|
@@ -48538,8 +48542,8 @@ async function getEncryptionKey() {
|
|
|
48538
48542
|
["encrypt", "decrypt"]
|
|
48539
48543
|
);
|
|
48540
48544
|
}
|
|
48541
|
-
async function encryptData(plaintext) {
|
|
48542
|
-
const key = await getEncryptionKey();
|
|
48545
|
+
async function encryptData(plaintext, address) {
|
|
48546
|
+
const key = await getEncryptionKey(address);
|
|
48543
48547
|
const plaintextBytes = typeof plaintext === "string" ? new TextEncoder().encode(plaintext) : plaintext;
|
|
48544
48548
|
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
48545
48549
|
const encryptedData = await crypto.subtle.encrypt(
|
|
@@ -48556,8 +48560,8 @@ async function encryptData(plaintext) {
|
|
|
48556
48560
|
combined.set(encryptedBytes, iv.length);
|
|
48557
48561
|
return bytesToHex(combined);
|
|
48558
48562
|
}
|
|
48559
|
-
async function decryptData(encryptedHex) {
|
|
48560
|
-
const key = await getEncryptionKey();
|
|
48563
|
+
async function decryptData(encryptedHex, address) {
|
|
48564
|
+
const key = await getEncryptionKey(address);
|
|
48561
48565
|
const combined = hexToBytes(encryptedHex);
|
|
48562
48566
|
const iv = combined.slice(0, 12);
|
|
48563
48567
|
const encryptedData = combined.slice(12);
|
|
@@ -48571,8 +48575,8 @@ async function decryptData(encryptedHex) {
|
|
|
48571
48575
|
);
|
|
48572
48576
|
return new TextDecoder().decode(decryptedData);
|
|
48573
48577
|
}
|
|
48574
|
-
async function decryptDataBytes(encryptedHex) {
|
|
48575
|
-
const key = await getEncryptionKey();
|
|
48578
|
+
async function decryptDataBytes(encryptedHex, address) {
|
|
48579
|
+
const key = await getEncryptionKey(address);
|
|
48576
48580
|
const combined = hexToBytes(encryptedHex);
|
|
48577
48581
|
const iv = combined.slice(0, 12);
|
|
48578
48582
|
const encryptedData = combined.slice(12);
|
|
@@ -48586,58 +48590,31 @@ async function decryptDataBytes(encryptedHex) {
|
|
|
48586
48590
|
);
|
|
48587
48591
|
return new Uint8Array(decryptedData);
|
|
48588
48592
|
}
|
|
48589
|
-
function
|
|
48590
|
-
const
|
|
48591
|
-
|
|
48592
|
-
|
|
48593
|
-
|
|
48594
|
-
|
|
48595
|
-
|
|
48596
|
-
|
|
48597
|
-
|
|
48598
|
-
|
|
48599
|
-
|
|
48600
|
-
|
|
48601
|
-
|
|
48602
|
-
|
|
48603
|
-
|
|
48604
|
-
|
|
48605
|
-
|
|
48606
|
-
|
|
48607
|
-
|
|
48608
|
-
|
|
48609
|
-
|
|
48610
|
-
{ message: SIGN_MESSAGE },
|
|
48611
|
-
{
|
|
48612
|
-
address: wallets[0].address
|
|
48613
|
-
}
|
|
48614
|
-
);
|
|
48615
|
-
const encryptionKey = await deriveKeyFromSignature(signature);
|
|
48616
|
-
const stored = setStorageItem(SIGNATURE_STORAGE_KEY, encryptionKey);
|
|
48617
|
-
if (!stored) {
|
|
48618
|
-
throw new Error("Failed to store encryption key in localStorage");
|
|
48619
|
-
}
|
|
48620
|
-
} catch (error) {
|
|
48621
|
-
hasRequestedSignature.current = false;
|
|
48622
|
-
}
|
|
48623
|
-
}
|
|
48624
|
-
};
|
|
48625
|
-
requestSignature();
|
|
48626
|
-
}, [
|
|
48627
|
-
authenticated,
|
|
48628
|
-
wallets.length > 0 ? wallets[0]?.address : null,
|
|
48629
|
-
signMessage
|
|
48630
|
-
]);
|
|
48631
|
-
(0, import_react2.useEffect)(() => {
|
|
48632
|
-
if (!authenticated) {
|
|
48633
|
-
hasRequestedSignature.current = false;
|
|
48634
|
-
hasCheckedStorage.current = false;
|
|
48635
|
-
}
|
|
48636
|
-
}, [authenticated]);
|
|
48593
|
+
function hasEncryptionKey(address) {
|
|
48594
|
+
const storageKey = getStorageKey(address);
|
|
48595
|
+
return getStorageItem(storageKey) !== null;
|
|
48596
|
+
}
|
|
48597
|
+
async function requestEncryptionKey(walletAddress, signMessage) {
|
|
48598
|
+
const storageKey = getStorageKey(walletAddress);
|
|
48599
|
+
const existingKey = getStorageItem(storageKey);
|
|
48600
|
+
if (existingKey) {
|
|
48601
|
+
return;
|
|
48602
|
+
}
|
|
48603
|
+
const signature = await signMessage(SIGN_MESSAGE);
|
|
48604
|
+
const encryptionKey = await deriveKeyFromSignature(signature);
|
|
48605
|
+
const stored = setStorageItem(storageKey, encryptionKey);
|
|
48606
|
+
if (!stored) {
|
|
48607
|
+
throw new Error("Failed to store encryption key in localStorage");
|
|
48608
|
+
}
|
|
48609
|
+
}
|
|
48610
|
+
function useEncryption(signMessage) {
|
|
48611
|
+
return {
|
|
48612
|
+
requestEncryptionKey: (walletAddress) => requestEncryptionKey(walletAddress, signMessage)
|
|
48613
|
+
};
|
|
48637
48614
|
}
|
|
48638
48615
|
|
|
48639
48616
|
// src/react/useMemory.ts
|
|
48640
|
-
var
|
|
48617
|
+
var import_react2 = require("react");
|
|
48641
48618
|
var import_client6 = require("@reverbia/sdk");
|
|
48642
48619
|
|
|
48643
48620
|
// src/lib/memory/service.ts
|
|
@@ -48645,10 +48622,12 @@ var FACT_EXTRACTION_PROMPT = `You are a memory extraction system. Extract durabl
|
|
|
48645
48622
|
|
|
48646
48623
|
CRITICAL: You MUST respond with ONLY valid JSON. No explanations, no markdown, no code blocks, just pure JSON.
|
|
48647
48624
|
|
|
48648
|
-
Only
|
|
48625
|
+
Only store clear, factual statements that might be relevant for future context or reference. Extract facts that will be useful in future conversations, such as identity, stable preferences, ongoing projects, skills, locations, favorites, and constraints.
|
|
48649
48626
|
|
|
48650
48627
|
Do not extract sensitive attributes, temporary things, or single-use instructions.
|
|
48651
48628
|
|
|
48629
|
+
You must also extract stable personal preferences, including food likes/dislikes, hobbies, favorite items, favorite genres, or other enduring tastes.
|
|
48630
|
+
|
|
48652
48631
|
If there are no memories to extract, return: {"items": []}
|
|
48653
48632
|
|
|
48654
48633
|
Response format (JSON only, no other text):
|
|
@@ -48673,6 +48652,24 @@ Response format (JSON only, no other text):
|
|
|
48673
48652
|
"confidence": 0.99,
|
|
48674
48653
|
"pii": false
|
|
48675
48654
|
},
|
|
48655
|
+
{
|
|
48656
|
+
"type": "identity",
|
|
48657
|
+
"namespace": "location",
|
|
48658
|
+
"key": "city",
|
|
48659
|
+
"value": "San Francisco",
|
|
48660
|
+
"rawEvidence": "I live in San Francisco",
|
|
48661
|
+
"confidence": 0.99,
|
|
48662
|
+
"pii": false
|
|
48663
|
+
},
|
|
48664
|
+
{
|
|
48665
|
+
"type": "preference",
|
|
48666
|
+
"namespace": "location",
|
|
48667
|
+
"key": "country",
|
|
48668
|
+
"value": "Japan",
|
|
48669
|
+
"rawEvidence": "I like to travel to the Japan",
|
|
48670
|
+
"confidence": 0.94,
|
|
48671
|
+
"pii": false
|
|
48672
|
+
},
|
|
48676
48673
|
{
|
|
48677
48674
|
"type": "preference",
|
|
48678
48675
|
"namespace": "answer_style",
|
|
@@ -48690,6 +48687,15 @@ Response format (JSON only, no other text):
|
|
|
48690
48687
|
"rawEvidence": "I'm in PST",
|
|
48691
48688
|
"confidence": 0.9,
|
|
48692
48689
|
"pii": false
|
|
48690
|
+
},
|
|
48691
|
+
{
|
|
48692
|
+
"type": "preference",
|
|
48693
|
+
"namespace": "food",
|
|
48694
|
+
"key": "likes_ice_cream",
|
|
48695
|
+
"value": "ice cream",
|
|
48696
|
+
"rawEvidence": "I like ice cream",
|
|
48697
|
+
"confidence": 0.95,
|
|
48698
|
+
"pii": false
|
|
48693
48699
|
}
|
|
48694
48700
|
]
|
|
48695
48701
|
}`;
|
|
@@ -49035,8 +49041,8 @@ function useMemory(options = {}) {
|
|
|
49035
49041
|
baseUrl = BASE_URL
|
|
49036
49042
|
} = options;
|
|
49037
49043
|
const embeddingModel = userEmbeddingModel === void 0 ? embeddingProvider === "local" ? DEFAULT_LOCAL_EMBEDDING_MODEL : DEFAULT_API_EMBEDDING_MODEL : userEmbeddingModel;
|
|
49038
|
-
const extractionInProgressRef = (0,
|
|
49039
|
-
const extractMemoriesFromMessage = (0,
|
|
49044
|
+
const extractionInProgressRef = (0, import_react2.useRef)(false);
|
|
49045
|
+
const extractMemoriesFromMessage = (0, import_react2.useCallback)(
|
|
49040
49046
|
async (options2) => {
|
|
49041
49047
|
const { messages, model } = options2;
|
|
49042
49048
|
if (!getToken || extractionInProgressRef.current) {
|
|
@@ -49219,7 +49225,7 @@ function useMemory(options = {}) {
|
|
|
49219
49225
|
baseUrl
|
|
49220
49226
|
]
|
|
49221
49227
|
);
|
|
49222
|
-
const searchMemories = (0,
|
|
49228
|
+
const searchMemories = (0, import_react2.useCallback)(
|
|
49223
49229
|
async (query, limit = 10, minSimilarity = 0.6) => {
|
|
49224
49230
|
if (!embeddingModel) {
|
|
49225
49231
|
console.warn("Cannot search memories: embeddingModel not provided");
|
|
@@ -49265,7 +49271,7 @@ function useMemory(options = {}) {
|
|
|
49265
49271
|
}
|
|
49266
49272
|
|
|
49267
49273
|
// src/react/usePdf.ts
|
|
49268
|
-
var
|
|
49274
|
+
var import_react3 = require("react");
|
|
49269
49275
|
|
|
49270
49276
|
// src/lib/pdf.ts
|
|
49271
49277
|
var pdfjs = __toESM(require("pdfjs-dist"));
|
|
@@ -49293,9 +49299,9 @@ async function extractTextFromPdf(pdfDataUrl) {
|
|
|
49293
49299
|
// src/react/usePdf.ts
|
|
49294
49300
|
var PDF_MIME_TYPE = "application/pdf";
|
|
49295
49301
|
function usePdf() {
|
|
49296
|
-
const [isProcessing, setIsProcessing] = (0,
|
|
49297
|
-
const [error, setError] = (0,
|
|
49298
|
-
const extractPdfContext = (0,
|
|
49302
|
+
const [isProcessing, setIsProcessing] = (0, import_react3.useState)(false);
|
|
49303
|
+
const [error, setError] = (0, import_react3.useState)(null);
|
|
49304
|
+
const extractPdfContext = (0, import_react3.useCallback)(
|
|
49299
49305
|
async (files) => {
|
|
49300
49306
|
setIsProcessing(true);
|
|
49301
49307
|
setError(null);
|
|
@@ -49342,22 +49348,22 @@ ${text}`;
|
|
|
49342
49348
|
}
|
|
49343
49349
|
|
|
49344
49350
|
// src/react/useModels.ts
|
|
49345
|
-
var
|
|
49351
|
+
var import_react4 = require("react");
|
|
49346
49352
|
function useModels(options = {}) {
|
|
49347
49353
|
const { getToken, baseUrl = BASE_URL, provider, autoFetch = true } = options;
|
|
49348
|
-
const [models, setModels] = (0,
|
|
49349
|
-
const [isLoading, setIsLoading] = (0,
|
|
49350
|
-
const [error, setError] = (0,
|
|
49351
|
-
const getTokenRef = (0,
|
|
49352
|
-
const baseUrlRef = (0,
|
|
49353
|
-
const providerRef = (0,
|
|
49354
|
-
const abortControllerRef = (0,
|
|
49355
|
-
(0,
|
|
49354
|
+
const [models, setModels] = (0, import_react4.useState)([]);
|
|
49355
|
+
const [isLoading, setIsLoading] = (0, import_react4.useState)(false);
|
|
49356
|
+
const [error, setError] = (0, import_react4.useState)(null);
|
|
49357
|
+
const getTokenRef = (0, import_react4.useRef)(getToken);
|
|
49358
|
+
const baseUrlRef = (0, import_react4.useRef)(baseUrl);
|
|
49359
|
+
const providerRef = (0, import_react4.useRef)(provider);
|
|
49360
|
+
const abortControllerRef = (0, import_react4.useRef)(null);
|
|
49361
|
+
(0, import_react4.useEffect)(() => {
|
|
49356
49362
|
getTokenRef.current = getToken;
|
|
49357
49363
|
baseUrlRef.current = baseUrl;
|
|
49358
49364
|
providerRef.current = provider;
|
|
49359
49365
|
});
|
|
49360
|
-
(0,
|
|
49366
|
+
(0, import_react4.useEffect)(() => {
|
|
49361
49367
|
return () => {
|
|
49362
49368
|
if (abortControllerRef.current) {
|
|
49363
49369
|
abortControllerRef.current.abort();
|
|
@@ -49365,7 +49371,7 @@ function useModels(options = {}) {
|
|
|
49365
49371
|
}
|
|
49366
49372
|
};
|
|
49367
49373
|
}, []);
|
|
49368
|
-
const fetchModels = (0,
|
|
49374
|
+
const fetchModels = (0, import_react4.useCallback)(async () => {
|
|
49369
49375
|
if (abortControllerRef.current) {
|
|
49370
49376
|
abortControllerRef.current.abort();
|
|
49371
49377
|
}
|
|
@@ -49423,12 +49429,12 @@ function useModels(options = {}) {
|
|
|
49423
49429
|
}
|
|
49424
49430
|
}
|
|
49425
49431
|
}, []);
|
|
49426
|
-
const refetch = (0,
|
|
49432
|
+
const refetch = (0, import_react4.useCallback)(async () => {
|
|
49427
49433
|
setModels([]);
|
|
49428
49434
|
await fetchModels();
|
|
49429
49435
|
}, [fetchModels]);
|
|
49430
|
-
const hasFetchedRef = (0,
|
|
49431
|
-
(0,
|
|
49436
|
+
const hasFetchedRef = (0, import_react4.useRef)(false);
|
|
49437
|
+
(0, import_react4.useEffect)(() => {
|
|
49432
49438
|
if (autoFetch && !hasFetchedRef.current) {
|
|
49433
49439
|
hasFetchedRef.current = true;
|
|
49434
49440
|
fetchModels();
|
|
@@ -49446,15 +49452,15 @@ function useModels(options = {}) {
|
|
|
49446
49452
|
}
|
|
49447
49453
|
|
|
49448
49454
|
// src/react/useSearch.ts
|
|
49449
|
-
var
|
|
49455
|
+
var import_react5 = require("react");
|
|
49450
49456
|
function useSearch(options = {}) {
|
|
49451
49457
|
const { getToken, baseUrl = BASE_URL, onError } = options;
|
|
49452
|
-
const [isLoading, setIsLoading] = (0,
|
|
49453
|
-
const [results, setResults] = (0,
|
|
49454
|
-
const [response, setResponse] = (0,
|
|
49455
|
-
const [error, setError] = (0,
|
|
49456
|
-
const abortControllerRef = (0,
|
|
49457
|
-
(0,
|
|
49458
|
+
const [isLoading, setIsLoading] = (0, import_react5.useState)(false);
|
|
49459
|
+
const [results, setResults] = (0, import_react5.useState)(null);
|
|
49460
|
+
const [response, setResponse] = (0, import_react5.useState)(null);
|
|
49461
|
+
const [error, setError] = (0, import_react5.useState)(null);
|
|
49462
|
+
const abortControllerRef = (0, import_react5.useRef)(null);
|
|
49463
|
+
(0, import_react5.useEffect)(() => {
|
|
49458
49464
|
return () => {
|
|
49459
49465
|
if (abortControllerRef.current) {
|
|
49460
49466
|
abortControllerRef.current.abort();
|
|
@@ -49462,7 +49468,7 @@ function useSearch(options = {}) {
|
|
|
49462
49468
|
}
|
|
49463
49469
|
};
|
|
49464
49470
|
}, []);
|
|
49465
|
-
const search = (0,
|
|
49471
|
+
const search = (0, import_react5.useCallback)(
|
|
49466
49472
|
async (query, searchOptions = {}) => {
|
|
49467
49473
|
if (abortControllerRef.current) {
|
|
49468
49474
|
abortControllerRef.current.abort();
|
|
@@ -49530,12 +49536,12 @@ function useSearch(options = {}) {
|
|
|
49530
49536
|
}
|
|
49531
49537
|
|
|
49532
49538
|
// src/react/useImageGeneration.ts
|
|
49533
|
-
var
|
|
49539
|
+
var import_react6 = require("react");
|
|
49534
49540
|
function useImageGeneration(options = {}) {
|
|
49535
49541
|
const { getToken, baseUrl = BASE_URL, onFinish, onError } = options;
|
|
49536
|
-
const [isLoading, setIsLoading] = (0,
|
|
49537
|
-
const abortControllerRef = (0,
|
|
49538
|
-
(0,
|
|
49542
|
+
const [isLoading, setIsLoading] = (0, import_react6.useState)(false);
|
|
49543
|
+
const abortControllerRef = (0, import_react6.useRef)(null);
|
|
49544
|
+
(0, import_react6.useEffect)(() => {
|
|
49539
49545
|
return () => {
|
|
49540
49546
|
if (abortControllerRef.current) {
|
|
49541
49547
|
abortControllerRef.current.abort();
|
|
@@ -49543,13 +49549,13 @@ function useImageGeneration(options = {}) {
|
|
|
49543
49549
|
}
|
|
49544
49550
|
};
|
|
49545
49551
|
}, []);
|
|
49546
|
-
const stop = (0,
|
|
49552
|
+
const stop = (0, import_react6.useCallback)(() => {
|
|
49547
49553
|
if (abortControllerRef.current) {
|
|
49548
49554
|
abortControllerRef.current.abort();
|
|
49549
49555
|
abortControllerRef.current = null;
|
|
49550
49556
|
}
|
|
49551
49557
|
}, []);
|
|
49552
|
-
const generateImage = (0,
|
|
49558
|
+
const generateImage = (0, import_react6.useCallback)(
|
|
49553
49559
|
async (args) => {
|
|
49554
49560
|
if (abortControllerRef.current) {
|
|
49555
49561
|
abortControllerRef.current.abort();
|
|
@@ -49675,6 +49681,8 @@ var extractConversationContext = (messages, maxMessages = 3) => {
|
|
|
49675
49681
|
executeTool,
|
|
49676
49682
|
extractConversationContext,
|
|
49677
49683
|
formatMemoriesForChat,
|
|
49684
|
+
hasEncryptionKey,
|
|
49685
|
+
requestEncryptionKey,
|
|
49678
49686
|
selectTool,
|
|
49679
49687
|
useChat,
|
|
49680
49688
|
useEncryption,
|
package/dist/react/index.d.mts
CHANGED
|
@@ -585,20 +585,43 @@ declare function useChat(options?: UseChatOptions): UseChatResult;
|
|
|
585
585
|
* @param plaintext - The data to encrypt (string or Uint8Array)
|
|
586
586
|
* @returns Encrypted data as hex string (IV + ciphertext + auth tag)
|
|
587
587
|
*/
|
|
588
|
-
declare function encryptData(plaintext: string | Uint8Array): Promise<string>;
|
|
588
|
+
declare function encryptData(plaintext: string | Uint8Array, address: string): Promise<string>;
|
|
589
589
|
/**
|
|
590
590
|
* Decrypts data using AES-GCM with the stored encryption key
|
|
591
591
|
* @param encryptedHex - Encrypted data as hex string (IV + ciphertext + auth tag)
|
|
592
592
|
* @returns Decrypted data as string
|
|
593
593
|
*/
|
|
594
|
-
declare function decryptData(encryptedHex: string): Promise<string>;
|
|
594
|
+
declare function decryptData(encryptedHex: string, address: string): Promise<string>;
|
|
595
595
|
/**
|
|
596
596
|
* Decrypts data and returns as Uint8Array (for binary data)
|
|
597
597
|
* @param encryptedHex - Encrypted data as hex string (IV + ciphertext + auth tag)
|
|
598
598
|
* @returns Decrypted data as Uint8Array
|
|
599
599
|
*/
|
|
600
|
-
declare function decryptDataBytes(encryptedHex: string): Promise<Uint8Array>;
|
|
601
|
-
|
|
600
|
+
declare function decryptDataBytes(encryptedHex: string, address: string): Promise<Uint8Array>;
|
|
601
|
+
/**
|
|
602
|
+
* Checks if an encryption key exists for the given wallet address
|
|
603
|
+
*/
|
|
604
|
+
declare function hasEncryptionKey(address: string): boolean;
|
|
605
|
+
/**
|
|
606
|
+
* Type for the signMessage function that client must provide
|
|
607
|
+
*/
|
|
608
|
+
type SignMessageFn = (message: string) => Promise<string>;
|
|
609
|
+
/**
|
|
610
|
+
* Requests the user to sign a message to generate an encryption key.
|
|
611
|
+
* If a key already exists for the given wallet, resolves immediately.
|
|
612
|
+
* @param walletAddress - The wallet address to generate the key for
|
|
613
|
+
* @param signMessage - Function to sign a message (returns signature hex string)
|
|
614
|
+
* @returns Promise that resolves when the key is available
|
|
615
|
+
*/
|
|
616
|
+
declare function requestEncryptionKey(walletAddress: string, signMessage: SignMessageFn): Promise<void>;
|
|
617
|
+
/**
|
|
618
|
+
* Hook that provides on-demand encryption key management.
|
|
619
|
+
* @param signMessage - Function to sign a message (from Privy's useSignMessage)
|
|
620
|
+
* @returns Functions to request encryption keys
|
|
621
|
+
*/
|
|
622
|
+
declare function useEncryption(signMessage: SignMessageFn): {
|
|
623
|
+
requestEncryptionKey: (walletAddress: string) => Promise<void>;
|
|
624
|
+
};
|
|
602
625
|
|
|
603
626
|
interface MemoryItem {
|
|
604
627
|
type: "identity" | "preference" | "project" | "skill" | "constraint";
|
|
@@ -857,4 +880,4 @@ declare function executeTool(tool: ClientTool, params: Record<string, unknown>):
|
|
|
857
880
|
error?: string;
|
|
858
881
|
}>;
|
|
859
882
|
|
|
860
|
-
export { type ClientTool, DEFAULT_TOOL_SELECTOR_MODEL, type PdfFile, type ToolExecutionResult, type ToolParameter, type ToolSelectionResult, createMemoryContextSystemMessage, decryptData, decryptDataBytes, encryptData, executeTool, extractConversationContext, formatMemoriesForChat, selectTool, useChat, useEncryption, useImageGeneration, useMemory, useModels, usePdf, useSearch };
|
|
883
|
+
export { type ClientTool, DEFAULT_TOOL_SELECTOR_MODEL, type PdfFile, type SignMessageFn, type ToolExecutionResult, type ToolParameter, type ToolSelectionResult, createMemoryContextSystemMessage, decryptData, decryptDataBytes, encryptData, executeTool, extractConversationContext, formatMemoriesForChat, hasEncryptionKey, requestEncryptionKey, selectTool, useChat, useEncryption, useImageGeneration, useMemory, useModels, usePdf, useSearch };
|
package/dist/react/index.d.ts
CHANGED
|
@@ -585,20 +585,43 @@ declare function useChat(options?: UseChatOptions): UseChatResult;
|
|
|
585
585
|
* @param plaintext - The data to encrypt (string or Uint8Array)
|
|
586
586
|
* @returns Encrypted data as hex string (IV + ciphertext + auth tag)
|
|
587
587
|
*/
|
|
588
|
-
declare function encryptData(plaintext: string | Uint8Array): Promise<string>;
|
|
588
|
+
declare function encryptData(plaintext: string | Uint8Array, address: string): Promise<string>;
|
|
589
589
|
/**
|
|
590
590
|
* Decrypts data using AES-GCM with the stored encryption key
|
|
591
591
|
* @param encryptedHex - Encrypted data as hex string (IV + ciphertext + auth tag)
|
|
592
592
|
* @returns Decrypted data as string
|
|
593
593
|
*/
|
|
594
|
-
declare function decryptData(encryptedHex: string): Promise<string>;
|
|
594
|
+
declare function decryptData(encryptedHex: string, address: string): Promise<string>;
|
|
595
595
|
/**
|
|
596
596
|
* Decrypts data and returns as Uint8Array (for binary data)
|
|
597
597
|
* @param encryptedHex - Encrypted data as hex string (IV + ciphertext + auth tag)
|
|
598
598
|
* @returns Decrypted data as Uint8Array
|
|
599
599
|
*/
|
|
600
|
-
declare function decryptDataBytes(encryptedHex: string): Promise<Uint8Array>;
|
|
601
|
-
|
|
600
|
+
declare function decryptDataBytes(encryptedHex: string, address: string): Promise<Uint8Array>;
|
|
601
|
+
/**
|
|
602
|
+
* Checks if an encryption key exists for the given wallet address
|
|
603
|
+
*/
|
|
604
|
+
declare function hasEncryptionKey(address: string): boolean;
|
|
605
|
+
/**
|
|
606
|
+
* Type for the signMessage function that client must provide
|
|
607
|
+
*/
|
|
608
|
+
type SignMessageFn = (message: string) => Promise<string>;
|
|
609
|
+
/**
|
|
610
|
+
* Requests the user to sign a message to generate an encryption key.
|
|
611
|
+
* If a key already exists for the given wallet, resolves immediately.
|
|
612
|
+
* @param walletAddress - The wallet address to generate the key for
|
|
613
|
+
* @param signMessage - Function to sign a message (returns signature hex string)
|
|
614
|
+
* @returns Promise that resolves when the key is available
|
|
615
|
+
*/
|
|
616
|
+
declare function requestEncryptionKey(walletAddress: string, signMessage: SignMessageFn): Promise<void>;
|
|
617
|
+
/**
|
|
618
|
+
* Hook that provides on-demand encryption key management.
|
|
619
|
+
* @param signMessage - Function to sign a message (from Privy's useSignMessage)
|
|
620
|
+
* @returns Functions to request encryption keys
|
|
621
|
+
*/
|
|
622
|
+
declare function useEncryption(signMessage: SignMessageFn): {
|
|
623
|
+
requestEncryptionKey: (walletAddress: string) => Promise<void>;
|
|
624
|
+
};
|
|
602
625
|
|
|
603
626
|
interface MemoryItem {
|
|
604
627
|
type: "identity" | "preference" | "project" | "skill" | "constraint";
|
|
@@ -857,4 +880,4 @@ declare function executeTool(tool: ClientTool, params: Record<string, unknown>):
|
|
|
857
880
|
error?: string;
|
|
858
881
|
}>;
|
|
859
882
|
|
|
860
|
-
export { type ClientTool, DEFAULT_TOOL_SELECTOR_MODEL, type PdfFile, type ToolExecutionResult, type ToolParameter, type ToolSelectionResult, createMemoryContextSystemMessage, decryptData, decryptDataBytes, encryptData, executeTool, extractConversationContext, formatMemoriesForChat, selectTool, useChat, useEncryption, useImageGeneration, useMemory, useModels, usePdf, useSearch };
|
|
883
|
+
export { type ClientTool, DEFAULT_TOOL_SELECTOR_MODEL, type PdfFile, type SignMessageFn, type ToolExecutionResult, type ToolParameter, type ToolSelectionResult, createMemoryContextSystemMessage, decryptData, decryptDataBytes, encryptData, executeTool, extractConversationContext, formatMemoriesForChat, hasEncryptionKey, requestEncryptionKey, selectTool, useChat, useEncryption, useImageGeneration, useMemory, useModels, usePdf, useSearch };
|
package/dist/react/index.mjs
CHANGED
|
@@ -1359,10 +1359,11 @@ Please inform the user about this issue and try to help them alternatively.`
|
|
|
1359
1359
|
}
|
|
1360
1360
|
|
|
1361
1361
|
// src/react/useEncryption.ts
|
|
1362
|
-
import { useEffect as useEffect2, useRef as useRef2 } from "react";
|
|
1363
|
-
import { useSignMessage, useWallets } from "@privy-io/react-auth";
|
|
1364
1362
|
var SIGN_MESSAGE = "The app is asking you to sign this message to generate a key, which will be used to encrypt data.";
|
|
1365
|
-
var
|
|
1363
|
+
var BASE_SIGNATURE_STORAGE_KEY = "privy_encryption_key";
|
|
1364
|
+
function getStorageKey(address) {
|
|
1365
|
+
return `${BASE_SIGNATURE_STORAGE_KEY}_${address}`;
|
|
1366
|
+
}
|
|
1366
1367
|
function getStorageItem(key) {
|
|
1367
1368
|
if (typeof window === "undefined" || !window.localStorage) {
|
|
1368
1369
|
return null;
|
|
@@ -1404,8 +1405,9 @@ async function deriveKeyFromSignature(signature) {
|
|
|
1404
1405
|
const hashBytes = new Uint8Array(hashBuffer);
|
|
1405
1406
|
return bytesToHex(hashBytes);
|
|
1406
1407
|
}
|
|
1407
|
-
async function getEncryptionKey() {
|
|
1408
|
-
const
|
|
1408
|
+
async function getEncryptionKey(address) {
|
|
1409
|
+
const storageKey = getStorageKey(address);
|
|
1410
|
+
const keyHex = getStorageItem(storageKey);
|
|
1409
1411
|
if (!keyHex) {
|
|
1410
1412
|
throw new Error("Encryption key not found. Please sign in first.");
|
|
1411
1413
|
}
|
|
@@ -1418,8 +1420,8 @@ async function getEncryptionKey() {
|
|
|
1418
1420
|
["encrypt", "decrypt"]
|
|
1419
1421
|
);
|
|
1420
1422
|
}
|
|
1421
|
-
async function encryptData(plaintext) {
|
|
1422
|
-
const key = await getEncryptionKey();
|
|
1423
|
+
async function encryptData(plaintext, address) {
|
|
1424
|
+
const key = await getEncryptionKey(address);
|
|
1423
1425
|
const plaintextBytes = typeof plaintext === "string" ? new TextEncoder().encode(plaintext) : plaintext;
|
|
1424
1426
|
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
1425
1427
|
const encryptedData = await crypto.subtle.encrypt(
|
|
@@ -1436,8 +1438,8 @@ async function encryptData(plaintext) {
|
|
|
1436
1438
|
combined.set(encryptedBytes, iv.length);
|
|
1437
1439
|
return bytesToHex(combined);
|
|
1438
1440
|
}
|
|
1439
|
-
async function decryptData(encryptedHex) {
|
|
1440
|
-
const key = await getEncryptionKey();
|
|
1441
|
+
async function decryptData(encryptedHex, address) {
|
|
1442
|
+
const key = await getEncryptionKey(address);
|
|
1441
1443
|
const combined = hexToBytes(encryptedHex);
|
|
1442
1444
|
const iv = combined.slice(0, 12);
|
|
1443
1445
|
const encryptedData = combined.slice(12);
|
|
@@ -1451,8 +1453,8 @@ async function decryptData(encryptedHex) {
|
|
|
1451
1453
|
);
|
|
1452
1454
|
return new TextDecoder().decode(decryptedData);
|
|
1453
1455
|
}
|
|
1454
|
-
async function decryptDataBytes(encryptedHex) {
|
|
1455
|
-
const key = await getEncryptionKey();
|
|
1456
|
+
async function decryptDataBytes(encryptedHex, address) {
|
|
1457
|
+
const key = await getEncryptionKey(address);
|
|
1456
1458
|
const combined = hexToBytes(encryptedHex);
|
|
1457
1459
|
const iv = combined.slice(0, 12);
|
|
1458
1460
|
const encryptedData = combined.slice(12);
|
|
@@ -1466,58 +1468,31 @@ async function decryptDataBytes(encryptedHex) {
|
|
|
1466
1468
|
);
|
|
1467
1469
|
return new Uint8Array(decryptedData);
|
|
1468
1470
|
}
|
|
1469
|
-
function
|
|
1470
|
-
const
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
{ message: SIGN_MESSAGE },
|
|
1491
|
-
{
|
|
1492
|
-
address: wallets[0].address
|
|
1493
|
-
}
|
|
1494
|
-
);
|
|
1495
|
-
const encryptionKey = await deriveKeyFromSignature(signature);
|
|
1496
|
-
const stored = setStorageItem(SIGNATURE_STORAGE_KEY, encryptionKey);
|
|
1497
|
-
if (!stored) {
|
|
1498
|
-
throw new Error("Failed to store encryption key in localStorage");
|
|
1499
|
-
}
|
|
1500
|
-
} catch (error) {
|
|
1501
|
-
hasRequestedSignature.current = false;
|
|
1502
|
-
}
|
|
1503
|
-
}
|
|
1504
|
-
};
|
|
1505
|
-
requestSignature();
|
|
1506
|
-
}, [
|
|
1507
|
-
authenticated,
|
|
1508
|
-
wallets.length > 0 ? wallets[0]?.address : null,
|
|
1509
|
-
signMessage
|
|
1510
|
-
]);
|
|
1511
|
-
useEffect2(() => {
|
|
1512
|
-
if (!authenticated) {
|
|
1513
|
-
hasRequestedSignature.current = false;
|
|
1514
|
-
hasCheckedStorage.current = false;
|
|
1515
|
-
}
|
|
1516
|
-
}, [authenticated]);
|
|
1471
|
+
function hasEncryptionKey(address) {
|
|
1472
|
+
const storageKey = getStorageKey(address);
|
|
1473
|
+
return getStorageItem(storageKey) !== null;
|
|
1474
|
+
}
|
|
1475
|
+
async function requestEncryptionKey(walletAddress, signMessage) {
|
|
1476
|
+
const storageKey = getStorageKey(walletAddress);
|
|
1477
|
+
const existingKey = getStorageItem(storageKey);
|
|
1478
|
+
if (existingKey) {
|
|
1479
|
+
return;
|
|
1480
|
+
}
|
|
1481
|
+
const signature = await signMessage(SIGN_MESSAGE);
|
|
1482
|
+
const encryptionKey = await deriveKeyFromSignature(signature);
|
|
1483
|
+
const stored = setStorageItem(storageKey, encryptionKey);
|
|
1484
|
+
if (!stored) {
|
|
1485
|
+
throw new Error("Failed to store encryption key in localStorage");
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
function useEncryption(signMessage) {
|
|
1489
|
+
return {
|
|
1490
|
+
requestEncryptionKey: (walletAddress) => requestEncryptionKey(walletAddress, signMessage)
|
|
1491
|
+
};
|
|
1517
1492
|
}
|
|
1518
1493
|
|
|
1519
1494
|
// src/react/useMemory.ts
|
|
1520
|
-
import { useCallback as useCallback2, useRef as
|
|
1495
|
+
import { useCallback as useCallback2, useRef as useRef2 } from "react";
|
|
1521
1496
|
import { postApiV1ChatCompletions } from "@reverbia/sdk";
|
|
1522
1497
|
|
|
1523
1498
|
// src/lib/memory/service.ts
|
|
@@ -1525,10 +1500,12 @@ var FACT_EXTRACTION_PROMPT = `You are a memory extraction system. Extract durabl
|
|
|
1525
1500
|
|
|
1526
1501
|
CRITICAL: You MUST respond with ONLY valid JSON. No explanations, no markdown, no code blocks, just pure JSON.
|
|
1527
1502
|
|
|
1528
|
-
Only
|
|
1503
|
+
Only store clear, factual statements that might be relevant for future context or reference. Extract facts that will be useful in future conversations, such as identity, stable preferences, ongoing projects, skills, locations, favorites, and constraints.
|
|
1529
1504
|
|
|
1530
1505
|
Do not extract sensitive attributes, temporary things, or single-use instructions.
|
|
1531
1506
|
|
|
1507
|
+
You must also extract stable personal preferences, including food likes/dislikes, hobbies, favorite items, favorite genres, or other enduring tastes.
|
|
1508
|
+
|
|
1532
1509
|
If there are no memories to extract, return: {"items": []}
|
|
1533
1510
|
|
|
1534
1511
|
Response format (JSON only, no other text):
|
|
@@ -1553,6 +1530,24 @@ Response format (JSON only, no other text):
|
|
|
1553
1530
|
"confidence": 0.99,
|
|
1554
1531
|
"pii": false
|
|
1555
1532
|
},
|
|
1533
|
+
{
|
|
1534
|
+
"type": "identity",
|
|
1535
|
+
"namespace": "location",
|
|
1536
|
+
"key": "city",
|
|
1537
|
+
"value": "San Francisco",
|
|
1538
|
+
"rawEvidence": "I live in San Francisco",
|
|
1539
|
+
"confidence": 0.99,
|
|
1540
|
+
"pii": false
|
|
1541
|
+
},
|
|
1542
|
+
{
|
|
1543
|
+
"type": "preference",
|
|
1544
|
+
"namespace": "location",
|
|
1545
|
+
"key": "country",
|
|
1546
|
+
"value": "Japan",
|
|
1547
|
+
"rawEvidence": "I like to travel to the Japan",
|
|
1548
|
+
"confidence": 0.94,
|
|
1549
|
+
"pii": false
|
|
1550
|
+
},
|
|
1556
1551
|
{
|
|
1557
1552
|
"type": "preference",
|
|
1558
1553
|
"namespace": "answer_style",
|
|
@@ -1570,6 +1565,15 @@ Response format (JSON only, no other text):
|
|
|
1570
1565
|
"rawEvidence": "I'm in PST",
|
|
1571
1566
|
"confidence": 0.9,
|
|
1572
1567
|
"pii": false
|
|
1568
|
+
},
|
|
1569
|
+
{
|
|
1570
|
+
"type": "preference",
|
|
1571
|
+
"namespace": "food",
|
|
1572
|
+
"key": "likes_ice_cream",
|
|
1573
|
+
"value": "ice cream",
|
|
1574
|
+
"rawEvidence": "I like ice cream",
|
|
1575
|
+
"confidence": 0.95,
|
|
1576
|
+
"pii": false
|
|
1573
1577
|
}
|
|
1574
1578
|
]
|
|
1575
1579
|
}`;
|
|
@@ -1915,7 +1919,7 @@ function useMemory(options = {}) {
|
|
|
1915
1919
|
baseUrl = BASE_URL
|
|
1916
1920
|
} = options;
|
|
1917
1921
|
const embeddingModel = userEmbeddingModel === void 0 ? embeddingProvider === "local" ? DEFAULT_LOCAL_EMBEDDING_MODEL : DEFAULT_API_EMBEDDING_MODEL : userEmbeddingModel;
|
|
1918
|
-
const extractionInProgressRef =
|
|
1922
|
+
const extractionInProgressRef = useRef2(false);
|
|
1919
1923
|
const extractMemoriesFromMessage = useCallback2(
|
|
1920
1924
|
async (options2) => {
|
|
1921
1925
|
const { messages, model } = options2;
|
|
@@ -2222,22 +2226,22 @@ ${text}`;
|
|
|
2222
2226
|
}
|
|
2223
2227
|
|
|
2224
2228
|
// src/react/useModels.ts
|
|
2225
|
-
import { useCallback as useCallback4, useEffect as
|
|
2229
|
+
import { useCallback as useCallback4, useEffect as useEffect2, useRef as useRef3, useState as useState3 } from "react";
|
|
2226
2230
|
function useModels(options = {}) {
|
|
2227
2231
|
const { getToken, baseUrl = BASE_URL, provider, autoFetch = true } = options;
|
|
2228
2232
|
const [models, setModels] = useState3([]);
|
|
2229
2233
|
const [isLoading, setIsLoading] = useState3(false);
|
|
2230
2234
|
const [error, setError] = useState3(null);
|
|
2231
|
-
const getTokenRef =
|
|
2232
|
-
const baseUrlRef =
|
|
2233
|
-
const providerRef =
|
|
2234
|
-
const abortControllerRef =
|
|
2235
|
-
|
|
2235
|
+
const getTokenRef = useRef3(getToken);
|
|
2236
|
+
const baseUrlRef = useRef3(baseUrl);
|
|
2237
|
+
const providerRef = useRef3(provider);
|
|
2238
|
+
const abortControllerRef = useRef3(null);
|
|
2239
|
+
useEffect2(() => {
|
|
2236
2240
|
getTokenRef.current = getToken;
|
|
2237
2241
|
baseUrlRef.current = baseUrl;
|
|
2238
2242
|
providerRef.current = provider;
|
|
2239
2243
|
});
|
|
2240
|
-
|
|
2244
|
+
useEffect2(() => {
|
|
2241
2245
|
return () => {
|
|
2242
2246
|
if (abortControllerRef.current) {
|
|
2243
2247
|
abortControllerRef.current.abort();
|
|
@@ -2307,8 +2311,8 @@ function useModels(options = {}) {
|
|
|
2307
2311
|
setModels([]);
|
|
2308
2312
|
await fetchModels();
|
|
2309
2313
|
}, [fetchModels]);
|
|
2310
|
-
const hasFetchedRef =
|
|
2311
|
-
|
|
2314
|
+
const hasFetchedRef = useRef3(false);
|
|
2315
|
+
useEffect2(() => {
|
|
2312
2316
|
if (autoFetch && !hasFetchedRef.current) {
|
|
2313
2317
|
hasFetchedRef.current = true;
|
|
2314
2318
|
fetchModels();
|
|
@@ -2326,15 +2330,15 @@ function useModels(options = {}) {
|
|
|
2326
2330
|
}
|
|
2327
2331
|
|
|
2328
2332
|
// src/react/useSearch.ts
|
|
2329
|
-
import { useCallback as useCallback5, useEffect as
|
|
2333
|
+
import { useCallback as useCallback5, useEffect as useEffect3, useRef as useRef4, useState as useState4 } from "react";
|
|
2330
2334
|
function useSearch(options = {}) {
|
|
2331
2335
|
const { getToken, baseUrl = BASE_URL, onError } = options;
|
|
2332
2336
|
const [isLoading, setIsLoading] = useState4(false);
|
|
2333
2337
|
const [results, setResults] = useState4(null);
|
|
2334
2338
|
const [response, setResponse] = useState4(null);
|
|
2335
2339
|
const [error, setError] = useState4(null);
|
|
2336
|
-
const abortControllerRef =
|
|
2337
|
-
|
|
2340
|
+
const abortControllerRef = useRef4(null);
|
|
2341
|
+
useEffect3(() => {
|
|
2338
2342
|
return () => {
|
|
2339
2343
|
if (abortControllerRef.current) {
|
|
2340
2344
|
abortControllerRef.current.abort();
|
|
@@ -2410,12 +2414,12 @@ function useSearch(options = {}) {
|
|
|
2410
2414
|
}
|
|
2411
2415
|
|
|
2412
2416
|
// src/react/useImageGeneration.ts
|
|
2413
|
-
import { useCallback as useCallback6, useEffect as
|
|
2417
|
+
import { useCallback as useCallback6, useEffect as useEffect4, useRef as useRef5, useState as useState5 } from "react";
|
|
2414
2418
|
function useImageGeneration(options = {}) {
|
|
2415
2419
|
const { getToken, baseUrl = BASE_URL, onFinish, onError } = options;
|
|
2416
2420
|
const [isLoading, setIsLoading] = useState5(false);
|
|
2417
|
-
const abortControllerRef =
|
|
2418
|
-
|
|
2421
|
+
const abortControllerRef = useRef5(null);
|
|
2422
|
+
useEffect4(() => {
|
|
2419
2423
|
return () => {
|
|
2420
2424
|
if (abortControllerRef.current) {
|
|
2421
2425
|
abortControllerRef.current.abort();
|
|
@@ -2554,6 +2558,8 @@ export {
|
|
|
2554
2558
|
executeTool,
|
|
2555
2559
|
extractConversationContext,
|
|
2556
2560
|
formatMemoriesForChat,
|
|
2561
|
+
hasEncryptionKey,
|
|
2562
|
+
requestEncryptionKey,
|
|
2557
2563
|
selectTool,
|
|
2558
2564
|
useChat,
|
|
2559
2565
|
useEncryption,
|