@reverbia/sdk 1.0.0-next.20251212012743 → 1.0.0-next.20251215143604

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.
@@ -30,7 +30,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/react/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ ChatConversation: () => Conversation,
34
+ ChatMessage: () => Message,
33
35
  DEFAULT_TOOL_SELECTOR_MODEL: () => DEFAULT_TOOL_SELECTOR_MODEL,
36
+ StoredMemoryModel: () => Memory,
37
+ chatStorageSchema: () => chatStorageSchema,
34
38
  createMemoryContextSystemMessage: () => createMemoryContextSystemMessage,
35
39
  decryptData: () => decryptData,
36
40
  decryptDataBytes: () => decryptDataBytes,
@@ -38,13 +42,18 @@ __export(index_exports, {
38
42
  executeTool: () => executeTool,
39
43
  extractConversationContext: () => extractConversationContext,
40
44
  formatMemoriesForChat: () => formatMemoriesForChat,
45
+ generateCompositeKey: () => generateCompositeKey,
46
+ generateConversationId: () => generateConversationId,
47
+ generateUniqueKey: () => generateUniqueKey,
41
48
  hasEncryptionKey: () => hasEncryptionKey,
49
+ memoryStorageSchema: () => memoryStorageSchema,
42
50
  requestEncryptionKey: () => requestEncryptionKey,
43
51
  selectTool: () => selectTool,
44
52
  useChat: () => useChat,
53
+ useChatStorage: () => useChatStorage,
45
54
  useEncryption: () => useEncryption,
46
55
  useImageGeneration: () => useImageGeneration,
47
- useMemory: () => useMemory,
56
+ useMemoryStorage: () => useMemoryStorage,
48
57
  useModels: () => useModels,
49
58
  useOCR: () => useOCR,
50
59
  usePdf: () => usePdf,
@@ -1280,7 +1289,8 @@ function useChat(options) {
1280
1289
  model,
1281
1290
  onData,
1282
1291
  runTools = true,
1283
- headers
1292
+ headers,
1293
+ memoryContext
1284
1294
  }) => {
1285
1295
  const messagesValidation = validateMessages(messages);
1286
1296
  if (!messagesValidation.valid) {
@@ -1293,7 +1303,20 @@ function useChat(options) {
1293
1303
  abortControllerRef.current = abortController;
1294
1304
  setIsLoading(true);
1295
1305
  let toolExecutionResult;
1296
- let messagesWithToolContext = messages;
1306
+ let messagesWithContext = messages;
1307
+ if (memoryContext) {
1308
+ const memorySystemMessage = {
1309
+ role: "system",
1310
+ content: [
1311
+ {
1312
+ type: "text",
1313
+ text: memoryContext
1314
+ }
1315
+ ]
1316
+ };
1317
+ messagesWithContext = [memorySystemMessage, ...messages];
1318
+ }
1319
+ let messagesWithToolContext = messagesWithContext;
1297
1320
  const shouldRunTools = runTools && tools && tools.length > 0;
1298
1321
  if (shouldRunTools) {
1299
1322
  const lastUserMessage = [...messages].reverse().find((m) => m.role === "user");
@@ -1670,16 +1693,926 @@ async function requestEncryptionKey(walletAddress, signMessage) {
1670
1693
  throw new Error("Failed to store encryption key in localStorage");
1671
1694
  }
1672
1695
  }
1673
- function useEncryption(signMessage) {
1674
- return {
1675
- requestEncryptionKey: (walletAddress) => requestEncryptionKey(walletAddress, signMessage)
1676
- };
1696
+ function useEncryption(signMessage) {
1697
+ return {
1698
+ requestEncryptionKey: (walletAddress) => requestEncryptionKey(walletAddress, signMessage)
1699
+ };
1700
+ }
1701
+
1702
+ // src/react/useChatStorage.ts
1703
+ var import_react2 = require("react");
1704
+
1705
+ // src/lib/chatStorage/types.ts
1706
+ function convertUsageToStored(usage) {
1707
+ if (!usage) return void 0;
1708
+ return {
1709
+ promptTokens: usage.prompt_tokens,
1710
+ completionTokens: usage.completion_tokens,
1711
+ totalTokens: usage.total_tokens,
1712
+ costMicroUsd: usage.cost_micro_usd
1713
+ };
1714
+ }
1715
+ function generateConversationId() {
1716
+ return `conv_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
1717
+ }
1718
+
1719
+ // src/lib/chatStorage/operations.ts
1720
+ var import_watermelondb = require("@nozbe/watermelondb");
1721
+ function messageToStored(message) {
1722
+ return {
1723
+ uniqueId: message.id,
1724
+ messageId: message.messageId,
1725
+ conversationId: message.conversationId,
1726
+ role: message.role,
1727
+ content: message.content,
1728
+ model: message.model,
1729
+ files: message.files,
1730
+ createdAt: message.createdAt,
1731
+ updatedAt: message.updatedAt,
1732
+ vector: message.vector,
1733
+ embeddingModel: message.embeddingModel,
1734
+ usage: message.usage,
1735
+ sources: message.sources,
1736
+ responseDuration: message.responseDuration
1737
+ };
1738
+ }
1739
+ function conversationToStored(conversation) {
1740
+ return {
1741
+ uniqueId: conversation.id,
1742
+ conversationId: conversation.conversationId,
1743
+ title: conversation.title,
1744
+ createdAt: conversation.createdAt,
1745
+ updatedAt: conversation.updatedAt,
1746
+ isDeleted: conversation.isDeleted
1747
+ };
1748
+ }
1749
+ async function createConversationOp(ctx, opts, defaultTitle = "New Conversation") {
1750
+ const convId = opts?.conversationId || generateConversationId();
1751
+ const title = opts?.title || defaultTitle;
1752
+ const created = await ctx.database.write(async () => {
1753
+ return await ctx.conversationsCollection.create((conv) => {
1754
+ conv._setRaw("conversation_id", convId);
1755
+ conv._setRaw("title", title);
1756
+ conv._setRaw("is_deleted", false);
1757
+ });
1758
+ });
1759
+ return conversationToStored(created);
1760
+ }
1761
+ async function getConversationOp(ctx, id) {
1762
+ const results = await ctx.conversationsCollection.query(import_watermelondb.Q.where("conversation_id", id), import_watermelondb.Q.where("is_deleted", false)).fetch();
1763
+ return results.length > 0 ? conversationToStored(results[0]) : null;
1764
+ }
1765
+ async function getConversationsOp(ctx) {
1766
+ const results = await ctx.conversationsCollection.query(import_watermelondb.Q.where("is_deleted", false), import_watermelondb.Q.sortBy("created_at", import_watermelondb.Q.desc)).fetch();
1767
+ return results.map(conversationToStored);
1768
+ }
1769
+ async function updateConversationTitleOp(ctx, id, title) {
1770
+ const results = await ctx.conversationsCollection.query(import_watermelondb.Q.where("conversation_id", id), import_watermelondb.Q.where("is_deleted", false)).fetch();
1771
+ if (results.length > 0) {
1772
+ await ctx.database.write(async () => {
1773
+ await results[0].update((conv) => {
1774
+ conv._setRaw("title", title);
1775
+ });
1776
+ });
1777
+ return true;
1778
+ }
1779
+ return false;
1780
+ }
1781
+ async function deleteConversationOp(ctx, id) {
1782
+ const results = await ctx.conversationsCollection.query(import_watermelondb.Q.where("conversation_id", id), import_watermelondb.Q.where("is_deleted", false)).fetch();
1783
+ if (results.length > 0) {
1784
+ await ctx.database.write(async () => {
1785
+ await results[0].update((conv) => {
1786
+ conv._setRaw("is_deleted", true);
1787
+ });
1788
+ });
1789
+ return true;
1790
+ }
1791
+ return false;
1792
+ }
1793
+ async function getMessagesOp(ctx, convId) {
1794
+ const results = await ctx.messagesCollection.query(import_watermelondb.Q.where("conversation_id", convId), import_watermelondb.Q.sortBy("message_id", import_watermelondb.Q.asc)).fetch();
1795
+ return results.map(messageToStored);
1796
+ }
1797
+ async function getMessageCountOp(ctx, convId) {
1798
+ return await ctx.messagesCollection.query(import_watermelondb.Q.where("conversation_id", convId)).fetchCount();
1799
+ }
1800
+ async function clearMessagesOp(ctx, convId) {
1801
+ const messages = await ctx.messagesCollection.query(import_watermelondb.Q.where("conversation_id", convId)).fetch();
1802
+ await ctx.database.write(async () => {
1803
+ for (const message of messages) {
1804
+ await message.destroyPermanently();
1805
+ }
1806
+ });
1807
+ }
1808
+ async function createMessageOp(ctx, opts) {
1809
+ const existingCount = await getMessageCountOp(ctx, opts.conversationId);
1810
+ const messageId = existingCount + 1;
1811
+ const created = await ctx.database.write(async () => {
1812
+ return await ctx.messagesCollection.create((msg) => {
1813
+ msg._setRaw("message_id", messageId);
1814
+ msg._setRaw("conversation_id", opts.conversationId);
1815
+ msg._setRaw("role", opts.role);
1816
+ msg._setRaw("content", opts.content);
1817
+ if (opts.model) msg._setRaw("model", opts.model);
1818
+ if (opts.files) msg._setRaw("files", JSON.stringify(opts.files));
1819
+ if (opts.usage) msg._setRaw("usage", JSON.stringify(opts.usage));
1820
+ if (opts.sources) msg._setRaw("sources", JSON.stringify(opts.sources));
1821
+ if (opts.responseDuration !== void 0)
1822
+ msg._setRaw("response_duration", opts.responseDuration);
1823
+ if (opts.vector) msg._setRaw("vector", JSON.stringify(opts.vector));
1824
+ if (opts.embeddingModel) msg._setRaw("embedding_model", opts.embeddingModel);
1825
+ });
1826
+ });
1827
+ return messageToStored(created);
1828
+ }
1829
+ async function updateMessageEmbeddingOp(ctx, uniqueId, vector, embeddingModel) {
1830
+ let message;
1831
+ try {
1832
+ message = await ctx.messagesCollection.find(uniqueId);
1833
+ } catch {
1834
+ return null;
1835
+ }
1836
+ await ctx.database.write(async () => {
1837
+ await message.update((msg) => {
1838
+ msg._setRaw("vector", JSON.stringify(vector));
1839
+ msg._setRaw("embedding_model", embeddingModel);
1840
+ });
1841
+ });
1842
+ return messageToStored(message);
1843
+ }
1844
+ function cosineSimilarity(a, b) {
1845
+ if (a.length !== b.length) return 0;
1846
+ let dotProduct = 0;
1847
+ let normA = 0;
1848
+ let normB = 0;
1849
+ for (let i = 0; i < a.length; i++) {
1850
+ dotProduct += a[i] * b[i];
1851
+ normA += a[i] * a[i];
1852
+ normB += b[i] * b[i];
1853
+ }
1854
+ const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
1855
+ return magnitude === 0 ? 0 : dotProduct / magnitude;
1856
+ }
1857
+ async function searchMessagesOp(ctx, queryVector, options) {
1858
+ const { limit = 10, minSimilarity = 0.5, conversationId } = options || {};
1859
+ const activeConversations = await ctx.conversationsCollection.query(import_watermelondb.Q.where("is_deleted", false)).fetch();
1860
+ const activeConversationIds = new Set(
1861
+ activeConversations.map((c) => c.conversationId)
1862
+ );
1863
+ const queryConditions = conversationId ? [import_watermelondb.Q.where("conversation_id", conversationId)] : [];
1864
+ const messages = await ctx.messagesCollection.query(...queryConditions).fetch();
1865
+ const resultsWithSimilarity = [];
1866
+ for (const message of messages) {
1867
+ if (!activeConversationIds.has(message.conversationId)) continue;
1868
+ const messageVector = message.vector;
1869
+ if (!messageVector || messageVector.length === 0) continue;
1870
+ const similarity = cosineSimilarity(queryVector, messageVector);
1871
+ if (similarity >= minSimilarity) {
1872
+ resultsWithSimilarity.push({
1873
+ ...messageToStored(message),
1874
+ similarity
1875
+ });
1876
+ }
1877
+ }
1878
+ return resultsWithSimilarity.sort((a, b) => b.similarity - a.similarity).slice(0, limit);
1879
+ }
1880
+
1881
+ // src/react/useChatStorage.ts
1882
+ function storedToLlmapiMessage(stored) {
1883
+ const content = [
1884
+ { type: "text", text: stored.content }
1885
+ ];
1886
+ if (stored.files?.length) {
1887
+ for (const file of stored.files) {
1888
+ if (file.url) {
1889
+ content.push({
1890
+ type: "image_url",
1891
+ image_url: { url: file.url }
1892
+ });
1893
+ }
1894
+ }
1895
+ }
1896
+ return {
1897
+ role: stored.role,
1898
+ content
1899
+ };
1900
+ }
1901
+ function useChatStorage(options) {
1902
+ const {
1903
+ database,
1904
+ conversationId: initialConversationId,
1905
+ autoCreateConversation = true,
1906
+ defaultConversationTitle = "New Conversation",
1907
+ getToken,
1908
+ baseUrl,
1909
+ onData,
1910
+ onFinish,
1911
+ onError,
1912
+ chatProvider,
1913
+ localModel,
1914
+ tools,
1915
+ toolSelectorModel,
1916
+ onToolExecution
1917
+ } = options;
1918
+ const [currentConversationId, setCurrentConversationId] = (0, import_react2.useState)(initialConversationId || null);
1919
+ const messagesCollection = (0, import_react2.useMemo)(
1920
+ () => database.get("history"),
1921
+ [database]
1922
+ );
1923
+ const conversationsCollection = (0, import_react2.useMemo)(
1924
+ () => database.get("conversations"),
1925
+ [database]
1926
+ );
1927
+ const storageCtx = (0, import_react2.useMemo)(
1928
+ () => ({
1929
+ database,
1930
+ messagesCollection,
1931
+ conversationsCollection
1932
+ }),
1933
+ [database, messagesCollection, conversationsCollection]
1934
+ );
1935
+ const {
1936
+ isLoading,
1937
+ isSelectingTool,
1938
+ sendMessage: baseSendMessage,
1939
+ stop
1940
+ } = useChat({
1941
+ getToken,
1942
+ baseUrl,
1943
+ onData,
1944
+ onFinish,
1945
+ onError,
1946
+ chatProvider,
1947
+ localModel,
1948
+ tools,
1949
+ toolSelectorModel,
1950
+ onToolExecution
1951
+ });
1952
+ const createConversation = (0, import_react2.useCallback)(
1953
+ async (opts) => {
1954
+ const created = await createConversationOp(
1955
+ storageCtx,
1956
+ opts,
1957
+ defaultConversationTitle
1958
+ );
1959
+ setCurrentConversationId(created.conversationId);
1960
+ return created;
1961
+ },
1962
+ [storageCtx, defaultConversationTitle]
1963
+ );
1964
+ const getConversation = (0, import_react2.useCallback)(
1965
+ async (id) => {
1966
+ return getConversationOp(storageCtx, id);
1967
+ },
1968
+ [storageCtx]
1969
+ );
1970
+ const getConversations = (0, import_react2.useCallback)(async () => {
1971
+ return getConversationsOp(storageCtx);
1972
+ }, [storageCtx]);
1973
+ const updateConversationTitle = (0, import_react2.useCallback)(
1974
+ async (id, title) => {
1975
+ return updateConversationTitleOp(storageCtx, id, title);
1976
+ },
1977
+ [storageCtx]
1978
+ );
1979
+ const deleteConversation = (0, import_react2.useCallback)(
1980
+ async (id) => {
1981
+ const deleted = await deleteConversationOp(storageCtx, id);
1982
+ if (deleted && currentConversationId === id) {
1983
+ setCurrentConversationId(null);
1984
+ }
1985
+ return deleted;
1986
+ },
1987
+ [storageCtx, currentConversationId]
1988
+ );
1989
+ const getMessages = (0, import_react2.useCallback)(
1990
+ async (convId) => {
1991
+ return getMessagesOp(storageCtx, convId);
1992
+ },
1993
+ [storageCtx]
1994
+ );
1995
+ const getMessageCount = (0, import_react2.useCallback)(
1996
+ async (convId) => {
1997
+ return getMessageCountOp(storageCtx, convId);
1998
+ },
1999
+ [storageCtx]
2000
+ );
2001
+ const clearMessages = (0, import_react2.useCallback)(
2002
+ async (convId) => {
2003
+ return clearMessagesOp(storageCtx, convId);
2004
+ },
2005
+ [storageCtx]
2006
+ );
2007
+ const ensureConversation = (0, import_react2.useCallback)(async () => {
2008
+ if (currentConversationId) {
2009
+ const existing = await getConversation(currentConversationId);
2010
+ if (existing) {
2011
+ return currentConversationId;
2012
+ }
2013
+ if (autoCreateConversation) {
2014
+ const newConv = await createConversation({
2015
+ conversationId: currentConversationId
2016
+ });
2017
+ return newConv.conversationId;
2018
+ }
2019
+ }
2020
+ if (autoCreateConversation) {
2021
+ const newConv = await createConversation();
2022
+ return newConv.conversationId;
2023
+ }
2024
+ throw new Error(
2025
+ "No conversation ID provided and autoCreateConversation is disabled"
2026
+ );
2027
+ }, [
2028
+ currentConversationId,
2029
+ getConversation,
2030
+ autoCreateConversation,
2031
+ createConversation
2032
+ ]);
2033
+ const sendMessage = (0, import_react2.useCallback)(
2034
+ async (args) => {
2035
+ const {
2036
+ content,
2037
+ model,
2038
+ messages: providedMessages,
2039
+ includeHistory = true,
2040
+ maxHistoryMessages = 50,
2041
+ files,
2042
+ onData: perRequestOnData,
2043
+ runTools,
2044
+ headers,
2045
+ memoryContext
2046
+ } = args;
2047
+ let convId;
2048
+ try {
2049
+ convId = await ensureConversation();
2050
+ } catch (err) {
2051
+ return {
2052
+ data: null,
2053
+ error: err instanceof Error ? err.message : "Failed to ensure conversation"
2054
+ };
2055
+ }
2056
+ let messagesToSend = [];
2057
+ if (includeHistory && !providedMessages) {
2058
+ const storedMessages = await getMessages(convId);
2059
+ const limitedMessages = storedMessages.slice(-maxHistoryMessages);
2060
+ messagesToSend = limitedMessages.map(storedToLlmapiMessage);
2061
+ } else if (providedMessages) {
2062
+ messagesToSend = providedMessages;
2063
+ }
2064
+ const userMessageContent = [
2065
+ { type: "text", text: content }
2066
+ ];
2067
+ if (files && files.length > 0) {
2068
+ for (const file of files) {
2069
+ if (file.url && file.type.startsWith("image/")) {
2070
+ userMessageContent.push({
2071
+ type: "image_url",
2072
+ image_url: { url: file.url }
2073
+ });
2074
+ }
2075
+ }
2076
+ }
2077
+ const userMessage = {
2078
+ role: "user",
2079
+ content: userMessageContent
2080
+ };
2081
+ messagesToSend.push(userMessage);
2082
+ const sanitizedFiles = files?.map((file) => ({
2083
+ id: file.id,
2084
+ name: file.name,
2085
+ type: file.type,
2086
+ size: file.size,
2087
+ // Only keep URL if it's not a data URI (e.g., external URLs)
2088
+ url: file.url && !file.url.startsWith("data:") ? file.url : void 0
2089
+ }));
2090
+ let storedUserMessage;
2091
+ try {
2092
+ storedUserMessage = await createMessageOp(storageCtx, {
2093
+ conversationId: convId,
2094
+ role: "user",
2095
+ content,
2096
+ files: sanitizedFiles
2097
+ });
2098
+ } catch (err) {
2099
+ return {
2100
+ data: null,
2101
+ error: err instanceof Error ? err.message : "Failed to store user message"
2102
+ };
2103
+ }
2104
+ const startTime = Date.now();
2105
+ const result = await baseSendMessage({
2106
+ messages: messagesToSend,
2107
+ model,
2108
+ onData: perRequestOnData,
2109
+ runTools,
2110
+ headers,
2111
+ memoryContext
2112
+ });
2113
+ const responseDuration = (Date.now() - startTime) / 1e3;
2114
+ if (result.error || !result.data) {
2115
+ return {
2116
+ data: null,
2117
+ error: result.error || "No response data received",
2118
+ toolExecution: result.toolExecution,
2119
+ userMessage: storedUserMessage
2120
+ };
2121
+ }
2122
+ const responseData = result.data;
2123
+ const assistantContent = responseData.choices?.[0]?.message?.content?.map((part) => part.text || "").join("") || "";
2124
+ let storedAssistantMessage;
2125
+ try {
2126
+ storedAssistantMessage = await createMessageOp(storageCtx, {
2127
+ conversationId: convId,
2128
+ role: "assistant",
2129
+ content: assistantContent,
2130
+ model: responseData.model,
2131
+ usage: convertUsageToStored(responseData.usage),
2132
+ responseDuration
2133
+ });
2134
+ } catch (err) {
2135
+ return {
2136
+ data: null,
2137
+ error: err instanceof Error ? err.message : "Failed to store assistant message",
2138
+ toolExecution: result.toolExecution,
2139
+ userMessage: storedUserMessage
2140
+ };
2141
+ }
2142
+ return {
2143
+ data: responseData,
2144
+ error: null,
2145
+ toolExecution: result.toolExecution,
2146
+ userMessage: storedUserMessage,
2147
+ assistantMessage: storedAssistantMessage
2148
+ };
2149
+ },
2150
+ [ensureConversation, getMessages, storageCtx, baseSendMessage]
2151
+ );
2152
+ const searchMessages = (0, import_react2.useCallback)(
2153
+ async (queryVector, options2) => {
2154
+ return searchMessagesOp(storageCtx, queryVector, options2);
2155
+ },
2156
+ [storageCtx]
2157
+ );
2158
+ const updateMessageEmbedding = (0, import_react2.useCallback)(
2159
+ async (uniqueId, vector, embeddingModel) => {
2160
+ return updateMessageEmbeddingOp(storageCtx, uniqueId, vector, embeddingModel);
2161
+ },
2162
+ [storageCtx]
2163
+ );
2164
+ return {
2165
+ isLoading,
2166
+ isSelectingTool,
2167
+ sendMessage,
2168
+ stop,
2169
+ conversationId: currentConversationId,
2170
+ setConversationId: setCurrentConversationId,
2171
+ createConversation,
2172
+ getConversation,
2173
+ getConversations,
2174
+ updateConversationTitle,
2175
+ deleteConversation,
2176
+ getMessages,
2177
+ getMessageCount,
2178
+ clearMessages,
2179
+ searchMessages,
2180
+ updateMessageEmbedding
2181
+ };
2182
+ }
2183
+
2184
+ // src/lib/chatStorage/schema.ts
2185
+ var import_watermelondb2 = require("@nozbe/watermelondb");
2186
+ var chatStorageSchema = (0, import_watermelondb2.appSchema)({
2187
+ version: 1,
2188
+ tables: [
2189
+ (0, import_watermelondb2.tableSchema)({
2190
+ name: "history",
2191
+ columns: [
2192
+ { name: "message_id", type: "number" },
2193
+ // Sequential ID within conversation
2194
+ { name: "conversation_id", type: "string", isIndexed: true },
2195
+ { name: "role", type: "string", isIndexed: true },
2196
+ // 'user' | 'assistant' | 'system'
2197
+ { name: "content", type: "string" },
2198
+ { name: "model", type: "string", isOptional: true },
2199
+ { name: "files", type: "string", isOptional: true },
2200
+ // JSON stringified FileMetadata[]
2201
+ { name: "created_at", type: "number", isIndexed: true },
2202
+ { name: "updated_at", type: "number" },
2203
+ { name: "vector", type: "string", isOptional: true },
2204
+ // JSON stringified number[]
2205
+ { name: "embedding_model", type: "string", isOptional: true },
2206
+ { name: "usage", type: "string", isOptional: true },
2207
+ // JSON stringified ChatCompletionUsage
2208
+ { name: "sources", type: "string", isOptional: true },
2209
+ // JSON stringified SearchSource[]
2210
+ { name: "response_duration", type: "number", isOptional: true }
2211
+ ]
2212
+ }),
2213
+ (0, import_watermelondb2.tableSchema)({
2214
+ name: "conversations",
2215
+ columns: [
2216
+ { name: "conversation_id", type: "string", isIndexed: true },
2217
+ { name: "title", type: "string" },
2218
+ { name: "created_at", type: "number" },
2219
+ { name: "updated_at", type: "number" },
2220
+ { name: "is_deleted", type: "boolean", isIndexed: true }
2221
+ ]
2222
+ })
2223
+ ]
2224
+ });
2225
+
2226
+ // src/lib/chatStorage/models.ts
2227
+ var import_watermelondb3 = require("@nozbe/watermelondb");
2228
+ var Message = class extends import_watermelondb3.Model {
2229
+ /** Sequential message ID within conversation */
2230
+ get messageId() {
2231
+ return this._getRaw("message_id");
2232
+ }
2233
+ /** Links message to its conversation */
2234
+ get conversationId() {
2235
+ return this._getRaw("conversation_id");
2236
+ }
2237
+ /** Who sent the message: 'user' | 'assistant' | 'system' */
2238
+ get role() {
2239
+ return this._getRaw("role");
2240
+ }
2241
+ /** The message text content */
2242
+ get content() {
2243
+ return this._getRaw("content");
2244
+ }
2245
+ /** LLM model used (e.g., GPT-4, Claude) */
2246
+ get model() {
2247
+ const value = this._getRaw("model");
2248
+ return value ? value : void 0;
2249
+ }
2250
+ /** Optional attached files */
2251
+ get files() {
2252
+ const raw = this._getRaw("files");
2253
+ if (!raw) return void 0;
2254
+ try {
2255
+ return JSON.parse(raw);
2256
+ } catch {
2257
+ return void 0;
2258
+ }
2259
+ }
2260
+ /** Created timestamp */
2261
+ get createdAt() {
2262
+ return new Date(this._getRaw("created_at"));
2263
+ }
2264
+ /** Updated timestamp */
2265
+ get updatedAt() {
2266
+ return new Date(this._getRaw("updated_at"));
2267
+ }
2268
+ /** Embedding vector for semantic search */
2269
+ get vector() {
2270
+ const raw = this._getRaw("vector");
2271
+ if (!raw) return void 0;
2272
+ try {
2273
+ return JSON.parse(raw);
2274
+ } catch {
2275
+ return void 0;
2276
+ }
2277
+ }
2278
+ /** Model used to generate embedding */
2279
+ get embeddingModel() {
2280
+ const value = this._getRaw("embedding_model");
2281
+ return value ? value : void 0;
2282
+ }
2283
+ /** Token counts and cost */
2284
+ get usage() {
2285
+ const raw = this._getRaw("usage");
2286
+ if (!raw) return void 0;
2287
+ try {
2288
+ return JSON.parse(raw);
2289
+ } catch {
2290
+ return void 0;
2291
+ }
2292
+ }
2293
+ /** Web search sources */
2294
+ get sources() {
2295
+ const raw = this._getRaw("sources");
2296
+ if (!raw) return void 0;
2297
+ try {
2298
+ return JSON.parse(raw);
2299
+ } catch {
2300
+ return void 0;
2301
+ }
2302
+ }
2303
+ /** Response time in seconds */
2304
+ get responseDuration() {
2305
+ const value = this._getRaw("response_duration");
2306
+ return value !== null && value !== void 0 ? value : void 0;
2307
+ }
2308
+ };
2309
+ Message.table = "history";
2310
+ Message.associations = {
2311
+ conversations: { type: "belongs_to", key: "conversation_id" }
2312
+ };
2313
+ var Conversation = class extends import_watermelondb3.Model {
2314
+ /** Unique conversation identifier */
2315
+ get conversationId() {
2316
+ return this._getRaw("conversation_id");
2317
+ }
2318
+ /** Conversation title */
2319
+ get title() {
2320
+ return this._getRaw("title");
2321
+ }
2322
+ /** Created timestamp */
2323
+ get createdAt() {
2324
+ return new Date(this._getRaw("created_at"));
2325
+ }
2326
+ /** Updated timestamp */
2327
+ get updatedAt() {
2328
+ return new Date(this._getRaw("updated_at"));
2329
+ }
2330
+ /** Soft delete flag */
2331
+ get isDeleted() {
2332
+ return this._getRaw("is_deleted");
2333
+ }
2334
+ };
2335
+ Conversation.table = "conversations";
2336
+ Conversation.associations = {
2337
+ history: { type: "has_many", foreignKey: "conversation_id" }
2338
+ };
2339
+
2340
+ // src/react/useMemoryStorage.ts
2341
+ var import_react3 = require("react");
2342
+ var import_client6 = require("@reverbia/sdk");
2343
+
2344
+ // src/lib/memoryStorage/operations.ts
2345
+ var import_watermelondb4 = require("@nozbe/watermelondb");
2346
+
2347
+ // src/lib/memoryStorage/types.ts
2348
+ function generateCompositeKey(namespace, key) {
2349
+ return `${namespace}:${key}`;
2350
+ }
2351
+ function generateUniqueKey(namespace, key, value) {
2352
+ return `${namespace}:${key}:${value}`;
2353
+ }
2354
+ function cosineSimilarity2(a, b) {
2355
+ if (a.length !== b.length) {
2356
+ throw new Error("Vectors must have the same length");
2357
+ }
2358
+ let dotProduct = 0;
2359
+ let normA = 0;
2360
+ let normB = 0;
2361
+ for (let i = 0; i < a.length; i++) {
2362
+ dotProduct += a[i] * b[i];
2363
+ normA += a[i] * a[i];
2364
+ normB += b[i] * b[i];
2365
+ }
2366
+ const denominator = Math.sqrt(normA) * Math.sqrt(normB);
2367
+ if (denominator === 0) {
2368
+ return 0;
2369
+ }
2370
+ return dotProduct / denominator;
2371
+ }
2372
+
2373
+ // src/lib/memoryStorage/operations.ts
2374
+ function memoryToStored(memory) {
2375
+ return {
2376
+ uniqueId: memory.id,
2377
+ type: memory.type,
2378
+ namespace: memory.namespace,
2379
+ key: memory.key,
2380
+ value: memory.value,
2381
+ rawEvidence: memory.rawEvidence,
2382
+ confidence: memory.confidence,
2383
+ pii: memory.pii,
2384
+ compositeKey: memory.compositeKey,
2385
+ uniqueKey: memory.uniqueKey,
2386
+ createdAt: memory.createdAt,
2387
+ updatedAt: memory.updatedAt,
2388
+ embedding: memory.embedding,
2389
+ embeddingModel: memory.embeddingModel,
2390
+ isDeleted: memory.isDeleted
2391
+ };
2392
+ }
2393
+ async function getAllMemoriesOp(ctx) {
2394
+ const results = await ctx.memoriesCollection.query(import_watermelondb4.Q.where("is_deleted", false), import_watermelondb4.Q.sortBy("created_at", import_watermelondb4.Q.desc)).fetch();
2395
+ return results.map(memoryToStored);
2396
+ }
2397
+ async function getMemoryByIdOp(ctx, id) {
2398
+ try {
2399
+ const memory = await ctx.memoriesCollection.find(id);
2400
+ if (memory.isDeleted) return null;
2401
+ return memoryToStored(memory);
2402
+ } catch {
2403
+ return null;
2404
+ }
2405
+ }
2406
+ async function getMemoriesByNamespaceOp(ctx, namespace) {
2407
+ const results = await ctx.memoriesCollection.query(
2408
+ import_watermelondb4.Q.where("namespace", namespace),
2409
+ import_watermelondb4.Q.where("is_deleted", false),
2410
+ import_watermelondb4.Q.sortBy("created_at", import_watermelondb4.Q.desc)
2411
+ ).fetch();
2412
+ return results.map(memoryToStored);
2413
+ }
2414
+ async function getMemoriesByKeyOp(ctx, namespace, key) {
2415
+ const compositeKey = generateCompositeKey(namespace, key);
2416
+ const results = await ctx.memoriesCollection.query(
2417
+ import_watermelondb4.Q.where("composite_key", compositeKey),
2418
+ import_watermelondb4.Q.where("is_deleted", false),
2419
+ import_watermelondb4.Q.sortBy("created_at", import_watermelondb4.Q.desc)
2420
+ ).fetch();
2421
+ return results.map(memoryToStored);
2422
+ }
2423
+ async function saveMemoryOp(ctx, opts) {
2424
+ const compositeKey = generateCompositeKey(opts.namespace, opts.key);
2425
+ const uniqueKey = generateUniqueKey(opts.namespace, opts.key, opts.value);
2426
+ const result = await ctx.database.write(async () => {
2427
+ const existing = await ctx.memoriesCollection.query(import_watermelondb4.Q.where("unique_key", uniqueKey)).fetch();
2428
+ if (existing.length > 0) {
2429
+ const existingMemory = existing[0];
2430
+ const shouldPreserveEmbedding = existingMemory.value === opts.value && existingMemory.rawEvidence === opts.rawEvidence && existingMemory.type === opts.type && existingMemory.namespace === opts.namespace && existingMemory.key === opts.key && existingMemory.embedding !== void 0 && existingMemory.embedding.length > 0 && !opts.embedding;
2431
+ await existingMemory.update((mem) => {
2432
+ mem._setRaw("type", opts.type);
2433
+ mem._setRaw("namespace", opts.namespace);
2434
+ mem._setRaw("key", opts.key);
2435
+ mem._setRaw("value", opts.value);
2436
+ mem._setRaw("raw_evidence", opts.rawEvidence);
2437
+ mem._setRaw("confidence", opts.confidence);
2438
+ mem._setRaw("pii", opts.pii);
2439
+ mem._setRaw("composite_key", compositeKey);
2440
+ mem._setRaw("unique_key", uniqueKey);
2441
+ mem._setRaw("is_deleted", false);
2442
+ if (shouldPreserveEmbedding) {
2443
+ } else if (opts.embedding) {
2444
+ mem._setRaw("embedding", JSON.stringify(opts.embedding));
2445
+ if (opts.embeddingModel) {
2446
+ mem._setRaw("embedding_model", opts.embeddingModel);
2447
+ }
2448
+ } else {
2449
+ mem._setRaw("embedding", null);
2450
+ mem._setRaw("embedding_model", null);
2451
+ }
2452
+ });
2453
+ return existingMemory;
2454
+ }
2455
+ return await ctx.memoriesCollection.create((mem) => {
2456
+ mem._setRaw("type", opts.type);
2457
+ mem._setRaw("namespace", opts.namespace);
2458
+ mem._setRaw("key", opts.key);
2459
+ mem._setRaw("value", opts.value);
2460
+ mem._setRaw("raw_evidence", opts.rawEvidence);
2461
+ mem._setRaw("confidence", opts.confidence);
2462
+ mem._setRaw("pii", opts.pii);
2463
+ mem._setRaw("composite_key", compositeKey);
2464
+ mem._setRaw("unique_key", uniqueKey);
2465
+ mem._setRaw("is_deleted", false);
2466
+ if (opts.embedding) {
2467
+ mem._setRaw("embedding", JSON.stringify(opts.embedding));
2468
+ if (opts.embeddingModel) {
2469
+ mem._setRaw("embedding_model", opts.embeddingModel);
2470
+ }
2471
+ }
2472
+ });
2473
+ });
2474
+ return memoryToStored(result);
2475
+ }
2476
+ async function saveMemoriesOp(ctx, memories) {
2477
+ const results = [];
2478
+ for (const memory of memories) {
2479
+ const saved = await saveMemoryOp(ctx, memory);
2480
+ results.push(saved);
2481
+ }
2482
+ return results;
2483
+ }
2484
+ async function updateMemoryOp(ctx, id, updates) {
2485
+ let memory;
2486
+ try {
2487
+ memory = await ctx.memoriesCollection.find(id);
2488
+ } catch {
2489
+ return { ok: false, reason: "not_found" };
2490
+ }
2491
+ if (memory.isDeleted) {
2492
+ return { ok: false, reason: "not_found" };
2493
+ }
2494
+ const newNamespace = updates.namespace ?? memory.namespace;
2495
+ const newKey = updates.key ?? memory.key;
2496
+ const newValue = updates.value ?? memory.value;
2497
+ const newCompositeKey = generateCompositeKey(newNamespace, newKey);
2498
+ const newUniqueKey = generateUniqueKey(newNamespace, newKey, newValue);
2499
+ if (newUniqueKey !== memory.uniqueKey) {
2500
+ const existing = await ctx.memoriesCollection.query(import_watermelondb4.Q.where("unique_key", newUniqueKey), import_watermelondb4.Q.where("is_deleted", false)).fetch();
2501
+ if (existing.length > 0) {
2502
+ return { ok: false, reason: "conflict", conflictingKey: newUniqueKey };
2503
+ }
2504
+ }
2505
+ try {
2506
+ const updated = await ctx.database.write(async () => {
2507
+ await memory.update((mem) => {
2508
+ if (updates.type !== void 0) mem._setRaw("type", updates.type);
2509
+ if (updates.namespace !== void 0)
2510
+ mem._setRaw("namespace", updates.namespace);
2511
+ if (updates.key !== void 0) mem._setRaw("key", updates.key);
2512
+ if (updates.value !== void 0) mem._setRaw("value", updates.value);
2513
+ if (updates.rawEvidence !== void 0)
2514
+ mem._setRaw("raw_evidence", updates.rawEvidence);
2515
+ if (updates.confidence !== void 0)
2516
+ mem._setRaw("confidence", updates.confidence);
2517
+ if (updates.pii !== void 0) mem._setRaw("pii", updates.pii);
2518
+ if (updates.namespace !== void 0 || updates.key !== void 0 || updates.value !== void 0) {
2519
+ mem._setRaw("composite_key", newCompositeKey);
2520
+ mem._setRaw("unique_key", newUniqueKey);
2521
+ }
2522
+ if (updates.embedding !== void 0) {
2523
+ mem._setRaw(
2524
+ "embedding",
2525
+ updates.embedding ? JSON.stringify(updates.embedding) : null
2526
+ );
2527
+ }
2528
+ if (updates.embeddingModel !== void 0) {
2529
+ mem._setRaw("embedding_model", updates.embeddingModel || null);
2530
+ }
2531
+ });
2532
+ return memory;
2533
+ });
2534
+ return { ok: true, memory: memoryToStored(updated) };
2535
+ } catch (err) {
2536
+ return {
2537
+ ok: false,
2538
+ reason: "error",
2539
+ error: err instanceof Error ? err : new Error(String(err))
2540
+ };
2541
+ }
2542
+ }
2543
+ async function deleteMemoryByIdOp(ctx, id) {
2544
+ try {
2545
+ const memory = await ctx.memoriesCollection.find(id);
2546
+ await ctx.database.write(async () => {
2547
+ await memory.update((mem) => {
2548
+ mem._setRaw("is_deleted", true);
2549
+ });
2550
+ });
2551
+ } catch {
2552
+ }
2553
+ }
2554
+ async function deleteMemoryOp(ctx, namespace, key, value) {
2555
+ const uniqueKey = generateUniqueKey(namespace, key, value);
2556
+ const results = await ctx.memoriesCollection.query(import_watermelondb4.Q.where("unique_key", uniqueKey)).fetch();
2557
+ if (results.length > 0) {
2558
+ await ctx.database.write(async () => {
2559
+ await results[0].update((mem) => {
2560
+ mem._setRaw("is_deleted", true);
2561
+ });
2562
+ });
2563
+ }
2564
+ }
2565
+ async function deleteMemoriesByKeyOp(ctx, namespace, key) {
2566
+ const compositeKey = generateCompositeKey(namespace, key);
2567
+ const results = await ctx.memoriesCollection.query(import_watermelondb4.Q.where("composite_key", compositeKey), import_watermelondb4.Q.where("is_deleted", false)).fetch();
2568
+ await ctx.database.write(async () => {
2569
+ for (const memory of results) {
2570
+ await memory.update((mem) => {
2571
+ mem._setRaw("is_deleted", true);
2572
+ });
2573
+ }
2574
+ });
2575
+ }
2576
+ async function clearAllMemoriesOp(ctx) {
2577
+ const results = await ctx.memoriesCollection.query(import_watermelondb4.Q.where("is_deleted", false)).fetch();
2578
+ await ctx.database.write(async () => {
2579
+ for (const memory of results) {
2580
+ await memory.update((mem) => {
2581
+ mem._setRaw("is_deleted", true);
2582
+ });
2583
+ }
2584
+ });
2585
+ }
2586
+ async function searchSimilarMemoriesOp(ctx, queryEmbedding, limit = 10, minSimilarity = 0.6) {
2587
+ const allMemories = await ctx.memoriesCollection.query(import_watermelondb4.Q.where("is_deleted", false)).fetch();
2588
+ const memoriesWithEmbeddings = allMemories.filter(
2589
+ (m) => m.embedding && m.embedding.length > 0
2590
+ );
2591
+ if (memoriesWithEmbeddings.length === 0) {
2592
+ return [];
2593
+ }
2594
+ const results = memoriesWithEmbeddings.map((memory) => {
2595
+ const similarity = cosineSimilarity2(queryEmbedding, memory.embedding);
2596
+ return {
2597
+ ...memoryToStored(memory),
2598
+ similarity
2599
+ };
2600
+ }).filter((result) => result.similarity >= minSimilarity).sort((a, b) => b.similarity - a.similarity).slice(0, limit);
2601
+ return results;
2602
+ }
2603
+ async function updateMemoryEmbeddingOp(ctx, id, embedding, embeddingModel) {
2604
+ try {
2605
+ const memory = await ctx.memoriesCollection.find(id);
2606
+ await ctx.database.write(async () => {
2607
+ await memory.update((mem) => {
2608
+ mem._setRaw("embedding", JSON.stringify(embedding));
2609
+ mem._setRaw("embedding_model", embeddingModel);
2610
+ });
2611
+ });
2612
+ } catch {
2613
+ }
1677
2614
  }
1678
2615
 
1679
- // src/react/useMemory.ts
1680
- var import_react2 = require("react");
1681
- var import_client6 = require("@reverbia/sdk");
1682
-
1683
2616
  // src/lib/memory/service.ts
1684
2617
  var FACT_EXTRACTION_PROMPT = `You are a memory extraction system. Extract durable user memories from chat messages.
1685
2618
 
@@ -1809,180 +2742,6 @@ var preprocessMemories = (items, minConfidence = 0.6) => {
1809
2742
  return Array.from(deduplicatedMap.values());
1810
2743
  };
1811
2744
 
1812
- // src/lib/memory/db.ts
1813
- var import_dexie = __toESM(require("dexie"));
1814
- var MemoryDatabase = class extends import_dexie.default {
1815
- constructor() {
1816
- super("MemoryDatabase");
1817
- this.version(2).stores({
1818
- memories: "++id, uniqueKey, compositeKey, namespace, key, type, createdAt, updatedAt"
1819
- });
1820
- this.version(3).stores({
1821
- memories: "++id, uniqueKey, compositeKey, namespace, key, type, createdAt, updatedAt"
1822
- });
1823
- }
1824
- };
1825
- var memoryDb = new MemoryDatabase();
1826
- var saveMemory = async (memory) => {
1827
- const compositeKey = `${memory.namespace}:${memory.key}`;
1828
- const uniqueKey = `${memory.namespace}:${memory.key}:${memory.value}`;
1829
- const now = Date.now();
1830
- const existing = await memoryDb.memories.where("uniqueKey").equals(uniqueKey).first();
1831
- if (existing) {
1832
- 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;
1833
- const updateData = {
1834
- ...memory,
1835
- compositeKey,
1836
- uniqueKey,
1837
- updatedAt: now,
1838
- createdAt: existing.createdAt
1839
- };
1840
- if (shouldPreserveEmbedding) {
1841
- updateData.embedding = existing.embedding;
1842
- updateData.embeddingModel = existing.embeddingModel;
1843
- } else {
1844
- updateData.embedding = [];
1845
- updateData.embeddingModel = void 0;
1846
- }
1847
- await memoryDb.memories.update(existing.id, updateData);
1848
- } else {
1849
- await memoryDb.memories.add({
1850
- ...memory,
1851
- compositeKey,
1852
- uniqueKey,
1853
- createdAt: now,
1854
- updatedAt: now
1855
- });
1856
- }
1857
- };
1858
- var saveMemories = async (memories) => {
1859
- await Promise.all(memories.map((memory) => saveMemory(memory)));
1860
- };
1861
- var updateMemoryById = async (id, updates, existingMemory, embedding, embeddingModel) => {
1862
- const now = Date.now();
1863
- const updatedMemory = {
1864
- ...updates,
1865
- updatedAt: now
1866
- };
1867
- if ("namespace" in updates || "key" in updates || "value" in updates) {
1868
- const namespace = updates.namespace ?? existingMemory.namespace;
1869
- const key = updates.key ?? existingMemory.key;
1870
- const value = updates.value ?? existingMemory.value;
1871
- const newUniqueKey = `${namespace}:${key}:${value}`;
1872
- if (newUniqueKey !== existingMemory.uniqueKey) {
1873
- const conflicting = await getMemory(namespace, key, value);
1874
- if (conflicting) {
1875
- throw new Error(
1876
- `A memory with uniqueKey "${newUniqueKey}" already exists (id: ${conflicting.id})`
1877
- );
1878
- }
1879
- }
1880
- updatedMemory.compositeKey = `${namespace}:${key}`;
1881
- updatedMemory.uniqueKey = newUniqueKey;
1882
- }
1883
- updatedMemory.embedding = embedding;
1884
- updatedMemory.embeddingModel = embeddingModel;
1885
- return await memoryDb.transaction("rw", memoryDb.memories, async () => {
1886
- await memoryDb.memories.update(id, updatedMemory);
1887
- return await memoryDb.memories.get(id);
1888
- });
1889
- };
1890
- var getAllMemories = async () => {
1891
- return memoryDb.memories.toArray();
1892
- };
1893
- var getMemoryById = async (id) => {
1894
- return memoryDb.memories.get(id);
1895
- };
1896
- var getMemoriesByNamespace = async (namespace) => {
1897
- return memoryDb.memories.where("namespace").equals(namespace).toArray();
1898
- };
1899
- var getMemories = async (namespace, key) => {
1900
- const compositeKey = `${namespace}:${key}`;
1901
- return memoryDb.memories.where("compositeKey").equals(compositeKey).toArray();
1902
- };
1903
- var getMemory = async (namespace, key, value) => {
1904
- const uniqueKey = `${namespace}:${key}:${value}`;
1905
- return memoryDb.memories.where("uniqueKey").equals(uniqueKey).first();
1906
- };
1907
- var deleteMemories = async (namespace, key) => {
1908
- const compositeKey = `${namespace}:${key}`;
1909
- await memoryDb.memories.where("compositeKey").equals(compositeKey).delete();
1910
- };
1911
- var deleteMemory = async (namespace, key, value) => {
1912
- const uniqueKey = `${namespace}:${key}:${value}`;
1913
- const existing = await memoryDb.memories.where("uniqueKey").equals(uniqueKey).first();
1914
- if (existing?.id) {
1915
- await memoryDb.memories.delete(existing.id);
1916
- }
1917
- };
1918
- var deleteMemoryById = async (id) => {
1919
- await memoryDb.memories.delete(id);
1920
- };
1921
- var clearAllMemories = async () => {
1922
- await memoryDb.memories.clear();
1923
- };
1924
- var cosineSimilarity = (a, b) => {
1925
- if (a.length !== b.length) {
1926
- throw new Error("Vectors must have the same length");
1927
- }
1928
- let dotProduct = 0;
1929
- let normA = 0;
1930
- let normB = 0;
1931
- for (let i = 0; i < a.length; i++) {
1932
- dotProduct += a[i] * b[i];
1933
- normA += a[i] * a[i];
1934
- normB += b[i] * b[i];
1935
- }
1936
- const denominator = Math.sqrt(normA) * Math.sqrt(normB);
1937
- if (denominator === 0) {
1938
- return 0;
1939
- }
1940
- return dotProduct / denominator;
1941
- };
1942
- var searchSimilarMemories = async (queryEmbedding, limit = 10, minSimilarity = 0.6) => {
1943
- const allMemories = await getAllMemories();
1944
- const memoriesWithEmbeddings = allMemories.filter(
1945
- (m) => m.embedding && m.embedding.length > 0
1946
- );
1947
- console.log(
1948
- `[Memory Search] Total memories: ${allMemories.length}, memories with embeddings: ${memoriesWithEmbeddings.length}`
1949
- );
1950
- if (memoriesWithEmbeddings.length === 0) {
1951
- console.warn(
1952
- "[Memory Search] No memories with embeddings found. Memories may need embeddings generated. Use generateAndStoreEmbeddings() to generate embeddings for existing memories."
1953
- );
1954
- return [];
1955
- }
1956
- const allResults = memoriesWithEmbeddings.map((memory) => {
1957
- const similarity = cosineSimilarity(queryEmbedding, memory.embedding);
1958
- return {
1959
- ...memory,
1960
- similarity
1961
- };
1962
- }).sort((a, b) => b.similarity - a.similarity);
1963
- console.log(
1964
- `[Memory Search] All similarity scores:`,
1965
- allResults.map((r) => ({
1966
- key: `${r.namespace}:${r.key}`,
1967
- value: r.value,
1968
- similarity: r.similarity.toFixed(4)
1969
- }))
1970
- );
1971
- const results = allResults.filter((result) => result.similarity >= minSimilarity).slice(0, limit);
1972
- if (results.length === 0 && allResults.length > 0) {
1973
- const topSimilarity = allResults[0].similarity;
1974
- const suggestedThreshold = Math.max(0.3, topSimilarity - 0.1);
1975
- console.warn(
1976
- `[Memory Search] No memories above threshold ${minSimilarity}. Highest similarity was ${topSimilarity.toFixed(4)}. Consider lowering the threshold to ${suggestedThreshold.toFixed(2)}`
1977
- );
1978
- } else {
1979
- console.log(
1980
- `[Memory Search] Found ${results.length} memories above similarity threshold ${minSimilarity}. Top similarity: ${results[0]?.similarity.toFixed(4) || "N/A"}`
1981
- );
1982
- }
1983
- return results;
1984
- };
1985
-
1986
2745
  // src/client/sdk.gen.ts
1987
2746
  var postApiV1Embeddings = (options) => {
1988
2747
  return (options.client ?? client).post({
@@ -2091,70 +2850,11 @@ var generateEmbeddingForMemory = async (memory, options = {}) => {
2091
2850
  ].filter(Boolean).join(" ");
2092
2851
  return generateEmbeddingForText(text, options);
2093
2852
  };
2094
- var generateEmbeddingsForMemories = async (memories, options = {}) => {
2095
- const embeddings = /* @__PURE__ */ new Map();
2096
- for (const memory of memories) {
2097
- const uniqueKey = `${memory.namespace}:${memory.key}:${memory.value}`;
2098
- try {
2099
- const embedding = await generateEmbeddingForMemory(memory, options);
2100
- embeddings.set(uniqueKey, embedding);
2101
- } catch (error) {
2102
- console.error(
2103
- `Failed to generate embedding for memory ${uniqueKey}:`,
2104
- error
2105
- );
2106
- }
2107
- }
2108
- return embeddings;
2109
- };
2110
- var updateMemoriesWithEmbeddings = async (embeddings, embeddingModel) => {
2111
- const updates = Array.from(embeddings.entries()).map(
2112
- async ([uniqueKey, embedding]) => {
2113
- const existing = await memoryDb.memories.where("uniqueKey").equals(uniqueKey).first();
2114
- if (existing?.id) {
2115
- await memoryDb.memories.update(existing.id, {
2116
- embedding,
2117
- embeddingModel,
2118
- updatedAt: Date.now(),
2119
- createdAt: existing.createdAt
2120
- });
2121
- } else {
2122
- console.warn(
2123
- `[Embeddings] Memory with uniqueKey ${uniqueKey} not found. It may have been updated or deleted before embedding was generated.`
2124
- );
2125
- }
2126
- }
2127
- );
2128
- await Promise.all(updates);
2129
- };
2130
- var generateAndStoreEmbeddings = async (memories, options = {}) => {
2131
- let { model } = options;
2132
- const { provider = "local" } = options;
2133
- if (!model) {
2134
- if (provider === "local") {
2135
- model = DEFAULT_LOCAL_EMBEDDING_MODEL;
2136
- } else {
2137
- model = DEFAULT_API_EMBEDDING_MODEL;
2138
- }
2139
- }
2140
- if (provider === "local" && model === DEFAULT_API_EMBEDDING_MODEL) {
2141
- model = DEFAULT_LOCAL_EMBEDDING_MODEL;
2142
- }
2143
- if (memories.length === 0) {
2144
- return;
2145
- }
2146
- console.log(`Generating embeddings for ${memories.length} memories...`);
2147
- const embeddings = await generateEmbeddingsForMemories(memories, {
2148
- ...options,
2149
- model
2150
- });
2151
- await updateMemoriesWithEmbeddings(embeddings, model);
2152
- console.log(`Generated and stored ${embeddings.size} embeddings`);
2153
- };
2154
2853
 
2155
- // src/react/useMemory.ts
2156
- function useMemory(options = {}) {
2854
+ // src/react/useMemoryStorage.ts
2855
+ function useMemoryStorage(options) {
2157
2856
  const {
2857
+ database,
2158
2858
  completionsModel = DEFAULT_COMPLETION_MODEL,
2159
2859
  embeddingModel: userEmbeddingModel,
2160
2860
  embeddingProvider = "local",
@@ -2164,10 +2864,39 @@ function useMemory(options = {}) {
2164
2864
  baseUrl = BASE_URL
2165
2865
  } = options;
2166
2866
  const embeddingModel = userEmbeddingModel === void 0 ? embeddingProvider === "local" ? DEFAULT_LOCAL_EMBEDDING_MODEL : DEFAULT_API_EMBEDDING_MODEL : userEmbeddingModel;
2167
- const extractionInProgressRef = (0, import_react2.useRef)(false);
2168
- const extractMemoriesFromMessage = (0, import_react2.useCallback)(
2169
- async (options2) => {
2170
- const { messages, model } = options2;
2867
+ const [memories, setMemories] = (0, import_react3.useState)([]);
2868
+ const extractionInProgressRef = (0, import_react3.useRef)(false);
2869
+ const memoriesCollection = (0, import_react3.useMemo)(
2870
+ () => database.get("memories"),
2871
+ [database]
2872
+ );
2873
+ const storageCtx = (0, import_react3.useMemo)(
2874
+ () => ({
2875
+ database,
2876
+ memoriesCollection
2877
+ }),
2878
+ [database, memoriesCollection]
2879
+ );
2880
+ const effectiveEmbeddingModel = (0, import_react3.useMemo)(
2881
+ () => embeddingModel ?? (embeddingProvider === "api" ? DEFAULT_API_EMBEDDING_MODEL : DEFAULT_LOCAL_EMBEDDING_MODEL),
2882
+ [embeddingModel, embeddingProvider]
2883
+ );
2884
+ const embeddingOptions = (0, import_react3.useMemo)(
2885
+ () => ({
2886
+ model: effectiveEmbeddingModel,
2887
+ provider: embeddingProvider,
2888
+ getToken: getToken || void 0,
2889
+ baseUrl
2890
+ }),
2891
+ [effectiveEmbeddingModel, embeddingProvider, getToken, baseUrl]
2892
+ );
2893
+ const refreshMemories = (0, import_react3.useCallback)(async () => {
2894
+ const storedMemories = await getAllMemoriesOp(storageCtx);
2895
+ setMemories(storedMemories);
2896
+ }, [storageCtx]);
2897
+ const extractMemoriesFromMessage = (0, import_react3.useCallback)(
2898
+ async (opts) => {
2899
+ const { messages, model } = opts;
2171
2900
  if (!getToken || extractionInProgressRef.current) {
2172
2901
  return null;
2173
2902
  }
@@ -2253,11 +2982,7 @@ function useMemory(options = {}) {
2253
2982
  if (jsonObjectMatch && jsonObjectMatch[0]) {
2254
2983
  jsonContent = jsonObjectMatch[0];
2255
2984
  } else {
2256
- console.warn(
2257
- "Memory extraction returned non-JSON response. The model may not have found any memories to extract, or it returned natural language instead of JSON.",
2258
- "\nFirst 200 chars of response:",
2259
- content.substring(0, 200)
2260
- );
2985
+ console.warn("Memory extraction returned non-JSON response");
2261
2986
  return { items: [] };
2262
2987
  }
2263
2988
  }
@@ -2265,9 +2990,7 @@ function useMemory(options = {}) {
2265
2990
  const trimmedJson = jsonContent.trim();
2266
2991
  if (!trimmedJson.startsWith("{") || !trimmedJson.includes("items")) {
2267
2992
  console.warn(
2268
- "Memory extraction response doesn't appear to be valid JSON. The model may not have found any memories to extract, or returned natural language instead of JSON.",
2269
- "\nResponse preview:",
2270
- content.substring(0, 200)
2993
+ "Memory extraction response doesn't appear to be valid JSON"
2271
2994
  );
2272
2995
  return { items: [] };
2273
2996
  }
@@ -2278,10 +3001,7 @@ function useMemory(options = {}) {
2278
3001
  throw new Error("Invalid JSON structure: not an object");
2279
3002
  }
2280
3003
  if (!Array.isArray(result.items)) {
2281
- console.warn(
2282
- "Memory extraction result missing 'items' array. Result:",
2283
- result
2284
- );
3004
+ console.warn("Memory extraction result missing 'items' array");
2285
3005
  return { items: [] };
2286
3006
  }
2287
3007
  } catch (parseError) {
@@ -2289,42 +3009,61 @@ function useMemory(options = {}) {
2289
3009
  "Failed to parse memory extraction JSON:",
2290
3010
  parseError instanceof Error ? parseError.message : parseError
2291
3011
  );
2292
- console.error("Attempted to parse:", jsonContent.substring(0, 200));
2293
- console.error("Full raw content:", content.substring(0, 500));
2294
3012
  return { items: [] };
2295
3013
  }
2296
3014
  if (result.items && Array.isArray(result.items)) {
2297
- const originalCount = result.items.length;
2298
3015
  result.items = preprocessMemories(result.items);
2299
- const filteredCount = result.items.length;
2300
- if (originalCount !== filteredCount) {
2301
- console.log(
2302
- `Preprocessed memories: ${originalCount} -> ${filteredCount} (dropped ${originalCount - filteredCount} entries)`
2303
- );
2304
- }
2305
3016
  }
2306
- console.log("Extracted memories:", JSON.stringify(result, null, 2));
2307
3017
  if (result.items && result.items.length > 0) {
2308
3018
  try {
2309
- await saveMemories(result.items);
2310
- console.log(`Saved ${result.items.length} memories to IndexedDB`);
3019
+ const createOptions = result.items.map(
3020
+ (item) => ({
3021
+ type: item.type,
3022
+ namespace: item.namespace,
3023
+ key: item.key,
3024
+ value: item.value,
3025
+ rawEvidence: item.rawEvidence,
3026
+ confidence: item.confidence,
3027
+ pii: item.pii
3028
+ })
3029
+ );
3030
+ const savedMemories = await saveMemoriesOp(storageCtx, createOptions);
3031
+ console.log(
3032
+ `Saved ${savedMemories.length} memories to WatermelonDB`
3033
+ );
2311
3034
  if (generateEmbeddings && embeddingModel) {
2312
3035
  try {
2313
- await generateAndStoreEmbeddings(result.items, {
2314
- model: embeddingModel,
2315
- provider: embeddingProvider,
2316
- getToken: getToken || void 0,
2317
- baseUrl
2318
- });
3036
+ for (const saved of savedMemories) {
3037
+ const memoryItem = {
3038
+ type: saved.type,
3039
+ namespace: saved.namespace,
3040
+ key: saved.key,
3041
+ value: saved.value,
3042
+ rawEvidence: saved.rawEvidence,
3043
+ confidence: saved.confidence,
3044
+ pii: saved.pii
3045
+ };
3046
+ const embedding = await generateEmbeddingForMemory(
3047
+ memoryItem,
3048
+ embeddingOptions
3049
+ );
3050
+ await updateMemoryEmbeddingOp(
3051
+ storageCtx,
3052
+ saved.uniqueId,
3053
+ embedding,
3054
+ effectiveEmbeddingModel
3055
+ );
3056
+ }
2319
3057
  console.log(
2320
- `Generated embeddings for ${result.items.length} memories`
3058
+ `Generated embeddings for ${savedMemories.length} memories`
2321
3059
  );
2322
3060
  } catch (error) {
2323
3061
  console.error("Failed to generate embeddings:", error);
2324
3062
  }
2325
3063
  }
3064
+ await refreshMemories();
2326
3065
  } catch (error) {
2327
- console.error("Failed to save memories to IndexedDB:", error);
3066
+ console.error("Failed to save memories to WatermelonDB:", error);
2328
3067
  }
2329
3068
  }
2330
3069
  if (onFactsExtracted) {
@@ -2341,38 +3080,35 @@ function useMemory(options = {}) {
2341
3080
  [
2342
3081
  completionsModel,
2343
3082
  embeddingModel,
2344
- embeddingProvider,
3083
+ embeddingOptions,
2345
3084
  generateEmbeddings,
2346
3085
  getToken,
2347
3086
  onFactsExtracted,
2348
- baseUrl
3087
+ baseUrl,
3088
+ storageCtx,
3089
+ refreshMemories
2349
3090
  ]
2350
3091
  );
2351
- const searchMemories = (0, import_react2.useCallback)(
3092
+ const searchMemories = (0, import_react3.useCallback)(
2352
3093
  async (query, limit = 10, minSimilarity = 0.6) => {
2353
3094
  if (!embeddingModel) {
2354
3095
  console.warn("Cannot search memories: embeddingModel not provided");
2355
3096
  return [];
2356
3097
  }
2357
3098
  try {
2358
- console.log(`[Memory Search] Searching for: "${query}"`);
2359
- const queryEmbedding = await generateEmbeddingForText(query, {
2360
- model: embeddingModel,
2361
- provider: embeddingProvider,
2362
- getToken,
2363
- baseUrl
2364
- });
2365
- console.log(
2366
- `[Memory Search] Generated query embedding (${queryEmbedding.length} dimensions)`
3099
+ const queryEmbedding = await generateEmbeddingForText(
3100
+ query,
3101
+ embeddingOptions
2367
3102
  );
2368
- const results = await searchSimilarMemories(
3103
+ const results = await searchSimilarMemoriesOp(
3104
+ storageCtx,
2369
3105
  queryEmbedding,
2370
3106
  limit,
2371
3107
  minSimilarity
2372
3108
  );
2373
3109
  if (results.length === 0) {
2374
3110
  console.warn(
2375
- `[Memory Search] No memories found above similarity threshold ${minSimilarity}. Try lowering the threshold or ensure memories have embeddings generated.`
3111
+ `[Memory Search] No memories found above similarity threshold ${minSimilarity}.`
2376
3112
  );
2377
3113
  } else {
2378
3114
  console.log(
@@ -2380,175 +3116,282 @@ function useMemory(options = {}) {
2380
3116
  );
2381
3117
  }
2382
3118
  return results;
2383
- } catch (error) {
2384
- console.error("Failed to search memories:", error);
3119
+ } catch {
2385
3120
  return [];
2386
3121
  }
2387
3122
  },
2388
- [embeddingModel, embeddingProvider, getToken, baseUrl]
3123
+ [embeddingModel, embeddingOptions, storageCtx]
2389
3124
  );
2390
- const fetchAllMemories = (0, import_react2.useCallback)(async () => {
3125
+ const fetchAllMemories = (0, import_react3.useCallback)(async () => {
2391
3126
  try {
2392
- return await getAllMemories();
3127
+ return await getAllMemoriesOp(storageCtx);
2393
3128
  } catch (error) {
2394
3129
  throw new Error(
2395
3130
  "Failed to fetch all memories: " + (error instanceof Error ? error.message : String(error))
2396
3131
  );
2397
3132
  }
2398
- }, []);
2399
- const fetchMemoriesByNamespace = (0, import_react2.useCallback)(
3133
+ }, [storageCtx]);
3134
+ const fetchMemoriesByNamespace = (0, import_react3.useCallback)(
2400
3135
  async (namespace) => {
2401
3136
  if (!namespace) {
2402
3137
  throw new Error("Missing required field: namespace");
2403
3138
  }
2404
3139
  try {
2405
- return await getMemoriesByNamespace(namespace);
3140
+ return await getMemoriesByNamespaceOp(storageCtx, namespace);
2406
3141
  } catch (error) {
2407
3142
  throw new Error(
2408
3143
  `Failed to fetch memories for namespace "${namespace}": ` + (error instanceof Error ? error.message : String(error))
2409
3144
  );
2410
3145
  }
2411
3146
  },
2412
- []
3147
+ [storageCtx]
2413
3148
  );
2414
- const fetchMemoriesByKey = (0, import_react2.useCallback)(
3149
+ const fetchMemoriesByKey = (0, import_react3.useCallback)(
2415
3150
  async (namespace, key) => {
2416
3151
  if (!namespace || !key) {
2417
3152
  throw new Error("Missing required fields: namespace, key");
2418
3153
  }
2419
3154
  try {
2420
- return await getMemories(namespace, key);
3155
+ return await getMemoriesByKeyOp(storageCtx, namespace, key);
2421
3156
  } catch (error) {
2422
3157
  throw new Error(
2423
3158
  `Failed to fetch memories for "${namespace}:${key}": ` + (error instanceof Error ? error.message : String(error))
2424
3159
  );
2425
3160
  }
2426
3161
  },
2427
- []
3162
+ [storageCtx]
2428
3163
  );
2429
- const updateMemory = (0, import_react2.useCallback)(
2430
- async (id, updates) => {
2431
- if (!Number.isInteger(id) || id <= 0) {
2432
- throw new Error("id must be a non-negative integer");
3164
+ const getMemoryById = (0, import_react3.useCallback)(
3165
+ async (id) => {
3166
+ try {
3167
+ return await getMemoryByIdOp(storageCtx, id);
3168
+ } catch (error) {
3169
+ throw new Error(
3170
+ `Failed to get memory ${id}: ` + (error instanceof Error ? error.message : String(error))
3171
+ );
2433
3172
  }
3173
+ },
3174
+ [storageCtx]
3175
+ );
3176
+ const saveMemory = (0, import_react3.useCallback)(
3177
+ async (memory) => {
2434
3178
  try {
2435
- const embeddingModelToUse = embeddingProvider === "api" ? embeddingModel ?? DEFAULT_API_EMBEDDING_MODEL : embeddingModel && embeddingModel !== DEFAULT_API_EMBEDDING_MODEL ? embeddingModel : DEFAULT_LOCAL_EMBEDDING_MODEL;
2436
- const embeddingOptions = {
2437
- model: embeddingModelToUse,
2438
- provider: embeddingProvider,
2439
- getToken: getToken || void 0,
2440
- baseUrl
2441
- };
2442
- if (!updates.type || !updates.namespace || !updates.key || !updates.value || !updates.rawEvidence || updates.confidence === void 0 || updates.confidence === null || updates.pii === void 0 || updates.pii === null) {
2443
- throw new Error(
2444
- "Missing required fields: type, namespace, key, value, rawEvidence, confidence, pii"
2445
- );
2446
- }
2447
- const existingMemory = await getMemoryById(id);
2448
- if (!existingMemory) {
2449
- throw new Error(`Memory with id ${id} not found`);
2450
- }
2451
- const embeddingFieldsChanged = updates.value !== void 0 && updates.value !== existingMemory.value || updates.rawEvidence !== void 0 && updates.rawEvidence !== existingMemory.rawEvidence || updates.type !== void 0 && updates.type !== existingMemory.type || updates.namespace !== void 0 && updates.namespace !== existingMemory.namespace || updates.key !== void 0 && updates.key !== existingMemory.key;
2452
- if (!embeddingFieldsChanged) {
2453
- return existingMemory;
2454
- }
2455
- const memory = {
2456
- type: updates.type,
2457
- namespace: updates.namespace,
2458
- key: updates.key,
2459
- value: updates.value,
2460
- rawEvidence: updates.rawEvidence,
2461
- confidence: updates.confidence,
2462
- pii: updates.pii
2463
- };
2464
- let embedding = existingMemory.embedding ?? [];
2465
- let embeddingModelToStore = existingMemory.embeddingModel ?? "";
2466
- if (generateEmbeddings && embeddingModelToUse) {
3179
+ const saved = await saveMemoryOp(storageCtx, memory);
3180
+ if (generateEmbeddings && embeddingModel && !memory.embedding) {
2467
3181
  try {
2468
- embedding = await generateEmbeddingForMemory(
2469
- memory,
3182
+ const memoryItem = {
3183
+ type: memory.type,
3184
+ namespace: memory.namespace,
3185
+ key: memory.key,
3186
+ value: memory.value,
3187
+ rawEvidence: memory.rawEvidence,
3188
+ confidence: memory.confidence,
3189
+ pii: memory.pii
3190
+ };
3191
+ const embedding = await generateEmbeddingForMemory(
3192
+ memoryItem,
2470
3193
  embeddingOptions
2471
3194
  );
2472
- embeddingModelToStore = embeddingModelToUse;
2473
- } catch (embeddingError) {
2474
- console.error(
2475
- "Failed to generate embedding, keeping existing:",
2476
- embeddingError
3195
+ await updateMemoryEmbeddingOp(
3196
+ storageCtx,
3197
+ saved.uniqueId,
3198
+ embedding,
3199
+ effectiveEmbeddingModel
2477
3200
  );
3201
+ } catch (error) {
3202
+ console.error("Failed to generate embedding:", error);
2478
3203
  }
2479
3204
  }
2480
- return await updateMemoryById(
2481
- id,
2482
- updates,
2483
- existingMemory,
2484
- embedding,
2485
- embeddingModelToStore
3205
+ setMemories((prev) => {
3206
+ const existing = prev.find((m) => m.uniqueId === saved.uniqueId);
3207
+ if (existing) {
3208
+ return prev.map((m) => m.uniqueId === saved.uniqueId ? saved : m);
3209
+ }
3210
+ return [saved, ...prev];
3211
+ });
3212
+ return saved;
3213
+ } catch (error) {
3214
+ throw new Error(
3215
+ "Failed to save memory: " + (error instanceof Error ? error.message : String(error))
2486
3216
  );
3217
+ }
3218
+ },
3219
+ [storageCtx, generateEmbeddings, embeddingModel, embeddingOptions]
3220
+ );
3221
+ const saveMemories = (0, import_react3.useCallback)(
3222
+ async (memoriesToSave) => {
3223
+ try {
3224
+ const saved = await saveMemoriesOp(storageCtx, memoriesToSave);
3225
+ if (generateEmbeddings && embeddingModel) {
3226
+ for (let i = 0; i < saved.length; i++) {
3227
+ const memory = memoriesToSave[i];
3228
+ if (!memory.embedding) {
3229
+ try {
3230
+ const memoryItem = {
3231
+ type: memory.type,
3232
+ namespace: memory.namespace,
3233
+ key: memory.key,
3234
+ value: memory.value,
3235
+ rawEvidence: memory.rawEvidence,
3236
+ confidence: memory.confidence,
3237
+ pii: memory.pii
3238
+ };
3239
+ const embedding = await generateEmbeddingForMemory(
3240
+ memoryItem,
3241
+ embeddingOptions
3242
+ );
3243
+ await updateMemoryEmbeddingOp(
3244
+ storageCtx,
3245
+ saved[i].uniqueId,
3246
+ embedding,
3247
+ effectiveEmbeddingModel
3248
+ );
3249
+ } catch (error) {
3250
+ console.error("Failed to generate embedding:", error);
3251
+ }
3252
+ }
3253
+ }
3254
+ }
3255
+ await refreshMemories();
3256
+ return saved;
2487
3257
  } catch (error) {
2488
3258
  throw new Error(
2489
- `Failed to update memory ${id}: ` + (error instanceof Error ? error.message : String(error))
3259
+ "Failed to save memories: " + (error instanceof Error ? error.message : String(error))
3260
+ );
3261
+ }
3262
+ },
3263
+ [
3264
+ storageCtx,
3265
+ generateEmbeddings,
3266
+ embeddingModel,
3267
+ embeddingOptions,
3268
+ refreshMemories
3269
+ ]
3270
+ );
3271
+ const updateMemory = (0, import_react3.useCallback)(
3272
+ async (id, updates) => {
3273
+ const result = await updateMemoryOp(storageCtx, id, updates);
3274
+ if (!result.ok) {
3275
+ if (result.reason === "not_found") {
3276
+ return null;
3277
+ }
3278
+ if (result.reason === "conflict") {
3279
+ throw new Error(
3280
+ `Cannot update memory: a memory with key "${result.conflictingKey}" already exists`
3281
+ );
3282
+ }
3283
+ throw new Error(
3284
+ `Failed to update memory ${id}: ${result.error.message}`
2490
3285
  );
2491
3286
  }
3287
+ const updated = result.memory;
3288
+ const contentChanged = updates.value !== void 0 || updates.rawEvidence !== void 0 || updates.type !== void 0 || updates.namespace !== void 0 || updates.key !== void 0;
3289
+ if (contentChanged && generateEmbeddings && embeddingModel && !updates.embedding) {
3290
+ try {
3291
+ const memoryItem = {
3292
+ type: updated.type,
3293
+ namespace: updated.namespace,
3294
+ key: updated.key,
3295
+ value: updated.value,
3296
+ rawEvidence: updated.rawEvidence,
3297
+ confidence: updated.confidence,
3298
+ pii: updated.pii
3299
+ };
3300
+ const embedding = await generateEmbeddingForMemory(
3301
+ memoryItem,
3302
+ embeddingOptions
3303
+ );
3304
+ await updateMemoryEmbeddingOp(
3305
+ storageCtx,
3306
+ id,
3307
+ embedding,
3308
+ effectiveEmbeddingModel
3309
+ );
3310
+ } catch (error) {
3311
+ console.error("Failed to regenerate embedding:", error);
3312
+ }
3313
+ }
3314
+ setMemories(
3315
+ (prev) => prev.map((m) => m.uniqueId === id ? updated : m)
3316
+ );
3317
+ return updated;
2492
3318
  },
2493
- [embeddingModel, embeddingProvider, generateEmbeddings, getToken, baseUrl]
3319
+ [storageCtx, generateEmbeddings, embeddingModel, embeddingOptions]
2494
3320
  );
2495
- const removeMemory = (0, import_react2.useCallback)(
3321
+ const removeMemory = (0, import_react3.useCallback)(
2496
3322
  async (namespace, key, value) => {
2497
3323
  if (!namespace || !key || !value) {
2498
3324
  throw new Error("Missing required fields: namespace, key, value");
2499
3325
  }
2500
3326
  try {
2501
- await deleteMemory(namespace, key, value);
3327
+ await deleteMemoryOp(storageCtx, namespace, key, value);
3328
+ setMemories(
3329
+ (prev) => prev.filter(
3330
+ (m) => !(m.namespace === namespace && m.key === key && m.value === value)
3331
+ )
3332
+ );
2502
3333
  } catch (error) {
2503
3334
  throw new Error(
2504
3335
  `Failed to delete memory "${namespace}:${key}:${value}": ` + (error instanceof Error ? error.message : String(error))
2505
3336
  );
2506
3337
  }
2507
3338
  },
2508
- []
3339
+ [storageCtx]
2509
3340
  );
2510
- const removeMemoryById = (0, import_react2.useCallback)(async (id) => {
2511
- if (!Number.isInteger(id) || id <= 0) {
2512
- throw new Error("id must be a non-negative integer");
2513
- }
2514
- try {
2515
- await deleteMemoryById(id);
2516
- } catch (error) {
2517
- throw new Error(
2518
- `Failed to delete memory with id ${id}: ` + (error instanceof Error ? error.message : String(error))
2519
- );
2520
- }
2521
- }, []);
2522
- const removeMemories = (0, import_react2.useCallback)(
3341
+ const removeMemoryById = (0, import_react3.useCallback)(
3342
+ async (id) => {
3343
+ try {
3344
+ await deleteMemoryByIdOp(storageCtx, id);
3345
+ setMemories((prev) => prev.filter((m) => m.uniqueId !== id));
3346
+ } catch (error) {
3347
+ throw new Error(
3348
+ `Failed to delete memory with id ${id}: ` + (error instanceof Error ? error.message : String(error))
3349
+ );
3350
+ }
3351
+ },
3352
+ [storageCtx]
3353
+ );
3354
+ const removeMemories = (0, import_react3.useCallback)(
2523
3355
  async (namespace, key) => {
2524
3356
  if (!namespace || !key) {
2525
3357
  throw new Error("Missing required fields: namespace, key");
2526
3358
  }
2527
3359
  try {
2528
- await deleteMemories(namespace, key);
3360
+ await deleteMemoriesByKeyOp(storageCtx, namespace, key);
3361
+ setMemories(
3362
+ (prev) => prev.filter(
3363
+ (m) => !(m.namespace === namespace && m.key === key)
3364
+ )
3365
+ );
2529
3366
  } catch (error) {
2530
3367
  throw new Error(
2531
3368
  `Failed to delete memories for "${namespace}:${key}": ` + (error instanceof Error ? error.message : String(error))
2532
3369
  );
2533
3370
  }
2534
3371
  },
2535
- []
3372
+ [storageCtx]
2536
3373
  );
2537
- const clearMemories = (0, import_react2.useCallback)(async () => {
3374
+ const clearMemories = (0, import_react3.useCallback)(async () => {
2538
3375
  try {
2539
- await clearAllMemories();
3376
+ await clearAllMemoriesOp(storageCtx);
3377
+ setMemories([]);
2540
3378
  } catch (error) {
2541
3379
  throw new Error(
2542
3380
  "Failed to clear all memories: " + (error instanceof Error ? error.message : String(error))
2543
3381
  );
2544
3382
  }
2545
- }, []);
3383
+ }, [storageCtx]);
2546
3384
  return {
3385
+ memories,
3386
+ refreshMemories,
2547
3387
  extractMemoriesFromMessage,
2548
3388
  searchMemories,
2549
3389
  fetchAllMemories,
2550
3390
  fetchMemoriesByNamespace,
2551
3391
  fetchMemoriesByKey,
3392
+ getMemoryById,
3393
+ saveMemory,
3394
+ saveMemories,
2552
3395
  updateMemory,
2553
3396
  removeMemory,
2554
3397
  removeMemoryById,
@@ -2557,8 +3400,115 @@ function useMemory(options = {}) {
2557
3400
  };
2558
3401
  }
2559
3402
 
3403
+ // src/lib/memoryStorage/schema.ts
3404
+ var import_watermelondb5 = require("@nozbe/watermelondb");
3405
+ var memoryStorageSchema = (0, import_watermelondb5.appSchema)({
3406
+ version: 1,
3407
+ tables: [
3408
+ (0, import_watermelondb5.tableSchema)({
3409
+ name: "memories",
3410
+ columns: [
3411
+ // Memory type classification
3412
+ { name: "type", type: "string", isIndexed: true },
3413
+ // 'identity' | 'preference' | 'project' | 'skill' | 'constraint'
3414
+ // Hierarchical key structure
3415
+ { name: "namespace", type: "string", isIndexed: true },
3416
+ { name: "key", type: "string", isIndexed: true },
3417
+ { name: "value", type: "string" },
3418
+ // Evidence and confidence
3419
+ { name: "raw_evidence", type: "string" },
3420
+ { name: "confidence", type: "number" },
3421
+ { name: "pii", type: "boolean", isIndexed: true },
3422
+ // Composite keys for efficient lookups
3423
+ { name: "composite_key", type: "string", isIndexed: true },
3424
+ // namespace:key
3425
+ { name: "unique_key", type: "string", isIndexed: true },
3426
+ // namespace:key:value
3427
+ // Timestamps
3428
+ { name: "created_at", type: "number", isIndexed: true },
3429
+ { name: "updated_at", type: "number" },
3430
+ // Vector embeddings for semantic search
3431
+ { name: "embedding", type: "string", isOptional: true },
3432
+ // JSON stringified number[]
3433
+ { name: "embedding_model", type: "string", isOptional: true },
3434
+ // Soft delete flag
3435
+ { name: "is_deleted", type: "boolean", isIndexed: true }
3436
+ ]
3437
+ })
3438
+ ]
3439
+ });
3440
+
3441
+ // src/lib/memoryStorage/models.ts
3442
+ var import_watermelondb6 = require("@nozbe/watermelondb");
3443
+ var Memory = class extends import_watermelondb6.Model {
3444
+ /** Memory type classification */
3445
+ get type() {
3446
+ return this._getRaw("type");
3447
+ }
3448
+ /** Namespace for grouping related memories */
3449
+ get namespace() {
3450
+ return this._getRaw("namespace");
3451
+ }
3452
+ /** Key within the namespace */
3453
+ get key() {
3454
+ return this._getRaw("key");
3455
+ }
3456
+ /** The memory value/content */
3457
+ get value() {
3458
+ return this._getRaw("value");
3459
+ }
3460
+ /** Raw evidence from which this memory was extracted */
3461
+ get rawEvidence() {
3462
+ return this._getRaw("raw_evidence");
3463
+ }
3464
+ /** Confidence score (0-1) */
3465
+ get confidence() {
3466
+ return this._getRaw("confidence");
3467
+ }
3468
+ /** Whether this memory contains PII */
3469
+ get pii() {
3470
+ return this._getRaw("pii");
3471
+ }
3472
+ /** Composite key (namespace:key) for efficient lookups */
3473
+ get compositeKey() {
3474
+ return this._getRaw("composite_key");
3475
+ }
3476
+ /** Unique key (namespace:key:value) for deduplication */
3477
+ get uniqueKey() {
3478
+ return this._getRaw("unique_key");
3479
+ }
3480
+ /** Created timestamp */
3481
+ get createdAt() {
3482
+ return new Date(this._getRaw("created_at"));
3483
+ }
3484
+ /** Updated timestamp */
3485
+ get updatedAt() {
3486
+ return new Date(this._getRaw("updated_at"));
3487
+ }
3488
+ /** Embedding vector for semantic search */
3489
+ get embedding() {
3490
+ const raw = this._getRaw("embedding");
3491
+ if (!raw) return void 0;
3492
+ try {
3493
+ return JSON.parse(raw);
3494
+ } catch {
3495
+ return void 0;
3496
+ }
3497
+ }
3498
+ /** Model used to generate embedding */
3499
+ get embeddingModel() {
3500
+ const value = this._getRaw("embedding_model");
3501
+ return value ? value : void 0;
3502
+ }
3503
+ /** Soft delete flag */
3504
+ get isDeleted() {
3505
+ return this._getRaw("is_deleted");
3506
+ }
3507
+ };
3508
+ Memory.table = "memories";
3509
+
2560
3510
  // src/react/usePdf.ts
2561
- var import_react3 = require("react");
3511
+ var import_react4 = require("react");
2562
3512
 
2563
3513
  // src/lib/pdf.ts
2564
3514
  var pdfjs = __toESM(require("pdfjs-dist"));
@@ -2611,9 +3561,9 @@ async function convertPdfToImages(pdfDataUrl) {
2611
3561
  // src/react/usePdf.ts
2612
3562
  var PDF_MIME_TYPE = "application/pdf";
2613
3563
  function usePdf() {
2614
- const [isProcessing, setIsProcessing] = (0, import_react3.useState)(false);
2615
- const [error, setError] = (0, import_react3.useState)(null);
2616
- const extractPdfContext = (0, import_react3.useCallback)(
3564
+ const [isProcessing, setIsProcessing] = (0, import_react4.useState)(false);
3565
+ const [error, setError] = (0, import_react4.useState)(null);
3566
+ const extractPdfContext = (0, import_react4.useCallback)(
2617
3567
  async (files) => {
2618
3568
  setIsProcessing(true);
2619
3569
  setError(null);
@@ -2660,12 +3610,12 @@ ${text}`;
2660
3610
  }
2661
3611
 
2662
3612
  // src/react/useOCR.ts
2663
- var import_react4 = require("react");
3613
+ var import_react5 = require("react");
2664
3614
  var import_tesseract = __toESM(require("tesseract.js"));
2665
3615
  function useOCR() {
2666
- const [isProcessing, setIsProcessing] = (0, import_react4.useState)(false);
2667
- const [error, setError] = (0, import_react4.useState)(null);
2668
- const extractOCRContext = (0, import_react4.useCallback)(
3616
+ const [isProcessing, setIsProcessing] = (0, import_react5.useState)(false);
3617
+ const [error, setError] = (0, import_react5.useState)(null);
3618
+ const extractOCRContext = (0, import_react5.useCallback)(
2669
3619
  async (files) => {
2670
3620
  setIsProcessing(true);
2671
3621
  setError(null);
@@ -2751,22 +3701,22 @@ ${text}`;
2751
3701
  }
2752
3702
 
2753
3703
  // src/react/useModels.ts
2754
- var import_react5 = require("react");
3704
+ var import_react6 = require("react");
2755
3705
  function useModels(options = {}) {
2756
3706
  const { getToken, baseUrl = BASE_URL, provider, autoFetch = true } = options;
2757
- const [models, setModels] = (0, import_react5.useState)([]);
2758
- const [isLoading, setIsLoading] = (0, import_react5.useState)(false);
2759
- const [error, setError] = (0, import_react5.useState)(null);
2760
- const getTokenRef = (0, import_react5.useRef)(getToken);
2761
- const baseUrlRef = (0, import_react5.useRef)(baseUrl);
2762
- const providerRef = (0, import_react5.useRef)(provider);
2763
- const abortControllerRef = (0, import_react5.useRef)(null);
2764
- (0, import_react5.useEffect)(() => {
3707
+ const [models, setModels] = (0, import_react6.useState)([]);
3708
+ const [isLoading, setIsLoading] = (0, import_react6.useState)(false);
3709
+ const [error, setError] = (0, import_react6.useState)(null);
3710
+ const getTokenRef = (0, import_react6.useRef)(getToken);
3711
+ const baseUrlRef = (0, import_react6.useRef)(baseUrl);
3712
+ const providerRef = (0, import_react6.useRef)(provider);
3713
+ const abortControllerRef = (0, import_react6.useRef)(null);
3714
+ (0, import_react6.useEffect)(() => {
2765
3715
  getTokenRef.current = getToken;
2766
3716
  baseUrlRef.current = baseUrl;
2767
3717
  providerRef.current = provider;
2768
3718
  });
2769
- (0, import_react5.useEffect)(() => {
3719
+ (0, import_react6.useEffect)(() => {
2770
3720
  return () => {
2771
3721
  if (abortControllerRef.current) {
2772
3722
  abortControllerRef.current.abort();
@@ -2774,7 +3724,7 @@ function useModels(options = {}) {
2774
3724
  }
2775
3725
  };
2776
3726
  }, []);
2777
- const fetchModels = (0, import_react5.useCallback)(async () => {
3727
+ const fetchModels = (0, import_react6.useCallback)(async () => {
2778
3728
  if (abortControllerRef.current) {
2779
3729
  abortControllerRef.current.abort();
2780
3730
  }
@@ -2832,12 +3782,12 @@ function useModels(options = {}) {
2832
3782
  }
2833
3783
  }
2834
3784
  }, []);
2835
- const refetch = (0, import_react5.useCallback)(async () => {
3785
+ const refetch = (0, import_react6.useCallback)(async () => {
2836
3786
  setModels([]);
2837
3787
  await fetchModels();
2838
3788
  }, [fetchModels]);
2839
- const hasFetchedRef = (0, import_react5.useRef)(false);
2840
- (0, import_react5.useEffect)(() => {
3789
+ const hasFetchedRef = (0, import_react6.useRef)(false);
3790
+ (0, import_react6.useEffect)(() => {
2841
3791
  if (autoFetch && !hasFetchedRef.current) {
2842
3792
  hasFetchedRef.current = true;
2843
3793
  fetchModels();
@@ -2855,15 +3805,15 @@ function useModels(options = {}) {
2855
3805
  }
2856
3806
 
2857
3807
  // src/react/useSearch.ts
2858
- var import_react6 = require("react");
3808
+ var import_react7 = require("react");
2859
3809
  function useSearch(options = {}) {
2860
3810
  const { getToken, baseUrl = BASE_URL, onError } = options;
2861
- const [isLoading, setIsLoading] = (0, import_react6.useState)(false);
2862
- const [results, setResults] = (0, import_react6.useState)(null);
2863
- const [response, setResponse] = (0, import_react6.useState)(null);
2864
- const [error, setError] = (0, import_react6.useState)(null);
2865
- const abortControllerRef = (0, import_react6.useRef)(null);
2866
- (0, import_react6.useEffect)(() => {
3811
+ const [isLoading, setIsLoading] = (0, import_react7.useState)(false);
3812
+ const [results, setResults] = (0, import_react7.useState)(null);
3813
+ const [response, setResponse] = (0, import_react7.useState)(null);
3814
+ const [error, setError] = (0, import_react7.useState)(null);
3815
+ const abortControllerRef = (0, import_react7.useRef)(null);
3816
+ (0, import_react7.useEffect)(() => {
2867
3817
  return () => {
2868
3818
  if (abortControllerRef.current) {
2869
3819
  abortControllerRef.current.abort();
@@ -2871,7 +3821,7 @@ function useSearch(options = {}) {
2871
3821
  }
2872
3822
  };
2873
3823
  }, []);
2874
- const search = (0, import_react6.useCallback)(
3824
+ const search = (0, import_react7.useCallback)(
2875
3825
  async (query, searchOptions = {}) => {
2876
3826
  if (abortControllerRef.current) {
2877
3827
  abortControllerRef.current.abort();
@@ -2939,12 +3889,12 @@ function useSearch(options = {}) {
2939
3889
  }
2940
3890
 
2941
3891
  // src/react/useImageGeneration.ts
2942
- var import_react7 = require("react");
3892
+ var import_react8 = require("react");
2943
3893
  function useImageGeneration(options = {}) {
2944
3894
  const { getToken, baseUrl = BASE_URL, onFinish, onError } = options;
2945
- const [isLoading, setIsLoading] = (0, import_react7.useState)(false);
2946
- const abortControllerRef = (0, import_react7.useRef)(null);
2947
- (0, import_react7.useEffect)(() => {
3895
+ const [isLoading, setIsLoading] = (0, import_react8.useState)(false);
3896
+ const abortControllerRef = (0, import_react8.useRef)(null);
3897
+ (0, import_react8.useEffect)(() => {
2948
3898
  return () => {
2949
3899
  if (abortControllerRef.current) {
2950
3900
  abortControllerRef.current.abort();
@@ -2952,13 +3902,13 @@ function useImageGeneration(options = {}) {
2952
3902
  }
2953
3903
  };
2954
3904
  }, []);
2955
- const stop = (0, import_react7.useCallback)(() => {
3905
+ const stop = (0, import_react8.useCallback)(() => {
2956
3906
  if (abortControllerRef.current) {
2957
3907
  abortControllerRef.current.abort();
2958
3908
  abortControllerRef.current = null;
2959
3909
  }
2960
3910
  }, []);
2961
- const generateImage = (0, import_react7.useCallback)(
3911
+ const generateImage = (0, import_react8.useCallback)(
2962
3912
  async (args) => {
2963
3913
  if (abortControllerRef.current) {
2964
3914
  abortControllerRef.current.abort();
@@ -3076,7 +4026,11 @@ var extractConversationContext = (messages, maxMessages = 3) => {
3076
4026
  };
3077
4027
  // Annotate the CommonJS export names for ESM import in node:
3078
4028
  0 && (module.exports = {
4029
+ ChatConversation,
4030
+ ChatMessage,
3079
4031
  DEFAULT_TOOL_SELECTOR_MODEL,
4032
+ StoredMemoryModel,
4033
+ chatStorageSchema,
3080
4034
  createMemoryContextSystemMessage,
3081
4035
  decryptData,
3082
4036
  decryptDataBytes,
@@ -3084,13 +4038,18 @@ var extractConversationContext = (messages, maxMessages = 3) => {
3084
4038
  executeTool,
3085
4039
  extractConversationContext,
3086
4040
  formatMemoriesForChat,
4041
+ generateCompositeKey,
4042
+ generateConversationId,
4043
+ generateUniqueKey,
3087
4044
  hasEncryptionKey,
4045
+ memoryStorageSchema,
3088
4046
  requestEncryptionKey,
3089
4047
  selectTool,
3090
4048
  useChat,
4049
+ useChatStorage,
3091
4050
  useEncryption,
3092
4051
  useImageGeneration,
3093
- useMemory,
4052
+ useMemoryStorage,
3094
4053
  useModels,
3095
4054
  useOCR,
3096
4055
  usePdf,