@reverbia/sdk 1.0.0-next.20251124100226 → 1.0.0-next.20251125084053

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.
@@ -1,288 +1,5 @@
1
1
  // src/react/useChat.ts
2
- import { useCallback, useState } from "react";
3
- import {
4
- postApiV1ChatCompletions
5
- } from "@reverbia/sdk";
6
- function useChat(options) {
7
- const { getToken } = options || {};
8
- const [isLoading, setIsLoading] = useState(false);
9
- const sendMessage = useCallback(
10
- async ({
11
- messages,
12
- model
13
- }) => {
14
- if (!messages?.length) {
15
- const error = "messages are required to call sendMessage.";
16
- return { data: null, error };
17
- }
18
- if (!model) {
19
- const error = "model is required to call sendMessage.";
20
- return { data: null, error };
21
- }
22
- if (!getToken) {
23
- const error = "Token getter function is required.";
24
- return { data: null, error };
25
- }
26
- setIsLoading(true);
27
- try {
28
- const token = await getToken();
29
- if (!token) {
30
- const error = "No access token available.";
31
- setIsLoading(false);
32
- return { data: null, error };
33
- }
34
- const completion = await postApiV1ChatCompletions({
35
- body: {
36
- messages,
37
- model
38
- },
39
- headers: {
40
- Authorization: `Bearer ${token}`
41
- }
42
- });
43
- if (!completion.data) {
44
- const error = completion.error?.error ?? "API did not return a completion response.";
45
- setIsLoading(false);
46
- return { data: null, error };
47
- }
48
- if (typeof completion.data === "string") {
49
- const error = "API returned a string response instead of a completion object.";
50
- setIsLoading(false);
51
- return { data: null, error };
52
- }
53
- setIsLoading(false);
54
- return { data: completion.data, error: null };
55
- } catch (err) {
56
- const error = err instanceof Error ? err.message : "Failed to send message.";
57
- setIsLoading(false);
58
- return { data: null, error };
59
- }
60
- },
61
- [getToken]
62
- );
63
- return {
64
- isLoading,
65
- sendMessage
66
- };
67
- }
68
-
69
- // src/react/useMemory.ts
70
- import { useCallback as useCallback2, useRef } from "react";
71
- import { postApiV1ChatCompletions as postApiV1ChatCompletions2 } from "@reverbia/sdk";
72
-
73
- // src/lib/memory/service.ts
74
- var FACT_EXTRACTION_PROMPT = `You are a memory extraction system. Extract durable user memories from chat messages.
75
-
76
- CRITICAL: You MUST respond with ONLY valid JSON. No explanations, no markdown, no code blocks, just pure JSON.
77
-
78
- Only extract facts that will be useful in future conversations, such as identity, stable preferences, ongoing projects, skills, and constraints.
79
-
80
- Do not extract sensitive attributes, temporary things, or single-use instructions.
81
-
82
- If there are no memories to extract, return: {"items": []}
83
-
84
- Response format (JSON only, no other text):
85
-
86
- {
87
- "items": [
88
- {
89
- "type": "identity",
90
- "namespace": "identity",
91
- "key": "name",
92
- "value": "Charlie",
93
- "rawEvidence": "I'm Charlie",
94
- "confidence": 0.98,
95
- "pii": true
96
- },
97
- {
98
- "type": "identity",
99
- "namespace": "work",
100
- "key": "company",
101
- "value": "ZetaChain",
102
- "rawEvidence": "called ZetaChain",
103
- "confidence": 0.99,
104
- "pii": false
105
- },
106
- {
107
- "type": "preference",
108
- "namespace": "answer_style",
109
- "key": "verbosity",
110
- "value": "concise_direct",
111
- "rawEvidence": "I prefer concise, direct answers",
112
- "confidence": 0.96,
113
- "pii": false
114
- },
115
- {
116
- "type": "identity",
117
- "namespace": "timezone",
118
- "key": "tz",
119
- "value": "America/Los_Angeles",
120
- "rawEvidence": "I'm in PST",
121
- "confidence": 0.9,
122
- "pii": false
123
- }
124
- ]
125
- }`;
126
- var preprocessMemories = (items, minConfidence = 0.6) => {
127
- if (!items || !Array.isArray(items)) {
128
- return [];
129
- }
130
- const validItems = items.filter((item) => {
131
- if (item.namespace == null || item.key == null || item.value == null) {
132
- console.warn(
133
- "Dropping memory item with null/undefined namespace, key, or value:",
134
- item
135
- );
136
- return false;
137
- }
138
- const namespace = String(item.namespace).trim();
139
- const key = String(item.key).trim();
140
- const value = String(item.value).trim();
141
- if (namespace === "" || key === "" || value === "") {
142
- console.warn(
143
- "Dropping memory item with empty namespace, key, or value after trimming:",
144
- item
145
- );
146
- return false;
147
- }
148
- if (typeof item.confidence !== "number" || item.confidence < minConfidence) {
149
- console.warn(
150
- `Dropping memory item with confidence ${item.confidence} below threshold ${minConfidence}:`,
151
- item
152
- );
153
- return false;
154
- }
155
- return true;
156
- });
157
- const deduplicatedMap = /* @__PURE__ */ new Map();
158
- for (const item of validItems) {
159
- const uniqueKey = `${item.namespace}:${item.key}:${item.value}`;
160
- const existing = deduplicatedMap.get(uniqueKey);
161
- if (!existing || item.confidence > existing.confidence) {
162
- deduplicatedMap.set(uniqueKey, item);
163
- } else {
164
- console.debug(
165
- `Deduplicating memory item: keeping entry with higher confidence (${existing.confidence} > ${item.confidence})`,
166
- { namespace: item.namespace, key: item.key, value: item.value }
167
- );
168
- }
169
- }
170
- return Array.from(deduplicatedMap.values());
171
- };
172
-
173
- // src/lib/memory/db.ts
174
- import Dexie from "dexie";
175
- var MemoryDatabase = class extends Dexie {
176
- constructor() {
177
- super("MemoryDatabase");
178
- this.version(2).stores({
179
- memories: "++id, uniqueKey, compositeKey, namespace, key, type, createdAt, updatedAt"
180
- });
181
- this.version(3).stores({
182
- memories: "++id, uniqueKey, compositeKey, namespace, key, type, createdAt, updatedAt"
183
- });
184
- }
185
- };
186
- var memoryDb = new MemoryDatabase();
187
- var saveMemory = async (memory) => {
188
- const compositeKey = `${memory.namespace}:${memory.key}`;
189
- const uniqueKey = `${memory.namespace}:${memory.key}:${memory.value}`;
190
- const now = Date.now();
191
- const existing = await memoryDb.memories.where("uniqueKey").equals(uniqueKey).first();
192
- if (existing) {
193
- const shouldPreserveEmbedding = existing.value === memory.value && existing.rawEvidence === memory.rawEvidence && existing.type === memory.type && existing.namespace === memory.namespace && existing.key === memory.key && existing.embedding !== void 0 && existing.embedding.length > 0;
194
- const updateData = {
195
- ...memory,
196
- compositeKey,
197
- uniqueKey,
198
- updatedAt: now,
199
- createdAt: existing.createdAt
200
- };
201
- if (shouldPreserveEmbedding) {
202
- updateData.embedding = existing.embedding;
203
- updateData.embeddingModel = existing.embeddingModel;
204
- } else {
205
- updateData.embedding = [];
206
- updateData.embeddingModel = void 0;
207
- }
208
- await memoryDb.memories.update(existing.id, updateData);
209
- } else {
210
- await memoryDb.memories.add({
211
- ...memory,
212
- compositeKey,
213
- uniqueKey,
214
- createdAt: now,
215
- updatedAt: now
216
- });
217
- }
218
- };
219
- var saveMemories = async (memories) => {
220
- await Promise.all(memories.map((memory) => saveMemory(memory)));
221
- };
222
- var getAllMemories = async () => {
223
- return memoryDb.memories.toArray();
224
- };
225
- var cosineSimilarity = (a, b) => {
226
- if (a.length !== b.length) {
227
- throw new Error("Vectors must have the same length");
228
- }
229
- let dotProduct = 0;
230
- let normA = 0;
231
- let normB = 0;
232
- for (let i = 0; i < a.length; i++) {
233
- dotProduct += a[i] * b[i];
234
- normA += a[i] * a[i];
235
- normB += b[i] * b[i];
236
- }
237
- const denominator = Math.sqrt(normA) * Math.sqrt(normB);
238
- if (denominator === 0) {
239
- return 0;
240
- }
241
- return dotProduct / denominator;
242
- };
243
- var searchSimilarMemories = async (queryEmbedding, limit = 10, minSimilarity = 0.6) => {
244
- const allMemories = await getAllMemories();
245
- const memoriesWithEmbeddings = allMemories.filter(
246
- (m) => m.embedding && m.embedding.length > 0
247
- );
248
- console.log(
249
- `[Memory Search] Total memories: ${allMemories.length}, memories with embeddings: ${memoriesWithEmbeddings.length}`
250
- );
251
- if (memoriesWithEmbeddings.length === 0) {
252
- console.warn(
253
- "[Memory Search] No memories with embeddings found. Memories may need embeddings generated. Use generateAndStoreEmbeddings() to generate embeddings for existing memories."
254
- );
255
- return [];
256
- }
257
- const allResults = memoriesWithEmbeddings.map((memory) => {
258
- const similarity = cosineSimilarity(queryEmbedding, memory.embedding);
259
- return {
260
- ...memory,
261
- similarity
262
- };
263
- }).sort((a, b) => b.similarity - a.similarity);
264
- console.log(
265
- `[Memory Search] All similarity scores:`,
266
- allResults.map((r) => ({
267
- key: `${r.namespace}:${r.key}`,
268
- value: r.value,
269
- similarity: r.similarity.toFixed(4)
270
- }))
271
- );
272
- const results = allResults.filter((result) => result.similarity >= minSimilarity).slice(0, limit);
273
- if (results.length === 0 && allResults.length > 0) {
274
- const topSimilarity = allResults[0].similarity;
275
- const suggestedThreshold = Math.max(0.3, topSimilarity - 0.1);
276
- console.warn(
277
- `[Memory Search] No memories above threshold ${minSimilarity}. Highest similarity was ${topSimilarity.toFixed(4)}. Consider lowering the threshold to ${suggestedThreshold.toFixed(2)}`
278
- );
279
- } else {
280
- console.log(
281
- `[Memory Search] Found ${results.length} memories above similarity threshold ${minSimilarity}. Top similarity: ${results[0]?.similarity.toFixed(4) || "N/A"}`
282
- );
283
- }
284
- return results;
285
- };
2
+ import { useCallback, useEffect, useRef, useState } from "react";
286
3
 
