@anuma/sdk 10.0.3 → 10.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
@@ -1825,6 +1825,78 @@ function getImageModel(r) {
1825
1825
  return r.image_model;
1826
1826
  }
1827
1827
 
1828
+ // src/lib/memoryEngine/vector.ts
1829
+ function cosineSimilarity(a, b) {
1830
+ if (a.length !== b.length) return 0;
1831
+ let dot = 0;
1832
+ let normA = 0;
1833
+ let normB = 0;
1834
+ for (let i = 0; i < a.length; i++) {
1835
+ dot += a[i] * b[i];
1836
+ normA += a[i] * a[i];
1837
+ normB += b[i] * b[i];
1838
+ }
1839
+ const denom = Math.sqrt(normA) * Math.sqrt(normB);
1840
+ return denom === 0 ? 0 : dot / denom;
1841
+ }
1842
+
1843
+ // src/lib/processors/encoding.ts
1844
+ var B64_ENCODE_CHUNK = 32768 * 3;
1845
+ function uint8ArrayToBase64(data) {
1846
+ if (typeof Buffer !== "undefined") {
1847
+ return Buffer.from(data).toString("base64");
1848
+ }
1849
+ let base64 = "";
1850
+ for (let i = 0; i < data.length; i += B64_ENCODE_CHUNK) {
1851
+ const slice = data.subarray(i, i + B64_ENCODE_CHUNK);
1852
+ let binary = "";
1853
+ for (let j = 0; j < slice.length; j++) {
1854
+ binary += String.fromCharCode(slice[j]);
1855
+ }
1856
+ base64 += btoa(binary);
1857
+ }
1858
+ return base64;
1859
+ }
1860
+ function base64ToUint8Array(base64) {
1861
+ if (typeof Buffer !== "undefined") {
1862
+ const buf = Buffer.from(base64, "base64");
1863
+ return new Uint8Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength));
1864
+ }
1865
+ const binary = atob(base64);
1866
+ const bytes = new Uint8Array(binary.length);
1867
+ for (let i = 0; i < binary.length; i++) {
1868
+ bytes[i] = binary.charCodeAt(i);
1869
+ }
1870
+ return bytes;
1871
+ }
1872
+
1873
+ // src/lib/memoryEngine/vectorEncoding.ts
1874
+ var BYTES_PER_FLOAT32 = 4;
1875
+ var CANONICAL_BASE64 = /^[A-Za-z0-9+/]+={0,2}$/;
1876
+ function encodeChunkVector(vector2) {
1877
+ const f32 = vector2 instanceof Float32Array ? vector2 : Float32Array.from(vector2);
1878
+ return uint8ArrayToBase64(new Uint8Array(f32.buffer, f32.byteOffset, f32.byteLength));
1879
+ }
1880
+ function decodeChunkVector(vector2, onMalformed) {
1881
+ if (!vector2 || vector2.length === 0) return new Float32Array(0);
1882
+ if (typeof vector2 !== "string") return Float32Array.from(vector2);
1883
+ if (vector2.length % 4 !== 0 || !CANONICAL_BASE64.test(vector2)) {
1884
+ onMalformed?.();
1885
+ return new Float32Array(0);
1886
+ }
1887
+ try {
1888
+ const bytes = base64ToUint8Array(vector2);
1889
+ if (bytes.byteLength === 0 || bytes.byteLength % BYTES_PER_FLOAT32 !== 0) {
1890
+ onMalformed?.();
1891
+ return new Float32Array(0);
1892
+ }
1893
+ return new Float32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / BYTES_PER_FLOAT32);
1894
+ } catch {
1895
+ onMalformed?.();
1896
+ return new Float32Array(0);
1897
+ }
1898
+ }
1899
+
1828
1900
  // src/lib/taskType.ts
1829
1901
  var TASK_TYPE_HEADER = "X-Anuma-Task-Type";
