@anuma/sdk 10.0.4 → 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.
@@ -1,4 +1,4 @@
1
- import { Model, Database, Collection } from '@nozbe/watermelondb';
1
+ import { Database, Model, Collection } from '@nozbe/watermelondb';
2
2
  import Model$1, { Associations } from '@nozbe/watermelondb/Model';
3
3
  import * as _nozbe_watermelondb_Schema_migrations from '@nozbe/watermelondb/Schema/migrations';
4
4
  import * as _nozbe_watermelondb_Schema from '@nozbe/watermelondb/Schema';
@@ -3187,1101 +3187,1059 @@ interface WebSearchPreProcessorOptions {
3187
3187
  */
3188
3188
  declare function createWebSearchPreProcessor(options?: WebSearchPreProcessorOptions): PromptPreProcessor;
3189
3189
 
3190
- type ChatRecordKind = "conversation" | "message" | "summary" | "project" | "memory_links";
3191
- type ChatJson = null | boolean | number | string | ChatJson[] | {
3192
- [key: string]: ChatJson;
3193
- };
3194
- /** Whole-record JSON data is encrypted on the device, including all text, vectors and tool events. */
3195
- interface ChatRecord {
3196
- kind: ChatRecordKind;
3197
- id: string;
3198
- conversationId: string;
3199
- sortKey: number;
3200
- createdAt: number;
3201
- updatedAt: number;
3202
- isDeleted: boolean;
3203
- data: {
3204
- [key: string]: ChatJson;
3205
- };
3206
- }
3207
- interface ChatSnapshot {
3208
- record: ChatRecord;
3209
- version: number;
3210
- serverUpdatedAt: string;
3211
- }
3212
- interface ChatWrite {
3213
- record: ChatRecord;
3214
- expectedVersion: number;
3215
- /** Sent and stored unencrypted so vault can run vector search. */
3216
- embeddings?: number[][];
3217
- embeddingModel?: string;
3218
- }
3219
- interface ChatRef {
3220
- kind: ChatRecordKind;
3221
- id: string;
3222
- }
3223
- type ChatAccountState = "none" | "migrating" | "active";
3224
- interface ChatAccount {
3225
- keyId: string;
3226
- state: ChatAccountState;
3227
- recordCount: number;
3228
- storageBytes: number;
3229
- vectorCount: number;
3230
- }
3231
- interface ChatImport {
3232
- record: ChatRecord;
3233
- /** Sent and stored unencrypted so vault can run vector search. */
3234
- embeddings?: number[][];
3235
- embeddingModel?: string;
3236
- }
3237
- interface ChatRevision {
3238
- kind: ChatRecordKind;
3239
- id: string;
3240
- updatedAt: number;
3241
- isDeleted: boolean;
3242
- }
3243
- interface ChatChanges {
3244
- items: ChatSnapshot[];
3245
- nextCursor?: string;
3246
- changesCursor: string;
3247
- }
3248
- interface ChatSearchOptions {
3249
- limit?: number;
3250
- kinds?: ("message" | "summary")[];
3251
- conversationId?: string;
3252
- signal?: AbortSignal;
3253
- }
3254
- interface ChatSearchHit extends ChatSnapshot {
3255
- chunk: number;
3256
- score: number;
3257
- }
3258
- interface ChatAttachment {
3259
- id: string;
3260
- sizeBytes: number;
3261
- state: "pending" | "committed";
3262
- ownerKind?: "message" | "summary";
3263
- ownerId?: string;
3264
- createdAt: string;
3265
- committedAt?: string;
3266
- }
3267
- interface ChatPresignedUrl {
3268
- url: string;
3269
- method: string;
3270
- headers: Record<string, string>;
3271
- expiresAt: string;
3272
- }
3273
- interface ChatAttachments {
3274
- create(sizeBytes: number, signal?: AbortSignal): Promise<{
3275
- attachment: ChatAttachment;
3276
- upload: ChatPresignedUrl;
3277
- }>;
3278
- commit(attachmentId: string, owner: {
3279
- kind: "message" | "summary";
3280
- id: string;
3281
- }, signal?: AbortSignal): Promise<ChatAttachment>;
3282
- get(attachmentId: string, signal?: AbortSignal): Promise<{
3283
- attachment: ChatAttachment;
3284
- download?: ChatPresignedUrl;
3285
- } | null>;
3286
- delete(attachmentId: string, signal?: AbortSignal): Promise<void>;
3287
- }
3288
- interface ChatListOptions {
3289
- kind: ChatRecordKind;
3290
- conversationId?: string;
3291
- includeDeleted?: boolean;
3292
- cursor?: string;
3293
- limit?: number;
3294
- signal?: AbortSignal;
3295
- }
3296
- interface ChatPage {
3297
- items: ChatSnapshot[];
3298
- nextCursor?: string;
3299
- total?: number;
3300
- }
3301
- /** Explicit versions protect edits; ambiguous writes are never replayed automatically. */
3302
- interface ChatStore {
3303
- get(kind: ChatRecordKind, id: string, signal?: AbortSignal): Promise<ChatSnapshot | null>;
3304
- list(options: ChatListOptions): Promise<ChatPage>;
3305
- putMany(writes: readonly ChatWrite[], signal?: AbortSignal): Promise<ChatSnapshot[]>;
3306
- getMany(refs: readonly ChatRef[], signal?: AbortSignal): Promise<ChatSnapshot[]>;
3307
- account(signal?: AbortSignal): Promise<ChatAccount>;
3308
- importRecords(records: readonly ChatImport[], signal?: AbortSignal): Promise<number>;
3309
- verify(revisions: readonly ChatRevision[], signal?: AbortSignal): Promise<ChatRef[]>;
3310
- activate(signal?: AbortSignal): Promise<boolean>;
3311
- changes(cursor?: string, options?: {
3312
- limit?: number;
3313
- signal?: AbortSignal;
3314
- }): Promise<ChatChanges>;
3315
- search(embedding: readonly number[], options?: ChatSearchOptions): Promise<ChatSearchHit[]>;
3316
- deleteAll(signal?: AbortSignal): Promise<number>;
3317
- attachments: ChatAttachments;
3318
- }
3319
- interface RemoteChatStoreOptions {
3320
- baseUrl: string;
3321
- getToken: () => Promise<string | null>;
3322
- keyId: string;
3323
- encrypt: (plaintext: string) => Promise<string>;
3324
- decrypt: (ciphertext: string) => Promise<string>;
3325
- fetch?: typeof globalThis.fetch;
3326
- timeoutMs?: number;
3327
- signal?: AbortSignal;
3328
- }
3329
- declare class ChatStoreError extends Error {
3330
- readonly status: number;
3331
- readonly code?: string | undefined;
3332
- readonly retryAfterMs?: number | undefined;
3333
- constructor(message: string, status: number, code?: string | undefined, retryAfterMs?: number | undefined);
3334
- }
3335
-
3336
- /** Connect to owner-scoped server storage using the account's canonical device-held cipher. */
3337
- declare function createRemoteChatStore(options: RemoteChatStoreOptions): Promise<ChatStore>;
3338
-
3339
- declare class AppFile extends Model {
3340
- static table: string;
3341
- static associations: Associations;
3342
- conversationId: string;
3343
- path: string;
3344
- content: string;
3345
- createdAt: Date;
3346
- updatedAt: Date;
3347
- }
3348
-
3349
3190
  /**
3350
- * Types for the app files storage module.
3191
+ * Encryption key version type.
3192
+ * - "v2": Legacy SHA-256 derived key (for reading enc:v2: data)
3193
+ * - "v3": HKDF derived key with domain separation (for new encryption)
3351
3194
  *
3352
- * App files are the HTML/CSS/JS source files for LLM-generated apps,
3353
- * stored per conversation. Each file is identified by a conversationId + path pair.
3195
+ * Raw signature bytes (Privy Solana `signMessage` returns a `Uint8Array`) are
3196
+ * not a stored version. Derive them with {@link deriveKeyFromSignatureBytes}.
3197
+ * {@link requestEncryptionKey} still derives v2 and v3 from a hex signature only.
3354
3198
  */
3355
- /** Plain object representation of an app file record. */
3356
- interface StoredAppFile {
3357
- /** WatermelonDB internal ID */
3358
- uniqueId: string;
3359
- /** The conversation this file belongs to */
3360
- conversationId: string;
3361
- /** Normalized file path, no leading slash (e.g. "index.html", "src/App.tsx") */
3362
- path: string;
3363
- /** File content (UTF-8 text) */
3364
- content: string;
3365
- createdAt: Date;
3366
- updatedAt: Date;
3199
+ type EncryptionKeyVersion = "v2" | "v3";
3200
+ /**
3201
+ * Thrown by {@link getEncryptionKey} when the requested version is absent.
3202
+ * Distinct from AES-GCM auth-tag failures so decrypt callers can tell
3203
+ * "need to derive/hydrate this version" from "wrong key for intact ciphertext".
3204
+ */
3205
+ declare class EncryptionKeyMissingError extends Error {
3206
+ readonly address: string;
3207
+ readonly version: EncryptionKeyVersion;
3208
+ constructor(address: string, version: EncryptionKeyVersion);
3367
3209
  }
3368
-
3369
- /** Context required by app file operations. */
3370
- interface AppFileOperationsContext {
3371
- database: Database;
3372
- appFilesCollection: Collection<AppFile>;
3210
+ /**
3211
+ * Options for {@link requestEncryptionKey}.
3212
+ */
3213
+ interface RequestEncryptionKeyOptions {
3214
+ /**
3215
+ * When true, re-derive and replace any existing in-memory keys for this
3216
+ * address. Default false preserves the historical "if present, return"
3217
+ * short-circuit. Prefer {@link refreshEncryptionKeyIfMatches} when the
3218
+ * caller has ciphertext that must keep working — force-replace can pin a
3219
+ * newly derived wrong key over a still-valid one.
3220
+ */
3221
+ force?: boolean;
3373
3222
  }
3374
- /** Convert a WatermelonDB AppFile model to a plain StoredAppFile object. */
3375
- declare function appFileToStored(file: AppFile): StoredAppFile;
3376
3223
  /**
3377
- * Create or overwrite a file. If a file with the same conversationId + path
3378
- * already exists, it is updated in place.
3224
+ * Register a callback that fires when an encryption key becomes available for an address.
3225
+ * If the key is already available, the callback fires immediately.
3226
+ * @returns Unsubscribe function
3379
3227
  */
3380
- declare function putAppFileOp(ctx: AppFileOperationsContext, conversationId: string, path: string, content: string): Promise<StoredAppFile>;
3381
- /** Read a single file by conversationId and path. Returns null if not found. */
3382
- declare function getAppFileOp(ctx: AppFileOperationsContext, conversationId: string, path: string): Promise<StoredAppFile | null>;
3383
- /** List all files for a conversation. */
3384
- declare function getAppFilesOp(ctx: AppFileOperationsContext, conversationId: string): Promise<StoredAppFile[]>;
3385
- /** Get all files for a conversation as a path → content map (for sending to the runner). */
3386
- declare function getAppFileMapOp(ctx: AppFileOperationsContext, conversationId: string): Promise<Record<string, string>>;
3387
- /** Delete a single file by conversationId and path. */
3388
- declare function deleteAppFileOp(ctx: AppFileOperationsContext, conversationId: string, path: string): Promise<boolean>;
3389
- /** Delete all files for a conversation. */
3390
- declare function deleteAllAppFilesOp(ctx: AppFileOperationsContext, conversationId: string): Promise<void>;
3391
-
3228
+ declare function onKeyAvailable(address: string, callback: () => void): () => void;
3392
3229
  /**
3393
- * Drop every cached plaintext title and pending decrypt promise.
3394
- *
3395
- * Wired into `clearAllEncryptionState()` via the listener registry in
3396
- * `useEncryption.ts`. Also exported so consumers can clear the cache
3397
- * proactively (e.g. on wallet switch within a session before the
3398
- * full encryption-state teardown lands).
3230
+ * Clears the encryption key for a wallet address from memory
3231
+ * @param address - The wallet address
3399
3232
  */
3400
- declare function clearLazyTitleCache(): void;
3233
+ declare function clearEncryptionKey(address: string): void;
3401
3234
  /**
3402
- * Decrypt a single conversation title on demand.
3235
+ * Clears all encryption-related state from memory and any derived persistence.
3403
3236
  *
3404
- * Designed for the lazy display path: pair with `listConversationsLazy`
3405
- * and call this once a row is actually visible.
3237
+ * This is the canonical session-teardown entry point. It wipes every module-level
3238
+ * map that retains key material or listeners tied to a session: the raw
3239
+ * encryption keys, cached imported CryptoKey objects, availability callbacks,
3240
+ * pending sign-in flights, and derived ECDH key pairs. It also removes any
3241
+ * persisted ECDH key pairs from localStorage so they can't be decrypted by a
3242
+ * subsequent user on a shared browser.
3406
3243
  *
3407
- * Behavior:
3408
- * - Plaintext input (no `enc:` prefix) is returned unchanged. This
3409
- * covers conversations created before encryption was enabled and
3410
- * keeps the helper safe to call unconditionally from rendering
3411
- * code that may receive a mix of encrypted and plaintext titles.
3412
- * - Encrypted input is decrypted via `decryptField`, which uses the
3413
- * same per-version cached `CryptoKey` as the eager path — no new
3414
- * key derivations are triggered.
3415
- * - Concurrent calls for the same `(address, encryptedTitle)` share
3416
- * a single decrypt promise.
3417
- * - The result is memoized in a 256-entry LRU.
3244
+ * Call this on logout / session-end to prevent cross-user key leakage on shared
3245
+ * browsers. If you manage auth outside the SDK, wire this into your logout flow.
3418
3246
  *
3419
- * Throws if the encryption key for `address` isn't loaded. (The
3420
- * underlying `decryptField` would otherwise silently return the
3421
- * ciphertext, which would surface to the UI as a literal `enc:v3:...`
3422
- * title — strictly worse than a thrown error the caller can catch.)
3247
+ * @example
3248
+ * ```tsx
3249
+ * import { clearAllEncryptionState } from "@anuma/sdk/react";
3423
3250
  *
3424
- * @param encryptedTitle - The stored title. May be ciphertext or plaintext.
3425
- * @param address - Wallet address that owns the encryption key.
3426
- * @returns The decrypted plaintext title.
3251
+ * async function handleLogout() {
3252
+ * clearAllEncryptionState();
3253
+ * await privy.logout();
3254
+ * }
3255
+ * ```
3427
3256
  */
3428
- declare function decryptConversationTitle(encryptedTitle: string, address: string): Promise<string>;
3429
-
3430
- declare class VaultMemory extends Model {
3431
- static table: string;
3432
- content: string;
3433
- scope: string;
3434
- /** Profile kind, or null for a free-form memory. */
3435
- kind: string | null;
3436
- /** Canonical JSON value of a kinded memory, encrypted at rest. */
3437
- kindValue: string | null;
3438
- /** private | matching | profile. */
3439
- level: string | null;
3440
- folderId: string | null;
3441
- userId: string | null;
3442
- embedding: string | null;
3443
- /** Model that produced `embedding`. Null on legacy rows (grandfathered). */
3444
- embeddingModel: string | null;
3445
- sourceChunkIds: string | null;
3446
- proofCount: number | null;
3447
- source: string | null;
3448
- /** W6 temporal lane — Unix ms timestamp of when the event occurred. */
3449
- eventTimeStart: number | null;
3450
- /** W6 temporal lane — Unix ms timestamp of event end (range/ongoing). */
3451
- eventTimeEnd: number | null;
3452
- /** W6 temporal lane — `point | range | ongoing | null`. */
3453
- eventTimeKind: string | null;
3454
- /** When true, the user has manually set this memory's topics; auto-extraction
3455
- * leaves its entity links alone. Null on legacy rows (treated as false). */
3456
- topicsUserManaged: boolean | null;
3457
- /** The durable, synced record of this memory's topics — JSON `StoredTopic[]`.
3458
- * `entity` / `memory_entity` are a device-local index over it. Null = pre-v42
3459
- * (backfilled from the row's current links by the sweep). */
3460
- topics: string | null;
3461
- /** Unix ms of the last `topics` write. Separate from `updated_at`, which every
3462
- * topic writer pins on purpose (recall recency) — see the schema note. */
3463
- topicsUpdatedAt: number | null;
3464
- /** The photo(s) a SERVER-EXTRACTED memory came from — JSON
3465
- * `[{feed_item_id, object_key}]`, exactly the shape
3466
- * GET /api/memories/published returns. Null on anything not from a photo. */
3467
- media: string | null;
3468
- /** Unix ms of the last LLM topic-extraction pass. Null = never extracted
3469
- * standalone (linked legacy rows are grandfathered as extracted).
3470
- * DEPRECATED (v42) — subsumed by `topics_updated_at`; see the schema note. */
3471
- topicsExtractedAt: number | null;
3472
- /** A2 supersession: newer memory id that replaced this one, or null if live. */
3473
- supersededBy: string | null;
3474
- supersededAt: number | null;
3475
- /** Extraction-logic version this memory was last stamped under. Null (pre-v38)
3476
- * reads as 0, so a TOPICS_EXTRACTION_VERSION bump re-extracts stale rows.
3477
- * DEPRECATED (v42) — subsumed by `topics_updated_at`; see the schema note. */
3478
- topicsExtractedVersion: number | null;
3479
- /** C3 re-observation watermark: Unix ms of the last retain() merge, or null. */
3480
- lastObservedAt: number | null;
3481
- /** Typed memory (PR1) — the extractor's FactType. Null on legacy/manual rows. */
3482
- factType: string | null;
3483
- /** Decay archive state (PR2) — Unix ms when archived, null when active. */
3484
- archivedAt: number | null;
3485
- /** Tier-0 security (PR3) — "quarantined" | "trusted" | null. */
3486
- trustTier: string | null;
3487
- /** People Nearby visibility: 'private' | 'public'. Null on legacy rows, and
3488
- * any unrecognised value, read as 'private' — never published without opt-in. */
3489
- visibility: string | null;
3490
- /** Owner opted this memory into their own digital twin (twin-scoped only). */
3491
- twinOptIn: boolean | null;
3492
- /** Unix ms when visibility last became non-private; null while private. */
3493
- publishedAt: number | null;
3494
- /** Reserved coarse-geohash slot for landmark/Trail memories. */
3495
- geohash: string | null;
3496
- createdAt: Date;
3497
- updatedAt: Date;
3498
- isDeleted: boolean;
3499
- }
3500
-
3257
+ declare function clearAllEncryptionState(): void;
3501
3258
  /**
3502
- * A canonical entity (person, place, thing) extracted from the user's
3503
- * conversations. Many-to-many with vault memories via {@link MemoryEntity}.
3259
+ * Clears all encryption keys from memory.
3504
3260
  *
3505
- * Created on the write path by the auto-extraction worker (W2) when a
3506
- * candidate fact arrives with non-empty `entities[]`. Used at retrieval
3507
- * time as a 3rd RRF lane (W5 graph traversal): query entity overlap
3508
- * with stored memories surfaces topically-related facts that pure
3509
- * semantic search misses.
3510
- */
3511
- declare class Entity extends Model {
3512
- static table: string;
3513
- /** Lowercased, trimmed name used for dedup and lookup. */
3514
- canonicalName: string;
3515
- /** Optional category — "person" | "place" | "thing" | "concept" | etc. */
3516
- kind: string | null;
3517
- createdAt: Date;
3518
- updatedAt: Date;
3519
- }
3520
- /**
3521
- * Join row: a memory references an entity (and vice versa). Multiple
3522
- * rows per memory (one per entity) and per entity (one per memory).
3523
- */
3524
- declare class MemoryEntity extends Model {
3525
- static table: string;
3526
- memoryId: string;
3527
- entityId: string;
3528
- /**
3529
- * User-scope for the W5 graph lane. Optional because client-side
3530
- * (single-user) deployments may leave it null; server-side multi-user
3531
- * deployments must set it so retrieval can filter cross-user IDs.
3532
- */
3533
- userId: string | null;
3534
- createdAt: Date;
3535
- }
3536
-
3537
- /**
3538
- * The recognized entity classifications. Runtime list + derived type kept
3539
- * in one place so the extractor's validation and the `EntityKind` union
3540
- * can't drift apart.
3541
- * @public
3261
+ * @deprecated Use {@link clearAllEncryptionState} instead. This function is kept
3262
+ * as an alias for backwards compatibility and now delegates to the canonical
3263
+ * teardown, which additionally clears `keyAvailableCallbacks`, pending key
3264
+ * requests, and derived ECDH key pairs (both in-memory and persisted).
3542
3265
  */
3543
- declare const ENTITY_KINDS: readonly ["person", "organization", "place", "event", "product", "thing", "concept", "other"];
3544
- /** @public */
3545
- type EntityKind = (typeof ENTITY_KINDS)[number];
3546
- interface StoredEntity {
3547
- uniqueId: string;
3548
- canonicalName: string;
3549
- kind: string | null;
3550
- createdAt: Date;
3551
- updatedAt: Date;
3552
- }
3266
+ declare function clearAllEncryptionKeys(): void;
3553
3267
  /**
3554
- * Who put a topic on a memory. Written to `memory_vault.topics` but not yet
3555
- * READ anywhere — it exists so a later improvement can refresh the `auto`
3556
- * entries of a curated memory while leaving `user` entries alone (today
3557
- * `topics_user_managed` is all-or-nothing per memory) without needing a second
3558
- * migration or backfill. Don't build that behavior off it yet.
3268
+ * Derives the bytes-native AES key from a raw signature.
3559
3269
  *
3560
- * When you do: a value written by the v42 backfill is NOT ground truth. Pre-v42
3561
- * rows carry no per-topic provenance, so `backfillMemoryTopicsOp` derives it
3562
- * from the per-memory `topics_user_managed` flag and stamps a curated legacy
3563
- * row's every topic `user` — see the note at that derivation.
3564
- * @public
3565
- */
3566
- type TopicSource = "user" | "auto";
3567
- /**
3568
- * One entry in `memory_vault.topics` — the durable, synced record of a memory's
3569
- * topics. `name` carries the CALLER's display casing, unlike
3570
- * {@link StoredEntity.canonicalName}, which {@link normalizeEntityName}
3571
- * lowercases and which has no display column: preserving casing here is the
3572
- * point of storing names on the memory row.
3573
- * @public
3270
+ * Privy Solana `signMessage` returns a `Uint8Array`. Pass those bytes here.
3271
+ * The signature is never hex-encoded, base58-encoded, or passed through
3272
+ * `String()`. That string round-trip is what made {@link hexToBytes} store
3273
+ * zeros for every non-hex pair and yield a low-entropy AES key.
3274
+ *
3275
+ * This is the derivation for the next key version (`anuma-sdk-aes-gcm-v4`).
3276
+ * {@link requestEncryptionKey} does not install it; v2 and v3 stay on the
3277
+ * hex-string path so existing ciphertext keeps decrypting. The return value
3278
+ * is the same 64-char hex form the in-memory store already uses.
3279
+ *
3280
+ * @param signature - Raw signature bytes. Must be at least 64 bytes.
3281
+ * @returns 32-byte AES-GCM key as hex, without a `0x` prefix.
3282
+ * @throws Error when `signature` is shorter than 64 bytes.
3283
+ * @category Encryption
3574
3284
  */
3575
- interface StoredTopic {
3576
- name: string;
3577
- kind?: string;
3578
- source: TopicSource;
3579
- /** How central the topic is to the memory, in (0, 1]; read it with {@link topicWeight}. */
3580
- weight?: number;
3581
- }
3285
+ declare function deriveKeyFromSignatureBytes(signature: Uint8Array): Promise<string>;
3582
3286
  /**
3583
- * Fixed weight per salience level the topic extractor assigns.
3584
- * @public
3287
+ * Gets the encryption key from in-memory storage and imports it as a CryptoKey.
3288
+ * The key must have been previously requested via requestEncryptionKey.
3289
+ * Uses a cache to avoid re-importing the same key on every call.
3290
+ *
3291
+ * @param address - The wallet address
3292
+ * @param version - Which key version to use (default: "v3" for HKDF key)
3293
+ * @returns The CryptoKey for AES-GCM encryption/decryption
3294
+ * @throws Error if the key hasn't been requested yet
3585
3295
  */
3586
- declare const TOPIC_SALIENCE_WEIGHTS: {
3587
- readonly primary: 1;
3588
- readonly secondary: 0.6;
3589
- readonly mention: 0.3;
3590
- };
3591
- /** @public */
3592
- type TopicSalience = keyof typeof TOPIC_SALIENCE_WEIGHTS;
3296
+ declare function getEncryptionKey(address: string, version?: EncryptionKeyVersion): Promise<CryptoKey>;
3593
3297
  /**
3594
- * A topic's weight: 1 when it is user-set or carries no weight.
3595
- * @public
3298
+ * Encrypts data using AES-GCM with the stored encryption key.
3299
+ *
3300
+ * This function uses the encryption key previously generated via `requestEncryptionKey`
3301
+ * to encrypt data. The key must exist in memory before calling this function, or it
3302
+ * will throw an error prompting the user to sign a message.
3303
+ *
3304
+ * @param plaintext - The data to encrypt (string or Uint8Array)
3305
+ * @param address - The wallet address associated with the encryption key
3306
+ * @returns Encrypted data as hex string (IV + ciphertext + auth tag)
3307
+ * @throws Error if encryption key is not found in memory
3308
+ *
3309
+ * @example
3310
+ * ```tsx
3311
+ * import { encryptData, requestEncryptionKey } from "@anuma/sdk/react";
3312
+ *
3313
+ * // First, ensure encryption key exists
3314
+ * await requestEncryptionKey(walletAddress);
3315
+ *
3316
+ * // Then encrypt data
3317
+ * const encrypted = await encryptData("my secret data", walletAddress);
3318
+ * localStorage.setItem("mySecret", encrypted);
3319
+ * ```
3320
+ *
3321
+ * @category Encryption
3596
3322
  */
3597
- declare function topicWeight(topic: StoredTopic): number;
3323
+ declare function encryptData(plaintext: string | Uint8Array, address: string): Promise<string>;
3598
3324
  /**
3599
- * The first topic with the highest weight, or null when there are none.
3600
- * @public
3325
+ * Like {@link encryptData} but takes raw bytes and returns the raw encrypted
3326
+ * `[IV][ciphertext+tag]` Uint8Array instead of a hex string. Avoids the hex
3327
+ * round-trip (`encryptData` returns hex, which callers immediately convert back
3328
+ * to bytes) — for large binary media that hex string is a ~1.37x copy of the
3329
+ * whole payload. Use for binary uploads (e.g. enc:v3 media frames).
3330
+ *
3331
+ * @param plaintext - The raw bytes to encrypt
3332
+ * @param address - The wallet address associated with the encryption key
3333
+ * @returns Encrypted data as raw bytes (IV + ciphertext + auth tag)
3334
+ * @category Encryption
3601
3335
  */
3602
- declare function primaryTopic(topics: readonly StoredTopic[] | null | undefined): StoredTopic | null;
3603
- /** @public */
3604
- interface CreateEntityOptions {
3605
- canonicalName: string;
3606
- kind?: EntityKind | (string & {});
3607
- }
3608
-
3336
+ declare function encryptDataBytes(plaintext: Uint8Array, address: string): Promise<Uint8Array>;
3609
3337
  /**
3610
- * Accepted entity shape for {@link linkMemoryEntitiesOp}. A bare string is
3611
- * a name with no kind (back-compat with the original signature); the object
3612
- * form carries an optional classification.
3613
- * @public
3614
- */
3615
- type EntityInput = string | {
3616
- name: string;
3617
- kind?: EntityKind | (string & {});
3618
- weight?: number;
3619
- };
3620
- interface EntityOperationsContext {
3621
- database: Database;
3622
- entityCollection: Collection<Entity>;
3623
- memoryEntityCollection: Collection<MemoryEntity>;
3624
- /**
3625
- * Optional user-scope. When provided, `linkMemoryEntitiesOp` stamps
3626
- * `user_id` on new memory_entity rows and `getMemoriesByEntityNamesOp`
3627
- * filters lookups by it. Leave undefined for single-user clients.
3628
- */
3629
- userId?: string;
3630
- /**
3631
- * When `true`, `getMemoriesByEntityNamesOp` admits rows with
3632
- * `user_id = null` alongside the strict `userId` match. Set this on
3633
- * LokiJS (web) adapters where the v31 `unsafeExecuteSql` backfill
3634
- * is a no-op — pre-v31 rows otherwise become invisible to the W5
3635
- * lane until `backfillMemoryEntityUserIdsOp` runs. Default `false`
3636
- * (server / SQLite, where the migration backfill is authoritative).
3637
- */
3638
- allowUnscopedRows?: boolean;
3639
- canWrite?: () => Promise<boolean>;
3640
- }
3641
- /**
3642
- * Link a memory to one or more entities. Accepts bare names (back-compat)
3643
- * or `{ name, kind }` objects. Names are normalized; missing entities are
3644
- * auto-created (with their kind), and an existing entity's null kind is
3645
- * back-filled — see {@link upsertEntitiesInWrite}. Idempotent — duplicate
3646
- * (memory_id, entity_id) pairs are skipped.
3338
+ * Decrypts data using AES-GCM with the stored encryption key.
3647
3339
  *
3648
- * `options.unlessTopicsUserManaged` re-checks the memory's vault row INSIDE
3649
- * the serialized writer and skips link creation when the row is user-managed
3650
- * (`topics_user_managed`), soft-deleted, or absent. Auto paths (extraction,
3651
- * topic worker) need this: a pre-call check races the LLM round-trip —
3652
- * `setMemoryEntitiesOp` sets the flag in its own writer and a delete can land
3653
- * mid-call (orphaning links the cascade already swept) — so only an in-write
3654
- * check guarantees a user's manual edit or delete can't be grafted over. The
3655
- * row read fails CLOSED (skip links) so a transient fault never attaches
3656
- * topics to a memory we couldn't verify. Entity upserts and link creation
3657
- * run in ONE writer to prevent orphan-prune races; returns [] when links
3658
- * were skipped.
3340
+ * This function uses the encryption key previously generated via `requestEncryptionKey`
3341
+ * to decrypt data. The key must exist in memory before calling this function, or it
3342
+ * will throw an error prompting the user to sign a message.
3659
3343
  *
3660
- * `options.topicsSource` (default `auto`) is the provenance recorded in
3661
- * `memory_vault.topics`, which this rewrites from the memory's FULL resulting
3662
- * link set — see {@link prepareTopicsUpdate}. Add semantics mean that set is
3663
- * old ∪ new, so already-linked entities are resolved for their names too.
3344
+ * @param encryptedHex - Encrypted data as hex string (IV + ciphertext + auth tag)
3345
+ * @param address - The wallet address associated with the encryption key
3346
+ * @returns Decrypted data as string
3347
+ * @throws Error if encryption key is not found in memory or if decryption fails
3664
3348
  *
3665
- * @deprecated App code: use `MemoryStore.addTopics` (`createLocalMemoryStore`).
3666
- */
3667
- declare function linkMemoryEntitiesOp(ctx: EntityOperationsContext, memoryId: string, entityInputs: ReadonlyArray<EntityInput>, options?: {
3668
- unlessTopicsUserManaged?: boolean;
3669
- topicsSource?: TopicSource;
3670
- }): Promise<StoredEntity[]>;
3671
- /**
3672
- * REPLACE a memory's entity links with an auto-derived set — the topic
3673
- * worker's write primitive. Unlike {@link setMemoryEntitiesOp} it does NOT
3674
- * mark the memory user-managed (the pass is automatic), and unlike
3675
- * {@link linkMemoryEntitiesOp} it removes stale links, so re-extracting an
3676
- * edited memory drops entities its previous content mentioned ("works at
3677
- * Acme" → "works at Globex" must unlink Acme). Insert-missing and
3678
- * destroy-stale are batched in ONE writer, after the same in-write guard as
3679
- * the link op (user-managed / deleted / absent / read-fault ⇒ skip).
3349
+ * @example
3350
+ * ```tsx
3351
+ * import { decryptData, requestEncryptionKey } from "@anuma/sdk/react";
3680
3352
  *
3681
- * That batch also prunes `entity` rows left with no links at all (see
3682
- * {@link findOrphanedEntities}) — otherwise a topic the extractor has disowned
3683
- * keeps rendering as a chip that matches no memory.
3353
+ * // First, ensure encryption key exists
3354
+ * await requestEncryptionKey(walletAddress);
3684
3355
  *
3685
- * Returns the linked entities ([] for an answered-empty set), or null when
3686
- * the guard skipped — callers must treat null as "not persisted" (e.g. don't
3687
- * stamp `topics_extracted_at`).
3356
+ * // Then decrypt data
3357
+ * const encrypted = localStorage.getItem("mySecret");
3358
+ * if (encrypted) {
3359
+ * const decrypted = await decryptData(encrypted, walletAddress);
3360
+ * console.log("Decrypted:", decrypted);
3361
+ * }
3362
+ * ```
3363
+ *
3364
+ * @category Encryption
3688
3365
  */
3689
- declare function replaceMemoryEntitiesGuardedOp(ctx: EntityOperationsContext, memoryId: string, entityInputs: ReadonlyArray<EntityInput>): Promise<StoredEntity[] | null>;
3366
+ declare function decryptData(encryptedHex: string, address: string, version?: EncryptionKeyVersion): Promise<string>;
3690
3367
  /**
3691
- * Backfill `memory_entity.user_id` from the parent vault row's user_id.
3692
- * Idempotent — only touches rows where user_id is null.
3693
- *
3694
- * Why this exists: the v31 schema migration backfills via
3695
- * `unsafeExecuteSql`, which is a no-op on the LokiJS (web) adapter. Native
3696
- * SQLite installs have already been filled by the migration; web installs
3697
- * upgrading through v31 keep `user_id=null` on every pre-existing
3698
- * `memory_entity` row until this helper runs.
3368
+ * Decrypts data and returns as Uint8Array (for binary data)
3369
+ * @param encryptedHex - Encrypted data as hex string (IV + ciphertext + auth tag)
3370
+ * @returns Decrypted data as Uint8Array
3371
+ */
3372
+ declare function decryptDataBytes(encryptedHex: string, address: string, version?: EncryptionKeyVersion): Promise<Uint8Array>;
3373
+ /**
3374
+ * Like {@link decryptDataBytes} but takes the raw encrypted bytes
3375
+ * (`[IV][ciphertext+tag]`) directly instead of a hex string. Skips the
3376
+ * `hexToBytes` conversion — for large binary media the hex string the caller
3377
+ * would otherwise build is a ~1.37x copy of the whole payload (a ~1GB string
3378
+ * for a 500MB video), plus this avoids a second byte copy. Same key resolution
3379
+ * as decryptDataBytes.
3699
3380
  *
3700
- * Consumers wiring an `EntityOperationsContext` with `userId` set are
3701
- * obliged to call this once on first use — `getMemoriesByEntityNamesOp`
3702
- * strictly filters by `user_id`, so unstamped rows are otherwise
3703
- * invisible to the W5 graph lane.
3381
+ * @param encrypted - Raw encrypted bytes (IV + ciphertext + auth tag), no hex
3382
+ * @param address - The wallet address associated with the encryption key
3383
+ * @param version - Encryption key version to decrypt with (defaults to "v3")
3384
+ * @returns Decrypted data as Uint8Array
3385
+ * @category Encryption
3386
+ */
3387
+ declare function decryptDataBytesFromBytes(encrypted: Uint8Array, address: string, version?: EncryptionKeyVersion): Promise<Uint8Array>;
3388
+ /**
3389
+ * Checks if an encryption key exists in memory for the given wallet address.
3704
3390
  *
3705
- * @public
3391
+ * @param address - Wallet address
3392
+ * @param version - When omitted, checks the **v3** (`current`) key — the key
3393
+ * write/OPFS/encrypt paths need. Callers that only need to read legacy
3394
+ * `enc:v2:` data should pass `"v2"` explicitly. (#561 / PR #828)
3706
3395
  */
3707
- declare function backfillMemoryEntityUserIdsOp(ctx: EntityOperationsContext, vaultMemoryCollection: {
3708
- find: (id: string) => Promise<{
3709
- userId?: string | null;
3710
- }>;
3711
- }): Promise<number>;
3396
+ declare function hasEncryptionKey(address: string, version?: EncryptionKeyVersion): boolean;
3712
3397
  /**
3713
- * W5 graph-lane read: given a set of entity names (e.g. extracted from
3714
- * a query), return the set of memory IDs linked to *any* of them, with
3715
- * a per-memory count of how many of the queried entities they match.
3398
+ * Seed (or merge) raw key hex into the in-memory store without signing.
3716
3399
  *
3717
- * Caller passes the result to `rankByEntityOverlap` to score each
3718
- * memory via `tanh(0.5 × shared_entity_count)` — this op only does the
3719
- * cheap "find candidate memories" step and leaves scoring to the
3720
- * ranker so callers can attach their own kind-weights or alternative
3721
- * scoring strategies later.
3400
+ * Used by platform polyfills that hydrate from SecureStore / keychain where
3401
+ * one version may be missing — callers must not require both versions to
3402
+ * exist before the other becomes usable (#561).
3722
3403
  *
3723
- * Names are normalized (lowercased, trimmed). Empty input returns an
3724
- * empty map. Names that don't exist as entities contribute nothing.
3404
+ * Existing versions are preserved when the corresponding argument is omitted.
3405
+ * Pass an explicit empty merge is not supported; omit the field to leave it.
3725
3406
  *
3726
- * Multi-user safety: when `ctx.userId` is set, results are filtered to
3727
- * memory_entity rows whose `user_id` matches. Without this filter the
3728
- * lane returns IDs from every user who tagged a matching entity.
3407
+ * Each provided key must be 64 hex characters (32-byte AES key).
3408
+ */
3409
+ declare function seedEncryptionKeys(address: string, keys: {
3410
+ legacy?: string;
3411
+ current?: string;
3412
+ }): void;
3413
+ /**
3414
+ * Encrypts data using a pre-fetched CryptoKey.
3415
+ * Use this for batch operations to avoid repeated key lookups.
3729
3416
  *
3730
- * @deprecated App code: use `MemoryStore.memoriesByTopics` (`createLocalMemoryStore`).
3417
+ * @param plaintext - The data to encrypt (string or Uint8Array)
3418
+ * @param key - The CryptoKey for AES-GCM encryption
3419
+ * @returns Encrypted data as hex string (IV + ciphertext + auth tag)
3420
+ * @internal
3731
3421
  */
3732
- declare function getMemoriesByEntityNamesOp(ctx: EntityOperationsContext, entityNames: readonly string[]): Promise<Map<string, Set<string>>>;
3422
+ declare function encryptDataWithKey(plaintext: string | Uint8Array, key: CryptoKey): Promise<string>;
3733
3423
  /**
3734
- * Reverse of {@link getMemoriesByEntityNamesOp}: given a set of memory IDs
3735
- * (e.g. the current BFS frontier), return each memory's set of linked
3736
- * canonical entity names. This is the missing primitive for multi-hop graph
3737
- * traversal (PR4) — one step outward from a memory to its neighbor entities,
3738
- * which the traversal then expands to reach topically-adjacent memories.
3424
+ * Decrypts data using a pre-fetched CryptoKey.
3425
+ * Use this for batch operations to avoid repeated key lookups.
3739
3426
  *
3740
- * Empty input returns an empty map. Memory IDs with no links contribute
3741
- * nothing (they simply don't appear as keys).
3427
+ * @param encryptedHex - Encrypted data as hex string (IV + ciphertext + auth tag)
3428
+ * @param key - The CryptoKey for AES-GCM decryption
3429
+ * @returns Decrypted data as string
3430
+ * @internal
3431
+ */
3432
+ declare function decryptDataWithKey(encryptedHex: string, key: CryptoKey): Promise<string>;
3433
+ /**
3434
+ * Batch encrypt multiple values efficiently with a single key lookup.
3435
+ * Much faster than calling encryptData for each value individually.
3742
3436
  *
3743
- * Multi-user safety mirrors {@link getMemoriesByEntityNamesOp} exactly: when
3744
- * `ctx.userId` is set, only `memory_entity` rows owned by that user are
3745
- * followed (with the same `allowUnscopedRows` LokiJS escape hatch for pre-v31
3746
- * rows whose `user_id` backfill was a no-op). Without the filter the reverse
3747
- * lookup would leak entity links written by other users.
3437
+ * @param values - Array of plaintext values to encrypt
3438
+ * @param address - The wallet address associated with the encryption key
3439
+ * @returns Array of encrypted values as hex strings
3440
+ * @throws Error if encryption key is not found in memory
3748
3441
  *
3749
- * @public
3442
+ * @example
3443
+ * ```tsx
3444
+ * const encrypted = await encryptDataBatch(
3445
+ * ["secret1", "secret2", "secret3"],
3446
+ * walletAddress
3447
+ * );
3448
+ * ```
3750
3449
  *
3751
- * @deprecated App code: use `MemoryStore.topicsByMemories` (`createLocalMemoryStore`).
3450
+ * @category Encryption
3752
3451
  */
3753
- declare function getEntitiesByMemoryIdsOp(ctx: EntityOperationsContext, memoryIds: readonly string[]): Promise<Map<string, Set<string>>>;
3754
-
3452
+ declare function encryptDataBatch(values: (string | Uint8Array)[], address: string): Promise<string[]>;
3755
3453
  /**
3756
- * Encryption key version type.
3757
- * - "v2": Legacy SHA-256 derived key (for reading enc:v2: data)
3758
- * - "v3": HKDF derived key with domain separation (for new encryption)
3454
+ * Batch decrypt multiple values efficiently with a single key lookup.
3455
+ * Much faster than calling decryptData for each value individually.
3759
3456
  *
3760
- * Raw signature bytes (Privy Solana `signMessage` returns a `Uint8Array`) are
3761
- * not a stored version. Derive them with {@link deriveKeyFromSignatureBytes}.
3762
- * {@link requestEncryptionKey} still derives v2 and v3 from a hex signature only.
3457
+ * @param encryptedValues - Array of encrypted hex strings
3458
+ * @param address - The wallet address associated with the encryption key
3459
+ * @returns Array of decrypted plaintext values
3460
+ * @throws Error if encryption key is not found in memory or decryption fails
3461
+ *
3462
+ * @example
3463
+ * ```tsx
3464
+ * const decrypted = await decryptDataBatch(
3465
+ * [encrypted1, encrypted2, encrypted3],
3466
+ * walletAddress
3467
+ * );
3468
+ * ```
3469
+ *
3470
+ * @category Encryption
3763
3471
  */
3764
- type EncryptionKeyVersion = "v2" | "v3";
3472
+ declare function decryptDataBatch(encryptedValues: string[], address: string): Promise<string[]>;
3765
3473
  /**
3766
- * Thrown by {@link getEncryptionKey} when the requested version is absent.
3767
- * Distinct from AES-GCM auth-tag failures so decrypt callers can tell
3768
- * "need to derive/hydrate this version" from "wrong key for intact ciphertext".
3474
+ * Options for signing messages.
3769
3475
  */
3770
- declare class EncryptionKeyMissingError extends Error {
3771
- readonly address: string;
3772
- readonly version: EncryptionKeyVersion;
3773
- constructor(address: string, version: EncryptionKeyVersion);
3476
+ interface SignMessageOptions {
3477
+ /** Whether to show wallet UI during signing. Default: true */
3478
+ showWalletUIs?: boolean;
3774
3479
  }
3775
3480
  /**
3776
- * Options for {@link requestEncryptionKey}.
3777
- */
3778
- interface RequestEncryptionKeyOptions {
3779
- /**
3780
- * When true, re-derive and replace any existing in-memory keys for this
3781
- * address. Default false preserves the historical "if present, return"
3782
- * short-circuit. Prefer {@link refreshEncryptionKeyIfMatches} when the
3783
- * caller has ciphertext that must keep working — force-replace can pin a
3784
- * newly derived wrong key over a still-valid one.
3785
- */
3786
- force?: boolean;
3787
- }
3788
- /**
3789
- * Register a callback that fires when an encryption key becomes available for an address.
3790
- * If the key is already available, the callback fires immediately.
3791
- * @returns Unsubscribe function
3481
+ * Type for the signMessage function that client must provide.
3482
+ * This is typically from Privy's useSignMessage hook.
3483
+ *
3484
+ * The resolved value must be a hex signature (`0x`-prefixed or bare). A
3485
+ * non-hex string — including `String(uint8Array)` or a base58 signature —
3486
+ * throws from key derivation instead of becoming a zero-filled AES key.
3487
+ * Raw signature bytes go to {@link deriveKeyFromSignatureBytes}.
3792
3488
  */
3793
- declare function onKeyAvailable(address: string, callback: () => void): () => void;
3489
+ type SignMessageFn = (message: string, options?: SignMessageOptions) => Promise<string>;
3794
3490
  /**
3795
- * Clears the encryption key for a wallet address from memory
3796
- * @param address - The wallet address
3491
+ * Type for embedded wallet signer function that enables silent signing.
3492
+ * For Privy embedded wallets, this can sign programmatically without user interaction
3493
+ * when configured correctly in the Privy dashboard.
3797
3494
  */
3798
- declare function clearEncryptionKey(address: string): void;
3495
+ type EmbeddedWalletSignerFn = (message: string, options?: SignMessageOptions) => Promise<string>;
3799
3496
  /**
3800
- * Clears all encryption-related state from memory and any derived persistence.
3801
- *
3802
- * This is the canonical session-teardown entry point. It wipes every module-level
3803
- * map that retains key material or listeners tied to a session: the raw
3804
- * encryption keys, cached imported CryptoKey objects, availability callbacks,
3805
- * pending sign-in flights, and derived ECDH key pairs. It also removes any
3806
- * persisted ECDH key pairs from localStorage so they can't be decrypted by a
3807
- * subsequent user on a shared browser.
3497
+ * Requests the user to sign a message to generate an encryption key.
3498
+ * If a key already exists in memory for the given wallet, resolves immediately
3499
+ * unless {@link RequestEncryptionKeyOptions.force} is set.
3808
3500
  *
3809
- * Call this on logout / session-end to prevent cross-user key leakage on shared
3810
- * browsers. If you manage auth outside the SDK, wire this into your logout flow.
3501
+ * Note: Keys are stored in memory only and do not persist across page reloads.
3502
+ * This is a security feature - users must sign once per session to derive their key.
3811
3503
  *
3812
- * @example
3813
- * ```tsx
3814
- * import { clearAllEncryptionState } from "@anuma/sdk/react";
3504
+ * When a seeded/pinned store already has keys and the fresh derive does not
3505
+ * match any of them, the store is left unchanged and this resolves to `false`
3506
+ * (without firing {@link onKeyAvailable}). Callers that need write readiness
3507
+ * should check the return value or {@link hasEncryptionKey} before encrypting
3508
+ * so they can surface a re-unlock UI instead of failing downstream (#828).
3815
3509
  *
3816
- * async function handleLogout() {
3817
- * clearAllEncryptionState();
3818
- * await privy.logout();
3819
- * }
3820
- * ```
3510
+ * @param walletAddress - The wallet address to generate the key for
3511
+ * @param signMessage - Function to sign a message (returns signature hex string)
3512
+ * @param embeddedWalletSigner - Optional function for silent signing with embedded wallets
3513
+ * @param options - Optional flags (e.g. force re-derive)
3514
+ * @returns `true` when keys are available after the call; `false` when a
3515
+ * divergent derive left the store unchanged (or the session was torn down
3516
+ * mid-flight).
3821
3517
  */
3822
- declare function clearAllEncryptionState(): void;
3518
+ declare function requestEncryptionKey(walletAddress: string, signMessage: SignMessageFn, embeddedWalletSigner?: EmbeddedWalletSignerFn, options?: RequestEncryptionKeyOptions): Promise<boolean>;
3823
3519
  /**
3824
- * Clears all encryption keys from memory.
3520
+ * Re-derive encryption keys from a fresh signature and commit them **only if**
3521
+ * they successfully decrypt `probeCiphertext` (a prefixed `enc:v2:` / `enc:v3:`
3522
+ * value). If they do not, the existing in-memory keys are left untouched.
3825
3523
  *
3826
- * @deprecated Use {@link clearAllEncryptionState} instead. This function is kept
3827
- * as an alias for backwards compatibility and now delegates to the canonical
3828
- * teardown, which additionally clears `keyAvailableCallbacks`, pending key
3829
- * requests, and derived ECDH key pairs (both in-memory and persisted).
3524
+ * Concurrent calls for the same wallet share one sign+derive. Each caller then
3525
+ * probes **its own** ciphertext against those candidates, so mixed-era messages
3526
+ * in one `Promise.all` batch can still recover when only the leader's probe
3527
+ * misses (#828 review). Failed candidates are memoized for the session so
3528
+ * pagination does not re-prompt on every page when the wallet has changed.
3529
+ *
3530
+ * @returns true when keys were refreshed (probe decrypted); false when the
3531
+ * probe failed under the candidate keys (store unchanged) or the probe was
3532
+ * not encrypted.
3830
3533
  */
3831
- declare function clearAllEncryptionKeys(): void;
3534
+ declare function refreshEncryptionKeyIfMatches(walletAddress: string, probeCiphertext: string, signMessage: SignMessageFn, embeddedWalletSigner?: EmbeddedWalletSignerFn): Promise<boolean>;
3832
3535
  /**
3833
- * Derives the bytes-native AES key from a raw signature.
3834
- *
3835
- * Privy Solana `signMessage` returns a `Uint8Array`. Pass those bytes here.
3836
- * The signature is never hex-encoded, base58-encoded, or passed through
3837
- * `String()`. That string round-trip is what made {@link hexToBytes} store
3838
- * zeros for every non-hex pair and yield a low-entropy AES key.
3536
+ * Requests the user to sign a message to generate an ECDH key pair.
3537
+ * If a key pair already exists in memory for the given wallet, resolves immediately.
3839
3538
  *
3840
- * This is the derivation for the next key version (`anuma-sdk-aes-gcm-v4`).
3841
- * {@link requestEncryptionKey} does not install it; v2 and v3 stay on the
3842
- * hex-string path so existing ciphertext keeps decrypting. The return value
3843
- * is the same 64-char hex form the in-memory store already uses.
3539
+ * Note: Key pairs are stored in memory only and do not persist across page reloads.
3540
+ * This is a security feature - users must sign once per session to derive their key pair.
3844
3541
  *
3845
- * @param signature - Raw signature bytes. Must be at least 64 bytes.
3846
- * @returns 32-byte AES-GCM key as hex, without a `0x` prefix.
3847
- * @throws Error when `signature` is shorter than 64 bytes.
3848
- * @category Encryption
3542
+ * @param walletAddress - The wallet address to generate the key pair for
3543
+ * @param signMessage - Function to sign a message (returns signature hex string)
3544
+ * @param embeddedWalletSigner - Optional function for silent signing with embedded wallets
3545
+ * @returns Promise that resolves when the key pair is available
3849
3546
  */
3850
- declare function deriveKeyFromSignatureBytes(signature: Uint8Array): Promise<string>;
3547
+ declare function requestKeyPair(walletAddress: string, signMessage: SignMessageFn, embeddedWalletSigner?: EmbeddedWalletSignerFn): Promise<void>;
3851
3548
  /**
3852
- * Gets the encryption key from in-memory storage and imports it as a CryptoKey.
3853
- * The key must have been previously requested via requestEncryptionKey.
3854
- * Uses a cache to avoid re-importing the same key on every call.
3855
- *
3549
+ * Exports the public key for a wallet address as SPKI format (base64)
3856
3550
  * @param address - The wallet address
3857
- * @param version - Which key version to use (default: "v3" for HKDF key)
3858
- * @returns The CryptoKey for AES-GCM encryption/decryption
3859
- * @throws Error if the key hasn't been requested yet
3551
+ * @param signMessage - Function to sign a message (returns signature hex string)
3552
+ * @param embeddedWalletSigner - Optional function for silent signing with embedded wallets
3553
+ * @returns The public key as base64-encoded SPKI string
3860
3554
  */
3861
- declare function getEncryptionKey(address: string, version?: EncryptionKeyVersion): Promise<CryptoKey>;
3555
+ declare function exportPublicKey(address: string, signMessage: SignMessageFn, embeddedWalletSigner?: EmbeddedWalletSignerFn): Promise<string>;
3862
3556
  /**
3863
- * Encrypts data using AES-GCM with the stored encryption key.
3557
+ * Checks if a key pair exists in memory for the given wallet address
3558
+ * @param address - The wallet address
3559
+ * @returns True if key pair exists, false otherwise
3560
+ */
3561
+ declare function hasKeyPair(address: string): boolean;
3562
+ /**
3563
+ * Clears the key pair for a wallet address from memory and localStorage
3564
+ * @param address - The wallet address
3565
+ */
3566
+ declare function clearKeyPair(address: string): void;
3567
+ /**
3568
+ * Clears all key pairs from memory and any persisted entries in localStorage.
3864
3569
  *
3865
- * This function uses the encryption key previously generated via `requestEncryptionKey`
3866
- * to encrypt data. The key must exist in memory before calling this function, or it
3867
- * will throw an error prompting the user to sign a message.
3570
+ * Matches the persistence behavior of the per-address {@link clearKeyPair};
3571
+ * without this, `clearAllKeyPairs()` would leave `ecdh_keypair_*` ciphertext
3572
+ * behind in storage while `clearKeyPair(address)` removes it.
3573
+ */
3574
+ declare function clearAllKeyPairs(): void;
3575
+ /**
3576
+ * Result returned by the useEncryption hook.
3577
+ * @category Hooks
3578
+ */
3579
+ interface UseEncryptionResult {
3580
+ /** Request and generate an encryption key for a wallet address */
3581
+ requestEncryptionKey: (walletAddress: string) => Promise<boolean>;
3582
+ /** Request and generate an ECDH key pair for a wallet address */
3583
+ requestKeyPair: (walletAddress: string) => Promise<void>;
3584
+ /** Export the public key for a wallet address as base64-encoded SPKI */
3585
+ exportPublicKey: (walletAddress: string) => Promise<string>;
3586
+ /** Check if a key pair exists in memory for a wallet address */
3587
+ hasKeyPair: (walletAddress: string) => boolean;
3588
+ /** Clear the key pair for a wallet address from memory */
3589
+ clearKeyPair: (walletAddress: string) => void;
3590
+ }
3591
+ /**
3592
+ * Hook that provides encryption key management for securing local data.
3868
3593
  *
3869
- * @param plaintext - The data to encrypt (string or Uint8Array)
3870
- * @param address - The wallet address associated with the encryption key
3871
- * @returns Encrypted data as hex string (IV + ciphertext + auth tag)
3872
- * @throws Error if encryption key is not found in memory
3594
+ * This hook helps you encrypt and decrypt data using a key derived from a wallet
3595
+ * signature. It requires `@privy-io/react-auth` for wallet authentication. Keys are
3596
+ * stored in memory only and do not persist across page reloads for security.
3873
3597
  *
3874
- * @example
3875
- * ```tsx
3876
- * import { encryptData, requestEncryptionKey } from "@anuma/sdk/react";
3598
+ * ## How it works
3877
3599
  *
3878
- * // First, ensure encryption key exists
3879
- * await requestEncryptionKey(walletAddress);
3600
+ * 1. User signs a message with their wallet
3601
+ * 2. The signature is used to deterministically derive an encryption key
3602
+ * 3. The key is stored in memory (not localStorage) for the session
3603
+ * 4. Data can be encrypted/decrypted using this key
3604
+ * 5. On page reload, user must sign again to derive the key
3880
3605
  *
3881
- * // Then encrypt data
3882
- * const encrypted = await encryptData("my secret data", walletAddress);
3883
- * localStorage.setItem("mySecret", encrypted);
3884
- * ```
3606
+ * ## Security Features
3885
3607
  *
3886
- * @category Encryption
3887
- */
3888
- declare function encryptData(plaintext: string | Uint8Array, address: string): Promise<string>;
3889
- /**
3890
- * Like {@link encryptData} but takes raw bytes and returns the raw encrypted
3891
- * `[IV][ciphertext+tag]` Uint8Array instead of a hex string. Avoids the hex
3892
- * round-trip (`encryptData` returns hex, which callers immediately convert back
3893
- * to bytes) — for large binary media that hex string is a ~1.37x copy of the
3894
- * whole payload. Use for binary uploads (e.g. enc:v3 media frames).
3608
+ * - **In-memory only**: Keys never touch disk or localStorage
3609
+ * - **Deterministic**: Same wallet + signature always generates same key
3610
+ * - **Session-scoped**: Keys cleared on page reload
3611
+ * - **XSS-resistant**: Keys not accessible after page reload
3895
3612
  *
3896
- * @param plaintext - The raw bytes to encrypt
3897
- * @param address - The wallet address associated with the encryption key
3898
- * @returns Encrypted data as raw bytes (IV + ciphertext + auth tag)
3899
- * @category Encryption
3900
- */
3901
- declare function encryptDataBytes(plaintext: Uint8Array, address: string): Promise<Uint8Array>;
3902
- /**
3903
- * Decrypts data using AES-GCM with the stored encryption key.
3613
+ * ## Embedded Wallet Support
3904
3614
  *
3905
- * This function uses the encryption key previously generated via `requestEncryptionKey`
3906
- * to decrypt data. The key must exist in memory before calling this function, or it
3907
- * will throw an error prompting the user to sign a message.
3615
+ * For Privy embedded wallets, you can provide an `embeddedWalletSigner` function
3616
+ * to enable silent signing without user confirmation modals. This is useful for
3617
+ * deterministic key generation that should happen automatically.
3908
3618
  *
3909
- * @param encryptedHex - Encrypted data as hex string (IV + ciphertext + auth tag)
3910
- * @param address - The wallet address associated with the encryption key
3911
- * @returns Decrypted data as string
3912
- * @throws Error if encryption key is not found in memory or if decryption fails
3619
+ * @param signMessage - Function to sign a message (from Privy's useSignMessage hook)
3620
+ * @param embeddedWalletSigner - Optional function for silent signing with embedded wallets
3621
+ * @returns Functions to request encryption keys and manage key pairs
3913
3622
  *
3914
3623
  * @example
3915
3624
  * ```tsx
3916
- * import { decryptData, requestEncryptionKey } from "@anuma/sdk/react";
3625
+ * import { usePrivy, useWallets } from "@privy-io/react-auth";
3626
+ * import { useEncryption, encryptData, decryptData } from "@anuma/sdk/react";
3917
3627
  *
3918
- * // First, ensure encryption key exists
3919
- * await requestEncryptionKey(walletAddress);
3628
+ * function SecureComponent() {
3629
+ * const { user, signMessage } = usePrivy();
3630
+ * const { wallets } = useWallets();
3631
+ * const embeddedWallet = wallets.find(w => w.walletClientType === 'privy');
3920
3632
  *
3921
- * // Then decrypt data
3922
- * const encrypted = localStorage.getItem("mySecret");
3923
- * if (encrypted) {
3924
- * const decrypted = await decryptData(encrypted, walletAddress);
3925
- * console.log("Decrypted:", decrypted);
3926
- * }
3927
- * ```
3633
+ * // Create silent signer for embedded wallets
3634
+ * const embeddedSigner = useCallback(async (message: string) => {
3635
+ * if (embeddedWallet) {
3636
+ * const { signature } = await embeddedWallet.signMessage({ message });
3637
+ * return signature;
3638
+ * }
3639
+ * throw new Error('No embedded wallet');
3640
+ * }, [embeddedWallet]);
3928
3641
  *
3929
- * @category Encryption
3930
- */
3931
- declare function decryptData(encryptedHex: string, address: string, version?: EncryptionKeyVersion): Promise<string>;
3932
- /**
3933
- * Decrypts data and returns as Uint8Array (for binary data)
3934
- * @param encryptedHex - Encrypted data as hex string (IV + ciphertext + auth tag)
3935
- * @returns Decrypted data as Uint8Array
3936
- */
3937
- declare function decryptDataBytes(encryptedHex: string, address: string, version?: EncryptionKeyVersion): Promise<Uint8Array>;
3938
- /**
3939
- * Like {@link decryptDataBytes} but takes the raw encrypted bytes
3940
- * (`[IV][ciphertext+tag]`) directly instead of a hex string. Skips the
3941
- * `hexToBytes` conversion — for large binary media the hex string the caller
3942
- * would otherwise build is a ~1.37x copy of the whole payload (a ~1GB string
3943
- * for a 500MB video), plus this avoids a second byte copy. Same key resolution
3944
- * as decryptDataBytes.
3945
- *
3946
- * @param encrypted - Raw encrypted bytes (IV + ciphertext + auth tag), no hex
3947
- * @param address - The wallet address associated with the encryption key
3948
- * @param version - Encryption key version to decrypt with (defaults to "v3")
3949
- * @returns Decrypted data as Uint8Array
3950
- * @category Encryption
3951
- */
3952
- declare function decryptDataBytesFromBytes(encrypted: Uint8Array, address: string, version?: EncryptionKeyVersion): Promise<Uint8Array>;
3953
- /**
3954
- * Checks if an encryption key exists in memory for the given wallet address.
3955
- *
3956
- * @param address - Wallet address
3957
- * @param version - When omitted, checks the **v3** (`current`) key — the key
3958
- * write/OPFS/encrypt paths need. Callers that only need to read legacy
3959
- * `enc:v2:` data should pass `"v2"` explicitly. (#561 / PR #828)
3960
- */
3961
- declare function hasEncryptionKey(address: string, version?: EncryptionKeyVersion): boolean;
3962
- /**
3963
- * Seed (or merge) raw key hex into the in-memory store without signing.
3964
- *
3965
- * Used by platform polyfills that hydrate from SecureStore / keychain where
3966
- * one version may be missing — callers must not require both versions to
3967
- * exist before the other becomes usable (#561).
3968
- *
3969
- * Existing versions are preserved when the corresponding argument is omitted.
3970
- * Pass an explicit empty merge is not supported; omit the field to leave it.
3642
+ * const { requestEncryptionKey } = useEncryption(signMessage, embeddedSigner);
3971
3643
  *
3972
- * Each provided key must be 64 hex characters (32-byte AES key).
3973
- */
3974
- declare function seedEncryptionKeys(address: string, keys: {
3975
- legacy?: string;
3976
- current?: string;
3977
- }): void;
3978
- /**
3979
- * Encrypts data using a pre-fetched CryptoKey.
3980
- * Use this for batch operations to avoid repeated key lookups.
3644
+ * // Request encryption key when user is authenticated
3645
+ * useEffect(() => {
3646
+ * if (user?.wallet?.address) {
3647
+ * // This will use silent signing for embedded wallets
3648
+ * await requestEncryptionKey(user.wallet.address);
3649
+ * }
3650
+ * }, [user]);
3981
3651
  *
3982
- * @param plaintext - The data to encrypt (string or Uint8Array)
3983
- * @param key - The CryptoKey for AES-GCM encryption
3984
- * @returns Encrypted data as hex string (IV + ciphertext + auth tag)
3985
- * @internal
3986
- */
3987
- declare function encryptDataWithKey(plaintext: string | Uint8Array, key: CryptoKey): Promise<string>;
3988
- /**
3989
- * Decrypts data using a pre-fetched CryptoKey.
3990
- * Use this for batch operations to avoid repeated key lookups.
3652
+ * // Encrypt data
3653
+ * const saveSecret = async (text: string) => {
3654
+ * const encrypted = await encryptData(text, user.wallet.address);
3655
+ * localStorage.setItem("mySecret", encrypted);
3656
+ * };
3991
3657
  *
3992
- * @param encryptedHex - Encrypted data as hex string (IV + ciphertext + auth tag)
3993
- * @param key - The CryptoKey for AES-GCM decryption
3994
- * @returns Decrypted data as string
3995
- * @internal
3996
- */
3997
- declare function decryptDataWithKey(encryptedHex: string, key: CryptoKey): Promise<string>;
3998
- /**
3999
- * Batch encrypt multiple values efficiently with a single key lookup.
4000
- * Much faster than calling encryptData for each value individually.
3658
+ * // Decrypt data
3659
+ * const loadSecret = async () => {
3660
+ * const encrypted = localStorage.getItem("mySecret");
3661
+ * if (encrypted) {
3662
+ * const decrypted = await decryptData(encrypted, user.wallet.address);
3663
+ * console.log(decrypted);
3664
+ * }
3665
+ * };
4001
3666
  *
4002
- * @param values - Array of plaintext values to encrypt
4003
- * @param address - The wallet address associated with the encryption key
4004
- * @returns Array of encrypted values as hex strings
4005
- * @throws Error if encryption key is not found in memory
3667
+ * return (
3668
+ * <div>
3669
+ * <button onClick={() => saveSecret("my secret data")}>Encrypt & Save</button>
3670
+ * <button onClick={loadSecret}>Load & Decrypt</button>
3671
+ * </div>
3672
+ * );
3673
+ * }
3674
+ * ```
4006
3675
  *
4007
3676
  * @example
4008
3677
  * ```tsx
4009
- * const encrypted = await encryptDataBatch(
4010
- * ["secret1", "secret2", "secret3"],
4011
- * walletAddress
4012
- * );
4013
- * ```
3678
+ * // Standard usage with external wallets (shows confirmation modal)
3679
+ * import { usePrivy } from "@privy-io/react-auth";
3680
+ * import { useEncryption, encryptData, decryptData } from "@anuma/sdk/react";
4014
3681
  *
4015
- * @category Encryption
4016
- */
4017
- declare function encryptDataBatch(values: (string | Uint8Array)[], address: string): Promise<string[]>;
4018
- /**
4019
- * Batch decrypt multiple values efficiently with a single key lookup.
4020
- * Much faster than calling decryptData for each value individually.
3682
+ * function SecureComponent() {
3683
+ * const { user, signMessage } = usePrivy();
3684
+ * const { requestEncryptionKey } = useEncryption(signMessage);
4021
3685
  *
4022
- * @param encryptedValues - Array of encrypted hex strings
4023
- * @param address - The wallet address associated with the encryption key
4024
- * @returns Array of decrypted plaintext values
4025
- * @throws Error if encryption key is not found in memory or decryption fails
3686
+ * // Request encryption key when user is authenticated
3687
+ * useEffect(() => {
3688
+ * if (user?.wallet?.address) {
3689
+ * // This will prompt user to sign if key doesn't exist
3690
+ * await requestEncryptionKey(user.wallet.address);
3691
+ * }
3692
+ * }, [user]);
3693
+ * }
3694
+ * ```
4026
3695
  *
4027
3696
  * @example
4028
3697
  * ```tsx
4029
- * const decrypted = await decryptDataBatch(
4030
- * [encrypted1, encrypted2, encrypted3],
4031
- * walletAddress
4032
- * );
4033
- * ```
4034
- *
4035
- * @category Encryption
4036
- */
4037
- declare function decryptDataBatch(encryptedValues: string[], address: string): Promise<string[]>;
4038
- /**
4039
- * Options for signing messages.
4040
- */
4041
- interface SignMessageOptions {
4042
- /** Whether to show wallet UI during signing. Default: true */
4043
- showWalletUIs?: boolean;
4044
- }
4045
- /**
4046
- * Type for the signMessage function that client must provide.
4047
- * This is typically from Privy's useSignMessage hook.
4048
- *
4049
- * The resolved value must be a hex signature (`0x`-prefixed or bare). A
4050
- * non-hex string — including `String(uint8Array)` or a base58 signature —
4051
- * throws from key derivation instead of becoming a zero-filled AES key.
4052
- * Raw signature bytes go to {@link deriveKeyFromSignatureBytes}.
4053
- */
4054
- type SignMessageFn = (message: string, options?: SignMessageOptions) => Promise<string>;
4055
- /**
4056
- * Type for embedded wallet signer function that enables silent signing.
4057
- * For Privy embedded wallets, this can sign programmatically without user interaction
4058
- * when configured correctly in the Privy dashboard.
4059
- */
4060
- type EmbeddedWalletSignerFn = (message: string, options?: SignMessageOptions) => Promise<string>;
4061
- /**
4062
- * Requests the user to sign a message to generate an encryption key.
4063
- * If a key already exists in memory for the given wallet, resolves immediately
4064
- * unless {@link RequestEncryptionKeyOptions.force} is set.
4065
- *
4066
- * Note: Keys are stored in memory only and do not persist across page reloads.
4067
- * This is a security feature - users must sign once per session to derive their key.
4068
- *
4069
- * When a seeded/pinned store already has keys and the fresh derive does not
4070
- * match any of them, the store is left unchanged and this resolves to `false`
4071
- * (without firing {@link onKeyAvailable}). Callers that need write readiness
4072
- * should check the return value or {@link hasEncryptionKey} before encrypting
4073
- * so they can surface a re-unlock UI instead of failing downstream (#828).
4074
- *
4075
- * @param walletAddress - The wallet address to generate the key for
4076
- * @param signMessage - Function to sign a message (returns signature hex string)
4077
- * @param embeddedWalletSigner - Optional function for silent signing with embedded wallets
4078
- * @param options - Optional flags (e.g. force re-derive)
4079
- * @returns `true` when keys are available after the call; `false` when a
4080
- * divergent derive left the store unchanged (or the session was torn down
4081
- * mid-flight).
4082
- */
4083
- declare function requestEncryptionKey(walletAddress: string, signMessage: SignMessageFn, embeddedWalletSigner?: EmbeddedWalletSignerFn, options?: RequestEncryptionKeyOptions): Promise<boolean>;
4084
- /**
4085
- * Re-derive encryption keys from a fresh signature and commit them **only if**
4086
- * they successfully decrypt `probeCiphertext` (a prefixed `enc:v2:` / `enc:v3:`
4087
- * value). If they do not, the existing in-memory keys are left untouched.
4088
- *
4089
- * Concurrent calls for the same wallet share one sign+derive. Each caller then
4090
- * probes **its own** ciphertext against those candidates, so mixed-era messages
4091
- * in one `Promise.all` batch can still recover when only the leader's probe
4092
- * misses (#828 review). Failed candidates are memoized for the session so
4093
- * pagination does not re-prompt on every page when the wallet has changed.
3698
+ * // ECDH key pair generation for end-to-end encryption
3699
+ * import { usePrivy } from "@privy-io/react-auth";
3700
+ * import { useEncryption } from "@anuma/sdk/react";
4094
3701
  *
4095
- * @returns true when keys were refreshed (probe decrypted); false when the
4096
- * probe failed under the candidate keys (store unchanged) or the probe was
4097
- * not encrypted.
4098
- */
4099
- declare function refreshEncryptionKeyIfMatches(walletAddress: string, probeCiphertext: string, signMessage: SignMessageFn, embeddedWalletSigner?: EmbeddedWalletSignerFn): Promise<boolean>;
4100
- /**
4101
- * Requests the user to sign a message to generate an ECDH key pair.
4102
- * If a key pair already exists in memory for the given wallet, resolves immediately.
3702
+ * function E2EEComponent() {
3703
+ * const { signMessage } = usePrivy();
3704
+ * const { requestKeyPair, exportPublicKey } = useEncryption(signMessage);
4103
3705
  *
4104
- * Note: Key pairs are stored in memory only and do not persist across page reloads.
4105
- * This is a security feature - users must sign once per session to derive their key pair.
3706
+ * const setupEncryption = async (walletAddress: string) => {
3707
+ * // Generate deterministic ECDH key pair from wallet signature
3708
+ * await requestKeyPair(walletAddress);
4106
3709
  *
4107
- * @param walletAddress - The wallet address to generate the key pair for
4108
- * @param signMessage - Function to sign a message (returns signature hex string)
4109
- * @param embeddedWalletSigner - Optional function for silent signing with embedded wallets
4110
- * @returns Promise that resolves when the key pair is available
4111
- */
4112
- declare function requestKeyPair(walletAddress: string, signMessage: SignMessageFn, embeddedWalletSigner?: EmbeddedWalletSignerFn): Promise<void>;
4113
- /**
4114
- * Exports the public key for a wallet address as SPKI format (base64)
4115
- * @param address - The wallet address
4116
- * @param signMessage - Function to sign a message (returns signature hex string)
4117
- * @param embeddedWalletSigner - Optional function for silent signing with embedded wallets
4118
- * @returns The public key as base64-encoded SPKI string
4119
- */
4120
- declare function exportPublicKey(address: string, signMessage: SignMessageFn, embeddedWalletSigner?: EmbeddedWalletSignerFn): Promise<string>;
4121
- /**
4122
- * Checks if a key pair exists in memory for the given wallet address
4123
- * @param address - The wallet address
4124
- * @returns True if key pair exists, false otherwise
4125
- */
4126
- declare function hasKeyPair(address: string): boolean;
4127
- /**
4128
- * Clears the key pair for a wallet address from memory and localStorage
4129
- * @param address - The wallet address
4130
- */
4131
- declare function clearKeyPair(address: string): void;
4132
- /**
4133
- * Clears all key pairs from memory and any persisted entries in localStorage.
3710
+ * // Export public key to share with others
3711
+ * const publicKey = await exportPublicKey(walletAddress);
3712
+ * console.log("Share this public key:", publicKey);
3713
+ * };
3714
+ * }
3715
+ * ```
4134
3716
  *
4135
- * Matches the persistence behavior of the per-address {@link clearKeyPair};
4136
- * without this, `clearAllKeyPairs()` would leave `ecdh_keypair_*` ciphertext
4137
- * behind in storage while `clearKeyPair(address)` removes it.
4138
- */
4139
- declare function clearAllKeyPairs(): void;
4140
- /**
4141
- * Result returned by the useEncryption hook.
4142
3717
  * @category Hooks
4143
3718
  */
4144
- interface UseEncryptionResult {
4145
- /** Request and generate an encryption key for a wallet address */
4146
- requestEncryptionKey: (walletAddress: string) => Promise<boolean>;
4147
- /** Request and generate an ECDH key pair for a wallet address */
4148
- requestKeyPair: (walletAddress: string) => Promise<void>;
4149
- /** Export the public key for a wallet address as base64-encoded SPKI */
4150
- exportPublicKey: (walletAddress: string) => Promise<string>;
4151
- /** Check if a key pair exists in memory for a wallet address */
4152
- hasKeyPair: (walletAddress: string) => boolean;
4153
- /** Clear the key pair for a wallet address from memory */
4154
- clearKeyPair: (walletAddress: string) => void;
4155
- }
4156
- /**
4157
- * Hook that provides encryption key management for securing local data.
4158
- *
4159
- * This hook helps you encrypt and decrypt data using a key derived from a wallet
4160
- * signature. It requires `@privy-io/react-auth` for wallet authentication. Keys are
4161
- * stored in memory only and do not persist across page reloads for security.
4162
- *
4163
- * ## How it works
4164
- *
4165
- * 1. User signs a message with their wallet
4166
- * 2. The signature is used to deterministically derive an encryption key
4167
- * 3. The key is stored in memory (not localStorage) for the session
4168
- * 4. Data can be encrypted/decrypted using this key
4169
- * 5. On page reload, user must sign again to derive the key
4170
- *
4171
- * ## Security Features
4172
- *
4173
- * - **In-memory only**: Keys never touch disk or localStorage
4174
- * - **Deterministic**: Same wallet + signature always generates same key
4175
- * - **Session-scoped**: Keys cleared on page reload
4176
- * - **XSS-resistant**: Keys not accessible after page reload
4177
- *
4178
- * ## Embedded Wallet Support
3719
+ declare function useEncryption(signMessage: SignMessageFn, embeddedWalletSigner?: EmbeddedWalletSignerFn): UseEncryptionResult;
3720
+
3721
+ type ChatRecordKind = "conversation" | "message" | "summary" | "project" | "memory_links";
3722
+ type ChatJson = null | boolean | number | string | ChatJson[] | {
3723
+ [key: string]: ChatJson;
3724
+ };
3725
+ /** Whole-record JSON data is encrypted on the device, including all text, vectors and tool events. */
3726
+ interface ChatRecord {
3727
+ kind: ChatRecordKind;
3728
+ id: string;
3729
+ conversationId: string;
3730
+ sortKey: number;
3731
+ createdAt: number;
3732
+ updatedAt: number;
3733
+ isDeleted: boolean;
3734
+ data: {
3735
+ [key: string]: ChatJson;
3736
+ };
3737
+ }
3738
+ interface ChatSnapshot {
3739
+ record: ChatRecord;
3740
+ version: number;
3741
+ serverUpdatedAt: string;
3742
+ }
3743
+ interface ChatWrite {
3744
+ record: ChatRecord;
3745
+ expectedVersion: number;
3746
+ /** Sent and stored unencrypted so vault can run vector search. */
3747
+ embeddings?: number[][];
3748
+ embeddingModel?: string;
3749
+ }
3750
+ interface ChatRef {
3751
+ kind: ChatRecordKind;
3752
+ id: string;
3753
+ }
3754
+ type ChatAccountState = "none" | "migrating" | "active";
3755
+ interface ChatAccount {
3756
+ keyId: string;
3757
+ state: ChatAccountState;
3758
+ recordCount: number;
3759
+ storageBytes: number;
3760
+ vectorCount: number;
3761
+ /** The newest change; read it before loading history and poll `changes` from it. Absent before the first record. */
3762
+ changesCursor?: string;
3763
+ }
3764
+ interface ChatImport {
3765
+ record: ChatRecord;
3766
+ /** Sent and stored unencrypted so vault can run vector search. */
3767
+ embeddings?: number[][];
3768
+ embeddingModel?: string;
3769
+ }
3770
+ interface ChatRevision {
3771
+ kind: ChatRecordKind;
3772
+ id: string;
3773
+ updatedAt: number;
3774
+ isDeleted: boolean;
3775
+ }
3776
+ interface ChatChanges {
3777
+ items: ChatSnapshot[];
3778
+ nextCursor?: string;
3779
+ changesCursor: string;
3780
+ }
3781
+ interface ChatSearchOptions {
3782
+ limit?: number;
3783
+ kinds?: ("message" | "summary")[];
3784
+ conversationId?: string;
3785
+ excludeConversationId?: string;
3786
+ /** Ranks only vectors from this model; vectors stored without one always count. */
3787
+ embeddingModel?: string;
3788
+ signal?: AbortSignal;
3789
+ }
3790
+ interface ChatSearchHit extends ChatSnapshot {
3791
+ chunk: number;
3792
+ score: number;
3793
+ }
3794
+ interface ChatAttachment {
3795
+ id: string;
3796
+ sizeBytes: number;
3797
+ state: "pending" | "committed";
3798
+ ownerKind?: "message" | "summary";
3799
+ ownerId?: string;
3800
+ createdAt: string;
3801
+ committedAt?: string;
3802
+ }
3803
+ interface ChatPresignedUrl {
3804
+ url: string;
3805
+ method: string;
3806
+ headers: Record<string, string>;
3807
+ expiresAt: string;
3808
+ }
3809
+ interface ChatAttachments {
3810
+ create(sizeBytes: number, signal?: AbortSignal): Promise<{
3811
+ attachment: ChatAttachment;
3812
+ upload: ChatPresignedUrl;
3813
+ }>;
3814
+ commit(attachmentId: string, owner: {
3815
+ kind: "message" | "summary";
3816
+ id: string;
3817
+ }, signal?: AbortSignal): Promise<ChatAttachment>;
3818
+ get(attachmentId: string, signal?: AbortSignal): Promise<{
3819
+ attachment: ChatAttachment;
3820
+ download?: ChatPresignedUrl;
3821
+ } | null>;
3822
+ delete(attachmentId: string, signal?: AbortSignal): Promise<void>;
3823
+ }
3824
+ interface ChatListOptions {
3825
+ kind: ChatRecordKind;
3826
+ conversationId?: string;
3827
+ includeDeleted?: boolean;
3828
+ cursor?: string;
3829
+ limit?: number;
3830
+ signal?: AbortSignal;
3831
+ }
3832
+ interface ChatPage {
3833
+ items: ChatSnapshot[];
3834
+ nextCursor?: string;
3835
+ total?: number;
3836
+ }
3837
+ /** Explicit versions protect edits; ambiguous writes are never replayed automatically. */
3838
+ interface ChatStore {
3839
+ get(kind: ChatRecordKind, id: string, signal?: AbortSignal): Promise<ChatSnapshot | null>;
3840
+ list(options: ChatListOptions): Promise<ChatPage>;
3841
+ putMany(writes: readonly ChatWrite[], signal?: AbortSignal): Promise<ChatSnapshot[]>;
3842
+ getMany(refs: readonly ChatRef[], signal?: AbortSignal): Promise<ChatSnapshot[]>;
3843
+ account(signal?: AbortSignal): Promise<ChatAccount>;
3844
+ importRecords(records: readonly ChatImport[], signal?: AbortSignal): Promise<number>;
3845
+ verify(revisions: readonly ChatRevision[], signal?: AbortSignal): Promise<ChatRef[]>;
3846
+ activate(signal?: AbortSignal): Promise<boolean>;
3847
+ changes(cursor?: string, options?: {
3848
+ limit?: number;
3849
+ signal?: AbortSignal;
3850
+ }): Promise<ChatChanges>;
3851
+ search(embedding: readonly number[], options?: ChatSearchOptions): Promise<ChatSearchHit[]>;
3852
+ deleteAll(signal?: AbortSignal): Promise<number>;
3853
+ attachments: ChatAttachments;
3854
+ }
3855
+ interface RemoteChatStoreOptions {
3856
+ baseUrl: string;
3857
+ getToken: () => Promise<string | null>;
3858
+ keyId: string;
3859
+ encrypt: (plaintext: string) => Promise<string>;
3860
+ decrypt: (ciphertext: string) => Promise<string>;
3861
+ fetch?: typeof globalThis.fetch;
3862
+ timeoutMs?: number;
3863
+ signal?: AbortSignal;
3864
+ }
3865
+ declare class ChatStoreError extends Error {
3866
+ readonly status: number;
3867
+ readonly code?: string | undefined;
3868
+ readonly retryAfterMs?: number | undefined;
3869
+ constructor(message: string, status: number, code?: string | undefined, retryAfterMs?: number | undefined);
3870
+ }
3871
+
3872
+ interface ChatMigrationOptions {
3873
+ /** The device's local chat database. */
3874
+ database: Database;
3875
+ /** Vault, opened with the account's canonical key. */
3876
+ store: ChatStore;
3877
+ walletAddress?: string;
3878
+ signMessage?: SignMessageFn;
3879
+ embeddedWalletSigner?: EmbeddedWalletSignerFn;
3880
+ /** Runs the final pass while local chat writers are held, so nothing lands locally after it. */
3881
+ withWriteBarrier: (task: () => Promise<ChatMigrationResult>) => Promise<ChatMigrationResult>;
3882
+ /** Called once vault holds everything; hand the device over to vault here. */
3883
+ onActivated: () => void | Promise<void>;
3884
+ /** Activate even when some rows could not be read; they stay on the device. */
3885
+ allowSkipped?: boolean;
3886
+ maxVectors?: number;
3887
+ maxStorageBytes?: number;
3888
+ signal?: AbortSignal;
3889
+ onProgress?: (progress: ChatMigrationProgress) => void;
3890
+ }
3891
+ interface ChatMigrationProgress {
3892
+ imported: number;
3893
+ toImport: number;
3894
+ }
3895
+ interface ChatMigrationSkip {
3896
+ kind: ChatRecordKind;
3897
+ id: string;
3898
+ reason: "unreadable" | "invalid";
3899
+ }
3900
+ interface ChatMigrationResult {
3901
+ state: "migrating" | "active";
3902
+ conversations: number;
3903
+ messages: number;
3904
+ imported: number;
3905
+ skipped: ChatMigrationSkip[];
3906
+ /** Conversations whose title could not be decrypted and went up untitled. */
3907
+ untitled: number;
3908
+ /** Messages sent without vectors to stay inside the account's vector quota. */
3909
+ unembedded: number;
3910
+ /** Messages shrunk to fit vault's record limit. */
3911
+ truncated: number;
3912
+ }
3913
+ /** Copies this device's chats to vault, verifies them under the write barrier, then activates vault and hands the device over. */
3914
+ declare function migrateChatsToRemote(options: ChatMigrationOptions): Promise<ChatMigrationResult>;
3915
+
3916
+ /** Connect to owner-scoped server storage using the account's canonical device-held cipher. */
3917
+ declare function createRemoteChatStore(options: RemoteChatStoreOptions): Promise<ChatStore>;
3918
+
3919
+ declare class VaultMemory extends Model {
3920
+ static table: string;
3921
+ content: string;
3922
+ scope: string;
3923
+ /** Profile kind, or null for a free-form memory. */
3924
+ kind: string | null;
3925
+ /** Canonical JSON value of a kinded memory, encrypted at rest. */
3926
+ kindValue: string | null;
3927
+ /** private | matching | profile. */
3928
+ level: string | null;
3929
+ folderId: string | null;
3930
+ userId: string | null;
3931
+ embedding: string | null;
3932
+ /** Model that produced `embedding`. Null on legacy rows (grandfathered). */
3933
+ embeddingModel: string | null;
3934
+ sourceChunkIds: string | null;
3935
+ proofCount: number | null;
3936
+ source: string | null;
3937
+ /** W6 temporal lane — Unix ms timestamp of when the event occurred. */
3938
+ eventTimeStart: number | null;
3939
+ /** W6 temporal lane — Unix ms timestamp of event end (range/ongoing). */
3940
+ eventTimeEnd: number | null;
3941
+ /** W6 temporal lane — `point | range | ongoing | null`. */
3942
+ eventTimeKind: string | null;
3943
+ /** When true, the user has manually set this memory's topics; auto-extraction
3944
+ * leaves its entity links alone. Null on legacy rows (treated as false). */
3945
+ topicsUserManaged: boolean | null;
3946
+ /** The durable, synced record of this memory's topics — JSON `StoredTopic[]`.
3947
+ * `entity` / `memory_entity` are a device-local index over it. Null = pre-v42
3948
+ * (backfilled from the row's current links by the sweep). */
3949
+ topics: string | null;
3950
+ /** Unix ms of the last `topics` write. Separate from `updated_at`, which every
3951
+ * topic writer pins on purpose (recall recency) — see the schema note. */
3952
+ topicsUpdatedAt: number | null;
3953
+ /** The photo(s) a SERVER-EXTRACTED memory came from — JSON
3954
+ * `[{feed_item_id, object_key}]`, exactly the shape
3955
+ * GET /api/memories/published returns. Null on anything not from a photo. */
3956
+ media: string | null;
3957
+ /** Unix ms of the last LLM topic-extraction pass. Null = never extracted
3958
+ * standalone (linked legacy rows are grandfathered as extracted).
3959
+ * DEPRECATED (v42) — subsumed by `topics_updated_at`; see the schema note. */
3960
+ topicsExtractedAt: number | null;
3961
+ /** A2 supersession: newer memory id that replaced this one, or null if live. */
3962
+ supersededBy: string | null;
3963
+ supersededAt: number | null;
3964
+ /** Extraction-logic version this memory was last stamped under. Null (pre-v38)
3965
+ * reads as 0, so a TOPICS_EXTRACTION_VERSION bump re-extracts stale rows.
3966
+ * DEPRECATED (v42) — subsumed by `topics_updated_at`; see the schema note. */
3967
+ topicsExtractedVersion: number | null;
3968
+ /** C3 re-observation watermark: Unix ms of the last retain() merge, or null. */
3969
+ lastObservedAt: number | null;
3970
+ /** Typed memory (PR1) — the extractor's FactType. Null on legacy/manual rows. */
3971
+ factType: string | null;
3972
+ /** Decay archive state (PR2) — Unix ms when archived, null when active. */
3973
+ archivedAt: number | null;
3974
+ /** Tier-0 security (PR3) — "quarantined" | "trusted" | null. */
3975
+ trustTier: string | null;
3976
+ /** People Nearby visibility: 'private' | 'public'. Null on legacy rows, and
3977
+ * any unrecognised value, read as 'private' — never published without opt-in. */
3978
+ visibility: string | null;
3979
+ /** Owner opted this memory into their own digital twin (twin-scoped only). */
3980
+ twinOptIn: boolean | null;
3981
+ /** Unix ms when visibility last became non-private; null while private. */
3982
+ publishedAt: number | null;
3983
+ /** Reserved coarse-geohash slot for landmark/Trail memories. */
3984
+ geohash: string | null;
3985
+ createdAt: Date;
3986
+ updatedAt: Date;
3987
+ isDeleted: boolean;
3988
+ }
3989
+
3990
+ /**
3991
+ * A canonical entity (person, place, thing) extracted from the user's
3992
+ * conversations. Many-to-many with vault memories via {@link MemoryEntity}.
4179
3993
  *
4180
- * For Privy embedded wallets, you can provide an `embeddedWalletSigner` function
4181
- * to enable silent signing without user confirmation modals. This is useful for
4182
- * deterministic key generation that should happen automatically.
3994
+ * Created on the write path by the auto-extraction worker (W2) when a
3995
+ * candidate fact arrives with non-empty `entities[]`. Used at retrieval
3996
+ * time as a 3rd RRF lane (W5 graph traversal): query entity overlap
3997
+ * with stored memories surfaces topically-related facts that pure
3998
+ * semantic search misses.
3999
+ */
4000
+ declare class Entity extends Model {
4001
+ static table: string;
4002
+ /** Lowercased, trimmed name used for dedup and lookup. */
4003
+ canonicalName: string;
4004
+ /** Optional category — "person" | "place" | "thing" | "concept" | etc. */
4005
+ kind: string | null;
4006
+ createdAt: Date;
4007
+ updatedAt: Date;
4008
+ }
4009
+ /**
4010
+ * Join row: a memory references an entity (and vice versa). Multiple
4011
+ * rows per memory (one per entity) and per entity (one per memory).
4012
+ */
4013
+ declare class MemoryEntity extends Model {
4014
+ static table: string;
4015
+ memoryId: string;
4016
+ entityId: string;
4017
+ /**
4018
+ * User-scope for the W5 graph lane. Optional because client-side
4019
+ * (single-user) deployments may leave it null; server-side multi-user
4020
+ * deployments must set it so retrieval can filter cross-user IDs.
4021
+ */
4022
+ userId: string | null;
4023
+ createdAt: Date;
4024
+ }
4025
+
4026
+ /**
4027
+ * The recognized entity classifications. Runtime list + derived type kept
4028
+ * in one place so the extractor's validation and the `EntityKind` union
4029
+ * can't drift apart.
4030
+ * @public
4031
+ */
4032
+ declare const ENTITY_KINDS: readonly ["person", "organization", "place", "event", "product", "thing", "concept", "other"];
4033
+ /** @public */
4034
+ type EntityKind = (typeof ENTITY_KINDS)[number];
4035
+ interface StoredEntity {
4036
+ uniqueId: string;
4037
+ canonicalName: string;
4038
+ kind: string | null;
4039
+ createdAt: Date;
4040
+ updatedAt: Date;
4041
+ }
4042
+ /**
4043
+ * Who put a topic on a memory. Written to `memory_vault.topics` but not yet
4044
+ * READ anywhere — it exists so a later improvement can refresh the `auto`
4045
+ * entries of a curated memory while leaving `user` entries alone (today
4046
+ * `topics_user_managed` is all-or-nothing per memory) without needing a second
4047
+ * migration or backfill. Don't build that behavior off it yet.
4183
4048
  *
4184
- * @param signMessage - Function to sign a message (from Privy's useSignMessage hook)
4185
- * @param embeddedWalletSigner - Optional function for silent signing with embedded wallets
4186
- * @returns Functions to request encryption keys and manage key pairs
4049
+ * When you do: a value written by the v42 backfill is NOT ground truth. Pre-v42
4050
+ * rows carry no per-topic provenance, so `backfillMemoryTopicsOp` derives it
4051
+ * from the per-memory `topics_user_managed` flag and stamps a curated legacy
4052
+ * row's every topic `user` — see the note at that derivation.
4053
+ * @public
4054
+ */
4055
+ type TopicSource = "user" | "auto";
4056
+ /**
4057
+ * One entry in `memory_vault.topics` — the durable, synced record of a memory's
4058
+ * topics. `name` carries the CALLER's display casing, unlike
4059
+ * {@link StoredEntity.canonicalName}, which {@link normalizeEntityName}
4060
+ * lowercases and which has no display column: preserving casing here is the
4061
+ * point of storing names on the memory row.
4062
+ * @public
4063
+ */
4064
+ interface StoredTopic {
4065
+ name: string;
4066
+ kind?: string;
4067
+ source: TopicSource;
4068
+ /** How central the topic is to the memory, in (0, 1]; read it with {@link topicWeight}. */
4069
+ weight?: number;
4070
+ }
4071
+ /**
4072
+ * Fixed weight per salience level the topic extractor assigns.
4073
+ * @public
4074
+ */
4075
+ declare const TOPIC_SALIENCE_WEIGHTS: {
4076
+ readonly primary: 1;
4077
+ readonly secondary: 0.6;
4078
+ readonly mention: 0.3;
4079
+ };
4080
+ /** @public */
4081
+ type TopicSalience = keyof typeof TOPIC_SALIENCE_WEIGHTS;
4082
+ /**
4083
+ * A topic's weight: 1 when it is user-set or carries no weight.
4084
+ * @public
4085
+ */
4086
+ declare function topicWeight(topic: StoredTopic): number;
4087
+ /**
4088
+ * The first topic with the highest weight, or null when there are none.
4089
+ * @public
4090
+ */
4091
+ declare function primaryTopic(topics: readonly StoredTopic[] | null | undefined): StoredTopic | null;
4092
+ /** @public */
4093
+ interface CreateEntityOptions {
4094
+ canonicalName: string;
4095
+ kind?: EntityKind | (string & {});
4096
+ }
4097
+
4098
+ /**
4099
+ * Accepted entity shape for {@link linkMemoryEntitiesOp}. A bare string is
4100
+ * a name with no kind (back-compat with the original signature); the object
4101
+ * form carries an optional classification.
4102
+ * @public
4103
+ */
4104
+ type EntityInput = string | {
4105
+ name: string;
4106
+ kind?: EntityKind | (string & {});
4107
+ weight?: number;
4108
+ };
4109
+ interface EntityOperationsContext {
4110
+ database: Database;
4111
+ entityCollection: Collection<Entity>;
4112
+ memoryEntityCollection: Collection<MemoryEntity>;
4113
+ /**
4114
+ * Optional user-scope. When provided, `linkMemoryEntitiesOp` stamps
4115
+ * `user_id` on new memory_entity rows and `getMemoriesByEntityNamesOp`
4116
+ * filters lookups by it. Leave undefined for single-user clients.
4117
+ */
4118
+ userId?: string;
4119
+ /**
4120
+ * When `true`, `getMemoriesByEntityNamesOp` admits rows with
4121
+ * `user_id = null` alongside the strict `userId` match. Set this on
4122
+ * LokiJS (web) adapters where the v31 `unsafeExecuteSql` backfill
4123
+ * is a no-op — pre-v31 rows otherwise become invisible to the W5
4124
+ * lane until `backfillMemoryEntityUserIdsOp` runs. Default `false`
4125
+ * (server / SQLite, where the migration backfill is authoritative).
4126
+ */
4127
+ allowUnscopedRows?: boolean;
4128
+ canWrite?: () => Promise<boolean>;
4129
+ }
4130
+ /**
4131
+ * Link a memory to one or more entities. Accepts bare names (back-compat)
4132
+ * or `{ name, kind }` objects. Names are normalized; missing entities are
4133
+ * auto-created (with their kind), and an existing entity's null kind is
4134
+ * back-filled — see {@link upsertEntitiesInWrite}. Idempotent — duplicate
4135
+ * (memory_id, entity_id) pairs are skipped.
4187
4136
  *
4188
- * @example
4189
- * ```tsx
4190
- * import { usePrivy, useWallets } from "@privy-io/react-auth";
4191
- * import { useEncryption, encryptData, decryptData } from "@anuma/sdk/react";
4137
+ * `options.unlessTopicsUserManaged` re-checks the memory's vault row INSIDE
4138
+ * the serialized writer and skips link creation when the row is user-managed
4139
+ * (`topics_user_managed`), soft-deleted, or absent. Auto paths (extraction,
4140
+ * topic worker) need this: a pre-call check races the LLM round-trip —
4141
+ * `setMemoryEntitiesOp` sets the flag in its own writer and a delete can land
4142
+ * mid-call (orphaning links the cascade already swept) — so only an in-write
4143
+ * check guarantees a user's manual edit or delete can't be grafted over. The
4144
+ * row read fails CLOSED (skip links) so a transient fault never attaches
4145
+ * topics to a memory we couldn't verify. Entity upserts and link creation
4146
+ * run in ONE writer to prevent orphan-prune races; returns [] when links
4147
+ * were skipped.
4192
4148
  *
4193
- * function SecureComponent() {
4194
- * const { user, signMessage } = usePrivy();
4195
- * const { wallets } = useWallets();
4196
- * const embeddedWallet = wallets.find(w => w.walletClientType === 'privy');
4149
+ * `options.topicsSource` (default `auto`) is the provenance recorded in
4150
+ * `memory_vault.topics`, which this rewrites from the memory's FULL resulting
4151
+ * link set — see {@link prepareTopicsUpdate}. Add semantics mean that set is
4152
+ * old ∪ new, so already-linked entities are resolved for their names too.
4197
4153
  *
4198
- * // Create silent signer for embedded wallets
4199
- * const embeddedSigner = useCallback(async (message: string) => {
4200
- * if (embeddedWallet) {
4201
- * const { signature } = await embeddedWallet.signMessage({ message });
4202
- * return signature;
4203
- * }
4204
- * throw new Error('No embedded wallet');
4205
- * }, [embeddedWallet]);
4154
+ * @deprecated App code: use `MemoryStore.addTopics` (`createLocalMemoryStore`).
4155
+ */
4156
+ declare function linkMemoryEntitiesOp(ctx: EntityOperationsContext, memoryId: string, entityInputs: ReadonlyArray<EntityInput>, options?: {
4157
+ unlessTopicsUserManaged?: boolean;
4158
+ topicsSource?: TopicSource;
4159
+ }): Promise<StoredEntity[]>;
4160
+ /**
4161
+ * REPLACE a memory's entity links with an auto-derived set — the topic
4162
+ * worker's write primitive. Unlike {@link setMemoryEntitiesOp} it does NOT
4163
+ * mark the memory user-managed (the pass is automatic), and unlike
4164
+ * {@link linkMemoryEntitiesOp} it removes stale links, so re-extracting an
4165
+ * edited memory drops entities its previous content mentioned ("works at
4166
+ * Acme" → "works at Globex" must unlink Acme). Insert-missing and
4167
+ * destroy-stale are batched in ONE writer, after the same in-write guard as
4168
+ * the link op (user-managed / deleted / absent / read-fault ⇒ skip).
4206
4169
  *
4207
- * const { requestEncryptionKey } = useEncryption(signMessage, embeddedSigner);
4170
+ * That batch also prunes `entity` rows left with no links at all (see
4171
+ * {@link findOrphanedEntities}) — otherwise a topic the extractor has disowned
4172
+ * keeps rendering as a chip that matches no memory.
4208
4173
  *
4209
- * // Request encryption key when user is authenticated
4210
- * useEffect(() => {
4211
- * if (user?.wallet?.address) {
4212
- * // This will use silent signing for embedded wallets
4213
- * await requestEncryptionKey(user.wallet.address);
4214
- * }
4215
- * }, [user]);
4174
+ * Returns the linked entities ([] for an answered-empty set), or null when
4175
+ * the guard skipped — callers must treat null as "not persisted" (e.g. don't
4176
+ * stamp `topics_extracted_at`).
4177
+ */
4178
+ declare function replaceMemoryEntitiesGuardedOp(ctx: EntityOperationsContext, memoryId: string, entityInputs: ReadonlyArray<EntityInput>): Promise<StoredEntity[] | null>;
4179
+ /**
4180
+ * Backfill `memory_entity.user_id` from the parent vault row's user_id.
4181
+ * Idempotent — only touches rows where user_id is null.
4216
4182
  *
4217
- * // Encrypt data
4218
- * const saveSecret = async (text: string) => {
4219
- * const encrypted = await encryptData(text, user.wallet.address);
4220
- * localStorage.setItem("mySecret", encrypted);
4221
- * };
4183
+ * Why this exists: the v31 schema migration backfills via
4184
+ * `unsafeExecuteSql`, which is a no-op on the LokiJS (web) adapter. Native
4185
+ * SQLite installs have already been filled by the migration; web installs
4186
+ * upgrading through v31 keep `user_id=null` on every pre-existing
4187
+ * `memory_entity` row until this helper runs.
4222
4188
  *
4223
- * // Decrypt data
4224
- * const loadSecret = async () => {
4225
- * const encrypted = localStorage.getItem("mySecret");
4226
- * if (encrypted) {
4227
- * const decrypted = await decryptData(encrypted, user.wallet.address);
4228
- * console.log(decrypted);
4229
- * }
4230
- * };
4189
+ * Consumers wiring an `EntityOperationsContext` with `userId` set are
4190
+ * obliged to call this once on first use — `getMemoriesByEntityNamesOp`
4191
+ * strictly filters by `user_id`, so unstamped rows are otherwise
4192
+ * invisible to the W5 graph lane.
4231
4193
  *
4232
- * return (
4233
- * <div>
4234
- * <button onClick={() => saveSecret("my secret data")}>Encrypt & Save</button>
4235
- * <button onClick={loadSecret}>Load & Decrypt</button>
4236
- * </div>
4237
- * );
4238
- * }
4239
- * ```
4194
+ * @public
4195
+ */
4196
+ declare function backfillMemoryEntityUserIdsOp(ctx: EntityOperationsContext, vaultMemoryCollection: {
4197
+ find: (id: string) => Promise<{
4198
+ userId?: string | null;
4199
+ }>;
4200
+ }): Promise<number>;
4201
+ /**
4202
+ * W5 graph-lane read: given a set of entity names (e.g. extracted from
4203
+ * a query), return the set of memory IDs linked to *any* of them, with
4204
+ * a per-memory count of how many of the queried entities they match.
4240
4205
  *
4241
- * @example
4242
- * ```tsx
4243
- * // Standard usage with external wallets (shows confirmation modal)
4244
- * import { usePrivy } from "@privy-io/react-auth";
4245
- * import { useEncryption, encryptData, decryptData } from "@anuma/sdk/react";
4206
+ * Caller passes the result to `rankByEntityOverlap` to score each
4207
+ * memory via `tanh(0.5 × shared_entity_count)` — this op only does the
4208
+ * cheap "find candidate memories" step and leaves scoring to the
4209
+ * ranker so callers can attach their own kind-weights or alternative
4210
+ * scoring strategies later.
4246
4211
  *
4247
- * function SecureComponent() {
4248
- * const { user, signMessage } = usePrivy();
4249
- * const { requestEncryptionKey } = useEncryption(signMessage);
4212
+ * Names are normalized (lowercased, trimmed). Empty input returns an
4213
+ * empty map. Names that don't exist as entities contribute nothing.
4250
4214
  *
4251
- * // Request encryption key when user is authenticated
4252
- * useEffect(() => {
4253
- * if (user?.wallet?.address) {
4254
- * // This will prompt user to sign if key doesn't exist
4255
- * await requestEncryptionKey(user.wallet.address);
4256
- * }
4257
- * }, [user]);
4258
- * }
4259
- * ```
4215
+ * Multi-user safety: when `ctx.userId` is set, results are filtered to
4216
+ * memory_entity rows whose `user_id` matches. Without this filter the
4217
+ * lane returns IDs from every user who tagged a matching entity.
4260
4218
  *
4261
- * @example
4262
- * ```tsx
4263
- * // ECDH key pair generation for end-to-end encryption
4264
- * import { usePrivy } from "@privy-io/react-auth";
4265
- * import { useEncryption } from "@anuma/sdk/react";
4219
+ * @deprecated App code: use `MemoryStore.memoriesByTopics` (`createLocalMemoryStore`).
4220
+ */
4221
+ declare function getMemoriesByEntityNamesOp(ctx: EntityOperationsContext, entityNames: readonly string[]): Promise<Map<string, Set<string>>>;
4222
+ /**
4223
+ * Reverse of {@link getMemoriesByEntityNamesOp}: given a set of memory IDs
4224
+ * (e.g. the current BFS frontier), return each memory's set of linked
4225
+ * canonical entity names. This is the missing primitive for multi-hop graph
4226
+ * traversal (PR4) — one step outward from a memory to its neighbor entities,
4227
+ * which the traversal then expands to reach topically-adjacent memories.
4266
4228
  *
4267
- * function E2EEComponent() {
4268
- * const { signMessage } = usePrivy();
4269
- * const { requestKeyPair, exportPublicKey } = useEncryption(signMessage);
4229
+ * Empty input returns an empty map. Memory IDs with no links contribute
4230
+ * nothing (they simply don't appear as keys).
4270
4231
  *
4271
- * const setupEncryption = async (walletAddress: string) => {
4272
- * // Generate deterministic ECDH key pair from wallet signature
4273
- * await requestKeyPair(walletAddress);
4232
+ * Multi-user safety mirrors {@link getMemoriesByEntityNamesOp} exactly: when
4233
+ * `ctx.userId` is set, only `memory_entity` rows owned by that user are
4234
+ * followed (with the same `allowUnscopedRows` LokiJS escape hatch for pre-v31
4235
+ * rows whose `user_id` backfill was a no-op). Without the filter the reverse
4236
+ * lookup would leak entity links written by other users.
4274
4237
  *
4275
- * // Export public key to share with others
4276
- * const publicKey = await exportPublicKey(walletAddress);
4277
- * console.log("Share this public key:", publicKey);
4278
- * };
4279
- * }
4280
- * ```
4238
+ * @public
4281
4239
  *
4282
- * @category Hooks
4240
+ * @deprecated App code: use `MemoryStore.topicsByMemories` (`createLocalMemoryStore`).
4283
4241
  */
4284
- declare function useEncryption(signMessage: SignMessageFn, embeddedWalletSigner?: EmbeddedWalletSignerFn): UseEncryptionResult;
4242
+ declare function getEntitiesByMemoryIdsOp(ctx: EntityOperationsContext, memoryIds: readonly string[]): Promise<Map<string, Set<string>>>;
4285
4243
 
4286
4244
  /**
4287
4245
  * Checks if a string value is encrypted (has the enc:v2: or enc:v3: prefix with valid hex payload).
@@ -4650,292 +4608,121 @@ interface MemoryVaultSearchOptions {
4650
4608
  admitFloor?: number;
4651
4609
  }
4652
4610
  /**
4653
- * Pre-embed all vault memories that are not yet in the cache.
4654
- * Call this at init time so searches are instant.
4655
- */
4656
- declare function preEmbedVaultMemories(vaultCtx: VaultMemoryOperationsContext, embeddingOptions: EmbeddingOptions, cache: VaultEmbeddingCache, options?: {
4657
- scopes?: string[];
4658
- }): Promise<void>;
4659
- /**
4660
- * Eagerly embed a single piece of content and store it in the cache.
4661
- * Call this when a vault memory is created or updated.
4662
- */
4663
- declare function eagerEmbedContent(content: string, embeddingOptions: EmbeddingOptions, cache: VaultEmbeddingCache, vaultCtx?: VaultMemoryOperationsContext, memoryId?: string,
4664
- /**
4665
- * `updatedAt` of the committed row this content belongs to. When given, the
4666
- * cache entry is tied to that row version; without it the entry is
4667
- * unversioned and a search re-resolves it from the stored column instead of
4668
- * trusting it (see `vectorVersion.ts`).
4669
- */
4670
- updatedAt?: Date): Promise<void>;
4671
- interface CorpusStats {
4672
- keysMs: number;
4673
- embeddingsFetchMs: number;
4674
- rowsFetchMs: number;
4675
- cacheHits: number;
4676
- cacheMisses: number;
4677
- }
4678
- /**
4679
- * A single vault search result with its similarity score.
4680
- */
4681
- interface VaultSearchResult {
4682
- uniqueId: string;
4683
- content: string;
4684
- similarity: number;
4685
- /** Optional — surfaced by the rankers so downstream `RankedMemory` carries
4686
- * real timestamps. Omitted when an item lacks the field upstream. */
4687
- createdAt?: Date;
4688
- updatedAt?: Date;
4689
- /** Times this fact has been re-observed — for C2 trend labels. */
4690
- proofCount?: number | null;
4691
- /** C3 re-observation watermark (Unix ms) — for C2 trends + C4 CE dates. */
4692
- lastObservedAt?: number | null;
4693
- /** W6 temporal-lane anchors carried through to downstream `RankedMemory`
4694
- * so the recall executor can surface dates to the answer model without
4695
- * a second per-fact DB lookup + decrypt. Unix ms; null when the fact
4696
- * has no anchored event time. */
4697
- eventTimeStart?: number | null;
4698
- eventTimeEnd?: number | null;
4699
- eventTimeKind?: "point" | "range" | "ongoing" | null;
4700
- /** Typed memory (PR1) — the fact's FactType, threaded through from the
4701
- * storage row alongside the event-time anchors. Null/undefined when
4702
- * untyped. Loose string (originates from a stored column). */
4703
- factType?: string | null;
4704
- /** Message ids this fact was extracted from (provenance). recall() uses
4705
- * these to suppress the originating chunk in the chunk lane. */
4706
- sourceChunkIds?: string[] | null;
4707
- }
4708
- /**
4709
- * Search + rank in one call. Thin wrapper over {@link prepareVaultCandidates} +
4710
- * {@link rankPreparedVaultCandidates}; behavior is unchanged.
4711
- */
4712
- declare function searchVaultMemoriesWithSize(query: string, vaultCtx: VaultMemoryOperationsContext, embeddingOptions: EmbeddingOptions, cache: VaultEmbeddingCache, searchOptions?: MemoryVaultSearchOptions): Promise<{
4713
- results: VaultSearchResult[];
4714
- vaultSize: number;
4715
- reranked: boolean;
4716
- /**
4717
- * Wall-clock ms this search spent inside the cross-encoder.
4718
- *
4719
- * 0 on every path that did not reach the CE, which `reranked` already
4720
- * distinguishes from "ran and cost nothing". Reported because `factLane`
4721
- * timing alone could not separate the rerank from the query embed, the vault
4722
- * read and the fused ranking — see {@link RerankStats}.
4723
- */
4724
- rerankMs: number;
4725
- hadV2Head: boolean;
4726
- /** True when this search had no usable cosine lane and ranked on BM25 alone. */
4727
- embeddingsUnavailable: boolean;
4728
- /**
4729
- * True when this search actually scored rows against a real query vector.
4730
- *
4731
- * NOT the inverse of `embeddingsUnavailable`. That flag answers "did cosine
4732
- * break?", and it is `false` on the degenerate returns below — an invalid
4733
- * query, an empty scope, nothing decryptable — where cosine did not break so
4734
- * much as never run. A caller asking "can this lane vouch that semantic
4735
- * ranking happened?" (recall's chunk-lane reconciliation) must not read those
4736
- * as a healthy cosine pass.
4737
- */
4738
- rankedOnCosine: boolean;
4739
- /**
4740
- * Which vault read path ran — projected key scan (`true`) or legacy whole-vault
4741
- * load (`false`). See {@link PreparedVaultCandidates.decryptLast}.
4742
- */
4743
- decryptLast: boolean;
4744
- /**
4745
- * Rows this search paid to decrypt. Read against `vaultSize` — see
4746
- * {@link PreparedVaultCandidates.rowsDecrypted}.
4747
- */
4748
- rowsDecrypted: number;
4749
- /**
4750
- * Wall-clock ms spent embedding the query, and rows the lane had to re-embed
4751
- * because their stored vector was unusable — see
4752
- * {@link PreparedVaultCandidates.queryEmbedMs} and `rowsEmbedded`.
4753
- */
4754
- queryEmbedMs: number;
4755
- rowsEmbedded: number;
4756
- corpusStats?: CorpusStats;
4757
- }>;
4758
- /**
4759
- * Search vault memories by semantic similarity. Returns structured results
4760
- * sorted by descending similarity, filtered by threshold and limit.
4761
- *
4762
- * This is the standalone search logic extracted from `createMemoryVaultSearchTool`
4763
- * so it can be called programmatically (e.g., for pre-retrieval injection).
4764
- *
4765
- * @returns Sorted results (empty array on invalid input or empty vault)
4766
- */
4767
- declare function searchVaultMemories(query: string, vaultCtx: VaultMemoryOperationsContext, embeddingOptions: EmbeddingOptions, cache: VaultEmbeddingCache, searchOptions?: MemoryVaultSearchOptions): Promise<VaultSearchResult[]>;
4768
-
4769
- interface StorageOperationsContext {
4770
- database: Database;
4771
- messagesCollection: Collection<Message>;
4772
- conversationsCollection: Collection<Conversation>;
4773
- /** Wallet address for encryption (optional - when present, enables field-level encryption) */
4774
- walletAddress?: string;
4775
- /** Function to sign a message for encryption key derivation */
4776
- signMessage?: SignMessageFn;
4777
- /** Function for silent signing with embedded wallets */
4778
- embeddedWalletSigner?: EmbeddedWalletSignerFn;
4779
- }
4780
- /**
4781
- * Lazy variant of {@link getConversationsOp}.
4782
- *
4783
- * Returns conversations with their raw stored title under
4784
- * `encryptedTitle` instead of a decrypted `title`. Callers should pair
4785
- * this with {@link decryptConversationTitle} (or the underlying
4786
- * `decryptField`) and decrypt only when a row is rendered.
4787
- *
4788
- * Behavior is identical to `getConversationsOp` except for the title
4789
- * projection — sort order, soft-delete filtering, and active-conversation
4790
- * scoping all match.
4791
- *
4792
- * Encryption context on `ctx` is intentionally ignored: this op never
4793
- * decrypts. That is also why the test for this op asserts call count
4794
- * for `decryptField` is exactly zero.
4795
- */
4796
- declare function getConversationsLazyOp(ctx: StorageOperationsContext): Promise<LazyStoredConversation[]>;
4797
- /**
4798
- * Keyset-paginated, lazy (no-decrypt) variant of {@link getConversationsLazyOp}.
4799
- *
4800
- * Returns at most `limit` conversations (newest first by `created_at`), each
4801
- * with its raw stored title under `encryptedTitle` — pair with
4802
- * {@link decryptConversationTitle} to decrypt on render. Page through older
4803
- * threads by passing the oldest loaded `createdAt` as `before` plus the
4804
- * uniqueIds held at that boundary as `boundaryExcludeUniqueIds`.
4805
- *
4806
- * Decrypts nothing and builds no WatermelonDB Model (the never-evicted
4807
- * RecordCache stays empty — web Pile-2). Sort order, soft-delete filtering,
4808
- * and the encrypted-title projection all match `getConversationsLazyOp`.
4809
- */
4810
- declare function getConversationsPageOp(ctx: StorageOperationsContext, options?: GetConversationsPageOptions): Promise<LazyStoredConversation[]>;
4811
- /**
4812
- * Lazy variant of {@link getConversationsByProjectOp}.
4813
- *
4814
- * Same encrypted-title projection as {@link getConversationsLazyOp},
4815
- * filtered by project assignment. Pass `null` to retrieve conversations
4816
- * with no project.
4817
- */
4818
- declare function getConversationsByProjectLazyOp(ctx: StorageOperationsContext, projectId: string | null): Promise<LazyStoredConversation[]>;
4819
- /**
4820
- * Update a conversation's project assignment.
4821
- * Pass null to remove the conversation from any project.
4822
- */
4823
- declare function updateConversationProjectOp(ctx: StorageOperationsContext, id: string, projectId: string | null): Promise<boolean>;
4824
- /**
4825
- * Get conversations filtered by project ID.
4826
- * Pass null to get conversations that don't belong to any project.
4827
- */
4828
- declare function getConversationsByProjectOp(ctx: StorageOperationsContext, projectId: string | null): Promise<StoredConversation[]>;
4829
- /**
4830
- * Delete a single message by its unique ID.
4831
- * Clears file_ids before deletion and returns the unique ID.
4832
- * Note: Callers should use deleteMediaByMessageOp to cascade delete media.
4833
- */
4834
- declare function deleteMessageOp(ctx: StorageOperationsContext, uniqueId: string): Promise<string | null>;
4835
- /** Decrypts raw message embedding columns with the cached wallet key. */
4836
- declare function decryptMessageEmbeddingFields(raw: Record<string, unknown>, walletAddress?: string): Promise<Record<string, unknown>>;
4837
- /** Seals legacy message embedding columns and discards chunks with invalid plaintext offsets. */
4838
- declare function sealLegacyMessageEmbeddingsOp(ctx: StorageOperationsContext): Promise<number>;
4839
- /**
4840
- * Removes the plaintext `text` that rows chunked before sdk#889 still carry in
4841
- * their `chunks` column. Since #889 `updateMessageChunksOp` never writes it, so
4842
- * a stored `text` key identifies exactly the rows written before that change.
4843
- * Readers rebuild the snippet from the offsets every row already has; a row
4844
- * edited after it was chunked fails `resolveChunkText`'s coverage check and
4845
- * shows the whole message instead.
4846
- *
4847
- * Every device must call it: each strips only its own local copy. Backups hold
4848
- * whole rows encrypted, and a restore brings the text back until the next call.
4849
- * Idempotent: a stripped row no longer matches, so calling it once per session
4850
- * is safe. `updated_at` is kept as it was, so backup sync does not re-upload
4851
- * every old row (the chunk vectors are most of each row's size).
4852
- *
4853
- * Reads raw rows a page at a time and builds Models only for the rows it
4854
- * changes, so unchanged candidates never enter the record cache, and each
4855
- * write stays small enough not to hold up chat saves.
4856
- *
4857
- * @returns Number of rows stripped.
4858
- */
4859
- declare function stripLegacyChunkTextOp(ctx: StorageOperationsContext): Promise<number>;
4860
- /**
4861
- * Encrypts tool call arguments and results still stored in plaintext and
4862
- * returns how many rows changed, giving each touched conversation a new
4863
- * `updatedAt` so backups re-upload it, which moves it to the top of any list
4864
- * sorted by `updatedAt`.
4865
- */
4866
- declare function encryptToolCallEventsOp(ctx: StorageOperationsContext): Promise<number>;
4867
- /**
4868
- * Update the feedback (like/dislike) for a message.
4869
- * Each regenerated response can have its own independent feedback.
4870
- *
4871
- * @param ctx - Storage operations context
4872
- * @param uniqueId - The unique ID of the message to update
4873
- * @param feedback - 'like', 'dislike', or null to clear feedback
4874
- * @returns The updated message or null if not found
4875
- */
4876
- declare function updateMessageFeedbackOp(ctx: StorageOperationsContext, uniqueId: string, feedback: MessageFeedback): Promise<StoredMessage | null>;
4877
- declare function searchMessagesOp(ctx: StorageOperationsContext, queryVector: number[], options?: {
4878
- limit?: number;
4879
- minSimilarity?: number;
4880
- conversationId?: string;
4881
- }): Promise<StoredMessageWithSimilarity[]>;
4882
- /**
4883
- * Decrypted, model-native chunk vectors for one message, cached across recall
4884
- * calls so the chunk lane doesn't re-decrypt + re-JSON.parse every message's
4885
- * embeddings on every query. Keyed by message id; `version` is the message's
4886
- * `updated_at` at cache time, so a re-embed (which bumps `updated_at`) misses
4887
- * and repopulates. Vectors are stored Float32 — model-native precision, half
4888
- * the RAM of float64 `number[]` — mirroring the vault embedding cache (#705).
4889
- * Content text is deliberately NOT cached (see searchChunksOp): it isn't
4890
- * needed for scoring, and keeping decrypted content out of the cache preserves
4891
- * the SDK's data-at-rest posture.
4892
- */
4893
- interface CachedChunkVectors {
4894
- /** Message `updated_at` (ms) at cache time — the invalidation token. */
4895
- version: number;
4896
- /**
4897
- * Per-chunk embedding vectors, index-aligned with the message's decrypted
4898
- * `chunks` array (empty-vector chunks kept as zero-length placeholders so
4899
- * indices stay aligned). Empty when the message has only a whole-message
4900
- * `fallback` vector.
4901
- */
4902
- chunks: Float32Array[];
4903
- /** Whole-message vector when the message was embedded without chunking. */
4904
- fallback?: Float32Array;
4905
- }
4906
- /**
4907
- * Cache consumed by {@link searchChunksOp}, keyed by message id. A plain `Map`
4908
- * (satisfied by the LRU from `createChunkVectorCache`) — mirrors
4909
- * `VaultEmbeddingCache` so consumers get the same `clear()`/`delete()`
4910
- * ergonomics on an encryption-key reset.
4611
+ * Pre-embed all vault memories that are not yet in the cache.
4612
+ * Call this at init time so searches are instant.
4911
4613
  */
4912
- type ChunkVectorCache = Map<string, CachedChunkVectors>;
4913
- /** Row counts from one {@link searchChunksOp} call. */
4914
- interface ChunkSearchStats {
4915
- /** Embedded messages in live conversations that the search considered. */
4916
- rowsScanned: number;
4917
- /** Messages whose vectors were read from storage because the cache missed. */
4918
- rowsFetched: number;
4919
- /** Messages scored straight from the vector cache. */
4614
+ declare function preEmbedVaultMemories(vaultCtx: VaultMemoryOperationsContext, embeddingOptions: EmbeddingOptions, cache: VaultEmbeddingCache, options?: {
4615
+ scopes?: string[];
4616
+ }): Promise<void>;
4617
+ /**
4618
+ * Eagerly embed a single piece of content and store it in the cache.
4619
+ * Call this when a vault memory is created or updated.
4620
+ */
4621
+ declare function eagerEmbedContent(content: string, embeddingOptions: EmbeddingOptions, cache: VaultEmbeddingCache, vaultCtx?: VaultMemoryOperationsContext, memoryId?: string,
4622
+ /**
4623
+ * `updatedAt` of the committed row this content belongs to. When given, the
4624
+ * cache entry is tied to that row version; without it the entry is
4625
+ * unversioned and a search re-resolves it from the stored column instead of
4626
+ * trusting it (see `vectorVersion.ts`).
4627
+ */
4628
+ updatedAt?: Date): Promise<void>;
4629
+ interface CorpusStats {
4630
+ keysMs: number;
4631
+ embeddingsFetchMs: number;
4632
+ rowsFetchMs: number;
4920
4633
  cacheHits: number;
4634
+ cacheMisses: number;
4921
4635
  }
4922
4636
  /**
4923
- * Search through message chunks for fine-grained semantic search.
4924
- * Returns the matching chunk text along with the parent message.
4637
+ * A single vault search result with its similarity score.
4925
4638
  */
4926
- declare function searchChunksOp(ctx: StorageOperationsContext, queryVector: number[], options?: {
4927
- limit?: number;
4928
- minSimilarity?: number;
4929
- conversationId?: string;
4930
- /** Skip every message in this conversation before scoring. */
4931
- excludeConversationId?: string;
4932
- /** Current embedding model; messages stored under a different non-null model are skipped. */
4933
- embeddingModel?: string;
4934
- /** Decrypted-vector cache, validated by `updated_at`. */
4935
- chunkCache?: ChunkVectorCache;
4936
- /** Receives row counts for the call. */
4937
- onStats?: (stats: ChunkSearchStats) => void;
4938
- }): Promise<ChunkSearchResult[]>;
4639
+ interface VaultSearchResult {
4640
+ uniqueId: string;
4641
+ content: string;
4642
+ similarity: number;
4643
+ /** Optional — surfaced by the rankers so downstream `RankedMemory` carries
4644
+ * real timestamps. Omitted when an item lacks the field upstream. */
4645
+ createdAt?: Date;
4646
+ updatedAt?: Date;
4647
+ /** Times this fact has been re-observed — for C2 trend labels. */
4648
+ proofCount?: number | null;
4649
+ /** C3 re-observation watermark (Unix ms) — for C2 trends + C4 CE dates. */
4650
+ lastObservedAt?: number | null;
4651
+ /** W6 temporal-lane anchors carried through to downstream `RankedMemory`
4652
+ * so the recall executor can surface dates to the answer model without
4653
+ * a second per-fact DB lookup + decrypt. Unix ms; null when the fact
4654
+ * has no anchored event time. */
4655
+ eventTimeStart?: number | null;
4656
+ eventTimeEnd?: number | null;
4657
+ eventTimeKind?: "point" | "range" | "ongoing" | null;
4658
+ /** Typed memory (PR1) — the fact's FactType, threaded through from the
4659
+ * storage row alongside the event-time anchors. Null/undefined when
4660
+ * untyped. Loose string (originates from a stored column). */
4661
+ factType?: string | null;
4662
+ /** Message ids this fact was extracted from (provenance). recall() uses
4663
+ * these to suppress the originating chunk in the chunk lane. */
4664
+ sourceChunkIds?: string[] | null;
4665
+ }
4666
+ /**
4667
+ * Search + rank in one call. Thin wrapper over {@link prepareVaultCandidates} +
4668
+ * {@link rankPreparedVaultCandidates}; behavior is unchanged.
4669
+ */
4670
+ declare function searchVaultMemoriesWithSize(query: string, vaultCtx: VaultMemoryOperationsContext, embeddingOptions: EmbeddingOptions, cache: VaultEmbeddingCache, searchOptions?: MemoryVaultSearchOptions): Promise<{
4671
+ results: VaultSearchResult[];
4672
+ vaultSize: number;
4673
+ reranked: boolean;
4674
+ /**
4675
+ * Wall-clock ms this search spent inside the cross-encoder.
4676
+ *
4677
+ * 0 on every path that did not reach the CE, which `reranked` already
4678
+ * distinguishes from "ran and cost nothing". Reported because `factLane`
4679
+ * timing alone could not separate the rerank from the query embed, the vault
4680
+ * read and the fused ranking — see {@link RerankStats}.
4681
+ */
4682
+ rerankMs: number;
4683
+ hadV2Head: boolean;
4684
+ /** True when this search had no usable cosine lane and ranked on BM25 alone. */
4685
+ embeddingsUnavailable: boolean;
4686
+ /**
4687
+ * True when this search actually scored rows against a real query vector.
4688
+ *
4689
+ * NOT the inverse of `embeddingsUnavailable`. That flag answers "did cosine
4690
+ * break?", and it is `false` on the degenerate returns below — an invalid
4691
+ * query, an empty scope, nothing decryptable — where cosine did not break so
4692
+ * much as never run. A caller asking "can this lane vouch that semantic
4693
+ * ranking happened?" (recall's chunk-lane reconciliation) must not read those
4694
+ * as a healthy cosine pass.
4695
+ */
4696
+ rankedOnCosine: boolean;
4697
+ /**
4698
+ * Which vault read path ran — projected key scan (`true`) or legacy whole-vault
4699
+ * load (`false`). See {@link PreparedVaultCandidates.decryptLast}.
4700
+ */
4701
+ decryptLast: boolean;
4702
+ /**
4703
+ * Rows this search paid to decrypt. Read against `vaultSize` — see
4704
+ * {@link PreparedVaultCandidates.rowsDecrypted}.
4705
+ */
4706
+ rowsDecrypted: number;
4707
+ /**
4708
+ * Wall-clock ms spent embedding the query, and rows the lane had to re-embed
4709
+ * because their stored vector was unusable — see
4710
+ * {@link PreparedVaultCandidates.queryEmbedMs} and `rowsEmbedded`.
4711
+ */
4712
+ queryEmbedMs: number;
4713
+ rowsEmbedded: number;
4714
+ corpusStats?: CorpusStats;
4715
+ }>;
4716
+ /**
4717
+ * Search vault memories by semantic similarity. Returns structured results
4718
+ * sorted by descending similarity, filtered by threshold and limit.
4719
+ *
4720
+ * This is the standalone search logic extracted from `createMemoryVaultSearchTool`
4721
+ * so it can be called programmatically (e.g., for pre-retrieval injection).
4722
+ *
4723
+ * @returns Sorted results (empty array on invalid input or empty vault)
4724
+ */
4725
+ declare function searchVaultMemories(query: string, vaultCtx: VaultMemoryOperationsContext, embeddingOptions: EmbeddingOptions, cache: VaultEmbeddingCache, searchOptions?: MemoryVaultSearchOptions): Promise<VaultSearchResult[]>;
4939
4726
 
4940
4727
  /** Recent window — observations inside this count as "active". */
4941
4728
  declare const TREND_RECENT_WINDOW_DAYS = 30;
@@ -5204,8 +4991,10 @@ interface RecallContext {
5204
4991
  factSource?: RecallFactSource;
5205
4992
  /** Required when `types` includes 'fact'. */
5206
4993
  vaultCtx?: VaultMemoryOperationsContext;
5207
- /** Required when `types` includes 'chunk'. */
4994
+ /** Required when `types` includes 'chunk', unless `chats` is given. */
5208
4995
  storageCtx?: StorageOperationsContext;
4996
+ /** Chat chunk search; takes precedence over `storageCtx`. */
4997
+ chats?: Pick<ChatBackend, "searchChunks">;
5209
4998
  /** Embedding API options. */
5210
4999
  embeddingOptions: EmbeddingOptions;
5211
5000
  /** Vault embedding LRU cache. */
@@ -8510,6 +8299,27 @@ interface LazyStoredConversation extends Omit<StoredConversation, "title"> {
8510
8299
  interface StoredMessageWithSimilarity extends StoredMessage {
8511
8300
  similarity: number;
8512
8301
  }
8302
+ /**
8303
+ * Cached conversation summary for progressive history summarization.
8304
+ *
8305
+ * Instead of sending all conversation history verbatim on every message,
8306
+ * older messages are progressively summarized into a compact text.
8307
+ * This reduces input tokens by 50-70% for long conversations.
8308
+ */
8309
+ interface StoredConversationSummary {
8310
+ /** WatermelonDB record ID */
8311
+ uniqueId: string;
8312
+ /** Conversation this summary belongs to */
8313
+ conversationId: string;
8314
+ /** The progressive summary text */
8315
+ summary: string;
8316
+ /** uniqueId of the last message included in the summary */
8317
+ summarizedUpTo: string;
8318
+ /** Approximate token count of the summary (chars / 4) */
8319
+ tokenCount: number;
8320
+ createdAt: Date;
8321
+ updatedAt: Date;
8322
+ }
8513
8323
  /**
8514
8324
  * A chunk of a message with its own embedding for fine-grained search
8515
8325
  */
@@ -8629,6 +8439,8 @@ interface BaseUseChatStorageOptions {
8629
8439
  database: Database;
8630
8440
  /** Route memory operations through this store; `null` disables memory access while `undefined` uses the local vault. Folders are unsupported. With `piiRedaction` on, build the store with `embeddingOptions.maskInput` or its memory calls throw. */
8631
8441
  memoryStore?: MemoryStore | null;
8442
+ /** Builds the chat storage backend (default: this `database`); keep it stable across renders, since a new factory rebuilds the backend and every callback. */
8443
+ chatBackend?: ChatBackendFactory;
8632
8444
  /** ID of an existing conversation to load and continue */
8633
8445
  conversationId?: string;
8634
8446
  /** Automatically create a new conversation if none is set (default: true) */
@@ -9004,206 +8816,721 @@ interface BaseSendMessageWithStorageArgs {
9004
8816
  * Additional context from memory/RAG system to include in the request.
9005
8817
  * Typically contains retrieved relevant information from past conversations.
9006
8818
  */
9007
- memoryContext?: string;
8819
+ memoryContext?: string;
8820
+ /**
8821
+ * Additional context from search results to include in the request.
8822
+ * Typically contains relevant information from web or document searches.
8823
+ */
8824
+ searchContext?: string;
8825
+ /**
8826
+ * Additional context from preprocessed file attachments.
8827
+ * Contains extracted text from Excel, Word, PDF, and other document files.
8828
+ * Injected as a system message so it's available throughout the conversation.
8829
+ */
8830
+ fileContext?: string;
8831
+ /**
8832
+ * Search sources to attach to the stored message for citation/reference.
8833
+ * Note: Sources are also automatically extracted from tool_call_events in the response.
8834
+ */
8835
+ sources?: SearchSource[];
8836
+ /**
8837
+ * Activity phases for tracking the request lifecycle in the UI.
8838
+ * Each phase represents a step like "Searching", "Thinking", "Generating".
8839
+ * The final phase is automatically marked as completed when stored.
8840
+ *
8841
+ * Note: If you need activity phases that are added during streaming (e.g., server tool calls),
8842
+ * use `getThoughtProcess` callback instead, which captures phases AFTER streaming completes.
8843
+ */
8844
+ thoughtProcess?: ActivityPhase[];
8845
+ /**
8846
+ * Callback to get activity phases AFTER streaming completes.
8847
+ * Use this instead of `thoughtProcess` when phases are added dynamically during streaming
8848
+ * (e.g., via server tool call events like "Searching...", "Generating image...").
8849
+ *
8850
+ * If both `thoughtProcess` and `getThoughtProcess` are provided, `getThoughtProcess` takes precedence.
8851
+ */
8852
+ getThoughtProcess?: () => ActivityPhase[];
8853
+ /**
8854
+ * Controls randomness in the response (0.0 to 2.0).
8855
+ * Lower values make output more deterministic, higher values more creative.
8856
+ */
8857
+ temperature?: number;
8858
+ /**
8859
+ * Maximum number of tokens to generate in the response.
8860
+ * Use this to limit response length and control costs.
8861
+ */
8862
+ maxOutputTokens?: number;
8863
+ /**
8864
+ * Client-side tools with optional executors.
8865
+ * These tools run in the browser/app and can have JavaScript executor functions.
8866
+ */
8867
+ clientTools?: LlmapiChatCompletionTool[];
8868
+ /**
8869
+ * Server-side tools to include from /api/v1/tools.
8870
+ * - undefined: Include all server-side tools (default)
8871
+ * - string[]: Include only tools with these names
8872
+ * - []: Include no server-side tools
8873
+ * - function: Dynamic filter that receives prompt embedding(s) and all tools,
8874
+ * returns tool names to include. Useful for semantic tool matching.
8875
+ *
8876
+ * @example
8877
+ * // Include only specific server tools
8878
+ * serverTools: ["anuma_create_image", "perplexity_search"]
8879
+ *
8880
+ * // Disable server tools for this request
8881
+ * serverTools: []
8882
+ *
8883
+ * // Semantic tool matching based on prompt
8884
+ * serverTools: (embeddings, tools) => {
8885
+ * const matches = findMatchingTools(embeddings, tools, { limit: 5 });
8886
+ * return matches.map(m => m.tool.name);
8887
+ * }
8888
+ */
8889
+ serverTools?: ServerToolsFilter;
8890
+ /**
8891
+ * Dynamic filter for client-side tools based on prompt embeddings.
8892
+ * Receives the prompt embedding(s) (or null for short messages) and all client tools,
8893
+ * returns tool names to include. Tools not in the returned list are excluded from the request.
8894
+ *
8895
+ * @example
8896
+ * clientToolsFilter: (embeddings, tools) => {
8897
+ * if (!embeddings) return []; // Short message — no client tools
8898
+ * const matches = findMatchingTools(embeddings, pseudoServerTools);
8899
+ * return matches.map(m => m.tool.name);
8900
+ * }
8901
+ */
8902
+ clientToolsFilter?: ClientToolsFilterFn;
8903
+ /**
8904
+ * Controls which tool the model should use:
8905
+ * - "auto": Model decides whether to use a tool (default)
8906
+ * - "any": Model must use one of the provided tools
8907
+ * - "none": Model cannot use any tools
8908
+ * - "required": Model must use a tool
8909
+ * - Specific tool name: Model must use that specific tool
8910
+ */
8911
+ toolChoice?: string;
8912
+ /**
8913
+ * Maximum number of tool execution rounds before forcing the model to respond with text.
8914
+ * After this many rounds, `toolChoice` is set to `"none"` on the next continuation,
8915
+ * so the model produces a text answer using whatever tool results it has gathered.
8916
+ * @default 3
8917
+ */
8918
+ maxToolRounds?: number;
8919
+ /**
8920
+ * Reasoning configuration for o-series and other reasoning models.
8921
+ * Controls reasoning effort level and whether to include reasoning summary.
8922
+ */
8923
+ reasoning?: LlmapiResponseReasoning;
8924
+ /**
8925
+ * Extended thinking configuration for Anthropic models (Claude).
8926
+ * Enables the model to think through complex problems step by step
8927
+ * before generating the final response.
8928
+ */
8929
+ thinking?: LlmapiThinkingOptions;
8930
+ /** User-selected image generation model for server-side enforcement. */
8931
+ imageModel?: string;
9008
8932
  /**
9009
- * Additional context from search results to include in the request.
9010
- * Typically contains relevant information from web or document searches.
8933
+ * Per-request callback for thinking/reasoning chunks.
8934
+ * Called with delta chunks as the model "thinks" through a problem.
8935
+ * Use this to display thinking progress in the UI.
9011
8936
  */
9012
- searchContext?: string;
8937
+ onThinking?: (chunk: string) => void;
8938
+ /** Parent message ID for branching (edit/regenerate). Sets on the user message. */
8939
+ parentMessageId?: string;
9013
8940
  /**
9014
- * Additional context from preprocessed file attachments.
9015
- * Contains extracted text from Excel, Word, PDF, and other document files.
9016
- * Injected as a system message so it's available throughout the conversation.
8941
+ * Pre-generated unique ID for the assistant response message.
8942
+ * When provided, the persisted assistant message will use this ID instead of
8943
+ * an auto-generated one. This lets the consumer show an in-flight streaming
8944
+ * placeholder under the same React key, avoiding an unmount/remount flash
8945
+ * when streaming completes and the message is loaded from the database.
9017
8946
  */
9018
- fileContext?: string;
8947
+ assistantUniqueId?: string;
8948
+ }
8949
+ interface BaseUseChatStorageResult {
8950
+ isLoading: boolean;
8951
+ stop: () => void;
8952
+ conversationId: string | null;
8953
+ setConversationId: (id: string | null) => void;
8954
+ createConversation: (options?: CreateConversationOptions) => Promise<StoredConversation>;
8955
+ getConversation: (id: string) => Promise<StoredConversation | null>;
8956
+ getConversations: () => Promise<StoredConversation[]>;
8957
+ updateConversationTitle: (id: string, title: string) => Promise<boolean>;
8958
+ updateConversationPinned: (id: string, pinned: boolean) => Promise<boolean>;
8959
+ deleteConversation: (id: string) => Promise<boolean>;
8960
+ getMessages: (conversationId: string) => Promise<StoredMessage[]>;
9019
8961
  /**
9020
- * Search sources to attach to the stored message for citation/reference.
9021
- * Note: Sources are also automatically extracted from tool_call_events in the response.
8962
+ * Paginated display read: the newest `limit` messages (optionally below
8963
+ * `beforeMessageId`), ascending, with embedding columns skipped.
9022
8964
  */
8965
+ getMessagesPage: (conversationId: string, options: GetMessagesPageOptions) => Promise<StoredMessage[]>;
8966
+ /** Whole-thread branch-tree skeleton — no field decryption. */
8967
+ getMessageSkeletons: (conversationId: string) => Promise<MessageSkeleton[]>;
8968
+ /** Total message count for a conversation. */
8969
+ getMessageCount: (conversationId: string) => Promise<number>;
8970
+ }
8971
+ declare function generateConversationId(): string;
8972
+
8973
+ declare class Message extends Model {
8974
+ static table: string;
8975
+ static associations: Associations;
8976
+ messageId: number;
8977
+ conversationId: string;
8978
+ role: ChatRole;
8979
+ content: string;
8980
+ model?: string;
8981
+ imageModel?: string;
8982
+ /** @deprecated Use fileIds with media table instead */
8983
+ files?: FileMetadata[];
8984
+ /** Array of media_id references for direct lookup */
8985
+ fileIds?: string[];
8986
+ createdAt: Date;
8987
+ updatedAt: Date;
8988
+ vector?: number[];
8989
+ embeddingModel?: string;
8990
+ chunks?: MessageChunk[];
8991
+ usage?: ChatCompletionUsage;
9023
8992
  sources?: SearchSource[];
8993
+ responseDuration?: number;
8994
+ wasStopped?: boolean;
8995
+ error?: string;
8996
+ thoughtProcess?: ActivityPhase[];
8997
+ thinking?: string;
8998
+ parentMessageId?: string;
8999
+ feedback?: MessageFeedback;
9000
+ toolCallEvents?: LlmapiToolCallEvent[];
9001
+ /** Plaintext by design — see MessageOrigin */
9002
+ origin?: MessageOrigin;
9003
+ }
9004
+ declare class Conversation extends Model {
9005
+ static table: string;
9006
+ static associations: Associations;
9007
+ conversationId: string;
9008
+ title: string;
9009
+ projectId?: string;
9010
+ createdAt: Date;
9011
+ updatedAt: Date;
9012
+ isDeleted: boolean;
9013
+ /** When the conversation was pinned to the top of the list; null/unset = not pinned.
9014
+ * `null` (not `undefined`) at runtime for unpinned rows — `@date` maps a null raw
9015
+ * column to null, and unpin stores an explicit null. */
9016
+ pinnedAt?: Date | null;
9017
+ }
9018
+
9019
+ interface StorageOperationsContext {
9020
+ database: Database;
9021
+ messagesCollection: Collection<Message>;
9022
+ conversationsCollection: Collection<Conversation>;
9023
+ /** Wallet address for encryption (optional - when present, enables field-level encryption) */
9024
+ walletAddress?: string;
9025
+ /** Function to sign a message for encryption key derivation */
9026
+ signMessage?: SignMessageFn;
9027
+ /** Function for silent signing with embedded wallets */
9028
+ embeddedWalletSigner?: EmbeddedWalletSignerFn;
9029
+ }
9030
+ /**
9031
+ * Lazy variant of {@link getConversationsOp}.
9032
+ *
9033
+ * Returns conversations with their raw stored title under
9034
+ * `encryptedTitle` instead of a decrypted `title`. Callers should pair
9035
+ * this with {@link decryptConversationTitle} (or the underlying
9036
+ * `decryptField`) and decrypt only when a row is rendered.
9037
+ *
9038
+ * Behavior is identical to `getConversationsOp` except for the title
9039
+ * projection — sort order, soft-delete filtering, and active-conversation
9040
+ * scoping all match.
9041
+ *
9042
+ * Encryption context on `ctx` is intentionally ignored: this op never
9043
+ * decrypts. That is also why the test for this op asserts call count
9044
+ * for `decryptField` is exactly zero.
9045
+ */
9046
+ declare function getConversationsLazyOp(ctx: StorageOperationsContext): Promise<LazyStoredConversation[]>;
9047
+ /**
9048
+ * Keyset-paginated, lazy (no-decrypt) variant of {@link getConversationsLazyOp}.
9049
+ *
9050
+ * Returns at most `limit` conversations (newest first by `created_at`), each
9051
+ * with its raw stored title under `encryptedTitle` — pair with
9052
+ * {@link decryptConversationTitle} to decrypt on render. Page through older
9053
+ * threads by passing the oldest loaded `createdAt` as `before` plus the
9054
+ * uniqueIds held at that boundary as `boundaryExcludeUniqueIds`.
9055
+ *
9056
+ * Decrypts nothing and builds no WatermelonDB Model (the never-evicted
9057
+ * RecordCache stays empty — web Pile-2). Sort order, soft-delete filtering,
9058
+ * and the encrypted-title projection all match `getConversationsLazyOp`.
9059
+ */
9060
+ declare function getConversationsPageOp(ctx: StorageOperationsContext, options?: GetConversationsPageOptions): Promise<LazyStoredConversation[]>;
9061
+ /**
9062
+ * Lazy variant of {@link getConversationsByProjectOp}.
9063
+ *
9064
+ * Same encrypted-title projection as {@link getConversationsLazyOp},
9065
+ * filtered by project assignment. Pass `null` to retrieve conversations
9066
+ * with no project.
9067
+ */
9068
+ declare function getConversationsByProjectLazyOp(ctx: StorageOperationsContext, projectId: string | null): Promise<LazyStoredConversation[]>;
9069
+ /**
9070
+ * Update a conversation's project assignment.
9071
+ * Pass null to remove the conversation from any project.
9072
+ */
9073
+ declare function updateConversationProjectOp(ctx: StorageOperationsContext, id: string, projectId: string | null): Promise<boolean>;
9074
+ /**
9075
+ * Get conversations filtered by project ID.
9076
+ * Pass null to get conversations that don't belong to any project.
9077
+ */
9078
+ declare function getConversationsByProjectOp(ctx: StorageOperationsContext, projectId: string | null): Promise<StoredConversation[]>;
9079
+ /**
9080
+ * Delete a single message by its unique ID.
9081
+ * Clears file_ids before deletion and returns the unique ID.
9082
+ * Note: Callers should use deleteMediaByMessageOp to cascade delete media.
9083
+ */
9084
+ declare function deleteMessageOp(ctx: StorageOperationsContext, uniqueId: string): Promise<string | null>;
9085
+ /** Decrypts raw message embedding columns with the cached wallet key. */
9086
+ declare function decryptMessageEmbeddingFields(raw: Record<string, unknown>, walletAddress?: string): Promise<Record<string, unknown>>;
9087
+ /** Seals legacy message embedding columns and discards chunks with invalid plaintext offsets. */
9088
+ declare function sealLegacyMessageEmbeddingsOp(ctx: StorageOperationsContext): Promise<number>;
9089
+ /**
9090
+ * Removes the plaintext `text` that rows chunked before sdk#889 still carry in
9091
+ * their `chunks` column. Since #889 `updateMessageChunksOp` never writes it, so
9092
+ * a stored `text` key identifies exactly the rows written before that change.
9093
+ * Readers rebuild the snippet from the offsets every row already has; a row
9094
+ * edited after it was chunked fails `resolveChunkText`'s coverage check and
9095
+ * shows the whole message instead.
9096
+ *
9097
+ * Every device must call it: each strips only its own local copy. Backups hold
9098
+ * whole rows encrypted, and a restore brings the text back until the next call.
9099
+ * Idempotent: a stripped row no longer matches, so calling it once per session
9100
+ * is safe. `updated_at` is kept as it was, so backup sync does not re-upload
9101
+ * every old row (the chunk vectors are most of each row's size).
9102
+ *
9103
+ * Reads raw rows a page at a time and builds Models only for the rows it
9104
+ * changes, so unchanged candidates never enter the record cache, and each
9105
+ * write stays small enough not to hold up chat saves.
9106
+ *
9107
+ * @returns Number of rows stripped.
9108
+ */
9109
+ declare function stripLegacyChunkTextOp(ctx: StorageOperationsContext): Promise<number>;
9110
+ /**
9111
+ * Encrypts tool call arguments and results still stored in plaintext and
9112
+ * returns how many rows changed, giving each touched conversation a new
9113
+ * `updatedAt` so backups re-upload it, which moves it to the top of any list
9114
+ * sorted by `updatedAt`.
9115
+ */
9116
+ declare function encryptToolCallEventsOp(ctx: StorageOperationsContext): Promise<number>;
9117
+ /**
9118
+ * Update the feedback (like/dislike) for a message.
9119
+ * Each regenerated response can have its own independent feedback.
9120
+ *
9121
+ * @param ctx - Storage operations context
9122
+ * @param uniqueId - The unique ID of the message to update
9123
+ * @param feedback - 'like', 'dislike', or null to clear feedback
9124
+ * @returns The updated message or null if not found
9125
+ */
9126
+ declare function updateMessageFeedbackOp(ctx: StorageOperationsContext, uniqueId: string, feedback: MessageFeedback): Promise<StoredMessage | null>;
9127
+ declare function searchMessagesOp(ctx: StorageOperationsContext, queryVector: number[], options?: {
9128
+ limit?: number;
9129
+ minSimilarity?: number;
9130
+ conversationId?: string;
9131
+ }): Promise<StoredMessageWithSimilarity[]>;
9132
+ /**
9133
+ * Decrypted, model-native chunk vectors for one message, cached across recall
9134
+ * calls so the chunk lane doesn't re-decrypt + re-JSON.parse every message's
9135
+ * embeddings on every query. Keyed by message id; `version` is the message's
9136
+ * `updated_at` at cache time, so a re-embed (which bumps `updated_at`) misses
9137
+ * and repopulates. Vectors are stored Float32 — model-native precision, half
9138
+ * the RAM of float64 `number[]` — mirroring the vault embedding cache (#705).
9139
+ * Content text is deliberately NOT cached (see searchChunksOp): it isn't
9140
+ * needed for scoring, and keeping decrypted content out of the cache preserves
9141
+ * the SDK's data-at-rest posture.
9142
+ */
9143
+ interface CachedChunkVectors {
9144
+ /** Message `updated_at` (ms) at cache time — the invalidation token. */
9145
+ version: number;
9024
9146
  /**
9025
- * Activity phases for tracking the request lifecycle in the UI.
9026
- * Each phase represents a step like "Searching", "Thinking", "Generating".
9027
- * The final phase is automatically marked as completed when stored.
9028
- *
9029
- * Note: If you need activity phases that are added during streaming (e.g., server tool calls),
9030
- * use `getThoughtProcess` callback instead, which captures phases AFTER streaming completes.
9147
+ * Per-chunk embedding vectors, index-aligned with the message's decrypted
9148
+ * `chunks` array (empty-vector chunks kept as zero-length placeholders so
9149
+ * indices stay aligned). Empty when the message has only a whole-message
9150
+ * `fallback` vector.
9031
9151
  */
9032
- thoughtProcess?: ActivityPhase[];
9152
+ chunks: Float32Array[];
9153
+ /** Whole-message vector when the message was embedded without chunking. */
9154
+ fallback?: Float32Array;
9155
+ }
9156
+ /**
9157
+ * Cache consumed by {@link searchChunksOp}, keyed by message id. A plain `Map`
9158
+ * (satisfied by the LRU from `createChunkVectorCache`) — mirrors
9159
+ * `VaultEmbeddingCache` so consumers get the same `clear()`/`delete()`
9160
+ * ergonomics on an encryption-key reset.
9161
+ */
9162
+ type ChunkVectorCache = Map<string, CachedChunkVectors>;
9163
+ /** Row counts from one {@link searchChunksOp} call. */
9164
+ interface ChunkSearchStats {
9165
+ /** Embedded messages in live conversations that the search considered. */
9166
+ rowsScanned: number;
9167
+ /** Messages whose vectors were read from storage because the cache missed. */
9168
+ rowsFetched: number;
9169
+ /** Messages scored straight from the vector cache. */
9170
+ cacheHits: number;
9171
+ }
9172
+ /**
9173
+ * Search through message chunks for fine-grained semantic search.
9174
+ * Returns the matching chunk text along with the parent message.
9175
+ */
9176
+ declare function searchChunksOp(ctx: StorageOperationsContext, queryVector: number[], options?: {
9177
+ limit?: number;
9178
+ minSimilarity?: number;
9179
+ conversationId?: string;
9180
+ /** Skip every message in this conversation before scoring. */
9181
+ excludeConversationId?: string;
9182
+ /** Current embedding model; messages stored under a different non-null model are skipped. */
9183
+ embeddingModel?: string;
9184
+ /** Decrypted-vector cache, validated by `updated_at`. */
9185
+ chunkCache?: ChunkVectorCache;
9186
+ /** Receives row counts for the call. */
9187
+ onStats?: (stats: ChunkSearchStats) => void;
9188
+ }): Promise<ChunkSearchResult[]>;
9189
+ /**
9190
+ * Get all files from all conversations, sorted by creation date (newest first).
9191
+ * Returns files with conversation context for building file browser UIs.
9192
+ */
9193
+ declare function getAllFilesOp(ctx: StorageOperationsContext, options?: {
9194
+ /** Filter files by conversation ID */
9195
+ conversationId?: string;
9196
+ /** Maximum number of files to return */
9197
+ limit?: number;
9198
+ }): Promise<StoredFileWithContext[]>;
9199
+
9200
+ /**
9201
+ * Types for the conversation-memory storage module.
9202
+ *
9203
+ * A conversation-memory row links a conversation to a vault memory it drew on,
9204
+ * so the conversation Memories panel survives reload. Only the memory id and
9205
+ * recall score are stored; content lives in the encrypted memory_vault.
9206
+ */
9207
+ /** Plain object representation of a conversation-memory record. */
9208
+ interface StoredConversationMemory {
9209
+ /** WatermelonDB internal ID */
9210
+ uniqueId: string;
9211
+ /** The conversation this memory was drawn on in */
9212
+ conversationId: string;
9213
+ /** The memory_vault record id this row points at */
9214
+ memoryId: string;
9215
+ /** Recall relevance score (~0–1) at the time it was recorded */
9216
+ score: number;
9217
+ createdAt: Date;
9218
+ }
9219
+ /** One memory drawn on during a turn, passed to addConversationMemoriesOp. */
9220
+ interface ConversationMemoryInput {
9221
+ memoryId: string;
9222
+ score: number;
9223
+ }
9224
+
9225
+ /**
9226
+ * Minimal interface for an observable (reactive) query result.
9227
+ *
9228
+ * Shaped to be compatible with RxJS-style `Observable` (which is what
9229
+ * WatermelonDB returns) and with a simple polling fallback, so non-reactive
9230
+ * backends can implement it without depending on rxjs.
9231
+ */
9232
+ interface ChatStorageObservable<T> {
9233
+ subscribe(observer: {
9234
+ next: (value: T) => void;
9235
+ error?: (err: unknown) => void;
9236
+ complete?: () => void;
9237
+ }): {
9238
+ unsubscribe: () => void;
9239
+ };
9240
+ }
9241
+ /**
9242
+ * Common filter options for conversation queries. Kept deliberately narrow —
9243
+ * most call sites only need these.
9244
+ */
9245
+ interface ConversationQueryOptions {
9246
+ /** If set, only return conversations in this project. `null` = no project. */
9247
+ projectId?: string | null;
9248
+ }
9249
+ /**
9250
+ * Backend-agnostic interface for chat/conversation storage.
9251
+ *
9252
+ * The method set mirrors the operations we actually use across the SDK:
9253
+ * `*Op` functions in `src/lib/db/chat/operations.ts` plus the `observe*`
9254
+ * patterns used by react hooks. Targeted updates (e.g., `updateMessageError`)
9255
+ * are exposed as separate methods rather than a generic `update()` because
9256
+ * several of them have special semantics (encryption bypass for embeddings,
9257
+ * unique constraints on feedback, etc).
9258
+ */
9259
+ interface ChatStorageAdapter {
9260
+ getConversation(conversationId: string): Promise<StoredConversation | null>;
9261
+ getConversations(options?: ConversationQueryOptions): Promise<StoredConversation[]>;
9262
+ createConversation(options?: CreateConversationOptions): Promise<StoredConversation>;
9263
+ updateConversationTitle(conversationId: string, title: string): Promise<boolean>;
9264
+ updateConversationProject(conversationId: string, projectId: string | null): Promise<boolean>;
9265
+ /** Pin or unpin a conversation. Pinning stamps `pinnedAt`; list queries are
9266
+ * NOT reordered — consumers sort pinned chats first using `pinnedAt`. */
9267
+ updateConversationPinned(conversationId: string, pinned: boolean): Promise<boolean>;
9268
+ /** Soft delete. Implementations are responsible for cascading to messages/media. */
9269
+ deleteConversation(conversationId: string): Promise<boolean>;
9270
+ observeConversations(options?: ConversationQueryOptions): ChatStorageObservable<StoredConversation[]>;
9271
+ getMessages(conversationId: string): Promise<StoredMessage[]>;
9033
9272
  /**
9034
- * Callback to get activity phases AFTER streaming completes.
9035
- * Use this instead of `thoughtProcess` when phases are added dynamically during streaming
9036
- * (e.g., via server tool call events like "Searching...", "Generating image...").
9273
+ * Paginated display read: newest `limit` messages (optionally below
9274
+ * `beforeMessageId`), ascending, with embeddings skipped. See
9275
+ * `getMessagesPageOp`.
9037
9276
  *
9038
- * If both `thoughtProcess` and `getThoughtProcess` are provided, `getThoughtProcess` takes precedence.
9039
- */
9040
- getThoughtProcess?: () => ActivityPhase[];
9041
- /**
9042
- * Controls randomness in the response (0.0 to 2.0).
9043
- * Lower values make output more deterministic, higher values more creative.
9044
- */
9045
- temperature?: number;
9046
- /**
9047
- * Maximum number of tokens to generate in the response.
9048
- * Use this to limit response length and control costs.
9277
+ * Optional so this is an additive, non-breaking interface change (same
9278
+ * rationale as {@link updateMessageFileIds}). The default
9279
+ * {@link WatermelonChatStorageAdapter} provides it.
9049
9280
  */
9050
- maxOutputTokens?: number;
9281
+ getMessagesPage?(conversationId: string, options: GetMessagesPageOptions): Promise<StoredMessage[]>;
9051
9282
  /**
9052
- * Client-side tools with optional executors.
9053
- * These tools run in the browser/app and can have JavaScript executor functions.
9283
+ * Whole-thread branch-tree skeleton (no decrypt). See
9284
+ * `getMessageSkeletonsOp`. Optional for the same additive-change rationale.
9054
9285
  */
9055
- clientTools?: LlmapiChatCompletionTool[];
9286
+ getMessageSkeletons?(conversationId: string): Promise<MessageSkeleton[]>;
9287
+ /** Total message count for a conversation. Optional (additive change). */
9288
+ getMessageCount?(conversationId: string): Promise<number>;
9289
+ createMessage(options: CreateMessageOptions): Promise<StoredMessage>;
9290
+ updateMessageEmbedding(uniqueId: string, vector: number[], embeddingModel: string): Promise<StoredMessage | null>;
9291
+ updateMessageChunks(uniqueId: string, chunks: MessageChunk[], embeddingModel: string): Promise<StoredMessage | null>;
9292
+ updateMessageError(uniqueId: string, error: string): Promise<StoredMessage | null>;
9293
+ updateMessageFeedback(uniqueId: string, feedback: MessageFeedback): Promise<StoredMessage | null>;
9056
9294
  /**
9057
- * Server-side tools to include from /api/v1/tools.
9058
- * - undefined: Include all server-side tools (default)
9059
- * - string[]: Include only tools with these names
9060
- * - []: Include no server-side tools
9061
- * - function: Dynamic filter that receives prompt embedding(s) and all tools,
9062
- * returns tool names to include. Useful for semantic tool matching.
9063
- *
9064
- * @example
9065
- * // Include only specific server tools
9066
- * serverTools: ["anuma_create_image", "perplexity_search"]
9067
- *
9068
- * // Disable server tools for this request
9069
- * serverTools: []
9295
+ * Replace a message's attached media ids (`fileIds`). Used to attach a
9296
+ * generated artifact (e.g. a rendered document PDF) to the assistant message
9297
+ * that produced it, after streaming. Pass the FULL desired list.
9070
9298
  *
9071
- * // Semantic tool matching based on prompt
9072
- * serverTools: (embeddings, tools) => {
9073
- * const matches = findMatchingTools(embeddings, tools, { limit: 5 });
9074
- * return matches.map(m => m.tool.name);
9075
- * }
9299
+ * Optional so this is an additive, non-breaking interface change: only hosts
9300
+ * wiring document/artifact generation need it, and existing custom adapters
9301
+ * keep compiling without implementing it. The default
9302
+ * {@link WatermelonChatStorageAdapter} provides it.
9076
9303
  */
9077
- serverTools?: ServerToolsFilter;
9304
+ updateMessageFileIds?(uniqueId: string, fileIds: string[]): Promise<StoredMessage | null>;
9305
+ /** Clears all messages in a conversation (used for the "clear chat" action). */
9306
+ clearMessages(conversationId: string): Promise<void>;
9307
+ observeMessages(conversationId: string): ChatStorageObservable<StoredMessage[]>;
9308
+ getAllFiles(): Promise<StoredFileWithContext[]>;
9078
9309
  /**
9079
- * Dynamic filter for client-side tools based on prompt embeddings.
9080
- * Receives the prompt embedding(s) (or null for short messages) and all client tools,
9081
- * returns tool names to include. Tools not in the returned list are excluded from the request.
9310
+ * Run a set of mutations inside a single write transaction. Any mutation
9311
+ * calls made on the adapter inside the callback are grouped into one atomic
9312
+ * write on backends that support it.
9082
9313
  *
9083
- * @example
9084
- * clientToolsFilter: (embeddings, tools) => {
9085
- * if (!embeddings) return []; // Short message — no client tools
9086
- * const matches = findMatchingTools(embeddings, pseudoServerTools);
9087
- * return matches.map(m => m.tool.name);
9088
- * }
9089
- */
9090
- clientToolsFilter?: ClientToolsFilterFn;
9091
- /**
9092
- * Controls which tool the model should use:
9093
- * - "auto": Model decides whether to use a tool (default)
9094
- * - "any": Model must use one of the provided tools
9095
- * - "none": Model cannot use any tools
9096
- * - "required": Model must use a tool
9097
- * - Specific tool name: Model must use that specific tool
9098
- */
9099
- toolChoice?: string;
9100
- /**
9101
- * Maximum number of tool execution rounds before forcing the model to respond with text.
9102
- * After this many rounds, `toolChoice` is set to `"none"` on the next continuation,
9103
- * so the model produces a text answer using whatever tool results it has gathered.
9104
- * @default 3
9105
- */
9106
- maxToolRounds?: number;
9107
- /**
9108
- * Reasoning configuration for o-series and other reasoning models.
9109
- * Controls reasoning effort level and whether to include reasoning summary.
9110
- */
9111
- reasoning?: LlmapiResponseReasoning;
9112
- /**
9113
- * Extended thinking configuration for Anthropic models (Claude).
9114
- * Enables the model to think through complex problems step by step
9115
- * before generating the final response.
9116
- */
9117
- thinking?: LlmapiThinkingOptions;
9118
- /** User-selected image generation model for server-side enforcement. */
9119
- imageModel?: string;
9120
- /**
9121
- * Per-request callback for thinking/reasoning chunks.
9122
- * Called with delta chunks as the model "thinks" through a problem.
9123
- * Use this to display thinking progress in the UI.
9124
- */
9125
- onThinking?: (chunk: string) => void;
9126
- /** Parent message ID for branching (edit/regenerate). Sets on the user message. */
9127
- parentMessageId?: string;
9128
- /**
9129
- * Pre-generated unique ID for the assistant response message.
9130
- * When provided, the persisted assistant message will use this ID instead of
9131
- * an auto-generated one. This lets the consumer show an in-flight streaming
9132
- * placeholder under the same React key, avoiding an unmount/remount flash
9133
- * when streaming completes and the message is loaded from the database.
9314
+ * On backends without transaction support, this may fall back to sequential
9315
+ * writes. Implementations must document the guarantee they provide.
9134
9316
  */
9135
- assistantUniqueId?: string;
9317
+ write<T>(fn: (adapter: ChatStorageAdapter) => Promise<T>): Promise<T>;
9136
9318
  }
9137
- interface BaseUseChatStorageResult {
9138
- isLoading: boolean;
9139
- stop: () => void;
9140
- conversationId: string | null;
9141
- setConversationId: (id: string | null) => void;
9142
- createConversation: (options?: CreateConversationOptions) => Promise<StoredConversation>;
9143
- getConversation: (id: string) => Promise<StoredConversation | null>;
9144
- getConversations: () => Promise<StoredConversation[]>;
9145
- updateConversationTitle: (id: string, title: string) => Promise<boolean>;
9146
- updateConversationPinned: (id: string, pinned: boolean) => Promise<boolean>;
9147
- deleteConversation: (id: string) => Promise<boolean>;
9148
- getMessages: (conversationId: string) => Promise<StoredMessage[]>;
9149
- /**
9150
- * Paginated display read: the newest `limit` messages (optionally below
9151
- * `beforeMessageId`), ascending, with embedding columns skipped.
9152
- */
9153
- getMessagesPage: (conversationId: string, options: GetMessagesPageOptions) => Promise<StoredMessage[]>;
9154
- /** Whole-thread branch-tree skeleton — no field decryption. */
9155
- getMessageSkeletons: (conversationId: string) => Promise<MessageSkeleton[]>;
9156
- /** Total message count for a conversation. */
9157
- getMessageCount: (conversationId: string) => Promise<number>;
9319
+
9320
+ interface ChatChunkSearchOptions {
9321
+ limit?: number;
9322
+ minSimilarity?: number;
9323
+ conversationId?: string;
9324
+ excludeConversationId?: string;
9325
+ embeddingModel?: string;
9326
+ chunkCache?: ChunkVectorCache;
9327
+ onStats?: (stats: ChunkSearchStats) => void;
9328
+ }
9329
+ /** Everything `useChatStorage` reads and writes for chats, so a hook can run on local or server storage. */
9330
+ interface ChatBackend extends ChatStorageAdapter {
9331
+ createConversation(options?: CreateConversationOptions, defaultTitle?: string): Promise<StoredConversation>;
9332
+ getAllFiles(options?: Parameters<typeof getAllFilesOp>[1]): Promise<StoredFileWithContext[]>;
9333
+ getMessagesPage(conversationId: string, options: GetMessagesPageOptions): Promise<StoredMessage[]>;
9334
+ getMessageSkeletons(conversationId: string): Promise<MessageSkeleton[]>;
9335
+ /** Reads messages by id in the order asked, leaving out ids that are not stored. */
9336
+ getMessagesByIds(uniqueIds: readonly string[]): Promise<StoredMessage[]>;
9337
+ getMessageCount(conversationId: string): Promise<number>;
9338
+ getToolCallEventIds(conversationId: string): Promise<Set<string>>;
9339
+ upsertMessage(options: CreateMessageOptions & {
9340
+ uniqueId: string;
9341
+ }): Promise<StoredMessage>;
9342
+ searchChunks(queryVector: number[], options?: ChatChunkSearchOptions): Promise<ChunkSearchResult[]>;
9343
+ getSummary(conversationId: string): Promise<StoredConversationSummary | null>;
9344
+ upsertSummary(conversationId: string, summary: string, summarizedUpTo: string, tokenCount: number): Promise<StoredConversationSummary>;
9345
+ deleteSummary(conversationId: string): Promise<void>;
9346
+ deleteMessage(uniqueId: string): Promise<string | null>;
9347
+ getMemoryLinks(conversationId: string): Promise<StoredConversationMemory[]>;
9348
+ /** Records the memories a turn drew on in recall order, moving already-linked ones to this turn with their new score. */
9349
+ addMemoryLinks(conversationId: string, items: ConversationMemoryInput[]): Promise<void>;
9350
+ clearMemoryLinks(conversationId: string): Promise<void>;
9351
+ }
9352
+ interface ChatBackendSigner {
9353
+ walletAddress?: string;
9354
+ signMessage?: SignMessageFn;
9355
+ embeddedWalletSigner?: EmbeddedWalletSignerFn;
9356
+ }
9357
+ /** Builds the chat backend for a signer; `useChatStorage` calls it for live writes and for queued writes replayed later. */
9358
+ type ChatBackendFactory = (signer: ChatBackendSigner) => ChatBackend;
9359
+
9360
+ /** Durable home for sealed outbox slots, one per running backend, so writes survive a reload while vault is unreachable. */
9361
+ interface ChatOutboxStorage {
9362
+ slots(): Promise<string[]>;
9363
+ get(slot: string): Promise<string | null>;
9364
+ set(slot: string, sealed: string | null): Promise<void>;
9365
+ }
9366
+ /** The part of the Web Locks API the outbox uses to tell a live tab's slot from an orphaned one. */
9367
+ interface ChatOutboxLocks {
9368
+ request<T>(name: string, options: {
9369
+ ifAvailable?: boolean;
9370
+ }, callback: (lock: object | null) => Promise<T> | T): Promise<T>;
9158
9371
  }
9159
- declare function generateConversationId(): string;
9160
9372
 
9161
- declare class Message extends Model {
9373
+ /** A change to the cached chats; `origin` is "remote" when another device or tab made it. */
9374
+ type VaultChatEvent = {
9375
+ type: "conversations";
9376
+ origin: "local" | "remote";
9377
+ } | {
9378
+ type: "messages";
9379
+ conversationId: string;
9380
+ origin: "local" | "remote";
9381
+ } | {
9382
+ type: "summary";
9383
+ conversationId: string;
9384
+ origin: "local" | "remote";
9385
+ } | {
9386
+ type: "links";
9387
+ conversationId: string;
9388
+ origin: "local" | "remote";
9389
+ } | {
9390
+ type: "outbox";
9391
+ pending: number;
9392
+ stopped?: string;
9393
+ } | {
9394
+ type: "dropped";
9395
+ kind: ChatRecordKind;
9396
+ id: string;
9397
+ reason: "missing" | "storage_quota" | "invalid" | "conversation_deleted";
9398
+ } | {
9399
+ type: "vector_quota";
9400
+ };
9401
+ interface VaultChatActivity {
9402
+ isActive(): boolean;
9403
+ subscribe(onChange: () => void): () => void;
9404
+ }
9405
+ interface VaultChatBackendOptions {
9406
+ store: ChatStore;
9407
+ /** Persists unsent writes, sealed with `seal`, so they survive a reload; `locks` defaults to `navigator.locks`. */
9408
+ outbox?: {
9409
+ storage: ChatOutboxStorage;
9410
+ seal: Pick<SealingCipher, "encrypt" | "decrypt">;
9411
+ locks?: ChatOutboxLocks;
9412
+ };
9413
+ activity?: VaultChatActivity;
9414
+ /** Polls `/changes` this often while active; 0 polls only on activity and broadcast hints. */
9415
+ pollIntervalMs?: number;
9416
+ /** BroadcastChannel name shared by this account's tabs, so one tab's writes prompt the others to poll. */
9417
+ channel?: string;
9418
+ threadCacheSize?: number;
9419
+ now?: () => number;
9420
+ }
9421
+ interface SealingCipher {
9422
+ encrypt(plaintext: string): Promise<string>;
9423
+ decrypt(ciphertext: string): Promise<string>;
9424
+ }
9425
+ /** A {@link ChatBackend} over vault: a cache, an optimistic outbox and a change poller. */
9426
+ interface VaultChatBackend extends ChatBackend {
9427
+ subscribe(listener: (event: VaultChatEvent) => void): () => void;
9428
+ /** Sends queued writes now; resolves once the outbox is empty, waiting on a retry, or stopped. */
9429
+ flush(): Promise<void>;
9430
+ /** Applies changes other devices made since the last poll. */
9431
+ poll(): Promise<void>;
9432
+ status(): {
9433
+ pending: number;
9434
+ stopped?: string;
9435
+ };
9436
+ close(): void;
9437
+ }
9438
+ /** Creates a vault chat backend for one account and key; build a new one after a wallet or key change. */
9439
+ declare function createVaultChatBackend(options: VaultChatBackendOptions): VaultChatBackend;
9440
+ /** A {@link ChatBackendFactory} that hands `useChatStorage` the same vault backend for every signer. */
9441
+ declare function vaultChatBackend(backend: VaultChatBackend): ChatBackendFactory;
9442
+
9443
+ declare class AppFile extends Model {
9162
9444
  static table: string;
9163
9445
  static associations: Associations;
9164
- messageId: number;
9165
9446
  conversationId: string;
9166
- role: ChatRole;
9447
+ path: string;
9167
9448
  content: string;
9168
- model?: string;
9169
- imageModel?: string;
9170
- /** @deprecated Use fileIds with media table instead */
9171
- files?: FileMetadata[];
9172
- /** Array of media_id references for direct lookup */
9173
- fileIds?: string[];
9174
9449
  createdAt: Date;
9175
9450
  updatedAt: Date;
9176
- vector?: number[];
9177
- embeddingModel?: string;
9178
- chunks?: MessageChunk[];
9179
- usage?: ChatCompletionUsage;
9180
- sources?: SearchSource[];
9181
- responseDuration?: number;
9182
- wasStopped?: boolean;
9183
- error?: string;
9184
- thoughtProcess?: ActivityPhase[];
9185
- thinking?: string;
9186
- parentMessageId?: string;
9187
- feedback?: MessageFeedback;
9188
- toolCallEvents?: LlmapiToolCallEvent[];
9189
- /** Plaintext by design — see MessageOrigin */
9190
- origin?: MessageOrigin;
9191
9451
  }
9192
- declare class Conversation extends Model {
9193
- static table: string;
9194
- static associations: Associations;
9452
+
9453
+ /**
9454
+ * Types for the app files storage module.
9455
+ *
9456
+ * App files are the HTML/CSS/JS source files for LLM-generated apps,
9457
+ * stored per conversation. Each file is identified by a conversationId + path pair.
9458
+ */
9459
+ /** Plain object representation of an app file record. */
9460
+ interface StoredAppFile {
9461
+ /** WatermelonDB internal ID */
9462
+ uniqueId: string;
9463
+ /** The conversation this file belongs to */
9195
9464
  conversationId: string;
9196
- title: string;
9197
- projectId?: string;
9465
+ /** Normalized file path, no leading slash (e.g. "index.html", "src/App.tsx") */
9466
+ path: string;
9467
+ /** File content (UTF-8 text) */
9468
+ content: string;
9198
9469
  createdAt: Date;
9199
9470
  updatedAt: Date;
9200
- isDeleted: boolean;
9201
- /** When the conversation was pinned to the top of the list; null/unset = not pinned.
9202
- * `null` (not `undefined`) at runtime for unpinned rows — `@date` maps a null raw
9203
- * column to null, and unpin stores an explicit null. */
9204
- pinnedAt?: Date | null;
9205
9471
  }
9206
9472
 
9473
+ /** Context required by app file operations. */
9474
+ interface AppFileOperationsContext {
9475
+ database: Database;
9476
+ appFilesCollection: Collection<AppFile>;
9477
+ }
9478
+ /** Convert a WatermelonDB AppFile model to a plain StoredAppFile object. */
9479
+ declare function appFileToStored(file: AppFile): StoredAppFile;
9480
+ /**
9481
+ * Create or overwrite a file. If a file with the same conversationId + path
9482
+ * already exists, it is updated in place.
9483
+ */
9484
+ declare function putAppFileOp(ctx: AppFileOperationsContext, conversationId: string, path: string, content: string): Promise<StoredAppFile>;
9485
+ /** Read a single file by conversationId and path. Returns null if not found. */
9486
+ declare function getAppFileOp(ctx: AppFileOperationsContext, conversationId: string, path: string): Promise<StoredAppFile | null>;
9487
+ /** List all files for a conversation. */
9488
+ declare function getAppFilesOp(ctx: AppFileOperationsContext, conversationId: string): Promise<StoredAppFile[]>;
9489
+ /** Get all files for a conversation as a path → content map (for sending to the runner). */
9490
+ declare function getAppFileMapOp(ctx: AppFileOperationsContext, conversationId: string): Promise<Record<string, string>>;
9491
+ /** Delete a single file by conversationId and path. */
9492
+ declare function deleteAppFileOp(ctx: AppFileOperationsContext, conversationId: string, path: string): Promise<boolean>;
9493
+ /** Delete all files for a conversation. */
9494
+ declare function deleteAllAppFilesOp(ctx: AppFileOperationsContext, conversationId: string): Promise<void>;
9495
+
9496
+ /**
9497
+ * Drop every cached plaintext title and pending decrypt promise.
9498
+ *
9499
+ * Wired into `clearAllEncryptionState()` via the listener registry in
9500
+ * `useEncryption.ts`. Also exported so consumers can clear the cache
9501
+ * proactively (e.g. on wallet switch within a session before the
9502
+ * full encryption-state teardown lands).
9503
+ */
9504
+ declare function clearLazyTitleCache(): void;
9505
+ /**
9506
+ * Decrypt a single conversation title on demand.
9507
+ *
9508
+ * Designed for the lazy display path: pair with `listConversationsLazy`
9509
+ * and call this once a row is actually visible.
9510
+ *
9511
+ * Behavior:
9512
+ * - Plaintext input (no `enc:` prefix) is returned unchanged. This
9513
+ * covers conversations created before encryption was enabled and
9514
+ * keeps the helper safe to call unconditionally from rendering
9515
+ * code that may receive a mix of encrypted and plaintext titles.
9516
+ * - Encrypted input is decrypted via `decryptField`, which uses the
9517
+ * same per-version cached `CryptoKey` as the eager path — no new
9518
+ * key derivations are triggered.
9519
+ * - Concurrent calls for the same `(address, encryptedTitle)` share
9520
+ * a single decrypt promise.
9521
+ * - The result is memoized in a 256-entry LRU.
9522
+ *
9523
+ * Throws if the encryption key for `address` isn't loaded. (The
9524
+ * underlying `decryptField` would otherwise silently return the
9525
+ * ciphertext, which would surface to the UI as a literal `enc:v3:...`
9526
+ * title — strictly worse than a thrown error the caller can catch.)
9527
+ *
9528
+ * @param encryptedTitle - The stored title. May be ciphertext or plaintext.
9529
+ * @param address - Wallet address that owns the encryption key.
9530
+ * @returns The decrypted plaintext title.
9531
+ */
9532
+ declare function decryptConversationTitle(encryptedTitle: string, address: string): Promise<string>;
9533
+
9207
9534
  declare const chatStorageSchema: Readonly<{
9208
9535
  version: _nozbe_watermelondb_Schema.SchemaVersion;
9209
9536
  tables: _nozbe_watermelondb_Schema.TableMap;
@@ -9231,31 +9558,6 @@ declare class ConversationMemory extends Model {
9231
9558
  createdAt: Date;
9232
9559
  }
9233
9560
 
9234
- /**
9235
- * Types for the conversation-memory storage module.
9236
- *
9237
- * A conversation-memory row links a conversation to a vault memory it drew on,
9238
- * so the conversation Memories panel survives reload. Only the memory id and
9239
- * recall score are stored; content lives in the encrypted memory_vault.
9240
- */
9241
- /** Plain object representation of a conversation-memory record. */
9242
- interface StoredConversationMemory {
9243
- /** WatermelonDB internal ID */
9244
- uniqueId: string;
9245
- /** The conversation this memory was drawn on in */
9246
- conversationId: string;
9247
- /** The memory_vault record id this row points at */
9248
- memoryId: string;
9249
- /** Recall relevance score (~0–1) at the time it was recorded */
9250
- score: number;
9251
- createdAt: Date;
9252
- }
9253
- /** One memory drawn on during a turn, passed to addConversationMemoriesOp. */
9254
- interface ConversationMemoryInput {
9255
- memoryId: string;
9256
- score: number;
9257
- }
9258
-
9259
9561
  /** Context required by conversation-memory operations. */
9260
9562
  interface ConversationMemoryOperationsContext {
9261
9563
  database: Database;
@@ -12594,7 +12896,7 @@ declare function cosineInt8(a: Int8Array, scaleA: number, b: Int8Array, scaleB:
12594
12896
  * The tool allows the LLM to search through past conversation messages
12595
12897
  * using semantic similarity. Messages must have embeddings stored to be searchable.
12596
12898
  *
12597
- * @param storageCtx - Storage operations context for database access
12899
+ * @param storage - Chat storage: a WatermelonDB operations context or a chat backend
12598
12900
  * @param embeddingOptions - Options for embedding generation
12599
12901
  * @param searchOptions - Default search options (can be overridden per-call)
12600
12902
  * @returns A ToolConfig that can be passed to chat completion tools
@@ -12614,7 +12916,7 @@ declare function cosineInt8(a: Int8Array, scaleA: number, b: Int8Array, scaleB:
12614
12916
  * });
12615
12917
  * ```
12616
12918
  */
12617
- declare function createMemoryEngineTool(storageCtx: StorageOperationsContext, embeddingOptions: EmbeddingOptions, searchOptions?: Partial<MemoryEngineSearchOptions>, callbacks?: {
12919
+ declare function createMemoryEngineTool(storage: StorageOperationsContext | Pick<ChatBackend, "searchChunks" | "getMessages">, embeddingOptions: EmbeddingOptions, searchOptions?: Partial<MemoryEngineSearchOptions>, callbacks?: {
12618
12920
  /** Called after retrieval with the conversation IDs that were actually returned to the LLM. */
12619
12921
  onRetrieve?: (conversationIds: string[]) => void;
12620
12922
  }): ToolConfig;
@@ -13081,101 +13383,6 @@ declare class ZipProcessor implements FileProcessor {
13081
13383
  private guessMimeType;
13082
13384
  }
13083
13385
 
13084
- /**
13085
- * Minimal interface for an observable (reactive) query result.
13086
- *
13087
- * Shaped to be compatible with RxJS-style `Observable` (which is what
13088
- * WatermelonDB returns) and with a simple polling fallback, so non-reactive
13089
- * backends can implement it without depending on rxjs.
13090
- */
13091
- interface ChatStorageObservable<T> {
13092
- subscribe(observer: {
13093
- next: (value: T) => void;
13094
- error?: (err: unknown) => void;
13095
- complete?: () => void;
13096
- }): {
13097
- unsubscribe: () => void;
13098
- };
13099
- }
13100
- /**
13101
- * Common filter options for conversation queries. Kept deliberately narrow —
13102
- * most call sites only need these.
13103
- */
13104
- interface ConversationQueryOptions {
13105
- /** If set, only return conversations in this project. `null` = no project. */
13106
- projectId?: string | null;
13107
- }
13108
- /**
13109
- * Backend-agnostic interface for chat/conversation storage.
13110
- *
13111
- * The method set mirrors the operations we actually use across the SDK:
13112
- * `*Op` functions in `src/lib/db/chat/operations.ts` plus the `observe*`
13113
- * patterns used by react hooks. Targeted updates (e.g., `updateMessageError`)
13114
- * are exposed as separate methods rather than a generic `update()` because
13115
- * several of them have special semantics (encryption bypass for embeddings,
13116
- * unique constraints on feedback, etc).
13117
- */
13118
- interface ChatStorageAdapter {
13119
- getConversation(conversationId: string): Promise<StoredConversation | null>;
13120
- getConversations(options?: ConversationQueryOptions): Promise<StoredConversation[]>;
13121
- createConversation(options?: CreateConversationOptions): Promise<StoredConversation>;
13122
- updateConversationTitle(conversationId: string, title: string): Promise<boolean>;
13123
- updateConversationProject(conversationId: string, projectId: string | null): Promise<boolean>;
13124
- /** Pin or unpin a conversation. Pinning stamps `pinnedAt`; list queries are
13125
- * NOT reordered — consumers sort pinned chats first using `pinnedAt`. */
13126
- updateConversationPinned(conversationId: string, pinned: boolean): Promise<boolean>;
13127
- /** Soft delete. Implementations are responsible for cascading to messages/media. */
13128
- deleteConversation(conversationId: string): Promise<boolean>;
13129
- observeConversations(options?: ConversationQueryOptions): ChatStorageObservable<StoredConversation[]>;
13130
- getMessages(conversationId: string): Promise<StoredMessage[]>;
13131
- /**
13132
- * Paginated display read: newest `limit` messages (optionally below
13133
- * `beforeMessageId`), ascending, with embeddings skipped. See
13134
- * `getMessagesPageOp`.
13135
- *
13136
- * Optional so this is an additive, non-breaking interface change (same
13137
- * rationale as {@link updateMessageFileIds}). The default
13138
- * {@link WatermelonChatStorageAdapter} provides it.
13139
- */
13140
- getMessagesPage?(conversationId: string, options: GetMessagesPageOptions): Promise<StoredMessage[]>;
13141
- /**
13142
- * Whole-thread branch-tree skeleton (no decrypt). See
13143
- * `getMessageSkeletonsOp`. Optional for the same additive-change rationale.
13144
- */
13145
- getMessageSkeletons?(conversationId: string): Promise<MessageSkeleton[]>;
13146
- /** Total message count for a conversation. Optional (additive change). */
13147
- getMessageCount?(conversationId: string): Promise<number>;
13148
- createMessage(options: CreateMessageOptions): Promise<StoredMessage>;
13149
- updateMessageEmbedding(uniqueId: string, vector: number[], embeddingModel: string): Promise<StoredMessage | null>;
13150
- updateMessageChunks(uniqueId: string, chunks: MessageChunk[], embeddingModel: string): Promise<StoredMessage | null>;
13151
- updateMessageError(uniqueId: string, error: string): Promise<StoredMessage | null>;
13152
- updateMessageFeedback(uniqueId: string, feedback: MessageFeedback): Promise<StoredMessage | null>;
13153
- /**
13154
- * Replace a message's attached media ids (`fileIds`). Used to attach a
13155
- * generated artifact (e.g. a rendered document PDF) to the assistant message
13156
- * that produced it, after streaming. Pass the FULL desired list.
13157
- *
13158
- * Optional so this is an additive, non-breaking interface change: only hosts
13159
- * wiring document/artifact generation need it, and existing custom adapters
13160
- * keep compiling without implementing it. The default
13161
- * {@link WatermelonChatStorageAdapter} provides it.
13162
- */
13163
- updateMessageFileIds?(uniqueId: string, fileIds: string[]): Promise<StoredMessage | null>;
13164
- /** Clears all messages in a conversation (used for the "clear chat" action). */
13165
- clearMessages(conversationId: string): Promise<void>;
13166
- observeMessages(conversationId: string): ChatStorageObservable<StoredMessage[]>;
13167
- getAllFiles(): Promise<StoredFileWithContext[]>;
13168
- /**
13169
- * Run a set of mutations inside a single write transaction. Any mutation
13170
- * calls made on the adapter inside the callback are grouped into one atomic
13171
- * write on backends that support it.
13172
- *
13173
- * On backends without transaction support, this may fall back to sequential
13174
- * writes. Implementations must document the guarantee they provide.
13175
- */
13176
- write<T>(fn: (adapter: ChatStorageAdapter) => Promise<T>): Promise<T>;
13177
- }
13178
-
13179
13386
  /**
13180
13387
  * Pure functions for extracting MCP media URLs (images and videos).
13181
13388
  *
@@ -13343,14 +13550,14 @@ interface WatermelonChatStorageAdapterOptions {
13343
13550
  /** Silent signing function for embedded wallets (optional). */
13344
13551
  embeddedWalletSigner?: EmbeddedWalletSignerFn;
13345
13552
  }
13346
- declare class WatermelonChatStorageAdapter implements ChatStorageAdapter {
13553
+ declare class WatermelonChatStorageAdapter implements ChatBackend {
13347
13554
  private readonly ctx;
13348
13555
  private readonly messages;
13349
13556
  private readonly conversations;
13350
13557
  constructor(options: WatermelonChatStorageAdapterOptions);
13351
13558
  getConversation(conversationId: string): Promise<StoredConversation | null>;
13352
13559
  getConversations(options?: ConversationQueryOptions): Promise<StoredConversation[]>;
13353
- createConversation(options?: CreateConversationOptions): Promise<StoredConversation>;
13560
+ createConversation(options?: CreateConversationOptions, defaultTitle?: string): Promise<StoredConversation>;
13354
13561
  updateConversationTitle(conversationId: string, title: string): Promise<boolean>;
13355
13562
  updateConversationProject(conversationId: string, projectId: string | null): Promise<boolean>;
13356
13563
  updateConversationPinned(conversationId: string, pinned: boolean): Promise<boolean>;
@@ -13358,6 +13565,7 @@ declare class WatermelonChatStorageAdapter implements ChatStorageAdapter {
13358
13565
  observeConversations(options?: ConversationQueryOptions): ChatStorageObservable<StoredConversation[]>;
13359
13566
  getMessages(conversationId: string): Promise<StoredMessage[]>;
13360
13567
  getMessagesPage(conversationId: string, options: GetMessagesPageOptions): Promise<StoredMessage[]>;
13568
+ getMessagesByIds(uniqueIds: readonly string[]): Promise<StoredMessage[]>;
13361
13569
  getMessageSkeletons(conversationId: string): Promise<MessageSkeleton[]>;
13362
13570
  getMessageCount(conversationId: string): Promise<number>;
13363
13571
  createMessage(options: CreateMessageOptions): Promise<StoredMessage>;
@@ -13368,7 +13576,20 @@ declare class WatermelonChatStorageAdapter implements ChatStorageAdapter {
13368
13576
  updateMessageFileIds(uniqueId: string, fileIds: string[]): Promise<StoredMessage | null>;
13369
13577
  clearMessages(conversationId: string): Promise<void>;
13370
13578
  observeMessages(conversationId: string): ChatStorageObservable<StoredMessage[]>;
13371
- getAllFiles(): Promise<StoredFileWithContext[]>;
13579
+ getAllFiles(options?: Parameters<typeof getAllFilesOp>[1]): Promise<StoredFileWithContext[]>;
13580
+ getToolCallEventIds(conversationId: string): Promise<Set<string>>;
13581
+ upsertMessage(options: CreateMessageOptions & {
13582
+ uniqueId: string;
13583
+ }): Promise<StoredMessage>;
13584
+ searchChunks(queryVector: number[], options?: ChatChunkSearchOptions): Promise<ChunkSearchResult[]>;
13585
+ getSummary(conversationId: string): Promise<StoredConversationSummary | null>;
13586
+ upsertSummary(conversationId: string, summary: string, summarizedUpTo: string, tokenCount: number): Promise<StoredConversationSummary>;
13587
+ deleteSummary(conversationId: string): Promise<void>;
13588
+ deleteMessage(uniqueId: string): Promise<string | null>;
13589
+ getMemoryLinks(conversationId: string): Promise<StoredConversationMemory[]>;
13590
+ addMemoryLinks(conversationId: string, items: ConversationMemoryInput[]): Promise<void>;
13591
+ clearMemoryLinks(conversationId: string): Promise<void>;
13592
+ private memoryCtx;
13372
13593
  /**
13373
13594
  * WatermelonDB nests `database.write()` safely: each method we call inside
13374
13595
  * the callback already wraps its own writes, and Watermelon collapses the
@@ -13377,6 +13598,7 @@ declare class WatermelonChatStorageAdapter implements ChatStorageAdapter {
13377
13598
  */
13378
13599
  write<T>(fn: (adapter: ChatStorageAdapter) => Promise<T>): Promise<T>;
13379
13600
  }
13601
+ declare function localChatBackend(database: Database): ChatBackendFactory;
13380
13602
 
13381
13603
  type WhisperModel = "whisper-tiny" | "whisper-tiny.en" | "whisper-base" | "whisper-base.en" | "whisper-small" | "whisper-small.en";
13382
13604
  interface VoiceRecording {
@@ -15964,4 +16186,4 @@ type UseWalletBindingResult = {
15964
16186
  */
15965
16187
  declare function useWalletBinding(options?: UseWalletBindingOptions): UseWalletBindingResult;
15966
16188
 
15967
- export { Anuma, type AnumaChild, AnumaJsxError, type AnumaNode, AnumaShadowIsolationProvider, type AnumaShadowIsolationProviderProps, type AnumaTheme, AnumaThemeProvider, type AnumaThemeProviderProps, AppFile as AppFileModel, type AppFileOperationsContext, type AttrValue, type AutoExtractMessage, type AutoExtractor, DEFAULT_BACKUP_FOLDER as BACKUP_ICLOUD_FOLDER, BUILT_IN_TOOL_SETS, type BackupAuthContextValue, BackupAuthProvider, type BackupAuthProviderProps, type BackupOperationOptions, BlobUrlManager, type Budget, CHUNKS_DISCARDED_ORIGIN, type CachedChunkVectors, type CachedServerTools, ChartCard, type ChartCardProps, type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, type ChatAccount, type ChatAccountState, type ChatAttachment, type ChatAttachments, type ChatChanges, Conversation as ChatConversation, type ChatImport, type ChatJson, type ChatListOptions, Message as ChatMessage, type ChatPage, type ChatPresignedUrl, type ChatRecord, type ChatRecordKind, type ChatRef, type ChatRevision, type ChatRole, type ChatSearchHit, type ChatSearchOptions, type ChatSnapshot, type ChatStorageAdapter, type ChatStorageObservable, type ChatStore, ChatStoreError, type ChatWrite, type ChunkSearchResult, type ChunkSearchStats, type ChunkVectorCache, type ChunkingOptions, type CircleProps, type ClientToolsFilterFn, type ConsolidationAction, type ConsolidationFallbackReason, type ConversationMemoryInput, ConversationMemory as ConversationMemoryModel, type ConversationMemoryOperationsContext, type ConversationQueryOptions, type CreateAutoExtractorOptions, type CreateConversationOptions, type CreateDecaySweeperOptions, type CreateEntityOptions, type CreateMediaOptions, type CreateMessageOptions, type CreateModelPreferenceOptions, type CreateProjectOptions, type CreateSavedToolOptions, type CreateSelectPaymentWalletToolOptions, type CreateServerToolsFilterOptions, type CreateUserPreferenceOptions, type CreateVaultFolderOptions, type CreateVaultMemoryOptions, type CreateWalletPaymentToolOptions, type CryptoPriceClassification, type CryptoPricePreProcessorOptions, DEFAULT_CACHE_EXPIRATION_MS, DEFAULT_CHUNK_CACHE_SIZE, DEFAULT_CHUNK_OVERLAP, DEFAULT_CHUNK_SIZE, DEFAULT_DECAY_POLICY, DEFAULT_EXCLUDED_SERVER_TOOLS, DEFAULT_BACKUP_FOLDER as DEFAULT_ICLOUD_BACKUP_FOLDER, DEFAULT_MAX_CLASSIFIER_CALLS_PER_SWEEP, DEFAULT_MIN_CHUNK_SIZE, DEFAULT_PERSONALITY_SETTINGS, DEFAULT_PROFILE_FACETS, DEFAULT_PROFILE_FACT_TYPE_WEIGHTS, DEFAULT_PROFILE_PROOF_ALPHA, DEFAULT_PROFILE_TREND_MULTIPLIERS, DEFAULT_SERVER_TOOLS_MATCH_OPTIONS, DEFAULT_VAULT_CACHE_SIZE, DatabaseManager, type DatabaseManagerLogger, type DatabaseManagerOptions, type DecayCandidateRaw, type DecayClassifier, type DecayInput, type DecayPolicy, type DecaySweepResult, type DecaySweeper, type DecayVerdict, type DeckProps, type DisplayToolMigrations, type DurableAutoExtractorOptions, ENTITY_FANOUT, ENTITY_KINDS, type EmbeddedWalletSignerFn, type EmbeddingRepairOptions, type EmbeddingRepairResult, EncryptionKeyMissingError, type EncryptionKeyVersion, type EntityInput, type EntityKind, Entity as EntityModel, type EntityOperationsContext, ExcelProcessor, type ExtractFactsOptions, type ExtractOutcome, type ExtractedCandidate, type ExtractedEntity, type ExtractionCursorStore, type ExtractionFunnel, type ExtractionMessageSource, type ExtractionSourceMessage, type ExtractionSourceStatus, type ExtractionTimings, FILE_PLACEHOLDER_PREFIX, FILE_PLACEHOLDER_REGEX, type FactType, type FileMetadata, type FileProcessingReason, type FileProcessingStatus, type FileProcessor, type FileTypeQuery, type FileWithData, type FlushResult, type GetConversationsPageOptions, type GetMessagesPageOptions, type GraphTraversalOptions, type GroupProps, HARD_DELETE_WINDOW_MS, type ICloudAuthContextValue, ICloudAuthProvider, type ICloudAuthProviderProps, type ICloudExportResult, type ICloudImportResult, INFERENCE_ID_HEADER, INTERNAL_FLOW_MARKER, type IconProps, type ImageProps, type InjectionClassifierOptions, type InjectionReason, type InteractionType, type KnownTag, type LazyStoredConversation, type LineProps, type LlmDecayClassifierOptions, type LlmNeighborRefinerOptions, type LocalMemoryStoreOptions, type Logger, LoggerProvider, type LoggerProviderProps, MAX_HOPS, MEDIUM_TTL_MS, MEMORY_KINDS, MEMORY_LEVELS, type ManualFactType, type MediaDimensions, type MediaFilterOptions, type MediaMetadata, type MediaOperationsContext, type MediaRole, type MediaType, type MemoriesNeedingTopicExtraction, type MemoryContextItem, type MemoryContextLane, type MemoryContextOptions, type MemoryContextResult, type MemoryCounts, type MemoryCreate, type MemoryDecay, type MemoryDecaySweeperOptions, type EmbeddingOptions as MemoryEngineEmbeddingOptions, type MemoryEngineResult, type MemoryEngineSearchOptions, MemoryEntity as MemoryEntityModel, type MemoryExtractedEvent, MemoryKeyError, type MemoryKeyRing, type MemoryKind, type MemoryLevel, MemoryLevelError, type MemoryListOptions, type MemoryMaintenance, type MemoryMigrationOptions, type MemoryMigrationProgress, type MemoryMigrationResult, type MemoryMigrationSkip, type MemoryQuarantinedEvent, type MemoryRecallOptions, type MemoryRetainOptions, type MemoryStore, type MemorySubscribeOptions, type MemoryToVerify, type MemoryTopic, type MemoryTopicBacklog, type MemoryTopicMaintenance, type MemoryUpdate, type MemoryVaultSearchOptions, type MemoryVaultToolOptions, type MemoryVerification, type MessageChunk, type MessageFeedback, type MessageOrigin, type MessageSkeleton, type ModelLoadProgress, NEVER_TTL_MS, NODE_BUDGET, type NeighborRefiner, type NowSource, type OCRFile, type ObservationTrend, type ObservationTrendInput, type OperationExecutor, PAST_EVENT_GRACE_MS, PROFILE_DOC_VERSION, type ParsedServerToolsResponse, type PaymentWallet, type PdfExportOptions, type PdfExportProgress, type PdfExportStage, type PdfFile, PdfProcessor, type PendingInteraction, type PersonalitySettings, type PersonalitySliders, type PersonalityStyle, type PhoneCallPollingOptions, type PhotoIngestResult, type PhotoMediaRef, type PlatformStorage, type PortalLlmAuth, type PortalLlmFailure, type PortalLlmFailureReason, type PreprocessingOptions, type PreprocessingResult, type ProcessedFileResult, ProcessorRegistry, type ProfileConfigFingerprint, type ProfileDoc, type ProfileFacet, type ProfileFacetKey, type ProfileSalienceInput, type ProfileSection, type ProfileUpdate, type ProgressCallback, Project, type ProjectOperationsContext, type PromptPreProcessor, type PromptPreProcessorContext, type ProviderAuthState, type ProviderBackupState, ProviderStreamError, type PublishedPhotoMemory, type QuantizedEmbedding, type QuarantinedMemoryInfo, type QueueEncryptionContext, QueueManager, type QueueStatus, type QueuedOperation, type QueuedOperationType, R2_DEFAULT_TTL_MS, RECALL_MAX_LIMIT, RECALL_TOOL_NAME, type RankableVaultMemory, type RankedMemory, type RankedProfileCandidate, type RecallContext, type RecallDegradation, type RecallDiagnostics, type RecallEmptyReason, type RecallOptions, type RecallResult, type RecallTelemetryCallbacks, type RecallToolCallbacks, type RecallToolOptions, type RecallTruncation, type RecencyOptions, type RectProps, type ReflectOptions, type ReflectResult, type RemoteChatStoreOptions, type RemoteMemoryCandidateOptions, type RemoteMemoryDecodeFailure, RemoteMemoryError, type RemoteMemoryListOptions, type RemoteMemoryMetadataPage, type RemoteMemoryMetadataRecord, type RemoteMemoryPage, RemoteMemoryPartialCreateError, type RemoteMemoryPersistence, type RemoteMemoryPersistenceOptions, type RemoteMemoryPipeline, type RemoteMemoryPipelineOptions, type RemoteMemoryQueryOptions, type RemoteMemoryQueryPage, type RemoteMemoryReadFilters, type RemoteMemoryRecord, type RemoteMemoryRow, type RemoteMemoryStoreOptions, type RemoteMemoryTopic, type RemoteMemoryWorkKind, type RemoteMemoryWorkLease, type RemoteMemoryWorkPersistence, type RemoteTopicPersistence, type RequestEncryptionKeyOptions, RerankerUnavailableError, type ReservationReceipt, type ResumeStreamOptions, type ResumeStreamResult, type RetainAction, type RetainContext, type RetainOptions, type RetainResult, type RetainSource, SDK_SCHEMA_VERSION, SELECT_PAYMENT_WALLET_TOOL_NAME, SERVER_TOOL_DEPENDENCY_SETS, SHORT_TTL_MS, SLIDER_CONFIG, SLIDES_FILE_PATH, SLIDE_CANVAS_HEIGHT, SLIDE_CANVAS_WIDTH, STREAM_RESUMABLE_HEADER, SavedTool as SavedToolModel, type SavedToolOperationsContext, type SavedToolParameter, type ScoreBreakdown, type ScoreProfileSalienceOptions, type ScreenProps, type ScreenResult, type ScreenedCandidate, type SearchMessagesOptions, type SearchSource, type SelectPaymentWalletResult, type SelectServerToolsForPromptOptions, type SendMessageWithStorageArgs, type SendMessageWithStorageResult, type ServerTool, type ServerToolsFilter, type ServerToolsFilterFn, type ServerToolsFilterFunction, type ServerToolsOptions, type ServerToolsResponse, type SignMessageFn, type SignMessageOptions, type SlideProps, type StepFinishEvent, type StockPriceClassification, type StockPricePreProcessorOptions, type StorageOperationsContext, type StoredAppFile, type ChatCompletionUsage as StoredChatCompletionUsage, type StoredConversation, type StoredConversationMemory, type StoredEntity, type StoredFileWithContext, type StoredMedia, Media as StoredMediaModel, type StoredMessage, type StoredMessageWithSimilarity, type StoredModelPreference, ModelPreference as StoredModelPreferenceModel, type StoredProject, type StoredSavedTool, type StoredTopic, type StoredUserPreference, UserPreference as StoredUserPreferenceModel, type StoredVaultFolder, VaultFolder as StoredVaultFolderModel, type StoredVaultMemory, VaultMemory as StoredVaultMemoryModel, StreamExpiredError, type StreamMetaEvent, type StreamResumeHandle, type StreamSmoothingConfig, type SynthesizeProfileOptions, THEME_ATTRS, TOOL_RESULT_ORIGIN, TOPICS_EXTRACTION_VERSION, TOPIC_EXTRACTION_BATCH_SIZE, TOPIC_SALIENCE_WEIGHTS, TREND_RECENT_WINDOW_DAYS, TREND_STALE_WINDOW_DAYS, type TextChunk, TextProcessor, type TextProps, type ThemeAttr, type ToolCallArgumentsDeltaEvent, type ToolMatchOptions, type ToolMatchResult, type ToolSet, type TopicExtractOptions, type TopicExtractionBatchDiagnostics, type TopicExtractionInput, type TopicExtractionRunResult, type TopicSalience, type TopicSkipReason, type TopicSource, type TranscriptionResult, type TurnCompleteEvent, type TurnSkippedEvent, type UIInteractionContextValue, UIInteractionProvider, type UIInteractionProviderProps, type UncheckedReason, type UnverifiableReason, type UpdateMediaOptions, type UpdateModelPreferenceOptions, type UpdateProjectOptions, type UpdateSavedToolOptions, type UpdateUserPreferenceOptions, type UpdateVaultFolderOptions, type UpdateVaultMemoryOptions, type UseBackupOptions, type UseBackupResult, type UseChatStorageOptions, type UseChatStorageResult, type UseCreditsOptions, type UseCreditsResult, type UseEncryptionResult, type UseExportPdfResult, type UseFilesOptions, type UseFilesResult, type UseICloudBackupOptions, type UseICloudBackupResult, type UseModelsResult, type UseOCRResult, type UsePdfResult, type UsePhoneCallsOptions, type UsePhoneCallsResult, type UseProjectsOptions, type UseProjectsResult, type UseSettingsOptions, type UseSettingsResult, type UseSubscriptionOptions, type UseSubscriptionResult, type UseToolsOptions, type UseToolsResult, type UseVoiceOptions, type UseVoiceResult, type UseWalletBindingOptions, type UseWalletBindingResult, VAULT_SIZE_HOP_CAP, type VaultCandidateKey, type VaultEmbeddingCache, type VaultEmbeddingExpectation, type VaultFolderOperationsContext, type VaultMemoryKind, type VaultMemoryOperationsContext, type VaultMemoryProjection, type VaultMemoryVisibility, type VaultMemoryWriter, type VaultSaveOperation, type VaultSearchResult, type VaultWriteAction, type VaultWriteInput, type VaultWriteOutcome, type VerificationSources, type VerifyMemoriesForPublishOptions, type VoiceRecording, WALLET_PAYMENT_TOOL_NAME, type WalletPaymentOutcome, type WalletPaymentPassenger, type WalletPaymentRequest, type WalletPaymentResult, WalletPoller, WatermelonChatStorageAdapter, type WatermelonChatStorageAdapterOptions, type WeatherClassification, type WeatherPreProcessorOptions, type WebSearchClassification, type WebSearchPreProcessorOptions, type WhisperModel, WordProcessor, type WriteFailureReason, ZipProcessor, type ZipProcessorOptions, addConversationMemoriesOp, appFileToStored, archiveVaultMemoryOp, assembleMemoryContext, attachFileContextToLastUserMessage, backfillMemoryEntityUserIdsOp, backfillMemoryTopicsOp, buildAttachedFilesText, capHopsForDensity, chatStorageMigrations, chatStorageSchema, chunkAndEmbedAllMessages, chunkAndEmbedMessage, chunkText, classifyCryptoPrice, classifyCryptoPriceBatch, classifyDecay, classifyInjectionCandidates, classifyObservationTrend, classifyStockPrice, classifyStockPriceBatch, classifyWeather, classifyWeatherBatch, classifyWebSearch, classifyWebSearchBatch, clearAllEncryptionKeys, clearAllEncryptionState, clearAllKeyPairs, clearConversationMemoriesOp, clearEncryptionKey, clearICloudAuth, clearKeyPair, clearLazyTitleCache, clearMemoryTopicsOverrideOp, clearModelsCache, clearNotionToken, clearServerToolsCache, consoleLogger, conversationMemoryToStored, cosineInt8, createAutoExtractor, createChunkVectorCache, createCryptoPricePreProcessor, createDecaySweeper, createDurableAutoExtractor, createGitHubTools, createLlmDecayClassifier, createLlmNeighborRefiner, createLocalMemoryStore, createMediaBatchOp, createMediaOp, createMemoryEngineTool, createMemoryVaultSearchTool, createMemoryVaultTool, createMessageSourceResolver, createPlatformCursorStore, createProjectOp, createRecallTool, createRemoteChatStore, createRemoteMemoryPersistence, createRemoteMemoryPipeline, createRemoteMemoryStore, createSavedToolOp, createSelectPaymentWalletTool, createServerToolsFilter, createStockPricePreProcessor, createVaultEmbeddingCache, createVaultFolderOp, createVaultMemoriesBatchOp, createVaultMemoryOp, createWalletPaymentTool, createWeatherPreProcessor, createWebSearchPreProcessor, decodeChunkVector, decryptConversationTitle, decryptData, decryptDataBatch, decryptDataBytes, decryptDataBytesFromBytes, decryptDataWithKey, decryptMessageEmbeddingFields, defaultServerToolsFilter, deleteAllAppFilesOp, deleteAllVaultMemoriesForUserOp, deleteAppFileOp, deleteEncryptedFile, deleteMediaByConversationOp, deleteMediaByMessageOp, deleteMediaOp, deleteMessageOp, deleteProjectOp, deleteSavedToolOp, deleteVaultFolderOp, deleteVaultMemoryOp, dequantizeEmbedding, deriveKeyFromSignatureBytes, deriveMemoryKeyRing, eagerEmbedContent, embedAllMessages, embedMessage, encodeChunkVector, encryptData, encryptDataBatch, encryptDataBytes, encryptDataWithKey, encryptToolCallEventsOp, ensureDefaultFoldersOp, expandToolSetsAdditive, exportElementToPdf, exportMarkdownToPdf, exportPublicKey, extractAndLinkEntitiesForMemoriesOp, extractAndRetain, extractEntitiesForMemories, extractFacts, extractFileIds, extractMCPImageUrls, extractReservationReceipts, fileExists, findById, findMatchingTools, findParentOfId, formatFileProcessingNotes, generateConversationId, generateEmbedding, generateEmbeddings, generateMediaId, generateProjectId, getAIGeneratedMediaOp, getAllSavedToolsOp, getAllVaultFoldersOp, getAllVaultMemoriesOp, getAllVaultMemoryContentsOp, getAndClearNotionPendingMessage, getAndClearNotionReturnUrl, getAppFileMapOp, getAppFileOp, getAppFilesOp, getAudioOp, getCachedServerTools, getConversationMemoriesOp, getConversationsByProjectLazyOp, getConversationsByProjectOp, getConversationsLazyOp, getConversationsPageOp, getDecayCandidatesRawOp, getDocumentsOp, getEncryptionKey, getEntitiesByMemoryIdsOp, getId, getImagesOp, getLogger, getMediaByConversationOp, getMediaByIdOp, getMediaByIdsOp, getMediaByMessageOp, getMediaByModelOp, getMediaByRoleOp, getMediaBySourceUrlOp, getMediaByTypeOp, getMediaCountOp, getMediaCountsByTypeOp, getMediaOp, getMediaTypeFromMime, getMemoriesByEntityNamesOp, getMemoriesNeedingTopicExtractionOp, getNotionAccessToken, getNotionMCPUrl, getNumberAttr, getProjectConversationCountOp, getProjectConversationsOp, getProjectOp, getProjectsOp, getRecentMediaOp, getSavedToolByIdOp, getServerTools, getStringAttr, getSupportedFileTypes, getToolsChecksum, getUnfiledVaultMemoriesOp, getUserUploadedMediaOp, getValidNotionToken, getVaultCandidateKeysOp, getVaultEmbeddingsByIdsOp, getVaultFolderMemoryCountOp, getVaultMemoriesByIdsOp, getVaultMemoryOp, getVaultRankingProjectionsOp, getVideosOp, handleNotionCallback, hardDeleteDecayedOp, hardDeleteMediaOp, hasEncryptionKey, hasICloudCredentials, hasKeyPair, hasNotionCredentials, ingestPublishedPhotoMemoriesOp, injectionSignatureCatalog, insertAfterId, insertChild, isAnumaTag, isAttachedFilesText, isDegradedTopicSkip, isEncrypted, isHtmlTag, isNotionCallback, isOPFSSupported, isR2UrlExpired, isRerankerAvailable, isSupportedFile, isSupportedMediaType, linkMemoryEntitiesOp, maskScopedEmbeddingCache, mediaToStored, memoryCipher, migrateDisplayResult, migrateMemoriesToRemote, migrateNotionClientRegistration, migrateNotionToken, moveMemoriesToFolderOp, noopLogger, onKeyAvailable, parseJsx, parseMedia, preEmbedVaultMemories, preprocessFiles, previewToolSelection, primaryTopic, projectToStored, putAppFileOp, quantizeEmbedding, queueManager, rankProfileCandidates, readEncryptedFile, recall, reencryptMemoryField, reflect, refreshEncryptionKeyIfMatches, refreshNotionToken, relinkMemoryTopicsOp, relinkMisclassifiedVideosOp, removeById, renderAnumaJsx, renderAnumaTree, renderElementToCanvas, replaceById, replaceMemoryEntitiesGuardedOp, requestEncryptionKey, requestKeyPair, resolveFilePlaceholders, resolveThemeColor, restoreVaultMemoryOp, resumeStream, retain, revokeNotionAccess, savedToolToStored, scoreProfileSalience, screenCandidatesForInjection, sdkMigrations, sdkModelClasses, sdkSchema, sealLegacyMessageEmbeddingsOp, searchChunksOp, searchMediaOp, searchMessagesOp, searchVaultMemories, seedEncryptionKeys, selectServerToolsForPrompt, serializeJsx, setLogger, setMemoryEntitiesOp, setMemoryVisibilityOp, settingsStorageSchema, shouldChunkMessage, shouldRecallMemory, shouldRefreshTools, stampTopicsExtractedAtOp, startNotionAuth, storeNotionPendingMessage, storeNotionReturnUrl, streamCancelPath, streamReplayPath, stripLegacyChunkTextOp, summarizeObservationTrends, supersedeVaultMemoryOp, synthesizeProfile, topicWeight, traverseGraphLane, ttlForType, updateAttrs, updateConversationProjectOp, updateMediaMessageIdBatchOp, updateMediaOp, updateMessageFeedbackOp, updateProjectNameOp, updateProjectOp, updateSavedToolOp, updateVaultFolderContextOp, updateVaultFolderOp, updateVaultMemoryEmbeddingOp, updateVaultMemoryOp, useAnumaTheme, useBackup, useBackupAuth, useChat, useChatStorage, useCredits, useDatabaseManager, useEncryption, useExportPdf, useFiles, useICloudAuth, useICloudBackup, useModels, useOCR, usePdf, usePhoneCalls, useProjects, useSettings, useSubscription, useTools, useUIInteraction, useVoice, useWalletBinding, userPreferencesStorageSchema, verifyMemoriesForPublish, walk, webPlatformStorage, withActiveToolSetServerTools, withInternalFlowMarker, writeEncryptedFile };
16189
+ export { Anuma, type AnumaChild, AnumaJsxError, type AnumaNode, AnumaShadowIsolationProvider, type AnumaShadowIsolationProviderProps, type AnumaTheme, AnumaThemeProvider, type AnumaThemeProviderProps, AppFile as AppFileModel, type AppFileOperationsContext, type AttrValue, type AutoExtractMessage, type AutoExtractor, DEFAULT_BACKUP_FOLDER as BACKUP_ICLOUD_FOLDER, BUILT_IN_TOOL_SETS, type BackupAuthContextValue, BackupAuthProvider, type BackupAuthProviderProps, type BackupOperationOptions, BlobUrlManager, type Budget, CHUNKS_DISCARDED_ORIGIN, type CachedChunkVectors, type CachedServerTools, ChartCard, type ChartCardProps, type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, type ChatAccount, type ChatAccountState, type ChatAttachment, type ChatAttachments, type ChatBackend, type ChatBackendFactory, type ChatBackendSigner, type ChatChanges, type ChatChunkSearchOptions, Conversation as ChatConversation, type ChatImport, type ChatJson, type ChatListOptions, Message as ChatMessage, type ChatMigrationOptions, type ChatMigrationProgress, type ChatMigrationResult, type ChatMigrationSkip, type ChatOutboxLocks, type ChatOutboxStorage, type ChatPage, type ChatPresignedUrl, type ChatRecord, type ChatRecordKind, type ChatRef, type ChatRevision, type ChatRole, type ChatSearchHit, type ChatSearchOptions, type ChatSnapshot, type ChatStorageAdapter, type ChatStorageObservable, type ChatStore, ChatStoreError, type ChatWrite, type ChunkSearchResult, type ChunkSearchStats, type ChunkVectorCache, type ChunkingOptions, type CircleProps, type ClientToolsFilterFn, type ConsolidationAction, type ConsolidationFallbackReason, type ConversationMemoryInput, ConversationMemory as ConversationMemoryModel, type ConversationMemoryOperationsContext, type ConversationQueryOptions, type CreateAutoExtractorOptions, type CreateConversationOptions, type CreateDecaySweeperOptions, type CreateEntityOptions, type CreateMediaOptions, type CreateMessageOptions, type CreateModelPreferenceOptions, type CreateProjectOptions, type CreateSavedToolOptions, type CreateSelectPaymentWalletToolOptions, type CreateServerToolsFilterOptions, type CreateUserPreferenceOptions, type CreateVaultFolderOptions, type CreateVaultMemoryOptions, type CreateWalletPaymentToolOptions, type CryptoPriceClassification, type CryptoPricePreProcessorOptions, DEFAULT_CACHE_EXPIRATION_MS, DEFAULT_CHUNK_CACHE_SIZE, DEFAULT_CHUNK_OVERLAP, DEFAULT_CHUNK_SIZE, DEFAULT_DECAY_POLICY, DEFAULT_EXCLUDED_SERVER_TOOLS, DEFAULT_BACKUP_FOLDER as DEFAULT_ICLOUD_BACKUP_FOLDER, DEFAULT_MAX_CLASSIFIER_CALLS_PER_SWEEP, DEFAULT_MIN_CHUNK_SIZE, DEFAULT_PERSONALITY_SETTINGS, DEFAULT_PROFILE_FACETS, DEFAULT_PROFILE_FACT_TYPE_WEIGHTS, DEFAULT_PROFILE_PROOF_ALPHA, DEFAULT_PROFILE_TREND_MULTIPLIERS, DEFAULT_SERVER_TOOLS_MATCH_OPTIONS, DEFAULT_VAULT_CACHE_SIZE, DatabaseManager, type DatabaseManagerLogger, type DatabaseManagerOptions, type DecayCandidateRaw, type DecayClassifier, type DecayInput, type DecayPolicy, type DecaySweepResult, type DecaySweeper, type DecayVerdict, type DeckProps, type DisplayToolMigrations, type DurableAutoExtractorOptions, ENTITY_FANOUT, ENTITY_KINDS, type EmbeddedWalletSignerFn, type EmbeddingRepairOptions, type EmbeddingRepairResult, EncryptionKeyMissingError, type EncryptionKeyVersion, type EntityInput, type EntityKind, Entity as EntityModel, type EntityOperationsContext, ExcelProcessor, type ExtractFactsOptions, type ExtractOutcome, type ExtractedCandidate, type ExtractedEntity, type ExtractionCursorStore, type ExtractionFunnel, type ExtractionMessageSource, type ExtractionSourceMessage, type ExtractionSourceStatus, type ExtractionTimings, FILE_PLACEHOLDER_PREFIX, FILE_PLACEHOLDER_REGEX, type FactType, type FileMetadata, type FileProcessingReason, type FileProcessingStatus, type FileProcessor, type FileTypeQuery, type FileWithData, type FlushResult, type GetConversationsPageOptions, type GetMessagesPageOptions, type GraphTraversalOptions, type GroupProps, HARD_DELETE_WINDOW_MS, type ICloudAuthContextValue, ICloudAuthProvider, type ICloudAuthProviderProps, type ICloudExportResult, type ICloudImportResult, INFERENCE_ID_HEADER, INTERNAL_FLOW_MARKER, type IconProps, type ImageProps, type InjectionClassifierOptions, type InjectionReason, type InteractionType, type KnownTag, type LazyStoredConversation, type LineProps, type LlmDecayClassifierOptions, type LlmNeighborRefinerOptions, type LocalMemoryStoreOptions, type Logger, LoggerProvider, type LoggerProviderProps, MAX_HOPS, MEDIUM_TTL_MS, MEMORY_KINDS, MEMORY_LEVELS, type ManualFactType, type MediaDimensions, type MediaFilterOptions, type MediaMetadata, type MediaOperationsContext, type MediaRole, type MediaType, type MemoriesNeedingTopicExtraction, type MemoryContextItem, type MemoryContextLane, type MemoryContextOptions, type MemoryContextResult, type MemoryCounts, type MemoryCreate, type MemoryDecay, type MemoryDecaySweeperOptions, type EmbeddingOptions as MemoryEngineEmbeddingOptions, type MemoryEngineResult, type MemoryEngineSearchOptions, MemoryEntity as MemoryEntityModel, type MemoryExtractedEvent, MemoryKeyError, type MemoryKeyRing, type MemoryKind, type MemoryLevel, MemoryLevelError, type MemoryListOptions, type MemoryMaintenance, type MemoryMigrationOptions, type MemoryMigrationProgress, type MemoryMigrationResult, type MemoryMigrationSkip, type MemoryQuarantinedEvent, type MemoryRecallOptions, type MemoryRetainOptions, type MemoryStore, type MemorySubscribeOptions, type MemoryToVerify, type MemoryTopic, type MemoryTopicBacklog, type MemoryTopicMaintenance, type MemoryUpdate, type MemoryVaultSearchOptions, type MemoryVaultToolOptions, type MemoryVerification, type MessageChunk, type MessageFeedback, type MessageOrigin, type MessageSkeleton, type ModelLoadProgress, NEVER_TTL_MS, NODE_BUDGET, type NeighborRefiner, type NowSource, type OCRFile, type ObservationTrend, type ObservationTrendInput, type OperationExecutor, PAST_EVENT_GRACE_MS, PROFILE_DOC_VERSION, type ParsedServerToolsResponse, type PaymentWallet, type PdfExportOptions, type PdfExportProgress, type PdfExportStage, type PdfFile, PdfProcessor, type PendingInteraction, type PersonalitySettings, type PersonalitySliders, type PersonalityStyle, type PhoneCallPollingOptions, type PhotoIngestResult, type PhotoMediaRef, type PlatformStorage, type PortalLlmAuth, type PortalLlmFailure, type PortalLlmFailureReason, type PreprocessingOptions, type PreprocessingResult, type ProcessedFileResult, ProcessorRegistry, type ProfileConfigFingerprint, type ProfileDoc, type ProfileFacet, type ProfileFacetKey, type ProfileSalienceInput, type ProfileSection, type ProfileUpdate, type ProgressCallback, Project, type ProjectOperationsContext, type PromptPreProcessor, type PromptPreProcessorContext, type ProviderAuthState, type ProviderBackupState, ProviderStreamError, type PublishedPhotoMemory, type QuantizedEmbedding, type QuarantinedMemoryInfo, type QueueEncryptionContext, QueueManager, type QueueStatus, type QueuedOperation, type QueuedOperationType, R2_DEFAULT_TTL_MS, RECALL_MAX_LIMIT, RECALL_TOOL_NAME, type RankableVaultMemory, type RankedMemory, type RankedProfileCandidate, type RecallContext, type RecallDegradation, type RecallDiagnostics, type RecallEmptyReason, type RecallOptions, type RecallResult, type RecallTelemetryCallbacks, type RecallToolCallbacks, type RecallToolOptions, type RecallTruncation, type RecencyOptions, type RectProps, type ReflectOptions, type ReflectResult, type RemoteChatStoreOptions, type RemoteMemoryCandidateOptions, type RemoteMemoryDecodeFailure, RemoteMemoryError, type RemoteMemoryListOptions, type RemoteMemoryMetadataPage, type RemoteMemoryMetadataRecord, type RemoteMemoryPage, RemoteMemoryPartialCreateError, type RemoteMemoryPersistence, type RemoteMemoryPersistenceOptions, type RemoteMemoryPipeline, type RemoteMemoryPipelineOptions, type RemoteMemoryQueryOptions, type RemoteMemoryQueryPage, type RemoteMemoryReadFilters, type RemoteMemoryRecord, type RemoteMemoryRow, type RemoteMemoryStoreOptions, type RemoteMemoryTopic, type RemoteMemoryWorkKind, type RemoteMemoryWorkLease, type RemoteMemoryWorkPersistence, type RemoteTopicPersistence, type RequestEncryptionKeyOptions, RerankerUnavailableError, type ReservationReceipt, type ResumeStreamOptions, type ResumeStreamResult, type RetainAction, type RetainContext, type RetainOptions, type RetainResult, type RetainSource, SDK_SCHEMA_VERSION, SELECT_PAYMENT_WALLET_TOOL_NAME, SERVER_TOOL_DEPENDENCY_SETS, SHORT_TTL_MS, SLIDER_CONFIG, SLIDES_FILE_PATH, SLIDE_CANVAS_HEIGHT, SLIDE_CANVAS_WIDTH, STREAM_RESUMABLE_HEADER, SavedTool as SavedToolModel, type SavedToolOperationsContext, type SavedToolParameter, type ScoreBreakdown, type ScoreProfileSalienceOptions, type ScreenProps, type ScreenResult, type ScreenedCandidate, type SearchMessagesOptions, type SearchSource, type SelectPaymentWalletResult, type SelectServerToolsForPromptOptions, type SendMessageWithStorageArgs, type SendMessageWithStorageResult, type ServerTool, type ServerToolsFilter, type ServerToolsFilterFn, type ServerToolsFilterFunction, type ServerToolsOptions, type ServerToolsResponse, type SignMessageFn, type SignMessageOptions, type SlideProps, type StepFinishEvent, type StockPriceClassification, type StockPricePreProcessorOptions, type StorageOperationsContext, type StoredAppFile, type ChatCompletionUsage as StoredChatCompletionUsage, type StoredConversation, type StoredConversationMemory, type StoredEntity, type StoredFileWithContext, type StoredMedia, Media as StoredMediaModel, type StoredMessage, type StoredMessageWithSimilarity, type StoredModelPreference, ModelPreference as StoredModelPreferenceModel, type StoredProject, type StoredSavedTool, type StoredTopic, type StoredUserPreference, UserPreference as StoredUserPreferenceModel, type StoredVaultFolder, VaultFolder as StoredVaultFolderModel, type StoredVaultMemory, VaultMemory as StoredVaultMemoryModel, StreamExpiredError, type StreamMetaEvent, type StreamResumeHandle, type StreamSmoothingConfig, type SynthesizeProfileOptions, THEME_ATTRS, TOOL_RESULT_ORIGIN, TOPICS_EXTRACTION_VERSION, TOPIC_EXTRACTION_BATCH_SIZE, TOPIC_SALIENCE_WEIGHTS, TREND_RECENT_WINDOW_DAYS, TREND_STALE_WINDOW_DAYS, type TextChunk, TextProcessor, type TextProps, type ThemeAttr, type ToolCallArgumentsDeltaEvent, type ToolMatchOptions, type ToolMatchResult, type ToolSet, type TopicExtractOptions, type TopicExtractionBatchDiagnostics, type TopicExtractionInput, type TopicExtractionRunResult, type TopicSalience, type TopicSkipReason, type TopicSource, type TranscriptionResult, type TurnCompleteEvent, type TurnSkippedEvent, type UIInteractionContextValue, UIInteractionProvider, type UIInteractionProviderProps, type UncheckedReason, type UnverifiableReason, type UpdateMediaOptions, type UpdateModelPreferenceOptions, type UpdateProjectOptions, type UpdateSavedToolOptions, type UpdateUserPreferenceOptions, type UpdateVaultFolderOptions, type UpdateVaultMemoryOptions, type UseBackupOptions, type UseBackupResult, type UseChatStorageOptions, type UseChatStorageResult, type UseCreditsOptions, type UseCreditsResult, type UseEncryptionResult, type UseExportPdfResult, type UseFilesOptions, type UseFilesResult, type UseICloudBackupOptions, type UseICloudBackupResult, type UseModelsResult, type UseOCRResult, type UsePdfResult, type UsePhoneCallsOptions, type UsePhoneCallsResult, type UseProjectsOptions, type UseProjectsResult, type UseSettingsOptions, type UseSettingsResult, type UseSubscriptionOptions, type UseSubscriptionResult, type UseToolsOptions, type UseToolsResult, type UseVoiceOptions, type UseVoiceResult, type UseWalletBindingOptions, type UseWalletBindingResult, VAULT_SIZE_HOP_CAP, type VaultCandidateKey, type VaultChatActivity, type VaultChatBackend, type VaultChatBackendOptions, type VaultChatEvent, type VaultEmbeddingCache, type VaultEmbeddingExpectation, type VaultFolderOperationsContext, type VaultMemoryKind, type VaultMemoryOperationsContext, type VaultMemoryProjection, type VaultMemoryVisibility, type VaultMemoryWriter, type VaultSaveOperation, type VaultSearchResult, type VaultWriteAction, type VaultWriteInput, type VaultWriteOutcome, type VerificationSources, type VerifyMemoriesForPublishOptions, type VoiceRecording, WALLET_PAYMENT_TOOL_NAME, type WalletPaymentOutcome, type WalletPaymentPassenger, type WalletPaymentRequest, type WalletPaymentResult, WalletPoller, WatermelonChatStorageAdapter, type WatermelonChatStorageAdapterOptions, type WeatherClassification, type WeatherPreProcessorOptions, type WebSearchClassification, type WebSearchPreProcessorOptions, type WhisperModel, WordProcessor, type WriteFailureReason, ZipProcessor, type ZipProcessorOptions, addConversationMemoriesOp, appFileToStored, archiveVaultMemoryOp, assembleMemoryContext, attachFileContextToLastUserMessage, backfillMemoryEntityUserIdsOp, backfillMemoryTopicsOp, buildAttachedFilesText, capHopsForDensity, chatStorageMigrations, chatStorageSchema, chunkAndEmbedAllMessages, chunkAndEmbedMessage, chunkText, classifyCryptoPrice, classifyCryptoPriceBatch, classifyDecay, classifyInjectionCandidates, classifyObservationTrend, classifyStockPrice, classifyStockPriceBatch, classifyWeather, classifyWeatherBatch, classifyWebSearch, classifyWebSearchBatch, clearAllEncryptionKeys, clearAllEncryptionState, clearAllKeyPairs, clearConversationMemoriesOp, clearEncryptionKey, clearICloudAuth, clearKeyPair, clearLazyTitleCache, clearMemoryTopicsOverrideOp, clearModelsCache, clearNotionToken, clearServerToolsCache, consoleLogger, conversationMemoryToStored, cosineInt8, createAutoExtractor, createChunkVectorCache, createCryptoPricePreProcessor, createDecaySweeper, createDurableAutoExtractor, createGitHubTools, createLlmDecayClassifier, createLlmNeighborRefiner, createLocalMemoryStore, createMediaBatchOp, createMediaOp, createMemoryEngineTool, createMemoryVaultSearchTool, createMemoryVaultTool, createMessageSourceResolver, createPlatformCursorStore, createProjectOp, createRecallTool, createRemoteChatStore, createRemoteMemoryPersistence, createRemoteMemoryPipeline, createRemoteMemoryStore, createSavedToolOp, createSelectPaymentWalletTool, createServerToolsFilter, createStockPricePreProcessor, createVaultChatBackend, createVaultEmbeddingCache, createVaultFolderOp, createVaultMemoriesBatchOp, createVaultMemoryOp, createWalletPaymentTool, createWeatherPreProcessor, createWebSearchPreProcessor, decodeChunkVector, decryptConversationTitle, decryptData, decryptDataBatch, decryptDataBytes, decryptDataBytesFromBytes, decryptDataWithKey, decryptMessageEmbeddingFields, defaultServerToolsFilter, deleteAllAppFilesOp, deleteAllVaultMemoriesForUserOp, deleteAppFileOp, deleteEncryptedFile, deleteMediaByConversationOp, deleteMediaByMessageOp, deleteMediaOp, deleteMessageOp, deleteProjectOp, deleteSavedToolOp, deleteVaultFolderOp, deleteVaultMemoryOp, dequantizeEmbedding, deriveKeyFromSignatureBytes, deriveMemoryKeyRing, eagerEmbedContent, embedAllMessages, embedMessage, encodeChunkVector, encryptData, encryptDataBatch, encryptDataBytes, encryptDataWithKey, encryptToolCallEventsOp, ensureDefaultFoldersOp, expandToolSetsAdditive, exportElementToPdf, exportMarkdownToPdf, exportPublicKey, extractAndLinkEntitiesForMemoriesOp, extractAndRetain, extractEntitiesForMemories, extractFacts, extractFileIds, extractMCPImageUrls, extractReservationReceipts, fileExists, findById, findMatchingTools, findParentOfId, formatFileProcessingNotes, generateConversationId, generateEmbedding, generateEmbeddings, generateMediaId, generateProjectId, getAIGeneratedMediaOp, getAllSavedToolsOp, getAllVaultFoldersOp, getAllVaultMemoriesOp, getAllVaultMemoryContentsOp, getAndClearNotionPendingMessage, getAndClearNotionReturnUrl, getAppFileMapOp, getAppFileOp, getAppFilesOp, getAudioOp, getCachedServerTools, getConversationMemoriesOp, getConversationsByProjectLazyOp, getConversationsByProjectOp, getConversationsLazyOp, getConversationsPageOp, getDecayCandidatesRawOp, getDocumentsOp, getEncryptionKey, getEntitiesByMemoryIdsOp, getId, getImagesOp, getLogger, getMediaByConversationOp, getMediaByIdOp, getMediaByIdsOp, getMediaByMessageOp, getMediaByModelOp, getMediaByRoleOp, getMediaBySourceUrlOp, getMediaByTypeOp, getMediaCountOp, getMediaCountsByTypeOp, getMediaOp, getMediaTypeFromMime, getMemoriesByEntityNamesOp, getMemoriesNeedingTopicExtractionOp, getNotionAccessToken, getNotionMCPUrl, getNumberAttr, getProjectConversationCountOp, getProjectConversationsOp, getProjectOp, getProjectsOp, getRecentMediaOp, getSavedToolByIdOp, getServerTools, getStringAttr, getSupportedFileTypes, getToolsChecksum, getUnfiledVaultMemoriesOp, getUserUploadedMediaOp, getValidNotionToken, getVaultCandidateKeysOp, getVaultEmbeddingsByIdsOp, getVaultFolderMemoryCountOp, getVaultMemoriesByIdsOp, getVaultMemoryOp, getVaultRankingProjectionsOp, getVideosOp, handleNotionCallback, hardDeleteDecayedOp, hardDeleteMediaOp, hasEncryptionKey, hasICloudCredentials, hasKeyPair, hasNotionCredentials, ingestPublishedPhotoMemoriesOp, injectionSignatureCatalog, insertAfterId, insertChild, isAnumaTag, isAttachedFilesText, isDegradedTopicSkip, isEncrypted, isHtmlTag, isNotionCallback, isOPFSSupported, isR2UrlExpired, isRerankerAvailable, isSupportedFile, isSupportedMediaType, linkMemoryEntitiesOp, localChatBackend, maskScopedEmbeddingCache, mediaToStored, memoryCipher, migrateChatsToRemote, migrateDisplayResult, migrateMemoriesToRemote, migrateNotionClientRegistration, migrateNotionToken, moveMemoriesToFolderOp, noopLogger, onKeyAvailable, parseJsx, parseMedia, preEmbedVaultMemories, preprocessFiles, previewToolSelection, primaryTopic, projectToStored, putAppFileOp, quantizeEmbedding, queueManager, rankProfileCandidates, readEncryptedFile, recall, reencryptMemoryField, reflect, refreshEncryptionKeyIfMatches, refreshNotionToken, relinkMemoryTopicsOp, relinkMisclassifiedVideosOp, removeById, renderAnumaJsx, renderAnumaTree, renderElementToCanvas, replaceById, replaceMemoryEntitiesGuardedOp, requestEncryptionKey, requestKeyPair, resolveFilePlaceholders, resolveThemeColor, restoreVaultMemoryOp, resumeStream, retain, revokeNotionAccess, savedToolToStored, scoreProfileSalience, screenCandidatesForInjection, sdkMigrations, sdkModelClasses, sdkSchema, sealLegacyMessageEmbeddingsOp, searchChunksOp, searchMediaOp, searchMessagesOp, searchVaultMemories, seedEncryptionKeys, selectServerToolsForPrompt, serializeJsx, setLogger, setMemoryEntitiesOp, setMemoryVisibilityOp, settingsStorageSchema, shouldChunkMessage, shouldRecallMemory, shouldRefreshTools, stampTopicsExtractedAtOp, startNotionAuth, storeNotionPendingMessage, storeNotionReturnUrl, streamCancelPath, streamReplayPath, stripLegacyChunkTextOp, summarizeObservationTrends, supersedeVaultMemoryOp, synthesizeProfile, topicWeight, traverseGraphLane, ttlForType, updateAttrs, updateConversationProjectOp, updateMediaMessageIdBatchOp, updateMediaOp, updateMessageFeedbackOp, updateProjectNameOp, updateProjectOp, updateSavedToolOp, updateVaultFolderContextOp, updateVaultFolderOp, updateVaultMemoryEmbeddingOp, updateVaultMemoryOp, useAnumaTheme, useBackup, useBackupAuth, useChat, useChatStorage, useCredits, useDatabaseManager, useEncryption, useExportPdf, useFiles, useICloudAuth, useICloudBackup, useModels, useOCR, usePdf, usePhoneCalls, useProjects, useSettings, useSubscription, useTools, useUIInteraction, useVoice, useWalletBinding, userPreferencesStorageSchema, vaultChatBackend, verifyMemoriesForPublish, walk, webPlatformStorage, withActiveToolSetServerTools, withInternalFlowMarker, writeEncryptedFile };