@anuma/sdk 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1655,6 +1655,204 @@ var getHealth = (options) => {
1655
1655
  });
1656
1656
  };
1657
1657
 
1658
+ // src/lib/memoryEngine/generate.ts
1659
+ init_clientConfig();
1660
+
1661
+ // src/lib/memoryEngine/constants.ts
1662
+ var DEFAULT_API_EMBEDDING_MODEL = "qwen/qwen3-embedding-8b";
1663
+
1664
+ // src/lib/memoryEngine/generate.ts
1665
+ var EMBED_MAX_ATTEMPTS = 4;
1666
+ async function withEmbeddingRetry(call) {
1667
+ let last;
1668
+ let lastThrown;
1669
+ let threw = false;
1670
+ for (let attempt = 1; attempt <= EMBED_MAX_ATTEMPTS; attempt++) {
1671
+ try {
1672
+ threw = false;
1673
+ last = await call();
1674
+ if (!last.error) return last;
1675
+ const status = last.response?.status;
1676
+ const retryable = status === void 0 || status === 429 || status >= 500;
1677
+ if (!retryable) return last;
1678
+ } catch (err) {
1679
+ threw = true;
1680
+ lastThrown = err;
1681
+ }
1682
+ if (attempt < EMBED_MAX_ATTEMPTS) {
1683
+ const base = 250 * 2 ** (attempt - 1);
1684
+ await new Promise((r) => setTimeout(r, base + Math.random() * 0.4 * base));
1685
+ }
1686
+ }
1687
+ if (threw) throw lastThrown;
1688
+ return last;
1689
+ }
1690
+ var EmbeddingHttpError = class extends Error {
1691
+ constructor(message, status) {
1692
+ super(message);
1693
+ this.name = "EmbeddingHttpError";
1694
+ this.status = status;
1695
+ }
1696
+ };
1697
+ function embeddingErrorFrom(response) {
1698
+ const message = typeof response.error === "object" && response.error && "error" in response.error ? response.error.error : "API embedding failed";
1699
+ return new EmbeddingHttpError(message, response.response?.status);
1700
+ }
1701
+ async function generateEmbedding(text, options) {
1702
+ const { baseUrl = BASE_URL, getToken, apiKey, model, cache } = options;
1703
+ if (cache) {
1704
+ const cached = cache.get(text);
1705
+ if (cached) return Array.from(cached);
1706
+ }
1707
+ let headers;
1708
+ if (apiKey) {
1709
+ headers = { "X-API-Key": apiKey };
1710
+ } else if (getToken) {
1711
+ const token = await getToken();
1712
+ if (!token) {
1713
+ throw new Error("No token available for embedding generation");
1714
+ }
1715
+ headers = { Authorization: `Bearer ${token}` };
1716
+ } else {
1717
+ throw new Error("Either apiKey or getToken must be provided");
1718
+ }
1719
+ const response = await withEmbeddingRetry(
1720
+ () => postApiV1Embeddings({
1721
+ baseUrl,
1722
+ body: {
1723
+ // Mask PII from the request body only — the cache above still keys on
1724
+ // the original `text`, so callers keep their original values.
1725
+ input: options.maskInput ? options.maskInput(text) : text,
1726
+ model: model ?? DEFAULT_API_EMBEDDING_MODEL
1727
+ },
1728
+ headers
1729
+ })
1730
+ );
1731
+ if (response.error) {
1732
+ throw embeddingErrorFrom(response);
1733
+ }
1734
+ if (!response.data?.data?.[0]?.embedding) {
1735
+ throw new Error("No embedding returned from API");
1736
+ }
1737
+ const embedding = response.data.data[0].embedding;
1738
+ if (options.onUsage && response.data.usage) {
1739
+ options.onUsage({
1740
+ promptTokens: response.data.usage.prompt_tokens ?? 0,
1741
+ totalTokens: response.data.usage.total_tokens ?? 0
1742
+ });
1743
+ }
1744
+ const f32Embedding = Float32Array.from(embedding);
1745
+ if (cache) {
1746
+ cache.set(text, f32Embedding);
1747
+ }
1748
+ return Array.from(f32Embedding);
1749
+ }
1750
+ var DEFAULT_EMBEDDING_BATCH_SIZE = 100;
1751
+ var DEFAULT_EMBEDDING_BATCH_CONCURRENCY = 3;
1752
+ async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage, maskInput) {
1753
+ const response = await withEmbeddingRetry(
1754
+ () => postApiV1Embeddings({
1755
+ baseUrl,
1756
+ // Mask PII from the request body only; cache/order still key on originals.
1757
+ body: { input: maskInput ? texts.map(maskInput) : texts, model },
1758
+ headers
1759
+ })
1760
+ );
1761
+ if (response.error) {
1762
+ throw embeddingErrorFrom(response);
1763
+ }
1764
+ if (!response.data?.data) {
1765
+ throw new Error("No embeddings returned from API");
1766
+ }
1767
+ if (onUsage && response.data.usage) {
1768
+ onUsage({
1769
+ promptTokens: response.data.usage.prompt_tokens ?? 0,
1770
+ totalTokens: response.data.usage.total_tokens ?? 0
1771
+ });
1772
+ }
1773
+ return response.data.data.map((item) => item.embedding ?? []);
1774
+ }
1775
+ async function generateEmbeddings(texts, options) {
1776
+ if (texts.length === 0) return [];
1777
+ const { baseUrl = BASE_URL, getToken, apiKey, model, batchSize, cache } = options;
1778
+ const chunkSize = batchSize ?? DEFAULT_EMBEDDING_BATCH_SIZE;
1779
+ const results = new Array(texts.length).fill(null);
1780
+ const uncachedIndices = [];
1781
+ const uncachedTexts = [];
1782
+ for (let i = 0; i < texts.length; i++) {
1783
+ if (cache) {
1784
+ const cached = cache.get(texts[i]);
1785
+ if (cached) {
1786
+ results[i] = Array.from(cached);
1787
+ continue;
1788
+ }
1789
+ }
1790
+ uncachedIndices.push(i);
1791
+ uncachedTexts.push(texts[i]);
1792
+ }
1793
+ if (uncachedTexts.length === 0) {
1794
+ return results;
1795
+ }
1796
+ let headers;
1797
+ if (apiKey) {
1798
+ headers = { "X-API-Key": apiKey };
1799
+ } else if (getToken) {
1800
+ const token = await getToken();
1801
+ if (!token) {
1802
+ throw new Error("No token available for embedding generation");
1803
+ }
1804
+ headers = { Authorization: `Bearer ${token}` };
1805
+ } else {
1806
+ throw new Error("Either apiKey or getToken must be provided");
1807
+ }
1808
+ const embeddingModel = model ?? DEFAULT_API_EMBEDDING_MODEL;
1809
+ let newEmbeddings;
1810
+ if (uncachedTexts.length <= chunkSize) {
1811
+ newEmbeddings = await generateEmbeddingsBatch(
1812
+ uncachedTexts,
1813
+ headers,
1814
+ baseUrl,
1815
+ embeddingModel,
1816
+ options.onUsage,
1817
+ options.maskInput
1818
+ );
1819
+ } else {
1820
+ const chunks = [];
1821
+ for (let i = 0; i < uncachedTexts.length; i += chunkSize) {
1822
+ chunks.push(uncachedTexts.slice(i, i + chunkSize));
1823
+ }
1824
+ const allEmbeddings = new Array(chunks.length);
1825
+ let nextIndex = 0;
1826
+ const worker = async () => {
1827
+ while (nextIndex < chunks.length) {
1828
+ const idx = nextIndex++;
1829
+ allEmbeddings[idx] = await generateEmbeddingsBatch(
1830
+ chunks[idx],
1831
+ headers,
1832
+ baseUrl,
1833
+ embeddingModel,
1834
+ options.onUsage,
1835
+ options.maskInput
1836
+ );
1837
+ }
1838
+ };
1839
+ const workers = Array.from(
1840
+ { length: Math.min(DEFAULT_EMBEDDING_BATCH_CONCURRENCY, chunks.length) },
1841
+ () => worker()
1842
+ );
1843
+ await Promise.all(workers);
1844
+ newEmbeddings = allEmbeddings.flat();
1845
+ }
1846
+ for (let i = 0; i < uncachedIndices.length; i++) {
1847
+ const f32Embedding = Float32Array.from(newEmbeddings[i]);
1848
+ results[uncachedIndices[i]] = Array.from(f32Embedding);
1849
+ if (cache) {
1850
+ cache.set(uncachedTexts[i], f32Embedding);
1851
+ }
1852
+ }
1853
+ return results;
1854
+ }
1855
+
1658
1856
  // src/tools/appBuilderPrompt.ts