1830
1902
  function taskTypeHeader(taskType) {
@@ -2231,7 +2303,7 @@ async function createRemoteChatStore(options) {
2231
2303
  async list(query) {
2232
2304
  const limit = query.limit ?? 20;
2233
2305
  const parent = query.conversationId ?? "";
2234
- if (!kinds.has(query.kind) || !integer(limit, 1) || query.includeDeleted !== void 0 && typeof query.includeDeleted !== "boolean" || limit > (query.kind === "message" ? 200 : 50) || (query.cursor?.length ?? 0) > 2048 || (query.kind === "conversation" || query.kind === "project" ? parent !== "" : !id(parent)))
2306
+ if (!kinds.has(query.kind) || !integer(limit, 1) || query.includeDeleted !== void 0 && typeof query.includeDeleted !== "boolean" || limit > 200 || (query.cursor?.length ?? 0) > 2048 || (query.kind === "conversation" || query.kind === "project" ? parent !== "" : !id(parent)))
2235
2307
  invalid();
2236
2308
  const params = new URLSearchParams({
2237
2309
  account_id: String(accountId),
@@ -2299,7 +2371,7 @@ async function createRemoteChatStore(options) {
2299
2371
  },
2300
2372
  async account(signal) {
2301
2373
  const value = await request("/account", {}, signal);
2302
- if (!object(value) || value.account_id !== accountId || !text2(value.key_id) || value.state !== "none" && value.state !== "migrating" && value.state !== "active" || !integer(value.record_count) || !integer(value.storage_bytes) || !integer(value.vector_count))
2374
+ if (!object(value) || value.account_id !== accountId || !text2(value.key_id) || value.state !== "none" && value.state !== "migrating" && value.state !== "active" || !integer(value.record_count) || !integer(value.storage_bytes) || !integer(value.vector_count) || value.changes_cursor !== void 0 && (!text2(value.changes_cursor) || value.changes_cursor.length > 2048))
2303
2375
  invalid();
2304
2376
  if (value.key_id && value.key_id !== keyId)
2305
2377
  throw new ChatStoreError("Canonical chat key does not match", 409, "key_mismatch");
@@ -2308,7 +2380,8 @@ async function createRemoteChatStore(options) {
2308
2380
  state: value.state,
2309
2381
  recordCount: value.record_count,
2310
2382
  storageBytes: value.storage_bytes,
2311
- vectorCount: value.vector_count
2383
+ vectorCount: value.vector_count,
2384
+ ...value.changes_cursor ? { changesCursor: value.changes_cursor } : {}
2312
2385
  };
2313
2386
  return out;
2314
2387
  },
@@ -2395,7 +2468,7 @@ async function createRemoteChatStore(options) {
2395
2468
  if (!Array.isArray(embedding) || !embeddings({
2396
2469
  record: { ...emptyMessage, isDeleted: false },
2397
2470
  embeddings: [embedding]
2398
- }) || !integer(limit, 1) || limit > 50 || kindsFilter !== void 0 && (!Array.isArray(kindsFilter) || kindsFilter.length === 0 || kindsFilter.some((k) => k !== "message" && k !== "summary")) || options2?.conversationId !== void 0 && !id(options2.conversationId))
2471
+ }) || !integer(limit, 1) || limit > 50 || kindsFilter !== void 0 && (!Array.isArray(kindsFilter) || kindsFilter.length === 0 || kindsFilter.some((k) => k !== "message" && k !== "summary")) || options2?.conversationId !== void 0 && !id(options2.conversationId) || options2?.excludeConversationId !== void 0 && !id(options2.excludeConversationId) || options2?.embeddingModel !== void 0 && (!text2(options2.embeddingModel) || options2.embeddingModel.length > 256))
2399
2472
  invalid();
2400
2473
  const value = await request(
2401
2474
  "/search",
@@ -2406,7 +2479,9 @@ async function createRemoteChatStore(options) {
2406
2479
  embedding: embedding.slice(0, storedDims),
2407
2480
  limit,
2408
2481
  ...kindsFilter ? { kinds: kindsFilter } : {},
2409
- ...options2?.conversationId ? { conversation_id: options2.conversationId } : {}
2482
+ ...options2?.conversationId ? { conversation_id: options2.conversationId } : {},
2483
+ ...options2?.excludeConversationId ? { exclude_conversation_id: options2.excludeConversationId } : {},
2484
+ ...options2?.embeddingModel ? { embedding_model: options2.embeddingModel } : {}
2410
2485
  })
2411
2486
  },
2412
2487
  options2?.signal
@@ -2417,7 +2492,7 @@ async function createRemoteChatStore(options) {
2417
2492
  if (!object(item) || !integer(item.chunk) || typeof item.score !== "number" || !Number.isFinite(item.score))
2418
2493
  invalid();
2419
2494
  const snapshot = await decode(item);
2420
- if (snapshot.record.isDeleted || kindsFilter !== void 0 && !kindsFilter.includes(snapshot.record.kind) || snapshot.record.kind !== "message" && snapshot.record.kind !== "summary" || options2?.conversationId !== void 0 && snapshot.record.conversationId !== options2.conversationId)
2495
+ if (snapshot.record.isDeleted || kindsFilter !== void 0 && !kindsFilter.includes(snapshot.record.kind) || snapshot.record.kind !== "message" && snapshot.record.kind !== "summary" || options2?.conversationId !== void 0 && snapshot.record.conversationId !== options2.conversationId || snapshot.record.conversationId === options2?.excludeConversationId)
2421
2496
  invalid();
2422
2497
  hits.push({ ...snapshot, chunk: item.chunk, score: item.score });
2423
2498
  }
@@ -2569,78 +2644,6 @@ async function decryptConversationTitle(encryptedTitle, address) {
2569
2644
  }
2570
2645
  }
2571
2646
 
2572
- // src/lib/memoryEngine/vector.ts
2573
- function cosineSimilarity(a, b) {
2574
- if (a.length !== b.length) return 0;
2575
- let dot = 0;
2576
- let normA = 0;
2577
- let normB = 0;
2578
- for (let i = 0; i < a.length; i++) {
2579
- dot += a[i] * b[i];
2580
- normA += a[i] * a[i];
2581
- normB += b[i] * b[i];
2582
- }
2583
- const denom = Math.sqrt(normA) * Math.sqrt(normB);
2584
- return denom === 0 ? 0 : dot / denom;
2585
- }
2586
-
2587
- // src/lib/processors/encoding.ts
2588
- var B64_ENCODE_CHUNK = 32768 * 3;
2589
- function uint8ArrayToBase64(data) {
2590
- if (typeof Buffer !== "undefined") {
2591
- return Buffer.from(data).toString("base64");
2592
- }
2593
- let base64 = "";
2594
- for (let i = 0; i < data.length; i += B64_ENCODE_CHUNK) {
2595
- const slice = data.subarray(i, i + B64_ENCODE_CHUNK);
2596
- let binary = "";
2597
- for (let j = 0; j < slice.length; j++) {
2598
- binary += String.fromCharCode(slice[j]);
2599
- }
2600
- base64 += btoa(binary);
2601
- }
2602
- return base64;
2603
- }
2604
- function base64ToUint8Array(base64) {
2605
- if (typeof Buffer !== "undefined") {
2606
- const buf = Buffer.from(base64, "base64");
2607
- return new Uint8Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength));
2608
- }
2609
- const binary = atob(base64);
2610
- const bytes = new Uint8Array(binary.length);
2611
- for (let i = 0; i < binary.length; i++) {
2612
- bytes[i] = binary.charCodeAt(i);
2613
- }
2614
- return bytes;
2615
- }
2616
-
2617
- // src/lib/memoryEngine/vectorEncoding.ts
2618
- var BYTES_PER_FLOAT32 = 4;
2619
- var CANONICAL_BASE64 = /^[A-Za-z0-9+/]+={0,2}$/;
2620
- function encodeChunkVector(vector2) {
2621
- const f32 = vector2 instanceof Float32Array ? vector2 : Float32Array.from(vector2);
2622
- return uint8ArrayToBase64(new Uint8Array(f32.buffer, f32.byteOffset, f32.byteLength));
2623
- }
2624
- function decodeChunkVector(vector2, onMalformed) {
2625
- if (!vector2 || vector2.length === 0) return new Float32Array(0);
2626
- if (typeof vector2 !== "string") return Float32Array.from(vector2);
2627
- if (vector2.length % 4 !== 0 || !CANONICAL_BASE64.test(vector2)) {
2628
- onMalformed?.();
2629
- return new Float32Array(0);
2630
- }
2631
- try {
2632
- const bytes = base64ToUint8Array(vector2);
2633
- if (bytes.byteLength === 0 || bytes.byteLength % BYTES_PER_FLOAT32 !== 0) {
2634
- onMalformed?.();
2635
- return new Float32Array(0);
2636
- }
2637
- return new Float32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / BYTES_PER_FLOAT32);
2638
- } catch {
2639
- onMalformed?.();
2640
- return new Float32Array(0);
2641
- }
2642
- }
2643
-
2644
2647
  // src/lib/memoryEngine/chunking.ts