287
4
  // src/client/core/bodySerializer.gen.ts
288
5
  var jsonBodySerializer = {
@@ -1012,91 +729,619 @@ var createClient = (config = {}) => {
1012
729
  ...result
1013
730
  };
1014
731
  }
1015
- const textError = await response.text();
1016
- let jsonError;
1017
- try {
1018
- jsonError = JSON.parse(textError);
1019
- } catch {
732
+ const textError = await response.text();
733
+ let jsonError;
734
+ try {
735
+ jsonError = JSON.parse(textError);
736
+ } catch {
737
+ }
738
+ const error = jsonError ?? textError;
739
+ let finalError = error;
740
+ for (const fn of interceptors.error.fns) {
741
+ if (fn) {
742
+ finalError = await fn(error, response, opts);
743
+ }
744
+ }
745
+ finalError = finalError || {};
746
+ if (opts.throwOnError) {
747
+ throw finalError;
748
+ }
749
+ return {
750
+ error: finalError,
751
+ ...result
752
+ };
753
+ };
754
+ const makeMethodFn = (method) => (options) => request({ ...options, method });
755
+ const makeSseFn = (method) => async (options) => {
756
+ const { opts, url } = await beforeRequest(options);
757
+ return createSseClient({
758
+ ...opts,
759
+ body: opts.body,
760
+ headers: opts.headers,
761
+ method,
762
+ onRequest: async (url2, init) => {
763
+ let request2 = new Request(url2, init);
764
+ const requestInit = {
765
+ ...init,
766
+ method: init.method,
767
+ url: url2
768
+ };
769
+ for (const fn of interceptors.request.fns) {
770
+ if (fn) {
771
+ await fn(requestInit);
772
+ request2 = new Request(requestInit.url, requestInit);
773
+ }
774
+ }
775
+ return request2;
776
+ },
777
+ url
778
+ });
779
+ };
780
+ return {
781
+ buildUrl,
782
+ connect: makeMethodFn("CONNECT"),
783
+ delete: makeMethodFn("DELETE"),
784
+ get: makeMethodFn("GET"),
785
+ getConfig,
786
+ head: makeMethodFn("HEAD"),
787
+ interceptors,
788
+ options: makeMethodFn("OPTIONS"),
789
+ patch: makeMethodFn("PATCH"),
790
+ post: makeMethodFn("POST"),
791
+ put: makeMethodFn("PUT"),
792
+ request,
793
+ setConfig,
794
+ sse: {
795
+ connect: makeSseFn("CONNECT"),
796
+ delete: makeSseFn("DELETE"),
797
+ get: makeSseFn("GET"),
798
+ head: makeSseFn("HEAD"),
799
+ options: makeSseFn("OPTIONS"),
800
+ patch: makeSseFn("PATCH"),
801
+ post: makeSseFn("POST"),
802
+ put: makeSseFn("PUT"),
803
+ trace: makeSseFn("TRACE")
804
+ },
805
+ trace: makeMethodFn("TRACE")
806
+ };
807
+ };
808
+
809
+ // src/clientConfig.ts
810
+ var createClientConfig = (config) => ({
811
+ ...config,
812
+ baseUrl: "https://ai-portal-dev.zetachain.com"
813
+ });
814
+
815
+ // src/client/client.gen.ts
816
+ var client = createClient(createClientConfig(createConfig()));
817
+
818
+ // src/react/useChat.ts
819
+ function useChat(options) {
820
+ const { getToken, onData: globalOnData, onFinish, onError } = options || {};
821
+ const [isLoading, setIsLoading] = useState(false);
822
+ const abortControllerRef = useRef(null);
823
+ const stop = useCallback(() => {
824
+ if (abortControllerRef.current) {
825
+ abortControllerRef.current.abort();
826
+ abortControllerRef.current = null;
827
+ }
828
+ }, []);
829
+ useEffect(() => {
830
+ return () => {
831
+ if (abortControllerRef.current) {
832
+ abortControllerRef.current.abort();
833
+ abortControllerRef.current = null;
834
+ }
835
+ };
836
+ }, []);
837
+ const sendMessage = useCallback(
838
+ async ({
839
+ messages,
840
+ model,
841
+ onData
842
+ }) => {
843
+ if (!messages?.length) {
844
+ const errorMsg = "messages are required to call sendMessage.";
845
+ if (onError) onError(new Error(errorMsg));
846
+ return { data: null, error: errorMsg };
847
+ }
848
+ if (!model) {
849
+ const errorMsg = "model is required to call sendMessage.";
850
+ if (onError) onError(new Error(errorMsg));
851
+ return { data: null, error: errorMsg };
852
+ }
853
+ if (!getToken) {
854
+ const errorMsg = "Token getter function is required.";
855
+ if (onError) onError(new Error(errorMsg));
856
+ return { data: null, error: errorMsg };
857
+ }
858
+ if (abortControllerRef.current) {
859
+ abortControllerRef.current.abort();
860
+ }
861
+ const abortController = new AbortController();
862
+ abortControllerRef.current = abortController;
863
+ setIsLoading(true);
864
+ try {
865
+ const token = await getToken();
866
+ if (!token) {
867
+ const errorMsg = "No access token available.";
868
+ setIsLoading(false);
869
+ if (onError) onError(new Error(errorMsg));
870
+ return { data: null, error: errorMsg };
871
+ }
872
+ const sseResult = await client.sse.post({
873
+ url: "/api/v1/chat/completions",
874
+ body: {
875
+ messages,
876
+ model,
877
+ stream: true
878
+ },
879
+ headers: {
880
+ "Content-Type": "application/json",
881
+ Authorization: `Bearer ${token}`
882
+ },
883
+ signal: abortController.signal
884
+ });
885
+ let accumulatedContent = "";
886
+ let completionId = "";
887
+ let completionModel = "";
888
+ let usage;
889
+ let finishReason;
890
+ for await (const chunk of sseResult.stream) {
891
+ if (typeof chunk === "string" && (chunk.trim() === "[DONE]" || chunk.includes("[DONE]"))) {
892
+ continue;
893
+ }
894
+ if (chunk && typeof chunk === "object") {
895
+ const chunkData = chunk;
896
+ if (chunkData.id && !completionId) {
897
+ completionId = chunkData.id;
898
+ }
899
+ if (chunkData.model && !completionModel) {
900
+ completionModel = chunkData.model;
901
+ }
902
+ if (chunkData.usage) {
903
+ usage = chunkData.usage;
904
+ }
905
+ if (chunkData.choices && Array.isArray(chunkData.choices) && chunkData.choices.length > 0) {
906
+ const choice = chunkData.choices[0];
907
+ if (choice.delta?.content) {
908
+ const content = choice.delta.content;
909
+ accumulatedContent += content;
910
+ if (onData) {
911
+ onData(content);
912
+ }
913
+ if (globalOnData) {
914
+ globalOnData(content);
915
+ }
916
+ }
917
+ if (choice.finish_reason) {
918
+ finishReason = choice.finish_reason;
919
+ }
920
+ }
921
+ }
922
+ }
923
+ const completion = {
924
+ id: completionId,
925
+ model: completionModel,
926
+ choices: [
927
+ {
928
+ index: 0,
929
+ message: {
930
+ role: "assistant",
931
+ content: accumulatedContent
932
+ },
933
+ finish_reason: finishReason
934
+ }
935
+ ],
936
+ usage
937
+ };
938
+ setIsLoading(false);
939
+ if (onFinish) {
940
+ onFinish(completion);
941
+ }
942
+ return { data: completion, error: null };
943
+ } catch (err) {
944
+ if (err instanceof Error && err.name === "AbortError") {
945
+ setIsLoading(false);
946
+ return { data: null, error: "Request aborted" };
947
+ }
948
+ const errorMsg = err instanceof Error ? err.message : "Failed to send message.";
949
+ const errorObj = err instanceof Error ? err : new Error(errorMsg);
950
+ setIsLoading(false);
951
+ if (onError) {
952
+ onError(errorObj);
953
+ }
954
+ return { data: null, error: errorMsg };
955
+ } finally {
956
+ if (abortControllerRef.current === abortController) {
957
+ abortControllerRef.current = null;
958
+ }
959
+ }
960
+ },
961
+ [getToken, globalOnData, onFinish, onError]
962
+ );
963
+ return {
964
+ isLoading,
965
+ sendMessage,
966
+ stop
967
+ };
968
+ }
969
+
970
+ // src/react/useEncryption.ts
971
+ import { useEffect as useEffect2, useRef as useRef2 } from "react";
972
+ import { useSignMessage, useWallets } from "@privy-io/react-auth";
973
+ var SIGN_MESSAGE = "The app is asking you to sign this message to generate a key, which will be used to encrypt data.";
974
+ var SIGNATURE_STORAGE_KEY = "privy_encryption_key";
975
+ function getStorageItem(key) {
976
+ if (typeof window === "undefined" || !window.localStorage) {
977
+ return null;
978
+ }
979
+ try {
980
+ return localStorage.getItem(key);
981
+ } catch {
982
+ return null;
983
+ }
984
+ }
985
+ function setStorageItem(key, value) {
986
+ if (typeof window === "undefined" || !window.localStorage) {
987
+ return false;
988
+ }
989
+ try {
990
+ localStorage.setItem(key, value);
991
+ return true;
992
+ } catch {
993
+ return false;
994
+ }
995
+ }
996
+ function hexToBytes(hex) {
997
+ const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
998
+ const bytes = new Uint8Array(cleanHex.length / 2);
999
+ for (let i = 0; i < cleanHex.length; i += 2) {
1000
+ bytes[i / 2] = parseInt(cleanHex.slice(i, i + 2), 16);
1001
+ }
1002
+ return bytes;
1003
+ }
1004
+ function bytesToHex(bytes) {
1005
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
1006
+ }
1007
+ async function deriveKeyFromSignature(signature) {
1008
+ const sigBytes = hexToBytes(signature);
1009
+ const hashBuffer = await crypto.subtle.digest(
1010
+ "SHA-256",
1011
+ sigBytes.buffer
1012
+ );
1013
+ const hashBytes = new Uint8Array(hashBuffer);
1014
+ return bytesToHex(hashBytes);
1015
+ }
1016
+ async function getEncryptionKey() {
1017
+ const keyHex = getStorageItem(SIGNATURE_STORAGE_KEY);
1018
+ if (!keyHex) {
1019
+ throw new Error("Encryption key not found. Please sign in first.");
1020
+ }
1021
+ const keyBytes = hexToBytes(keyHex);
1022
+ return crypto.subtle.importKey(
1023
+ "raw",
1024
+ keyBytes.buffer,
1025
+ { name: "AES-GCM" },
1026
+ false,
1027
+ ["encrypt", "decrypt"]
1028
+ );
1029
+ }
1030
+ async function encryptData(plaintext) {
1031
+ const key = await getEncryptionKey();
1032
+ const plaintextBytes = typeof plaintext === "string" ? new TextEncoder().encode(plaintext) : plaintext;
1033
+ const iv = crypto.getRandomValues(new Uint8Array(12));
1034
+ const encryptedData = await crypto.subtle.encrypt(
1035
+ {
1036
+ name: "AES-GCM",
1037
+ iv
1038
+ },
1039
+ key,
1040
+ plaintextBytes.buffer
1041
+ );
1042
+ const encryptedBytes = new Uint8Array(encryptedData);
1043
+ const combined = new Uint8Array(iv.length + encryptedBytes.length);
1044
+ combined.set(iv, 0);
1045
+ combined.set(encryptedBytes, iv.length);
1046
+ return bytesToHex(combined);
1047
+ }
1048
+ async function decryptData(encryptedHex) {
1049
+ const key = await getEncryptionKey();
1050
+ const combined = hexToBytes(encryptedHex);
1051
+ const iv = combined.slice(0, 12);
1052
+ const encryptedData = combined.slice(12);
1053
+ const decryptedData = await crypto.subtle.decrypt(
1054
+ {
1055
+ name: "AES-GCM",
1056
+ iv
1057
+ },
1058
+ key,
1059
+ encryptedData
1060
+ );
1061
+ return new TextDecoder().decode(decryptedData);
1062
+ }
1063
+ async function decryptDataBytes(encryptedHex) {
1064
+ const key = await getEncryptionKey();
1065
+ const combined = hexToBytes(encryptedHex);
1066
+ const iv = combined.slice(0, 12);
1067
+ const encryptedData = combined.slice(12);
1068
+ const decryptedData = await crypto.subtle.decrypt(
1069
+ {
1070
+ name: "AES-GCM",
1071
+ iv
1072
+ },
1073
+ key,
1074
+ encryptedData
1075
+ );
1076
+ return new Uint8Array(decryptedData);
1077
+ }
1078
+ function useEncryption(authenticated) {
1079
+ const { signMessage } = useSignMessage();
1080
+ const { wallets } = useWallets();
1081
+ const hasRequestedSignature = useRef2(false);
1082
+ const hasCheckedStorage = useRef2(false);
1083
+ useEffect2(() => {
1084
+ if (!authenticated || wallets.length === 0) {
1085
+ return;
1086
+ }
1087
+ const existingKey = getStorageItem(SIGNATURE_STORAGE_KEY);
1088
+ if (existingKey) {
1089
+ if (!hasCheckedStorage.current) {
1090
+ hasCheckedStorage.current = true;
1091
+ }
1092
+ return;
1093
+ }
1094
+ const requestSignature = async () => {
1095
+ if (!hasRequestedSignature.current) {
1096
+ hasRequestedSignature.current = true;
1097
+ try {
1098
+ const { signature } = await signMessage(
1099
+ { message: SIGN_MESSAGE },
1100
+ {
1101
+ address: wallets[0].address
1102
+ }
1103
+ );
1104
+ const encryptionKey = await deriveKeyFromSignature(signature);
1105
+ const stored = setStorageItem(SIGNATURE_STORAGE_KEY, encryptionKey);
1106
+ if (!stored) {
1107
+ throw new Error("Failed to store encryption key in localStorage");
1108
+ }
1109
+ } catch (error) {
1110
+ hasRequestedSignature.current = false;
1111
+ }
1112
+ }
1113
+ };
1114
+ requestSignature();
1115
+ }, [
1116
+ authenticated,
1117
+ wallets.length > 0 ? wallets[0]?.address : null,
1118
+ signMessage
1119
+ ]);
1120
+ useEffect2(() => {
1121
+ if (!authenticated) {
1122
+ hasRequestedSignature.current = false;
1123
+ hasCheckedStorage.current = false;
1124
+ }
1125
+ }, [authenticated]);
1126
+ }
1127
+
1128
+ // src/react/useMemory.ts
1129
+ import { useCallback as useCallback2, useRef as useRef3 } from "react";
1130
+ import { postApiV1ChatCompletions } from "@reverbia/sdk";
1131
+
1132
+ // src/lib/memory/service.ts
1133
+ var FACT_EXTRACTION_PROMPT = `You are a memory extraction system. Extract durable user memories from chat messages.
1134
+
1135
+ CRITICAL: You MUST respond with ONLY valid JSON. No explanations, no markdown, no code blocks, just pure JSON.
1136
+
1137
+ Only extract facts that will be useful in future conversations, such as identity, stable preferences, ongoing projects, skills, and constraints.
1138
+
1139
+ Do not extract sensitive attributes, temporary things, or single-use instructions.
1140
+
1141
+ If there are no memories to extract, return: {"items": []}
1142
+
1143
+ Response format (JSON only, no other text):
1144
+
1145
+ {
1146
+ "items": [
1147
+ {
1148
+ "type": "identity",
1149
+ "namespace": "identity",
1150
+ "key": "name",
1151
+ "value": "Charlie",
1152
+ "rawEvidence": "I'm Charlie",
1153
+ "confidence": 0.98,
1154
+ "pii": true
1155
+ },
1156
+ {
1157
+ "type": "identity",
1158
+ "namespace": "work",
1159
+ "key": "company",
1160
+ "value": "ZetaChain",
1161
+ "rawEvidence": "called ZetaChain",
1162
+ "confidence": 0.99,
1163
+ "pii": false
1164
+ },
1165
+ {
1166
+ "type": "preference",
1167
+ "namespace": "answer_style",
1168
+ "key": "verbosity",
1169
+ "value": "concise_direct",
1170
+ "rawEvidence": "I prefer concise, direct answers",
1171
+ "confidence": 0.96,
1172
+ "pii": false
1173
+ },
1174
+ {
1175
+ "type": "identity",
1176
+ "namespace": "timezone",
1177
+ "key": "tz",
1178
+ "value": "America/Los_Angeles",
1179
+ "rawEvidence": "I'm in PST",
1180
+ "confidence": 0.9,
1181
+ "pii": false
1182
+ }
1183
+ ]
1184
+ }`;
1185
+ var preprocessMemories = (items, minConfidence = 0.6) => {
1186
+ if (!items || !Array.isArray(items)) {
1187
+ return [];
1188
+ }
1189
+ const validItems = items.filter((item) => {
1190
+ if (item.namespace == null || item.key == null || item.value == null) {
1191
+ console.warn(
1192
+ "Dropping memory item with null/undefined namespace, key, or value:",
1193
+ item
1194
+ );
1195
+ return false;
1020
1196
  }
1021
- const error = jsonError ?? textError;
1022
- let finalError = error;
1023
- for (const fn of interceptors.error.fns) {
1024
- if (fn) {
1025
- finalError = await fn(error, response, opts);
1026
- }
1197
+ const namespace = String(item.namespace).trim();
1198
+ const key = String(item.key).trim();
1199
+ const value = String(item.value).trim();
1200
+ if (namespace === "" || key === "" || value === "") {
1201
+ console.warn(
1202
+ "Dropping memory item with empty namespace, key, or value after trimming:",
1203
+ item
1204
+ );
1205
+ return false;
1027
1206
  }
1028
- finalError = finalError || {};
1029
- if (opts.throwOnError) {
1030
- throw finalError;
1207
+ if (typeof item.confidence !== "number" || item.confidence < minConfidence) {
1208
+ console.warn(
1209
+ `Dropping memory item with confidence ${item.confidence} below threshold ${minConfidence}:`,
1210
+ item
1211
+ );
1212
+ return false;
1031
1213
  }
1032
- return {
1033
- error: finalError,
1034
- ...result
1214
+ return true;
1215
+ });
1216
+ const deduplicatedMap = /* @__PURE__ */ new Map();
1217
+ for (const item of validItems) {
1218
+ const uniqueKey = `${item.namespace}:${item.key}:${item.value}`;
1219
+ const existing = deduplicatedMap.get(uniqueKey);
1220
+ if (!existing || item.confidence > existing.confidence) {
1221
+ deduplicatedMap.set(uniqueKey, item);
1222
+ } else {
1223
+ console.debug(
1224
+ `Deduplicating memory item: keeping entry with higher confidence (${existing.confidence} > ${item.confidence})`,
1225
+ { namespace: item.namespace, key: item.key, value: item.value }
1226
+ );
1227
+ }
1228
+ }
1229
+ return Array.from(deduplicatedMap.values());
1230
+ };
1231
+
1232
+ // src/lib/memory/db.ts
1233
+ import Dexie from "dexie";
1234
+ var MemoryDatabase = class extends Dexie {
1235
+ constructor() {
1236
+ super("MemoryDatabase");
1237
+ this.version(2).stores({
1238
+ memories: "++id, uniqueKey, compositeKey, namespace, key, type, createdAt, updatedAt"
1239
+ });
1240
+ this.version(3).stores({
1241
+ memories: "++id, uniqueKey, compositeKey, namespace, key, type, createdAt, updatedAt"
1242
+ });
1243
+ }
1244
+ };
1245
+ var memoryDb = new MemoryDatabase();
1246
+ var saveMemory = async (memory) => {
1247
+ const compositeKey = `${memory.namespace}:${memory.key}`;
1248
+ const uniqueKey = `${memory.namespace}:${memory.key}:${memory.value}`;
1249
+ const now = Date.now();
1250
+ const existing = await memoryDb.memories.where("uniqueKey").equals(uniqueKey).first();
1251
+ if (existing) {
1252
+ const shouldPreserveEmbedding = existing.value === memory.value && existing.rawEvidence === memory.rawEvidence && existing.type === memory.type && existing.namespace === memory.namespace && existing.key === memory.key && existing.embedding !== void 0 && existing.embedding.length > 0;
1253
+ const updateData = {
1254
+ ...memory,
1255
+ compositeKey,
1256
+ uniqueKey,
1257
+ updatedAt: now,
1258
+ createdAt: existing.createdAt
1035
1259
  };
1036
- };
1037
- const makeMethodFn = (method) => (options) => request({ ...options, method });
1038
- const makeSseFn = (method) => async (options) => {
1039
- const { opts, url } = await beforeRequest(options);
1040
- return createSseClient({
1041
- ...opts,
1042
- body: opts.body,
1043
- headers: opts.headers,
1044
- method,
1045
- onRequest: async (url2, init) => {
1046
- let request2 = new Request(url2, init);
1047
- const requestInit = {
1048
- ...init,
1049
- method: init.method,
1050
- url: url2
1051
- };
1052
- for (const fn of interceptors.request.fns) {
1053
- if (fn) {
1054
- await fn(requestInit);
1055
- request2 = new Request(requestInit.url, requestInit);
1056
- }
1057
- }
1058
- return request2;
1059
- },
1060
- url
1260
+ if (shouldPreserveEmbedding) {
1261
+ updateData.embedding = existing.embedding;
1262
+ updateData.embeddingModel = existing.embeddingModel;
1263
+ } else {
1264
+ updateData.embedding = [];
1265
+ updateData.embeddingModel = void 0;
1266
+ }
1267
+ await memoryDb.memories.update(existing.id, updateData);
1268
+ } else {
1269
+ await memoryDb.memories.add({
1270
+ ...memory,
1271
+ compositeKey,
1272
+ uniqueKey,
1273
+ createdAt: now,
1274
+ updatedAt: now
1061
1275
  });
1062
- };
1063
- return {
1064
- buildUrl,
1065
- connect: makeMethodFn("CONNECT"),
1066
- delete: makeMethodFn("DELETE"),
1067
- get: makeMethodFn("GET"),
1068
- getConfig,
1069
- head: makeMethodFn("HEAD"),
1070
- interceptors,
1071
- options: makeMethodFn("OPTIONS"),
1072
- patch: makeMethodFn("PATCH"),
1073
- post: makeMethodFn("POST"),
1074
- put: makeMethodFn("PUT"),
1075
- request,
1076
- setConfig,
1077
- sse: {
1078
- connect: makeSseFn("CONNECT"),
1079
- delete: makeSseFn("DELETE"),
1080
- get: makeSseFn("GET"),
1081
- head: makeSseFn("HEAD"),
1082
- options: makeSseFn("OPTIONS"),
1083
- patch: makeSseFn("PATCH"),
1084
- post: makeSseFn("POST"),
1085
- put: makeSseFn("PUT"),
1086
- trace: makeSseFn("TRACE")
1087
- },
1088
- trace: makeMethodFn("TRACE")
1089
- };
1276
+ }
1277
+ };
1278
+ var saveMemories = async (memories) => {
1279
+ await Promise.all(memories.map((memory) => saveMemory(memory)));
1280
+ };
1281
+ var getAllMemories = async () => {
1282
+ return memoryDb.memories.toArray();
1283
+ };
1284
+ var cosineSimilarity = (a, b) => {
1285
+ if (a.length !== b.length) {
1286
+ throw new Error("Vectors must have the same length");
1287
+ }
1288
+ let dotProduct = 0;
1289
+ let normA = 0;
1290
+ let normB = 0;
1291
+ for (let i = 0; i < a.length; i++) {
1292
+ dotProduct += a[i] * b[i];
1293
+ normA += a[i] * a[i];
1294
+ normB += b[i] * b[i];
1295
+ }
1296
+ const denominator = Math.sqrt(normA) * Math.sqrt(normB);
1297
+ if (denominator === 0) {
1298
+ return 0;
1299
+ }
1300
+ return dotProduct / denominator;
1301
+ };
1302
+ var searchSimilarMemories = async (queryEmbedding, limit = 10, minSimilarity = 0.6) => {
1303
+ const allMemories = await getAllMemories();
1304
+ const memoriesWithEmbeddings = allMemories.filter(
1305
+ (m) => m.embedding && m.embedding.length > 0
1306
+ );
1307
+ console.log(
1308
+ `[Memory Search] Total memories: ${allMemories.length}, memories with embeddings: ${memoriesWithEmbeddings.length}`
1309
+ );
1310
+ if (memoriesWithEmbeddings.length === 0) {
1311
+ console.warn(
1312
+ "[Memory Search] No memories with embeddings found. Memories may need embeddings generated. Use generateAndStoreEmbeddings() to generate embeddings for existing memories."
1313
+ );
1314
+ return [];
1315
+ }
1316
+ const allResults = memoriesWithEmbeddings.map((memory) => {
1317
+ const similarity = cosineSimilarity(queryEmbedding, memory.embedding);
1318
+ return {
1319
+ ...memory,
1320
+ similarity
1321
+ };
1322
+ }).sort((a, b) => b.similarity - a.similarity);
1323
+ console.log(
1324
+ `[Memory Search] All similarity scores:`,
1325
+ allResults.map((r) => ({
1326
+ key: `${r.namespace}:${r.key}`,
1327
+ value: r.value,
1328
+ similarity: r.similarity.toFixed(4)
1329
+ }))
1330
+ );
1331
+ const results = allResults.filter((result) => result.similarity >= minSimilarity).slice(0, limit);
1332
+ if (results.length === 0 && allResults.length > 0) {
1333
+ const topSimilarity = allResults[0].similarity;
1334
+ const suggestedThreshold = Math.max(0.3, topSimilarity - 0.1);
1335
+ console.warn(
1336
+ `[Memory Search] No memories above threshold ${minSimilarity}. Highest similarity was ${topSimilarity.toFixed(4)}. Consider lowering the threshold to ${suggestedThreshold.toFixed(2)}`
1337
+ );
1338
+ } else {
1339
+ console.log(
1340
+ `[Memory Search] Found ${results.length} memories above similarity threshold ${minSimilarity}. Top similarity: ${results[0]?.similarity.toFixed(4) || "N/A"}`
1341
+ );
1342
+ }
1343
+ return results;
1090
1344
  };
1091
-
1092
- // src/clientConfig.ts
1093
- var createClientConfig = (config) => ({
1094
- ...config,
1095
- baseUrl: "https://ai-portal-dev.zetachain.com"
1096
- });
1097
-
1098
- // src/client/client.gen.ts
1099
- var client = createClient(createClientConfig(createConfig()));
1100
1345
 
1101
1346
  // src/client/sdk.gen.ts
1102
1347
  var postApiV1Embeddings = (options) => {
@@ -1214,7 +1459,7 @@ function useMemory(options = {}) {
1214
1459
  onFactsExtracted,
1215
1460
  getToken
1216
1461
  } = options;
1217
- const extractionInProgressRef = useRef(false);
1462
+ const extractionInProgressRef = useRef3(false);
1218
1463
  const extractMemoriesFromMessage = useCallback2(
1219
1464
  async (options2) => {
1220
1465
  const { messages, model } = options2;
@@ -1228,7 +1473,7 @@ function useMemory(options = {}) {
1228
1473
  console.error("No access token available for memory extraction");
1229
1474
  return null;
1230
1475
  }
1231
- const completion = await postApiV1ChatCompletions2({
1476
+ const completion = await postApiV1ChatCompletions({
1232
1477
  body: {
1233
1478
  messages: [
1234
1479
  {
@@ -1485,8 +1730,12 @@ var extractConversationContext = (messages, maxMessages = 3) => {
1485
1730
  };
1486
1731
  export {
1487
1732
  createMemoryContextSystemMessage,
1733
+ decryptData,
1734
+ decryptDataBytes,
1735
+ encryptData,
1488
1736
  extractConversationContext,
1489
1737
  formatMemoriesForChat,
1490
1738
  useChat,
1739
+ useEncryption,
1491
1740
  useMemory
1492
1741
  };