1659
1857
  var APP_BUILDER_PROMPT = `App Builder tools (create_file, patch_file, and the rest described below) are available this turn, but they are OPTIONAL \u2014 having them does not mean you should build anything.
1660
1858
 
@@ -1872,398 +2070,64 @@ function chunkText(text, options) {
1872
2070
  overlapSentences.unshift(currentChunkSentences[j]);
1873
2071
  overlapLength += currentChunkSentences[j].length + 1;
1874
2072
  }
1875
- if (overlapSentences.length > 0) {
1876
- currentChunkSentences = [...overlapSentences, sentence];
1877
- const overlapText = overlapSentences[0];
1878
- const overlapStart = text.lastIndexOf(overlapText, currentOffset);
1879
- currentChunkStart = overlapStart === -1 ? sentenceStart : overlapStart;
1880
- } else {
1881
- currentChunkSentences = [sentence];
1882
- currentChunkStart = sentenceStart;
1883
- }
1884
- } else {
1885
- if (currentChunkSentences.length === 0) {
1886
- currentChunkStart = sentenceStart;
1887
- }
1888
- currentChunkSentences.push(sentence);
1889
- }
1890
- currentOffset = sentenceEnd;
1891
- }
1892
- if (currentChunkSentences.length > 0) {
1893
- const chunkText2 = currentChunkSentences.join(" ");
1894
- if (chunkText2.length >= minChunkSize) {
1895
- chunks.push({
1896
- text: chunkText2,
1897
- startOffset: currentChunkStart,
1898
- endOffset: text.length
1899
- });
1900
- }
1901
- }
1902
- if (chunks.length === 0) {
1903
- const trimmedText = text.trim();
1904
- if (trimmedText.length > 0) {
1905
- return [
1906
- {
1907
- text: trimmedText,
1908
- startOffset: 0,
1909
- endOffset: text.length
1910
- }
1911
- ];
1912
- }
1913
- }
1914
- return chunks;
1915
- }
1916
- function shouldChunkMessage(content, chunkSize = DEFAULT_CHUNK_SIZE) {
1917
- return content.length > chunkSize;
1918
- }
1919
-
1920
- // src/lib/memoryEngine/embeddings.ts
1921
- init_clientConfig();
1922
-
1923
- // src/react/useEncryption.ts
1924
- var encryptionKeyStore = /* @__PURE__ */ new Map();
1925
- var cryptoKeyCache = /* @__PURE__ */ new Map();
1926
- var clearAllEncryptionStateCallbacks = /* @__PURE__ */ new Set();
1927
- function onClearAllEncryptionState(callback) {
1928
- clearAllEncryptionStateCallbacks.add(callback);
1929
- return () => {
1930
- clearAllEncryptionStateCallbacks.delete(callback);
1931
- };
1932
- }
1933
- function getStoredKey(address) {
1934
- const keys = encryptionKeyStore.get(address);
1935
- return keys?.current ?? null;
1936
- }
1937
- function getStoredKeyByVersion(address, version) {
1938
- const keys = encryptionKeyStore.get(address);
1939
- if (!keys) return null;
1940
- return version === "v2" ? keys.legacy : keys.current;
1941
- }
1942
- function hexToBytes(hex) {
1943
- const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
1944
- const bytes = new Uint8Array(cleanHex.length / 2);
1945
- for (let i = 0; i < cleanHex.length; i += 2) {
1946
- bytes[i / 2] = parseInt(cleanHex.slice(i, i + 2), 16);
1947
- }
1948
- return bytes;
1949
- }
1950
- var SHARED_TEXT_ENCODER = new TextEncoder();
1951
- var SHARED_TEXT_DECODER = new TextDecoder();
1952
- async function getEncryptionKey(address, version = "v3") {
1953
- const cacheKey = `${address}:${version}`;
1954
- const cachedKey = cryptoKeyCache.get(cacheKey);
1955
- if (cachedKey) {
1956
- return cachedKey;
1957
- }
1958
- const keyHex = getStoredKeyByVersion(address, version);
1959
- if (!keyHex) {
1960
- throw new Error(
1961
- "Encryption key not found. Please sign a message to generate your encryption key."
1962
- );
1963
- }
1964
- const keyBytes = hexToBytes(keyHex);
1965
- const cryptoKey = await crypto.subtle.importKey(
1966
- "raw",
1967
- keyBytes.buffer,
1968
- { name: "AES-GCM" },
1969
- false,
1970
- ["encrypt", "decrypt"]
1971
- );
1972
- cryptoKeyCache.set(cacheKey, cryptoKey);
1973
- return cryptoKey;
1974
- }
1975
- async function decryptData(encryptedHex, address, version = "v3") {
1976
- const key = await getEncryptionKey(address, version);
1977
- return decryptDataWithKey(encryptedHex, key);
1978
- }
1979
- function hasEncryptionKey(address) {
1980
- return getStoredKey(address) !== null;
1981
- }
1982
- async function decryptDataWithKey(encryptedHex, key) {
1983
- const combined = hexToBytes(encryptedHex);
1984
- const iv = combined.subarray(0, 12);
1985
- const encryptedData = combined.subarray(12);
1986
- const decryptedData = await crypto.subtle.decrypt(
1987
- {
1988
- name: "AES-GCM",
1989
- iv
1990
- },
1991
- key,
1992
- encryptedData
1993
- );
1994
- return SHARED_TEXT_DECODER.decode(decryptedData);
1995
- }
1996
-
1997
- // src/lib/memoryEngine/vector.ts
1998
- function cosineSimilarity(a, b) {
1999
- if (a.length !== b.length) return 0;
2000
- let dot = 0;
2001
- let normA = 0;
2002
- let normB = 0;
2003
- for (let i = 0; i < a.length; i++) {
2004
- dot += a[i] * b[i];
2005
- normA += a[i] * a[i];
2006
- normB += b[i] * b[i];
2007
- }
2008
- const denom = Math.sqrt(normA) * Math.sqrt(normB);
2009
- return denom === 0 ? 0 : dot / denom;
2010
- }
2011
-
2012
- // src/lib/db/encryption-utils.ts
2013
- function isEncrypted(value) {
2014
- const prefix = value.startsWith("enc:v3:") ? "enc:v3:" : value.startsWith("enc:v2:") ? "enc:v2:" : null;
2015
- if (!prefix) return false;
2016
- const payload = value.slice(prefix.length);
2017
- return payload.length >= 56 && /^[0-9a-f]+$/i.test(payload);
2018
- }
2019
- function detectEncryptionVersion(value) {
2020
- if (value.startsWith("enc:v3:")) {
2021
- return { version: "v3", encryptedData: value.slice("enc:v3:".length) };
2022
- }
2023
- if (value.startsWith("enc:v2:")) {
2024
- return { version: "v2", encryptedData: value.slice("enc:v2:".length) };
2025
- }
2026
- return null;
2027
- }
2028
- async function decryptField(value, address) {
2029
- if (!value) return value;
2030
- const detected = detectEncryptionVersion(value);
2031
- if (!detected) return value;
2032
- if (detected.encryptedData.length < 56 || !/^[0-9a-f]+$/i.test(detected.encryptedData)) {
2033
- return value;
2034
- }
2035
- try {
2036
- return await decryptData(detected.encryptedData, address, detected.version);
2037
- } catch (error) {
2038
- getLogger().warn("Failed to decrypt field, returning as-is:", error);
2039
- return value;
2040
- }
2041
- }
2042
-
2043
- // src/lib/chat/useChat/strategies/types.ts
2044
- function isChatCompletionResponse(r) {
2045
- if (r.object === "response") return false;
2046
- if (Array.isArray(r.output)) return false;
2047
- return true;
2048
- }
2049
- function getToolCallEvents(r) {
2050
- if (isChatCompletionResponse(r)) {
2051
- return r.portal?.tool_call_events ?? r.tool_call_events;
2052
- }
2053
- return r.tool_call_events;
2054
- }
2055
- function getCostMicroUsd(r) {
2056
- if (isChatCompletionResponse(r)) {
2057
- return r.portal?.cost_micro_usd ?? r.usage?.cost_micro_usd;
2058
- }
2059
- return r.usage?.cost_micro_usd;
2060
- }
2061
- function getCreditsUsed(r) {
2062
- if (isChatCompletionResponse(r)) {
2063
- return r.portal?.credits_used ?? r.usage?.credits_used;
2064
- }
2065
- return r.usage?.credits_used;
2066
- }
2067
- function getImageModel(r) {
2068
- if (isChatCompletionResponse(r)) {
2069
- return r.portal?.image_model ?? r.image_model;
2070
- }
2071
- return r.image_model;
2072
- }
2073
-
2074
- // src/lib/memoryEngine/constants.ts
2075
- var DEFAULT_API_EMBEDDING_MODEL = "qwen/qwen3-embedding-8b";
2076
-
2077
- // src/lib/memoryEngine/embeddings.ts
2078
- var EMBED_MAX_ATTEMPTS = 4;
2079
- async function withEmbeddingRetry(call) {
2080
- let last;
2081
- let lastThrown;
2082
- let threw = false;
2083
- for (let attempt = 1; attempt <= EMBED_MAX_ATTEMPTS; attempt++) {
2084
- try {
2085
- threw = false;
2086
- last = await call();
2087
- if (!last.error) return last;
2088
- const status = last.response?.status;
2089
- const retryable = status === void 0 || status === 429 || status >= 500;
2090
- if (!retryable) return last;
2091
- } catch (err) {
2092
- threw = true;
2093
- lastThrown = err;
2094
- }
2095
- if (attempt < EMBED_MAX_ATTEMPTS) {
2096
- const base = 250 * 2 ** (attempt - 1);
2097
- await new Promise((r) => setTimeout(r, base + Math.random() * 0.4 * base));
2098
- }
2099
- }
2100
- if (threw) throw lastThrown;
2101
- return last;
2102
- }
2103
- var EmbeddingHttpError = class extends Error {
2104
- constructor(message, status) {
2105
- super(message);
2106
- this.name = "EmbeddingHttpError";
2107
- this.status = status;
2108
- }
2109
- };
2110
- function embeddingErrorFrom(response) {
2111
- const message = typeof response.error === "object" && response.error && "error" in response.error ? response.error.error : "API embedding failed";
2112
- return new EmbeddingHttpError(message, response.response?.status);
2113
- }
2114
- async function generateEmbedding(text, options) {
2115
- const { baseUrl = BASE_URL, getToken, apiKey, model, cache } = options;
2116
- if (cache) {
2117
- const cached = cache.get(text);
2118
- if (cached) return Array.from(cached);
2119
- }
2120
- let headers;
2121
- if (apiKey) {
2122
- headers = { "X-API-Key": apiKey };
2123
- } else if (getToken) {
2124
- const token = await getToken();
2125
- if (!token) {
2126
- throw new Error("No token available for embedding generation");
2127
- }
2128
- headers = { Authorization: `Bearer ${token}` };
2129
- } else {
2130
- throw new Error("Either apiKey or getToken must be provided");
2131
- }
2132
- const response = await withEmbeddingRetry(
2133
- () => postApiV1Embeddings({
2134
- baseUrl,
2135
- body: {
2136
- // Mask PII from the request body only — the cache above still keys on
2137
- // the original `text`, so callers keep their original values.
2138
- input: options.maskInput ? options.maskInput(text) : text,
2139
- model: model ?? DEFAULT_API_EMBEDDING_MODEL
2140
- },
2141
- headers
2142
- })
2143
- );
2144
- if (response.error) {
2145
- throw embeddingErrorFrom(response);
2146
- }
2147
- if (!response.data?.data?.[0]?.embedding) {
2148
- throw new Error("No embedding returned from API");
2149
- }
2150
- const embedding = response.data.data[0].embedding;
2151
- if (options.onUsage && response.data.usage) {
2152
- options.onUsage({
2153
- promptTokens: response.data.usage.prompt_tokens ?? 0,
2154
- totalTokens: response.data.usage.total_tokens ?? 0
2155
- });
2156
- }
2157
- const f32Embedding = Float32Array.from(embedding);
2158
- if (cache) {
2159
- cache.set(text, f32Embedding);
2160
- }
2161
- return Array.from(f32Embedding);
2162
- }
2163
- var DEFAULT_EMBEDDING_BATCH_SIZE = 100;
2164
- var DEFAULT_EMBEDDING_BATCH_CONCURRENCY = 3;
2165
- async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage, maskInput) {
2166
- const response = await withEmbeddingRetry(
2167
- () => postApiV1Embeddings({
2168
- baseUrl,
2169
- // Mask PII from the request body only; cache/order still key on originals.
2170
- body: { input: maskInput ? texts.map(maskInput) : texts, model },
2171
- headers
2172
- })
2173
- );
2174
- if (response.error) {
2175
- throw embeddingErrorFrom(response);
2176
- }
2177
- if (!response.data?.data) {
2178
- throw new Error("No embeddings returned from API");
2179
- }
2180
- if (onUsage && response.data.usage) {
2181
- onUsage({
2182
- promptTokens: response.data.usage.prompt_tokens ?? 0,
2183
- totalTokens: response.data.usage.total_tokens ?? 0
2184
- });
2185
- }
2186
- return response.data.data.map((item) => item.embedding ?? []);
2187
- }
2188
- async function generateEmbeddings(texts, options) {
2189
- if (texts.length === 0) return [];
2190
- const { baseUrl = BASE_URL, getToken, apiKey, model, batchSize, cache } = options;
2191
- const chunkSize = batchSize ?? DEFAULT_EMBEDDING_BATCH_SIZE;
2192
- const results = new Array(texts.length).fill(null);
2193
- const uncachedIndices = [];
2194
- const uncachedTexts = [];
2195
- for (let i = 0; i < texts.length; i++) {
2196
- if (cache) {
2197
- const cached = cache.get(texts[i]);
2198
- if (cached) {
2199
- results[i] = Array.from(cached);
2200
- continue;
2073
+ if (overlapSentences.length > 0) {
2074
+ currentChunkSentences = [...overlapSentences, sentence];
2075
+ const overlapText = overlapSentences[0];
2076
+ const overlapStart = text.lastIndexOf(overlapText, currentOffset);
2077
+ currentChunkStart = overlapStart === -1 ? sentenceStart : overlapStart;
2078
+ } else {
2079
+ currentChunkSentences = [sentence];
2080
+ currentChunkStart = sentenceStart;
2201
2081
  }
2082
+ } else {
2083
+ if (currentChunkSentences.length === 0) {
2084
+ currentChunkStart = sentenceStart;
2085
+ }
2086
+ currentChunkSentences.push(sentence);
2202
2087
  }
2203
- uncachedIndices.push(i);
2204
- uncachedTexts.push(texts[i]);
2205
- }
2206
- if (uncachedTexts.length === 0) {
2207
- return results;
2088
+ currentOffset = sentenceEnd;
2208
2089
  }
2209
- let headers;
2210
- if (apiKey) {
2211
- headers = { "X-API-Key": apiKey };
2212
- } else if (getToken) {
2213
- const token = await getToken();
2214
- if (!token) {
2215
- throw new Error("No token available for embedding generation");
2090
+ if (currentChunkSentences.length > 0) {
2091
+ const chunkText2 = currentChunkSentences.join(" ");
2092
+ if (chunkText2.length >= minChunkSize) {
2093
+ chunks.push({
2094
+ text: chunkText2,
2095
+ startOffset: currentChunkStart,
2096
+ endOffset: text.length
2097
+ });
2216
2098
  }
2217
- headers = { Authorization: `Bearer ${token}` };
2218
- } else {
2219
- throw new Error("Either apiKey or getToken must be provided");
2220
2099
  }
2221
- const embeddingModel = model ?? DEFAULT_API_EMBEDDING_MODEL;
2222
- let newEmbeddings;
2223
- if (uncachedTexts.length <= chunkSize) {
2224
- newEmbeddings = await generateEmbeddingsBatch(
2225
- uncachedTexts,
2226
- headers,
2227
- baseUrl,
2228
- embeddingModel,
2229
- options.onUsage,
2230
- options.maskInput
2231
- );
2232
- } else {
2233
- const chunks = [];
2234
- for (let i = 0; i < uncachedTexts.length; i += chunkSize) {
2235
- chunks.push(uncachedTexts.slice(i, i + chunkSize));
2100
+ if (chunks.length === 0) {
2101
+ const trimmedText = text.trim();
2102
+ if (trimmedText.length > 0) {
2103
+ return [
2104
+ {
2105
+ text: trimmedText,
2106
+ startOffset: 0,
2107
+ endOffset: text.length
2108
+ }
2109
+ ];
2236
2110
  }
2237
- const allEmbeddings = new Array(chunks.length);
2238
- let nextIndex = 0;
2239
- const worker = async () => {
2240
- while (nextIndex < chunks.length) {
2241
- const idx = nextIndex++;
2242
- allEmbeddings[idx] = await generateEmbeddingsBatch(
2243
- chunks[idx],
2244
- headers,
2245
- baseUrl,
2246
- embeddingModel,
2247
- options.onUsage,
2248
- options.maskInput
2249
- );
2250
- }
2251
- };
2252
- const workers = Array.from(
2253
- { length: Math.min(DEFAULT_EMBEDDING_BATCH_CONCURRENCY, chunks.length) },
2254
- () => worker()
2255
- );
2256
- await Promise.all(workers);
2257
- newEmbeddings = allEmbeddings.flat();
2258
2111
  }
2259
- for (let i = 0; i < uncachedIndices.length; i++) {
2260
- const f32Embedding = Float32Array.from(newEmbeddings[i]);
2261
- results[uncachedIndices[i]] = Array.from(f32Embedding);
2262
- if (cache) {
2263
- cache.set(uncachedTexts[i], f32Embedding);
2264
- }
2112
+ return chunks;
2113
+ }
2114
+ function shouldChunkMessage(content, chunkSize = DEFAULT_CHUNK_SIZE) {
2115
+ return content.length > chunkSize;
2116
+ }
2117
+
2118
+ // src/lib/memoryEngine/vector.ts
2119
+ function cosineSimilarity(a, b) {
2120
+ if (a.length !== b.length) return 0;
2121
+ let dot = 0;
2122
+ let normA = 0;
2123
+ let normB = 0;
2124
+ for (let i = 0; i < a.length; i++) {
2125
+ dot += a[i] * b[i];
2126
+ normA += a[i] * a[i];
2127
+ normB += b[i] * b[i];
2265
2128
  }
2266
- return results;
2129
+ const denom = Math.sqrt(normA) * Math.sqrt(normB);
2130
+ return denom === 0 ? 0 : dot / denom;
2267
2131
  }
2268
2132
 
2269
2133
  // src/lib/tools/serverTools.ts
@@ -2330,7 +2194,7 @@ function getCachedServerTools() {
2330
2194
  if (!cached) return null;
2331
2195
  const parsed = JSON.parse(cached);
2332
2196
  if (parsed.version !== CACHE_VERSION) {
2333
- clearServerToolsCache();
2197
+ removeLocalStorageCache();
2334
2198
  return null;
2335
2199
  }
2336
2200
  return parsed;
@@ -2342,24 +2206,31 @@ function isCacheExpired(cache, expirationMs = DEFAULT_CACHE_EXPIRATION_MS) {
2342
2206
  if (!cache) return true;
2343
2207
  return Date.now() - cache.timestamp > expirationMs;
2344
2208
  }
2345
- function cacheServerTools(tools, checksum) {
2346
- if (typeof localStorage === "undefined") return;
2347
- const cacheData = {
2209
+ function buildCacheEntry(tools, checksum) {
2210
+ return {
2348
2211
  tools,
2349
2212
  timestamp: Date.now(),
2350
2213
  version: CACHE_VERSION,
2351
2214
  ...checksum && { checksum }
2352
2215
  };
2216
+ }
2217
+ function writeLocalStorageCache(entry) {
2218
+ if (typeof localStorage === "undefined") return;
2353
2219
  try {
2354
- localStorage.setItem(SERVER_TOOLS_CACHE_KEY, JSON.stringify(cacheData));
2220
+ localStorage.setItem(SERVER_TOOLS_CACHE_KEY, JSON.stringify(entry));
2355
2221
  } catch (error) {
2356
2222
  getLogger().warn("[serverTools] Failed to cache tools:", error);
2357
2223
  }
2358
2224
  }
2359
- function clearServerToolsCache() {
2225
+ function removeLocalStorageCache() {
2360
2226
  if (typeof localStorage === "undefined") return;
2361
2227
  localStorage.removeItem(SERVER_TOOLS_CACHE_KEY);
2362
2228
  }
2229
+ var localStorageToolsCache = {
2230
+ get: getCachedServerTools,
2231
+ set: writeLocalStorageCache,
2232
+ clear: removeLocalStorageCache
2233
+ };
2363
2234
  async function fetchServerToolsFromApi(baseUrl, token) {
2364
2235
  const response = await fetch(`${baseUrl}/api/v1/tools`, {
2365
2236
  method: "GET",
@@ -2380,9 +2251,23 @@ async function getServerTools(options) {
2380
2251
  cacheExpirationMs = DEFAULT_CACHE_EXPIRATION_MS,
2381
2252
  forceRefresh = false,
2382
2253
  getToken,
2383
- apiKey
2254
+ apiKey,
2255
+ cache = localStorageToolsCache
2384
2256
  } = options;
2385
- const cached = getCachedServerTools();
2257
+ const persistCache = async (entry) => {
2258
+ try {
2259
+ await cache.set(entry);
2260
+ } catch (error) {
2261
+ getLogger().warn("[serverTools] Cache write failed (non-fatal):", error);
2262
+ }
2263
+ };
2264
+ let rawCached = null;
2265
+ try {
2266
+ rawCached = await cache.get();
2267
+ } catch (error) {
2268
+ getLogger().warn("[serverTools] Cache read failed; falling through to server fetch:", error);
2269
+ }
2270
+ const cached = rawCached && rawCached.version === CACHE_VERSION ? rawCached : null;
2386
2271
  const cacheValid = !isCacheExpired(cached, cacheExpirationMs);
2387
2272
  if (cached && cacheValid && !forceRefresh) {
2388
2273
  return cached.tools;
@@ -2403,7 +2288,7 @@ async function getServerTools(options) {
2403
2288
  }
2404
2289
  const data = await response.json();
2405
2290
  const { tools: tools2, checksum: checksum2 } = convertServerToolsResponse(data);
2406
- cacheServerTools(tools2, checksum2);
2291
+ await persistCache(buildCacheEntry(tools2, checksum2));
2407
2292
  return tools2;
2408
2293
  }
2409
2294
  if (!getToken) {
@@ -2416,7 +2301,7 @@ async function getServerTools(options) {
2416
2301
  return cached?.tools ?? [];
2417
2302
  }
2418
2303
  const { tools, checksum } = await fetchServerToolsFromApi(effectiveBaseUrl, token);
2419
- cacheServerTools(tools, checksum);
2304
+ await persistCache(buildCacheEntry(tools, checksum));
2420
2305
  return tools;
2421
2306
  } catch (error) {
2422
2307
  getLogger().error("[serverTools] Failed to fetch server tools:", error);
@@ -3274,6 +3159,142 @@ function buildSystemPrompt(ctx, options) {
3274
3159
  return { prompt, activeSections };
3275
3160
  }
3276
3161
 
3162
+ // src/react/useEncryption.ts
3163
+ var encryptionKeyStore = /* @__PURE__ */ new Map();
3164
+ var cryptoKeyCache = /* @__PURE__ */ new Map();
3165
+ var clearAllEncryptionStateCallbacks = /* @__PURE__ */ new Set();
3166
+ function onClearAllEncryptionState(callback) {
3167
+ clearAllEncryptionStateCallbacks.add(callback);
3168
+ return () => {
3169
+ clearAllEncryptionStateCallbacks.delete(callback);
3170
+ };
3171
+ }
3172
+ function getStoredKey(address) {
3173
+ const keys = encryptionKeyStore.get(address);
3174
+ return keys?.current ?? null;
3175
+ }
3176
+ function getStoredKeyByVersion(address, version) {
3177
+ const keys = encryptionKeyStore.get(address);
3178
+ if (!keys) return null;
3179
+ return version === "v2" ? keys.legacy : keys.current;
3180
+ }
3181
+ function hexToBytes(hex) {
3182
+ const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
3183
+ const bytes = new Uint8Array(cleanHex.length / 2);
3184
+ for (let i = 0; i < cleanHex.length; i += 2) {
3185
+ bytes[i / 2] = parseInt(cleanHex.slice(i, i + 2), 16);
3186
+ }
3187
+ return bytes;
3188
+ }
3189
+ var SHARED_TEXT_ENCODER = new TextEncoder();
3190
+ var SHARED_TEXT_DECODER = new TextDecoder();
3191
+ async function getEncryptionKey(address, version = "v3") {
3192
+ const cacheKey = `${address}:${version}`;
3193
+ const cachedKey = cryptoKeyCache.get(cacheKey);
3194
+ if (cachedKey) {
3195
+ return cachedKey;
3196
+ }
3197
+ const keyHex = getStoredKeyByVersion(address, version);
3198
+ if (!keyHex) {
3199
+ throw new Error(
3200
+ "Encryption key not found. Please sign a message to generate your encryption key."
3201
+ );
3202
+ }
3203
+ const keyBytes = hexToBytes(keyHex);
3204
+ const cryptoKey = await crypto.subtle.importKey(
3205
+ "raw",
3206
+ keyBytes.buffer,
3207
+ { name: "AES-GCM" },
3208
+ false,
3209
+ ["encrypt", "decrypt"]
3210
+ );
3211
+ cryptoKeyCache.set(cacheKey, cryptoKey);
3212
+ return cryptoKey;
3213
+ }
3214
+ async function decryptData(encryptedHex, address, version = "v3") {
3215
+ const key = await getEncryptionKey(address, version);
3216
+ return decryptDataWithKey(encryptedHex, key);
3217
+ }
3218
+ function hasEncryptionKey(address) {
3219
+ return getStoredKey(address) !== null;
3220
+ }
3221
+ async function decryptDataWithKey(encryptedHex, key) {
3222
+ const combined = hexToBytes(encryptedHex);
3223
+ const iv = combined.subarray(0, 12);
3224
+ const encryptedData = combined.subarray(12);
3225
+ const decryptedData = await crypto.subtle.decrypt(
3226
+ {
3227
+ name: "AES-GCM",
3228
+ iv
3229
+ },
3230
+ key,
3231
+ encryptedData
3232
+ );
3233
+ return SHARED_TEXT_DECODER.decode(decryptedData);
3234
+ }
3235
+
3236
+ // src/lib/db/encryption-utils.ts
3237
+ function isEncrypted(value) {
3238
+ const prefix = value.startsWith("enc:v3:") ? "enc:v3:" : value.startsWith("enc:v2:") ? "enc:v2:" : null;
3239
+ if (!prefix) return false;
3240
+ const payload = value.slice(prefix.length);
3241
+ return payload.length >= 56 && /^[0-9a-f]+$/i.test(payload);
3242
+ }
3243
+ function detectEncryptionVersion(value) {
3244
+ if (value.startsWith("enc:v3:")) {
3245
+ return { version: "v3", encryptedData: value.slice("enc:v3:".length) };
3246
+ }
3247
+ if (value.startsWith("enc:v2:")) {
3248
+ return { version: "v2", encryptedData: value.slice("enc:v2:".length) };
3249
+ }
3250
+ return null;
3251
+ }
3252
+ async function decryptField(value, address) {
3253
+ if (!value) return value;
3254
+ const detected = detectEncryptionVersion(value);
3255
+ if (!detected) return value;
3256
+ if (detected.encryptedData.length < 56 || !/^[0-9a-f]+$/i.test(detected.encryptedData)) {
3257
+ return value;
3258
+ }
3259
+ try {
3260
+ return await decryptData(detected.encryptedData, address, detected.version);
3261
+ } catch (error) {
3262
+ getLogger().warn("Failed to decrypt field, returning as-is:", error);
3263
+ return value;
3264
+ }
3265
+ }
3266
+
3267
+ // src/lib/chat/useChat/strategies/types.ts
3268
+ function isChatCompletionResponse(r) {
3269
+ if (r.object === "response") return false;
3270
+ if (Array.isArray(r.output)) return false;
3271
+ return true;
3272
+ }
3273
+ function getToolCallEvents(r) {
3274
+ if (isChatCompletionResponse(r)) {
3275
+ return r.portal?.tool_call_events ?? r.tool_call_events;
3276
+ }
3277
+ return r.tool_call_events;
3278
+ }
3279
+ function getCostMicroUsd(r) {
3280
+ if (isChatCompletionResponse(r)) {
3281
+ return r.portal?.cost_micro_usd ?? r.usage?.cost_micro_usd;
3282
+ }
3283
+ return r.usage?.cost_micro_usd;
3284
+ }
3285
+ function getCreditsUsed(r) {
3286
+ if (isChatCompletionResponse(r)) {
3287
+ return r.portal?.credits_used ?? r.usage?.credits_used;
3288
+ }
3289
+ return r.usage?.credits_used;
3290
+ }
3291
+ function getImageModel(r) {
3292
+ if (isChatCompletionResponse(r)) {
3293
+ return r.portal?.image_model ?? r.image_model;
3294
+ }
3295
+ return r.image_model;
3296
+ }
3297
+
3277
3298
  // src/lib/memoryEngine/quantization.ts
3278
3299
  var INT8_MAX = 127;
3279
3300
  function quantizeEmbedding(v) {