2645
2648
  var DEFAULT_CHUNK_SIZE = 400;
2646
2649
  var DEFAULT_CHUNK_OVERLAP = 50;
package/dist/index.d.mts CHANGED
@@ -7918,6 +7918,8 @@ interface ChatAccount {
7918
7918
  recordCount: number;
7919
7919
  storageBytes: number;
7920
7920
  vectorCount: number;
7921
+ /** The newest change; read it before loading history and poll `changes` from it. Absent before the first record. */
7922
+ changesCursor?: string;
7921
7923
  }
7922
7924
  interface ChatImport {
7923
7925
  record: ChatRecord;
@@ -7940,6 +7942,9 @@ interface ChatSearchOptions {
7940
7942
  limit?: number;
7941
7943
  kinds?: ("message" | "summary")[];
7942
7944
  conversationId?: string;
7945
+ excludeConversationId?: string;
7946
+ /** Ranks only vectors from this model; vectors stored without one always count. */
7947
+ embeddingModel?: string;
7943
7948
  signal?: AbortSignal;
7944
7949
  }
7945
7950
  interface ChatSearchHit extends ChatSnapshot {
@@ -8027,44 +8032,6 @@ declare class ChatStoreError extends Error {
8027
8032
  /** Connect to owner-scoped server storage using the account's canonical device-held cipher. */
8028
8033
  declare function createRemoteChatStore(options: RemoteChatStoreOptions): Promise<ChatStore>;
8029
8034
 
8030
- /**
8031
- * Drop every cached plaintext title and pending decrypt promise.
8032
- *
8033
- * Wired into `clearAllEncryptionState()` via the listener registry in
8034
- * `useEncryption.ts`. Also exported so consumers can clear the cache
8035
- * proactively (e.g. on wallet switch within a session before the
8036
- * full encryption-state teardown lands).
8037
- */
8038
- declare function clearLazyTitleCache(): void;
8039
- /**
8040
- * Decrypt a single conversation title on demand.
8041
- *
8042
- * Designed for the lazy display path: pair with `listConversationsLazy`
8043
- * and call this once a row is actually visible.
8044
- *
8045
- * Behavior:
8046
- * - Plaintext input (no `enc:` prefix) is returned unchanged. This
8047
- * covers conversations created before encryption was enabled and
8048
- * keeps the helper safe to call unconditionally from rendering
8049
- * code that may receive a mix of encrypted and plaintext titles.
8050
- * - Encrypted input is decrypted via `decryptField`, which uses the
8051
- * same per-version cached `CryptoKey` as the eager path — no new
8052
- * key derivations are triggered.
8053
- * - Concurrent calls for the same `(address, encryptedTitle)` share
8054
- * a single decrypt promise.
8055
- * - The result is memoized in a 256-entry LRU.
8056
- *
8057
- * Throws if the encryption key for `address` isn't loaded. (The
8058
- * underlying `decryptField` would otherwise silently return the
8059
- * ciphertext, which would surface to the UI as a literal `enc:v3:...`
8060
- * title — strictly worse than a thrown error the caller can catch.)
8061
- *
8062
- * @param encryptedTitle - The stored title. May be ciphertext or plaintext.
8063
- * @param address - Wallet address that owns the encryption key.
8064
- * @returns The decrypted plaintext title.
8065
- */
8066
- declare function decryptConversationTitle(encryptedTitle: string, address: string): Promise<string>;
8067
-
8068
8035
  /**
8069
8036
  * Class-B task types — the vocabulary of the `X-Anuma-Task-Type` header.
8070
8037
  *
@@ -8575,6 +8542,44 @@ interface LazyStoredConversation extends Omit<StoredConversation, "title"> {
8575
8542
  encryptedTitle: string;
8576
8543
  }
8577
8544
 
8545
+ /**
8546
+ * Drop every cached plaintext title and pending decrypt promise.
8547
+ *
8548
+ * Wired into `clearAllEncryptionState()` via the listener registry in
8549
+ * `useEncryption.ts`. Also exported so consumers can clear the cache
8550
+ * proactively (e.g. on wallet switch within a session before the
8551
+ * full encryption-state teardown lands).
8552
+ */
8553
+ declare function clearLazyTitleCache(): void;
8554
+ /**
8555
+ * Decrypt a single conversation title on demand.
8556
+ *
8557
+ * Designed for the lazy display path: pair with `listConversationsLazy`
8558
+ * and call this once a row is actually visible.
8559
+ *
8560
+ * Behavior:
8561
+ * - Plaintext input (no `enc:` prefix) is returned unchanged. This
8562
+ * covers conversations created before encryption was enabled and
8563
+ * keeps the helper safe to call unconditionally from rendering
8564
+ * code that may receive a mix of encrypted and plaintext titles.
8565
+ * - Encrypted input is decrypted via `decryptField`, which uses the
8566
+ * same per-version cached `CryptoKey` as the eager path — no new
8567
+ * key derivations are triggered.
8568
+ * - Concurrent calls for the same `(address, encryptedTitle)` share
8569
+ * a single decrypt promise.
8570
+ * - The result is memoized in a 256-entry LRU.
8571
+ *
8572
+ * Throws if the encryption key for `address` isn't loaded. (The
8573
+ * underlying `decryptField` would otherwise silently return the
8574
+ * ciphertext, which would surface to the UI as a literal `enc:v3:...`
8575
+ * title — strictly worse than a thrown error the caller can catch.)
8576
+ *
8577
+ * @param encryptedTitle - The stored title. May be ciphertext or plaintext.
8578
+ * @param address - Wallet address that owns the encryption key.
8579
+ * @returns The decrypted plaintext title.
8580
+ */
8581
+ declare function decryptConversationTitle(encryptedTitle: string, address: string): Promise<string>;
8582
+
8578
8583
  /**
8579
8584
  * Pluggable logger for the Anuma SDK.
8580
8585
  *
package/dist/index.d.ts CHANGED
@@ -7918,6 +7918,8 @@ interface ChatAccount {
7918
7918
  recordCount: number;
7919
7919
  storageBytes: number;
7920
7920
  vectorCount: number;
7921
+ /** The newest change; read it before loading history and poll `changes` from it. Absent before the first record. */
7922
+ changesCursor?: string;
7921
7923
  }
7922
7924
  interface ChatImport {
7923
7925
  record: ChatRecord;
@@ -7940,6 +7942,9 @@ interface ChatSearchOptions {
7940
7942
  limit?: number;
7941
7943
  kinds?: ("message" | "summary")[];
7942
7944
  conversationId?: string;
7945
+ excludeConversationId?: string;
7946
+ /** Ranks only vectors from this model; vectors stored without one always count. */
7947
+ embeddingModel?: string;
7943
7948
  signal?: AbortSignal;
7944
7949
  }
7945
7950
  interface ChatSearchHit extends ChatSnapshot {
@@ -8027,44 +8032,6 @@ declare class ChatStoreError extends Error {
8027
8032
  /** Connect to owner-scoped server storage using the account's canonical device-held cipher. */
8028
8033
  declare function createRemoteChatStore(options: RemoteChatStoreOptions): Promise<ChatStore>;
8029
8034
 
8030
- /**
8031
- * Drop every cached plaintext title and pending decrypt promise.
8032
- *
8033
- * Wired into `clearAllEncryptionState()` via the listener registry in
8034
- * `useEncryption.ts`. Also exported so consumers can clear the cache
8035
- * proactively (e.g. on wallet switch within a session before the
8036
- * full encryption-state teardown lands).
8037
- */
8038
- declare function clearLazyTitleCache(): void;
8039
- /**
8040
- * Decrypt a single conversation title on demand.
8041
- *
8042
- * Designed for the lazy display path: pair with `listConversationsLazy`
8043
- * and call this once a row is actually visible.
8044
- *
8045
- * Behavior:
8046
- * - Plaintext input (no `enc:` prefix) is returned unchanged. This
8047
- * covers conversations created before encryption was enabled and
8048
- * keeps the helper safe to call unconditionally from rendering
8049
- * code that may receive a mix of encrypted and plaintext titles.
8050
- * - Encrypted input is decrypted via `decryptField`, which uses the
8051
- * same per-version cached `CryptoKey` as the eager path — no new
8052
- * key derivations are triggered.
8053
- * - Concurrent calls for the same `(address, encryptedTitle)` share
8054
- * a single decrypt promise.
8055
- * - The result is memoized in a 256-entry LRU.
8056
- *
8057
- * Throws if the encryption key for `address` isn't loaded. (The
8058
- * underlying `decryptField` would otherwise silently return the
8059
- * ciphertext, which would surface to the UI as a literal `enc:v3:...`
8060
- * title — strictly worse than a thrown error the caller can catch.)
8061
- *
8062
- * @param encryptedTitle - The stored title. May be ciphertext or plaintext.
8063
- * @param address - Wallet address that owns the encryption key.
8064
- * @returns The decrypted plaintext title.
8065
- */
8066
- declare function decryptConversationTitle(encryptedTitle: string, address: string): Promise<string>;
8067
-
8068
8035
  /**
8069
8036
  * Class-B task types — the vocabulary of the `X-Anuma-Task-Type` header.
8070
8037
  *
@@ -8575,6 +8542,44 @@ interface LazyStoredConversation extends Omit<StoredConversation, "title"> {
8575
8542
  encryptedTitle: string;
8576
8543
  }
8577
8544
 
8545
+ /**
8546
+ * Drop every cached plaintext title and pending decrypt promise.
8547
+ *
8548
+ * Wired into `clearAllEncryptionState()` via the listener registry in
8549
+ * `useEncryption.ts`. Also exported so consumers can clear the cache
8550
+ * proactively (e.g. on wallet switch within a session before the
8551
+ * full encryption-state teardown lands).
8552
+ */
8553
+ declare function clearLazyTitleCache(): void;
8554
+ /**
8555
+ * Decrypt a single conversation title on demand.
8556
+ *
8557
+ * Designed for the lazy display path: pair with `listConversationsLazy`
8558
+ * and call this once a row is actually visible.
8559
+ *
8560
+ * Behavior:
8561
+ * - Plaintext input (no `enc:` prefix) is returned unchanged. This
8562
+ * covers conversations created before encryption was enabled and
8563
+ * keeps the helper safe to call unconditionally from rendering
8564
+ * code that may receive a mix of encrypted and plaintext titles.
8565
+ * - Encrypted input is decrypted via `decryptField`, which uses the
8566
+ * same per-version cached `CryptoKey` as the eager path — no new
8567
+ * key derivations are triggered.
8568
+ * - Concurrent calls for the same `(address, encryptedTitle)` share
8569
+ * a single decrypt promise.
8570
+ * - The result is memoized in a 256-entry LRU.
8571
+ *
8572
+ * Throws if the encryption key for `address` isn't loaded. (The
8573
+ * underlying `decryptField` would otherwise silently return the
8574
+ * ciphertext, which would surface to the UI as a literal `enc:v3:...`
8575
+ * title — strictly worse than a thrown error the caller can catch.)
8576
+ *
8577
+ * @param encryptedTitle - The stored title. May be ciphertext or plaintext.
8578
+ * @param address - Wallet address that owns the encryption key.
8579
+ * @returns The decrypted plaintext title.
8580
+ */
8581
+ declare function decryptConversationTitle(encryptedTitle: string, address: string): Promise<string>;
8582
+
8578
8583
  /**
8579
8584
  * Pluggable logger for the Anuma SDK.
8580
8585
  *
package/dist/index.mjs CHANGED
@@ -1622,6 +1622,78 @@ function getImageModel(r) {
1622
1622
  return r.image_model;
1623
1623
  }
1624
1624
 
1625
+ // src/lib/memoryEngine/vector.ts
1626
+ function cosineSimilarity(a, b) {
1627
+ if (a.length !== b.length) return 0;
1628
+ let dot = 0;
1629
+ let normA = 0;
1630
+ let normB = 0;
1631
+ for (let i = 0; i < a.length; i++) {
1632
+ dot += a[i] * b[i];
1633
+ normA += a[i] * a[i];
1634
+ normB += b[i] * b[i];
1635
+ }
1636
+ const denom = Math.sqrt(normA) * Math.sqrt(normB);
1637
+ return denom === 0 ? 0 : dot / denom;
1638
+ }
1639
+
1640
+ // src/lib/processors/encoding.ts
1641
+ var B64_ENCODE_CHUNK = 32768 * 3;
1642
+ function uint8ArrayToBase64(data) {
1643
+ if (typeof Buffer !== "undefined") {
1644
+ return Buffer.from(data).toString("base64");
1645
+ }
1646
+ let base64 = "";
1647
+ for (let i = 0; i < data.length; i += B64_ENCODE_CHUNK) {
1648
+ const slice = data.subarray(i, i + B64_ENCODE_CHUNK);
1649
+ let binary = "";
1650
+ for (let j = 0; j < slice.length; j++) {
1651
+ binary += String.fromCharCode(slice[j]);
1652
+ }
1653
+ base64 += btoa(binary);
1654
+ }
1655
+ return base64;
1656
+ }
1657
+ function base64ToUint8Array(base64) {
1658
+ if (typeof Buffer !== "undefined") {
1659
+ const buf = Buffer.from(base64, "base64");
1660
+ return new Uint8Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength));
1661
+ }
1662
+ const binary = atob(base64);
1663
+ const bytes = new Uint8Array(binary.length);
1664
+ for (let i = 0; i < binary.length; i++) {
1665
+ bytes[i] = binary.charCodeAt(i);
1666
+ }
1667
+ return bytes;
1668
+ }
1669
+
1670
+ // src/lib/memoryEngine/vectorEncoding.ts
1671
+ var BYTES_PER_FLOAT32 = 4;
1672
+ var CANONICAL_BASE64 = /^[A-Za-z0-9+/]+={0,2}$/;
1673
+ function encodeChunkVector(vector2) {
1674
+ const f32 = vector2 instanceof Float32Array ? vector2 : Float32Array.from(vector2);
1675
+ return uint8ArrayToBase64(new Uint8Array(f32.buffer, f32.byteOffset, f32.byteLength));
1676
+ }
1677
+ function decodeChunkVector(vector2, onMalformed) {
1678
+ if (!vector2 || vector2.length === 0) return new Float32Array(0);
1679
+ if (typeof vector2 !== "string") return Float32Array.from(vector2);
1680
+ if (vector2.length % 4 !== 0 || !CANONICAL_BASE64.test(vector2)) {
1681
+ onMalformed?.();
1682
+ return new Float32Array(0);
1683
+ }
1684
+ try {
1685
+ const bytes = base64ToUint8Array(vector2);
1686
+ if (bytes.byteLength === 0 || bytes.byteLength % BYTES_PER_FLOAT32 !== 0) {
1687
+ onMalformed?.();
1688
+ return new Float32Array(0);
1689
+ }
1690
+ return new Float32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / BYTES_PER_FLOAT32);
1691
+ } catch {
1692
+ onMalformed?.();
1693
+ return new Float32Array(0);
1694
+ }
1695
+ }
1696
+
1625
1697
  // src/lib/taskType.ts
1626
1698
  var TASK_TYPE_HEADER = "X-Anuma-Task-Type";
1627
1699
  function taskTypeHeader(taskType) {
@@ -2028,7 +2100,7 @@ async function createRemoteChatStore(options) {
2028
2100
  async list(query) {
2029
2101
  const limit = query.limit ?? 20;
2030
2102
  const parent = query.conversationId ?? "";
2031
- if (!kinds.has(query.kind) || !integer(limit, 1) || query.includeDeleted !== void 0 && typeof query.includeDeleted !== "boolean" || limit > (query.kind === "message" ? 200 : 50) || (query.cursor?.length ?? 0) > 2048 || (query.kind === "conversation" || query.kind === "project" ? parent !== "" : !id(parent)))
2103
+ if (!kinds.has(query.kind) || !integer(limit, 1) || query.includeDeleted !== void 0 && typeof query.includeDeleted !== "boolean" || limit > 200 || (query.cursor?.length ?? 0) > 2048 || (query.kind === "conversation" || query.kind === "project" ? parent !== "" : !id(parent)))
2032
2104
  invalid();
2033
2105
  const params = new URLSearchParams({
2034
2106
  account_id: String(accountId),
@@ -2096,7 +2168,7 @@ async function createRemoteChatStore(options) {
2096
2168
  },
2097
2169
  async account(signal) {
2098
2170
  const value = await request("/account", {}, signal);
2099
- if (!object(value) || value.account_id !== accountId || !text2(value.key_id) || value.state !== "none" && value.state !== "migrating" && value.state !== "active" || !integer(value.record_count) || !integer(value.storage_bytes) || !integer(value.vector_count))
2171
+ if (!object(value) || value.account_id !== accountId || !text2(value.key_id) || value.state !== "none" && value.state !== "migrating" && value.state !== "active" || !integer(value.record_count) || !integer(value.storage_bytes) || !integer(value.vector_count) || value.changes_cursor !== void 0 && (!text2(value.changes_cursor) || value.changes_cursor.length > 2048))
2100
2172
  invalid();
2101
2173
  if (value.key_id && value.key_id !== keyId)
2102
2174
  throw new ChatStoreError("Canonical chat key does not match", 409, "key_mismatch");
@@ -2105,7 +2177,8 @@ async function createRemoteChatStore(options) {
2105
2177
  state: value.state,
2106
2178
  recordCount: value.record_count,
2107
2179
  storageBytes: value.storage_bytes,
2108
- vectorCount: value.vector_count
2180
+ vectorCount: value.vector_count,
2181
+ ...value.changes_cursor ? { changesCursor: value.changes_cursor } : {}
2109
2182
  };
2110
2183
  return out;
2111
2184
  },
@@ -2192,7 +2265,7 @@ async function createRemoteChatStore(options) {
2192
2265
  if (!Array.isArray(embedding) || !embeddings({
2193
2266
  record: { ...emptyMessage, isDeleted: false },
2194
2267
  embeddings: [embedding]
2195
- }) || !integer(limit, 1) || limit > 50 || kindsFilter !== void 0 && (!Array.isArray(kindsFilter) || kindsFilter.length === 0 || kindsFilter.some((k) => k !== "message" && k !== "summary")) || options2?.conversationId !== void 0 && !id(options2.conversationId))
2268
+ }) || !integer(limit, 1) || limit > 50 || kindsFilter !== void 0 && (!Array.isArray(kindsFilter) || kindsFilter.length === 0 || kindsFilter.some((k) => k !== "message" && k !== "summary")) || options2?.conversationId !== void 0 && !id(options2.conversationId) || options2?.excludeConversationId !== void 0 && !id(options2.excludeConversationId) || options2?.embeddingModel !== void 0 && (!text2(options2.embeddingModel) || options2.embeddingModel.length > 256))
2196
2269
  invalid();
2197
2270
  const value = await request(
2198
2271
  "/search",
@@ -2203,7 +2276,9 @@ async function createRemoteChatStore(options) {
2203
2276
  embedding: embedding.slice(0, storedDims),
2204
2277
  limit,
2205
2278
  ...kindsFilter ? { kinds: kindsFilter } : {},
2206
- ...options2?.conversationId ? { conversation_id: options2.conversationId } : {}
2279
+ ...options2?.conversationId ? { conversation_id: options2.conversationId } : {},
2280
+ ...options2?.excludeConversationId ? { exclude_conversation_id: options2.excludeConversationId } : {},
2281
+ ...options2?.embeddingModel ? { embedding_model: options2.embeddingModel } : {}
2207
2282
  })
2208
2283
  },
2209
2284
  options2?.signal
@@ -2214,7 +2289,7 @@ async function createRemoteChatStore(options) {
2214
2289
  if (!object(item) || !integer(item.chunk) || typeof item.score !== "number" || !Number.isFinite(item.score))
2215
2290
  invalid();
2216
2291
  const snapshot = await decode(item);
2217
- if (snapshot.record.isDeleted || kindsFilter !== void 0 && !kindsFilter.includes(snapshot.record.kind) || snapshot.record.kind !== "message" && snapshot.record.kind !== "summary" || options2?.conversationId !== void 0 && snapshot.record.conversationId !== options2.conversationId)
2292
+ if (snapshot.record.isDeleted || kindsFilter !== void 0 && !kindsFilter.includes(snapshot.record.kind) || snapshot.record.kind !== "message" && snapshot.record.kind !== "summary" || options2?.conversationId !== void 0 && snapshot.record.conversationId !== options2.conversationId || snapshot.record.conversationId === options2?.excludeConversationId)
2218
2293
  invalid();
2219
2294
  hits.push({ ...snapshot, chunk: item.chunk, score: item.score });
2220
2295
  }
@@ -2366,78 +2441,6 @@ async function decryptConversationTitle(encryptedTitle, address) {
2366
2441
  }
2367
2442
  }
2368
2443
 
2369
- // src/lib/memoryEngine/vector.ts
2370
- function cosineSimilarity(a, b) {
2371
- if (a.length !== b.length) return 0;
2372
- let dot = 0;
2373
- let normA = 0;
2374
- let normB = 0;
2375
- for (let i = 0; i < a.length; i++) {
2376
- dot += a[i] * b[i];
2377
- normA += a[i] * a[i];
2378
- normB += b[i] * b[i];
2379
- }
2380
- const denom = Math.sqrt(normA) * Math.sqrt(normB);
2381
- return denom === 0 ? 0 : dot / denom;
2382
- }
2383
-
2384
- // src/lib/processors/encoding.ts
2385
- var B64_ENCODE_CHUNK = 32768 * 3;
2386
- function uint8ArrayToBase64(data) {
2387
- if (typeof Buffer !== "undefined") {
2388
- return Buffer.from(data).toString("base64");
2389
- }
2390
- let base64 = "";
2391
- for (let i = 0; i < data.length; i += B64_ENCODE_CHUNK) {
2392
- const slice = data.subarray(i, i + B64_ENCODE_CHUNK);
2393
- let binary = "";
2394
- for (let j = 0; j < slice.length; j++) {
2395
- binary += String.fromCharCode(slice[j]);
2396
- }
2397
- base64 += btoa(binary);
2398
- }
2399
- return base64;
2400
- }
2401
- function base64ToUint8Array(base64) {
2402
- if (typeof Buffer !== "undefined") {
2403
- const buf = Buffer.from(base64, "base64");
2404
- return new Uint8Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength));
2405
- }
2406
- const binary = atob(base64);
2407
- const bytes = new Uint8Array(binary.length);
2408
- for (let i = 0; i < binary.length; i++) {
2409
- bytes[i] = binary.charCodeAt(i);
2410
- }
2411
- return bytes;
2412
- }
2413
-
2414
- // src/lib/memoryEngine/vectorEncoding.ts
2415
- var BYTES_PER_FLOAT32 = 4;
2416
- var CANONICAL_BASE64 = /^[A-Za-z0-9+/]+={0,2}$/;
2417
- function encodeChunkVector(vector2) {
2418
- const f32 = vector2 instanceof Float32Array ? vector2 : Float32Array.from(vector2);
2419
- return uint8ArrayToBase64(new Uint8Array(f32.buffer, f32.byteOffset, f32.byteLength));
2420
- }
2421
- function decodeChunkVector(vector2, onMalformed) {
2422
- if (!vector2 || vector2.length === 0) return new Float32Array(0);
2423
- if (typeof vector2 !== "string") return Float32Array.from(vector2);
2424
- if (vector2.length % 4 !== 0 || !CANONICAL_BASE64.test(vector2)) {
2425
- onMalformed?.();
2426
- return new Float32Array(0);
2427
- }
2428
- try {
2429
- const bytes = base64ToUint8Array(vector2);
2430
- if (bytes.byteLength === 0 || bytes.byteLength % BYTES_PER_FLOAT32 !== 0) {
2431
- onMalformed?.();
2432
- return new Float32Array(0);
2433
- }
2434
- return new Float32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / BYTES_PER_FLOAT32);
2435
- } catch {
2436
- onMalformed?.();
2437
- return new Float32Array(0);
2438
- }
2439
- }
2440
-
2441
2444
  // src/lib/memoryEngine/chunking.ts
2442
2445
  var DEFAULT_CHUNK_SIZE = 400;
2443
2446
  var DEFAULT_CHUNK_OVERLAP = 50;