@anuma/sdk 2.4.1 → 2.5.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.
@@ -4316,6 +4316,9 @@ declare class VaultMemory extends Model {
4316
4316
  /** Unix ms of the last LLM topic-extraction pass. Null = never extracted
4317
4317
  * standalone (linked legacy rows are grandfathered as extracted). */
4318
4318
  topicsExtractedAt: number | null;
4319
+ /** A2 supersession: newer memory id that replaced this one, or null if live. */
4320
+ supersededBy: string | null;
4321
+ supersededAt: number | null;
4319
4322
  createdAt: Date;
4320
4323
  updatedAt: Date;
4321
4324
  isDeleted: boolean;
@@ -4423,6 +4426,13 @@ interface StoredVaultMemory {
4423
4426
  * Null = never extracted standalone; rows that already carry entity links
4424
4427
  * are grandfathered as extracted (see getMemoriesNeedingTopicExtractionOp). */
4425
4428
  topicsExtractedAt: number | null;
4429
+ /** Write-time supersession (A2): id of the newer memory that replaced this
4430
+ * one (incompatible-value update, e.g. "Lives in Portland" → "Lives in SF").
4431
+ * Null = live. Superseded rows are excluded from recall/dedup by default but
4432
+ * kept for history + the read-time fallback. */
4433
+ supersededBy: string | null;
4434
+ /** Unix ms when this memory was superseded. Null when live. */
4435
+ supersededAt: number | null;
4426
4436
  createdAt: Date;
4427
4437
  updatedAt: Date;
4428
4438
  isDeleted: boolean;
@@ -4531,12 +4541,30 @@ declare function getAllVaultMemoriesOp(ctx: VaultMemoryOperationsContext, option
4531
4541
  * render "forgotten" nodes; ordinary consumers should leave this off.
4532
4542
  */
4533
4543
  includeDeleted?: boolean;
4544
+ /**
4545
+ * Include A2-superseded memories (each carries `supersededBy`). Default
4546
+ * `false` — superseded rows are excluded, as they are from recall/dedup.
4547
+ * Used by a "memory history" view to render retired facts.
4548
+ */
4549
+ includeSuperseded?: boolean;
4534
4550
  }): Promise<StoredVaultMemory[]>;
4535
4551
  declare function getAllVaultMemoryContentsOp(ctx: VaultMemoryOperationsContext, options?: {
4536
4552
  since?: Date;
4537
4553
  }): Promise<string[]>;
4538
4554
  declare function updateVaultMemoryOp(ctx: VaultMemoryOperationsContext, id: string, opts: UpdateVaultMemoryOptions): Promise<StoredVaultMemory | null>;
4539
4555
  declare function deleteVaultMemoryOp(ctx: VaultMemoryOperationsContext, id: string): Promise<boolean>;
4556
+ /**
4557
+ * Mark a memory as superseded by a newer one (A2 write-time supersession).
4558
+ * The row stays in the table (history + read-time fallback) but is excluded
4559
+ * from recall/dedup by default via `superseded_by`. Idempotent-ish: no-op if
4560
+ * the row is missing, not owned, deleted, or already superseded. Does NOT
4561
+ * preserve `updated_at` — superseded rows are hidden from recall, so their
4562
+ * recency is irrelevant.
4563
+ *
4564
+ * @param id - the memory being retired (e.g. "Lives in Portland")
4565
+ * @param supersededById - the newer memory that replaced it (e.g. "Lives in SF")
4566
+ */
4567
+ declare function supersedeVaultMemoryOp(ctx: VaultMemoryOperationsContext, id: string, supersededById: string): Promise<boolean>;
4540
4568
  /**
4541
4569
  * Get all non-deleted, unfiled vault memories (folder_id is null).
4542
4570
  */
@@ -5183,7 +5211,7 @@ interface RecallDiagnostics {
5183
5211
  /** Soft-degradation signals that fired this call (empty when clean). */
5184
5212
  degraded: RecallDegradation[];
5185
5213
  }
5186
- type RetainAction = "create" | "merge" | "update" | "skip" | "suppressed";
5214
+ type RetainAction = "create" | "merge" | "update" | "skip" | "suppressed" | "supersede";
5187
5215
  type RetainSource = "manual" | "auto-extracted" | "capsule";
5188
5216
  /** Why the consolidator fell back to "create" instead of a real decision. */
5189
5217
  type ConsolidationFallbackReason = "llm_error" | "invalid_response";
@@ -5249,7 +5277,8 @@ interface RetainOptions {
5249
5277
  interface RetainResult {
5250
5278
  action: RetainAction;
5251
5279
  memoryId: string;
5252
- /** When action is 'merge' or 'update', the prior memory's id. */
5280
+ /** When action is 'merge' or 'update', the prior memory's id. When action is
5281
+ * 'supersede', the stale memory that was retired (`memoryId` is the new one). */
5253
5282
  targetId?: string;
5254
5283
  /**
5255
5284
  * When action is 'suppressed', the id of the soft-deleted memory that blocked
@@ -5471,9 +5500,12 @@ declare function extractFacts(messages: AutoExtractMessage[], options: ExtractFa
5471
5500
  type ExtractOutcome = "extracted" | "no-facts" | "empty-after-retry" | "dropped-after-redaction";
5472
5501
  /**
5473
5502
  * Stage 2 — for each extracted candidate, call retain() with auto-merge
5474
- * enabled. The resolver path (decide create/merge/update via a second LLM
5475
- * call against the existing vault) is deferred — the auto-merge inside
5476
- * retain() handles dedup at the cosine-similarity level for hackathon.
5503
+ * enabled. When `consolidateOptions` are wired, retain()'s consolidation pass
5504
+ * is the "resolver": a second LLM call against the top-K existing vault
5505
+ * memories that decides create/update/noop/supersede — including retiring a
5506
+ * stale value on a state change (the supersession the extraction prompt above
5507
+ * promises). Without consolidation, retain() still dedups at the cosine-merge
5508
+ * level, and the read-time supersession heuristic remains the fallback.
5477
5509
  *
5478
5510
  * Returns the candidates that survived validation along with the retain
5479
5511
  * result for each (which captures whether the fact was created, merged,
@@ -6733,8 +6765,12 @@ declare function useChatStorage(options: UseChatStorageOptions): UseChatStorageR
6733
6765
  * LLM topic-extraction pass, so the background topic worker re-extracts only
6734
6766
  * memories edited since (updated_at > topics_extracted_at) instead of
6735
6767
  * re-running the whole vault
6768
+ * - v37: Added superseded_by + superseded_at columns to memory_vault for
6769
+ * write-time supersession — a changed fact retires the stale one (points at
6770
+ * the newer memory) instead of both surviving; superseded rows are excluded
6771
+ * from recall/dedup by default
6736
6772
  */
6737
- declare const SDK_SCHEMA_VERSION = 36;
6773
+ declare const SDK_SCHEMA_VERSION = 37;
6738
6774
  /**
6739
6775
  * Combined WatermelonDB schema for all SDK storage modules.
6740
6776
  *
@@ -6814,6 +6850,7 @@ declare const sdkSchema: Readonly<{
6814
6850
  * - v32 → v33: Added `embedding_model` column to memory_vault (null grandfathered as current-model-compatible)
6815
6851
  * - v34 → v35: Added `conversation_memory` table (conversation ↔ recalled memory ids)
6816
6852
  * - v35 → v36: Added `topics_extracted_at` column to memory_vault (watermark for the background topic-extraction worker; null + existing links grandfathered as extracted)
6853
+ * - v36 → v37: Added `superseded_by` + `superseded_at` columns to memory_vault (write-time supersession; null = live, excluded from recall/dedup when set)
6817
6854
  */
6818
6855
  declare const sdkMigrations: Readonly<{
6819
6856
  validated: true;
@@ -7335,4 +7372,4 @@ declare function refreshNotionAccessToken(params: NotionRefreshTokenParams): Pro
7335
7372
  */
7336
7373
  declare function createNotionTools(getAccessToken: () => string | null, requestNotionAccess: () => Promise<string>): ToolConfig[];
7337
7374
 
7338
- export { type AutoExtractMessage, type AutoExtractor, type Budget, type CachedChunkVectors, type CachedServerTools, Conversation as ChatConversation, Message as ChatMessage, type ChatRole, type ChunkVectorCache, type ChunkingOptions, type ConsolidationFallbackReason, type ConversationMemoryInput, ConversationMemory as ConversationMemoryModel, type ConversationMemoryOperationsContext, type CreateAutoExtractorOptions, type CreateConversationOptions, type CreateMessageOptions, type CreateVaultFolderOptions, type CreateVaultMemoryOptions, type CryptoPriceClassification, type CryptoPricePreProcessorOptions, DEFAULT_CACHE_EXPIRATION_MS, DEFAULT_CHUNK_CACHE_SIZE, DEFAULT_CHUNK_OVERLAP, DEFAULT_CHUNK_SIZE, DEFAULT_MIN_CHUNK_SIZE, DEFAULT_VAULT_CACHE_SIZE, DatabaseManager, type DatabaseManagerLogger, type DatabaseManagerOptions, type EmbeddedWalletSignerFn, type ExtractFactsOptions, type ExtractOutcome, type ExtractedCandidate, type ExtractedEntity, type ExtractionCursorStore, type FactType, type FileMetadata, type FlushResult, type GetMessagesPageOptions, INFERENCE_ID_HEADER, type LazyStoredConversation, type Logger, LoggerProvider, type LoggerProviderProps, type MemoriesNeedingTopicExtraction, type EmbeddingOptions as MemoryEngineEmbeddingOptions, type MemoryEngineResult, type MemoryEngineSearchOptions, type MemoryExtractedEvent, type MemoryKind, type MemoryVaultSearchOptions, type MemoryVaultToolOptions, type MessageRedactionResult, type MessageSkeleton, NOTION_OAUTH_CONFIG, type NotionAuthUrlParams, type NotionClientRegistration, type NotionExchangeCodeParams, type NotionOAuthEndpoints, type NotionPKCEChallenge, type NotionRefreshTokenParams, type NotionTokenResponse, PII_PATTERNS, type PiiCategory, type PiiMatch, type PiiPattern, PiiRedactor, type PiiRedactorOptions, type PlatformStorage, type PortalLlmAuth, type PromptPreProcessor, type PromptPreProcessorContext, type QuantizedEmbedding, QueueManager, type QueueStatus, RECALL_MAX_LIMIT, RECALL_TOOL_NAME, type RankedMemory, type RecallContext, type RecallDegradation, type RecallDiagnostics, type RecallOptions, type RecallResult, type RecallToolCallbacks, type RecallToolOptions, type RecencyOptions, type RedactionResult, type ReflectOptions, type ReflectResult, RerankerUnavailableError, type ResumeStreamOptions, type ResumeStreamResult, type ResumeStreamWithStorageResult, type RetainAction, type RetainContext, type RetainOptions, type RetainResult, type RetainSource, SDK_SCHEMA_VERSION, STREAM_RESUMABLE_HEADER, type ScoreBreakdown, type SearchSource, type SendMessageWithStorageArgs, type SendMessageWithStorageDetachedResult, type SendMessageWithStorageResult, type ServerToolsOptions, type ServerToolsResponse, type SignMessageFn, type StockPriceClassification, type StockPricePreProcessorOptions, type ChatCompletionUsage as StoredChatCompletionUsage, type StoredConversation, type StoredConversationMemory, type StoredMessage, type StoredMessageWithSimilarity, type StoredVaultFolder, VaultFolder as StoredVaultFolderModel, type StoredVaultMemory, VaultMemory as StoredVaultMemoryModel, StreamExpiredError, type StreamMetaEvent, type StreamResumeHandle, TOPIC_EXTRACTION_BATCH_SIZE, type TextChunk, type TopicExtractOptions, type TopicExtractionInput, type TopicExtractionRunResult, type TurnCompleteEvent, type TurnSkippedEvent, type UpdateVaultFolderOptions, type UpdateVaultMemoryOptions, type UseChatStorageOptions, type UseChatStorageResult, type UseCreditsOptions, type UseCreditsResult, type UseModelsOptions, type UseModelsResult, type VaultEmbeddingCache, type VaultFolderOperationsContext, type VaultMemoryOperationsContext, type VaultSaveOperation, type VaultSearchResult, WalletPoller, type WeatherClassification, type WeatherPreProcessorOptions, type WebSearchClassification, type WebSearchPreProcessorOptions, addConversationMemoriesOp, buildNotionAuthUrl, chatStorageMigrations, chatStorageSchema, chunkAndEmbedAllMessages, chunkAndEmbedMessage, chunkText, classifyCryptoPrice, classifyCryptoPriceBatch, classifyStockPrice, classifyStockPriceBatch, classifyWeather, classifyWeatherBatch, classifyWebSearch, classifyWebSearchBatch, clearAllEncryptionKeys, clearAllEncryptionState, clearConversationMemoriesOp, clearEncryptionKey, clearLazyTitleCache, clearServerToolsCache, consoleLogger, conversationMemoryToStored, cosineInt8, createAutoExtractor, createChunkVectorCache, createCryptoPricePreProcessor, createMemoryEngineTool, createMemoryVaultSearchTool, createMemoryVaultTool, createNotionTools, createPlatformCursorStore, createRecallTool, createStockPricePreProcessor, createStreamingDeAnonymizer, createVaultEmbeddingCache, createVaultFolderOp, createVaultMemoriesBatchOp, createVaultMemoryOp, createWeatherPreProcessor, createWebSearchPreProcessor, decryptConversationTitle, deleteAllVaultMemoriesForUserOp, deleteVaultFolderOp, deleteVaultMemoryOp, dequantizeEmbedding, discoverNotionOAuthEndpoints, eagerEmbedContent, embedAllMessages, embedMessage, ensureDefaultFoldersOp, exchangeNotionCode, extractAndLinkEntitiesForMemoriesOp, extractAndRetain, extractEntitiesForMemories, extractFacts, generateConversationId, generateEmbedding, generateEmbeddings, generateNotionPKCE, getAllVaultFoldersOp, getAllVaultMemoriesOp, getAllVaultMemoryContentsOp, getCachedServerTools, getConversationMemoriesOp, getConversationsByProjectLazyOp, getConversationsLazyOp, getLogger, getMemoriesNeedingTopicExtractionOp, getServerTools, getUnfiledVaultMemoriesOp, getVaultFolderMemoryCountOp, getVaultMemoryOp, hasEncryptionKey, isPiiRedactor, isRerankerAvailable, moveMemoriesToFolderOp, noopLogger, onKeyAvailable, preEmbedVaultMemories, quantizeEmbedding, queueManager, recall, reflect, refreshNotionAccessToken, registerNotionClient, requestEncryptionKey, resolvePiiRedactor, resumeStream, retain, sdkMigrations, sdkModelClasses, sdkSchema, searchVaultMemories, setLogger, shouldChunkMessage, stampTopicsExtractedAtOp, streamCancelPath, streamReplayPath, updateVaultFolderContextOp, updateVaultFolderOp, updateVaultMemoryEmbeddingOp, updateVaultMemoryOp, upsertMessageOp, useChat, useChatStorage, useCredits, useEncryption, useModels, xhrTransport };
7375
+ export { type AutoExtractMessage, type AutoExtractor, type Budget, type CachedChunkVectors, type CachedServerTools, Conversation as ChatConversation, Message as ChatMessage, type ChatRole, type ChunkVectorCache, type ChunkingOptions, type ConsolidationFallbackReason, type ConversationMemoryInput, ConversationMemory as ConversationMemoryModel, type ConversationMemoryOperationsContext, type CreateAutoExtractorOptions, type CreateConversationOptions, type CreateMessageOptions, type CreateVaultFolderOptions, type CreateVaultMemoryOptions, type CryptoPriceClassification, type CryptoPricePreProcessorOptions, DEFAULT_CACHE_EXPIRATION_MS, DEFAULT_CHUNK_CACHE_SIZE, DEFAULT_CHUNK_OVERLAP, DEFAULT_CHUNK_SIZE, DEFAULT_MIN_CHUNK_SIZE, DEFAULT_VAULT_CACHE_SIZE, DatabaseManager, type DatabaseManagerLogger, type DatabaseManagerOptions, type EmbeddedWalletSignerFn, type ExtractFactsOptions, type ExtractOutcome, type ExtractedCandidate, type ExtractedEntity, type ExtractionCursorStore, type FactType, type FileMetadata, type FlushResult, type GetMessagesPageOptions, INFERENCE_ID_HEADER, type LazyStoredConversation, type Logger, LoggerProvider, type LoggerProviderProps, type MemoriesNeedingTopicExtraction, type EmbeddingOptions as MemoryEngineEmbeddingOptions, type MemoryEngineResult, type MemoryEngineSearchOptions, type MemoryExtractedEvent, type MemoryKind, type MemoryVaultSearchOptions, type MemoryVaultToolOptions, type MessageRedactionResult, type MessageSkeleton, NOTION_OAUTH_CONFIG, type NotionAuthUrlParams, type NotionClientRegistration, type NotionExchangeCodeParams, type NotionOAuthEndpoints, type NotionPKCEChallenge, type NotionRefreshTokenParams, type NotionTokenResponse, PII_PATTERNS, type PiiCategory, type PiiMatch, type PiiPattern, PiiRedactor, type PiiRedactorOptions, type PlatformStorage, type PortalLlmAuth, type PromptPreProcessor, type PromptPreProcessorContext, type QuantizedEmbedding, QueueManager, type QueueStatus, RECALL_MAX_LIMIT, RECALL_TOOL_NAME, type RankedMemory, type RecallContext, type RecallDegradation, type RecallDiagnostics, type RecallOptions, type RecallResult, type RecallToolCallbacks, type RecallToolOptions, type RecencyOptions, type RedactionResult, type ReflectOptions, type ReflectResult, RerankerUnavailableError, type ResumeStreamOptions, type ResumeStreamResult, type ResumeStreamWithStorageResult, type RetainAction, type RetainContext, type RetainOptions, type RetainResult, type RetainSource, SDK_SCHEMA_VERSION, STREAM_RESUMABLE_HEADER, type ScoreBreakdown, type SearchSource, type SendMessageWithStorageArgs, type SendMessageWithStorageDetachedResult, type SendMessageWithStorageResult, type ServerToolsOptions, type ServerToolsResponse, type SignMessageFn, type StockPriceClassification, type StockPricePreProcessorOptions, type ChatCompletionUsage as StoredChatCompletionUsage, type StoredConversation, type StoredConversationMemory, type StoredMessage, type StoredMessageWithSimilarity, type StoredVaultFolder, VaultFolder as StoredVaultFolderModel, type StoredVaultMemory, VaultMemory as StoredVaultMemoryModel, StreamExpiredError, type StreamMetaEvent, type StreamResumeHandle, TOPIC_EXTRACTION_BATCH_SIZE, type TextChunk, type TopicExtractOptions, type TopicExtractionInput, type TopicExtractionRunResult, type TurnCompleteEvent, type TurnSkippedEvent, type UpdateVaultFolderOptions, type UpdateVaultMemoryOptions, type UseChatStorageOptions, type UseChatStorageResult, type UseCreditsOptions, type UseCreditsResult, type UseModelsOptions, type UseModelsResult, type VaultEmbeddingCache, type VaultFolderOperationsContext, type VaultMemoryOperationsContext, type VaultSaveOperation, type VaultSearchResult, WalletPoller, type WeatherClassification, type WeatherPreProcessorOptions, type WebSearchClassification, type WebSearchPreProcessorOptions, addConversationMemoriesOp, buildNotionAuthUrl, chatStorageMigrations, chatStorageSchema, chunkAndEmbedAllMessages, chunkAndEmbedMessage, chunkText, classifyCryptoPrice, classifyCryptoPriceBatch, classifyStockPrice, classifyStockPriceBatch, classifyWeather, classifyWeatherBatch, classifyWebSearch, classifyWebSearchBatch, clearAllEncryptionKeys, clearAllEncryptionState, clearConversationMemoriesOp, clearEncryptionKey, clearLazyTitleCache, clearServerToolsCache, consoleLogger, conversationMemoryToStored, cosineInt8, createAutoExtractor, createChunkVectorCache, createCryptoPricePreProcessor, createMemoryEngineTool, createMemoryVaultSearchTool, createMemoryVaultTool, createNotionTools, createPlatformCursorStore, createRecallTool, createStockPricePreProcessor, createStreamingDeAnonymizer, createVaultEmbeddingCache, createVaultFolderOp, createVaultMemoriesBatchOp, createVaultMemoryOp, createWeatherPreProcessor, createWebSearchPreProcessor, decryptConversationTitle, deleteAllVaultMemoriesForUserOp, deleteVaultFolderOp, deleteVaultMemoryOp, dequantizeEmbedding, discoverNotionOAuthEndpoints, eagerEmbedContent, embedAllMessages, embedMessage, ensureDefaultFoldersOp, exchangeNotionCode, extractAndLinkEntitiesForMemoriesOp, extractAndRetain, extractEntitiesForMemories, extractFacts, generateConversationId, generateEmbedding, generateEmbeddings, generateNotionPKCE, getAllVaultFoldersOp, getAllVaultMemoriesOp, getAllVaultMemoryContentsOp, getCachedServerTools, getConversationMemoriesOp, getConversationsByProjectLazyOp, getConversationsLazyOp, getLogger, getMemoriesNeedingTopicExtractionOp, getServerTools, getUnfiledVaultMemoriesOp, getVaultFolderMemoryCountOp, getVaultMemoryOp, hasEncryptionKey, isPiiRedactor, isRerankerAvailable, moveMemoriesToFolderOp, noopLogger, onKeyAvailable, preEmbedVaultMemories, quantizeEmbedding, queueManager, recall, reflect, refreshNotionAccessToken, registerNotionClient, requestEncryptionKey, resolvePiiRedactor, resumeStream, retain, sdkMigrations, sdkModelClasses, sdkSchema, searchVaultMemories, setLogger, shouldChunkMessage, stampTopicsExtractedAtOp, streamCancelPath, streamReplayPath, supersedeVaultMemoryOp, updateVaultFolderContextOp, updateVaultFolderOp, updateVaultMemoryEmbeddingOp, updateVaultMemoryOp, upsertMessageOp, useChat, useChatStorage, useCredits, useEncryption, useModels, xhrTransport };
@@ -21,6 +21,7 @@ import {
21
21
  createMemoryVaultSearchTool,
22
22
  createMessageOp,
23
23
  createSseClient,
24
+ createSupersedingMemoryOp,
24
25
  createVaultEmbeddingCache,
25
26
  createVaultMemoriesBatchOp,
26
27
  createVaultMemoryOp,
@@ -77,6 +78,7 @@ import {
77
78
  shouldChunkMessage,
78
79
  stampTopicsExtractedAtOp,
79
80
  stripToolCalls,
81
+ supersedeVaultMemoryOp,
80
82
  updateConversationPinnedOp,
81
83
  updateConversationTitleOp,
82
84
  updateMessageEmbeddingOp,
@@ -86,7 +88,7 @@ import {
86
88
  upsertMessageOp,
87
89
  useEncryption,
88
90
  vaultMemoryToStored
89
- } from "./chunk-UOUJUZM4.mjs";
91
+ } from "./chunk-A26RBLTJ.mjs";
90
92
  import {
91
93
  PII_PATTERNS,
92
94
  PiiRedactor,
@@ -5508,6 +5510,12 @@ __decorateClass([
5508
5510
  __decorateClass([
5509
5511
  field3("topics_extracted_at")
5510
5512
  ], VaultMemory.prototype, "topicsExtractedAt", 2);
5513
+ __decorateClass([
5514
+ field3("superseded_by")
5515
+ ], VaultMemory.prototype, "supersededBy", 2);
5516
+ __decorateClass([
5517
+ field3("superseded_at")
5518
+ ], VaultMemory.prototype, "supersededAt", 2);
5511
5519
  __decorateClass([
5512
5520
  readonly2,
5513
5521
  date3("created_at")
@@ -5874,53 +5882,62 @@ async function retain(content, ctx, options = {}) {
5874
5882
  const enableAutoMerge = options.enableAutoMerge ?? true;
5875
5883
  const threshold = options.autoMergeThreshold ?? DEFAULT_AUTO_MERGE_THRESHOLD;
5876
5884
  const resolvedScope = options.scope ?? DEFAULT_SCOPE;
5885
+ let supersedeTargetId;
5886
+ let supersedeContent;
5877
5887
  if (enableAutoMerge) {
5878
5888
  if (options.consolidateOptions) {
5879
- const consolidationResult = await tryConsolidate(trimmed, ctx, options);
5880
- if (consolidationResult) return consolidationResult;
5881
- }
5882
- const matches = await searchVaultMemories(
5883
- trimmed,
5884
- ctx.vaultCtx,
5885
- ctx.embeddingOptions,
5886
- ctx.vaultCache,
5887
- {
5888
- limit: 1,
5889
- minSimilarity: threshold,
5890
- useFusion: false,
5891
- scopes: [resolvedScope],
5892
- ...options.folderId !== void 0 && { folderId: options.folderId }
5893
- }
5894
- );
5895
- if (matches.length > 0) {
5896
- const targetId = matches[0].uniqueId;
5897
- const existing = await getVaultMemoryOp(ctx.vaultCtx, targetId);
5898
- if (existing) {
5899
- const mergedSourceIds = unionStrings(
5900
- existing.sourceChunkIds ?? [],
5901
- options.sourceChunkIds ?? []
5902
- );
5903
- const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
5904
- const updated = await updateVaultMemoryOp(ctx.vaultCtx, targetId, {
5905
- content: existing.content,
5906
- proofCountIncrement: 1,
5907
- sourceChunkIds: mergedSourceIds,
5908
- preserveUpdatedAt: true,
5909
- ...eventTimeUpdate && { eventTime: eventTimeUpdate }
5910
- });
5911
- if (updated) {
5912
- return {
5913
- action: "merge",
5914
- memoryId: targetId,
5915
- targetId,
5916
- proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
5917
- };
5889
+ const outcome = await tryConsolidate(trimmed, ctx, options);
5890
+ if (outcome) {
5891
+ if ("done" in outcome) return outcome.done;
5892
+ supersedeTargetId = outcome.supersede;
5893
+ supersedeContent = outcome.content;
5894
+ }
5895
+ }
5896
+ if (!supersedeTargetId) {
5897
+ const matches = await searchVaultMemories(
5898
+ trimmed,
5899
+ ctx.vaultCtx,
5900
+ ctx.embeddingOptions,
5901
+ ctx.vaultCache,
5902
+ {
5903
+ limit: 1,
5904
+ minSimilarity: threshold,
5905
+ useFusion: false,
5906
+ scopes: [resolvedScope],
5907
+ ...options.folderId !== void 0 && { folderId: options.folderId }
5908
+ }
5909
+ );
5910
+ if (matches.length > 0) {
5911
+ const targetId = matches[0].uniqueId;
5912
+ const existing = await getVaultMemoryOp(ctx.vaultCtx, targetId);
5913
+ if (existing && !existing.supersededBy) {
5914
+ const mergedSourceIds = unionStrings(
5915
+ existing.sourceChunkIds ?? [],
5916
+ options.sourceChunkIds ?? []
5917
+ );
5918
+ const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
5919
+ const updated = await updateVaultMemoryOp(ctx.vaultCtx, targetId, {
5920
+ content: existing.content,
5921
+ proofCountIncrement: 1,
5922
+ sourceChunkIds: mergedSourceIds,
5923
+ preserveUpdatedAt: true,
5924
+ ...eventTimeUpdate && { eventTime: eventTimeUpdate }
5925
+ });
5926
+ if (updated) {
5927
+ return {
5928
+ action: "merge",
5929
+ memoryId: targetId,
5930
+ targetId,
5931
+ proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
5932
+ };
5933
+ }
5934
+ await assertMergeTargetGoneOrThrow(ctx, targetId);
5918
5935
  }
5919
- await assertMergeTargetGoneOrThrow(ctx, targetId);
5920
5936
  }
5921
5937
  }
5922
5938
  }
5923
- const embedding = await generateEmbedding(trimmed, ctx.embeddingOptions);
5939
+ const contentToWrite = supersedeContent ?? trimmed;
5940
+ const embedding = await generateEmbedding(contentToWrite, ctx.embeddingOptions);
5924
5941
  const embeddingModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
5925
5942
  if (options.respectTombstones) {
5926
5943
  const tombstoneId = await findTombstoneMatch(embedding, embeddingModel, resolvedScope, ctx, {
@@ -5931,8 +5948,8 @@ async function retain(content, ctx, options = {}) {
5931
5948
  return { action: "suppressed", memoryId: tombstoneId, tombstoneId, proofCount: 0 };
5932
5949
  }
5933
5950
  }
5934
- const created = await createVaultMemoryOp(ctx.vaultCtx, {
5935
- content: trimmed,
5951
+ const createOpts = {
5952
+ content: contentToWrite,
5936
5953
  scope: resolvedScope,
5937
5954
  ...options.folderId !== void 0 && { folderId: options.folderId },
5938
5955
  embedding: JSON.stringify(embedding),
@@ -5949,7 +5966,24 @@ async function retain(content, ctx, options = {}) {
5949
5966
  kind: options.eventTime.kind
5950
5967
  }
5951
5968
  }
5952
- });
5969
+ };
5970
+ if (supersedeTargetId) {
5971
+ const { created: created2, retired } = await createSupersedingMemoryOp(
5972
+ ctx.vaultCtx,
5973
+ createOpts,
5974
+ supersedeTargetId
5975
+ );
5976
+ if (created2 && retired) {
5977
+ ctx.vaultCache.set(created2.uniqueId, Float32Array.from(embedding));
5978
+ return {
5979
+ action: "supersede",
5980
+ memoryId: created2.uniqueId,
5981
+ targetId: supersedeTargetId,
5982
+ proofCount: 1
5983
+ };
5984
+ }
5985
+ }
5986
+ const created = await createVaultMemoryOp(ctx.vaultCtx, createOpts);
5953
5987
  ctx.vaultCache.set(created.uniqueId, Float32Array.from(embedding));
5954
5988
  return {
5955
5989
  action: "create",
@@ -6016,12 +6050,17 @@ async function tryConsolidate(trimmed, ctx, options) {
6016
6050
  content: m.content,
6017
6051
  similarity: m.similarity
6018
6052
  }));
6019
- const { consolidateMemory: doConsolidate } = await import("./consolidate-HEMQGOUD.mjs");
6053
+ const { consolidateMemory: doConsolidate } = await import("./consolidate-3QQPUWD6.mjs");
6020
6054
  const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
6021
6055
  if (decision.action === "create") return null;
6056
+ if (decision.action === "supersede" && decision.targetId && decision.content) {
6057
+ const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
6058
+ if (!existing || existing.supersededBy) return null;
6059
+ return { supersede: decision.targetId, content: decision.content };
6060
+ }
6022
6061
  if (decision.action === "noop" && decision.targetId) {
6023
6062
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
6024
- if (!existing) return null;
6063
+ if (!existing || existing.supersededBy) return null;
6025
6064
  const mergedSourceIds = unionStrings(
6026
6065
  existing.sourceChunkIds ?? [],
6027
6066
  options.sourceChunkIds ?? []
@@ -6039,15 +6078,17 @@ async function tryConsolidate(trimmed, ctx, options) {
6039
6078
  return null;
6040
6079
  }
6041
6080
  return {
6042
- action: "merge",
6043
- memoryId: decision.targetId,
6044
- targetId: decision.targetId,
6045
- proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
6081
+ done: {
6082
+ action: "merge",
6083
+ memoryId: decision.targetId,
6084
+ targetId: decision.targetId,
6085
+ proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
6086
+ }
6046
6087
  };
6047
6088
  }
6048
6089
  if (decision.action === "update" && decision.targetId && decision.content) {
6049
6090
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
6050
- if (!existing) return null;
6091
+ if (!existing || existing.supersededBy) return null;
6051
6092
  const mergedSourceIds = unionStrings(
6052
6093
  existing.sourceChunkIds ?? [],
6053
6094
  options.sourceChunkIds ?? []
@@ -6074,10 +6115,12 @@ async function tryConsolidate(trimmed, ctx, options) {
6074
6115
  }
6075
6116
  ctx.vaultCache.set(decision.targetId, Float32Array.from(newEmbedding));
6076
6117
  return {
6077
- action: "update",
6078
- memoryId: decision.targetId,
6079
- targetId: decision.targetId,
6080
- proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
6118
+ done: {
6119
+ action: "update",
6120
+ memoryId: decision.targetId,
6121
+ targetId: decision.targetId,
6122
+ proofCount: updated.proofCount ?? (existing.proofCount ?? 1) + 1
6123
+ }
6081
6124
  };
6082
6125
  }
6083
6126
  return null;
@@ -9530,7 +9573,7 @@ __decorateClass([
9530
9573
  ], VaultFolder.prototype, "context", 2);
9531
9574
 
9532
9575
  // src/lib/db/schema.ts
9533
- var SDK_SCHEMA_VERSION = 36;
9576
+ var SDK_SCHEMA_VERSION = 37;
9534
9577
  var sdkSchema = appSchema2({
9535
9578
  version: SDK_SCHEMA_VERSION,
9536
9579
  tables: [
@@ -9655,7 +9698,16 @@ var sdkSchema = appSchema2({
9655
9698
  // Unix ms of the last LLM topic-extraction pass over this memory's
9656
9699
  // content. Null = never extracted standalone (legacy rows with entity
9657
9700
  // links are grandfathered — see getMemoriesNeedingTopicExtractionOp).
9658
- { name: "topics_extracted_at", type: "number", isOptional: true }
9701
+ { name: "topics_extracted_at", type: "number", isOptional: true },
9702
+ // Write-time supersession (A2). When set, this fact was replaced by a
9703
+ // newer, incompatible-value fact (e.g. "Lives in Portland" superseded by
9704
+ // "Lives in SF"); `superseded_by` points at the newer memory's id and
9705
+ // `superseded_at` is the Unix ms it happened. Superseded rows stay in
9706
+ // the table (history / read-time fallback) but are excluded from recall
9707
+ // and dedup by default. Null = live (not superseded). Indexed so the
9708
+ // recall filter stays cheap.
9709
+ { name: "superseded_by", type: "string", isOptional: true, isIndexed: true },
9710
+ { name: "superseded_at", type: "number", isOptional: true }
9659
9711
  ]
9660
9712
  }),
9661
9713
  // Entity table — canonical names extracted from auto-extraction (W5).
@@ -10266,6 +10318,21 @@ var sdkMigrations = schemaMigrations2({
10266
10318
  columns: [{ name: "topics_extracted_at", type: "number", isOptional: true }]
10267
10319
  })
10268
10320
  ]
10321
+ },
10322
+ // v36 -> v37: write-time supersession columns on memory_vault. Existing rows
10323
+ // keep both NULL (= live / not superseded), so no backfill — legacy
10324
+ // contradictory rows are handled by the read-time supersession fallback.
10325
+ {
10326
+ toVersion: 37,
10327
+ steps: [
10328
+ addColumns2({
10329
+ table: "memory_vault",
10330
+ columns: [
10331
+ { name: "superseded_by", type: "string", isOptional: true, isIndexed: true },
10332
+ { name: "superseded_at", type: "number", isOptional: true }
10333
+ ]
10334
+ })
10335
+ ]
10269
10336
  }
10270
10337
  ]
10271
10338
  });
@@ -11726,6 +11793,7 @@ export {
11726
11793
  stampTopicsExtractedAtOp,
11727
11794
  streamCancelPath,
11728
11795
  streamReplayPath,
11796
+ supersedeVaultMemoryOp,
11729
11797
  updateVaultFolderContextOp,
11730
11798
  updateVaultFolderOp,
11731
11799
  updateVaultMemoryEmbeddingOp,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  recall
3
- } from "./chunk-IYDQBFS2.mjs";
3
+ } from "./chunk-A26RBLTJ.mjs";
4
4
  import "./chunk-DFVCS3QQ.mjs";
5
5
  import "./chunk-GYKJOWEO.mjs";
6
6
  export {
@@ -2027,6 +2027,7 @@ function isOwnedByCtxUser(ctx, record) {
2027
2027
  function baseVaultConditions(ctx, options) {
2028
2028
  return [
2029
2029
  ...options?.includeDeleted ? [] : [Q3.where("is_deleted", false)],
2030
+ ...options?.includeSuperseded ? [] : [Q3.where("superseded_by", null)],
2030
2031
  ...ctx.userId !== void 0 ? [Q3.where("user_id", ctx.userId)] : [],
2031
2032
  ...options?.since ? [Q3.where("updated_at", Q3.gt(options.since.getTime()))] : []
2032
2033
  ];
@@ -2067,6 +2068,8 @@ function vaultMemoryToStoredRaw(memory) {
2067
2068
  eventTimeKind: memory.eventTimeKind ?? null,
2068
2069
  topicsUserManaged: memory.topicsUserManaged ?? false,
2069
2070
  topicsExtractedAt: memory.topicsExtractedAt ?? null,
2071
+ supersededBy: memory.supersededBy ?? null,
2072
+ supersededAt: memory.supersededAt ?? null,
2070
2073
  createdAt: memory.createdAt,
2071
2074
  updatedAt: memory.updatedAt,
2072
2075
  isDeleted: memory.isDeleted
@@ -2112,6 +2115,59 @@ async function createVaultMemoryOp(ctx, opts) {
2112
2115
  });
2113
2116
  return vaultMemoryToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
2114
2117
  }
2118
+ async function createSupersedingMemoryOp(ctx, opts, targetId) {
2119
+ if (!targetId) return { created: null, retired: false };
2120
+ const scope = opts.scope ?? "private";
2121
+ const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
2122
+ opts.content,
2123
+ ctx.walletAddress,
2124
+ ctx.signMessage,
2125
+ ctx.embeddedWalletSigner
2126
+ ) : opts.content;
2127
+ let createdRecord = null;
2128
+ await ctx.database.write(async () => {
2129
+ let target;
2130
+ try {
2131
+ target = await ctx.vaultMemoryCollection.find(targetId);
2132
+ } catch {
2133
+ return;
2134
+ }
2135
+ if (target.isDeleted || target.supersededBy || !isOwnedByCtxUser(ctx, target)) return;
2136
+ createdRecord = await ctx.vaultMemoryCollection.create((record) => {
2137
+ record._setRaw("content", encryptedContent);
2138
+ record._setRaw("scope", scope);
2139
+ record._setRaw("folder_id", opts.folderId ?? null);
2140
+ record._setRaw("user_id", ctx.userId ?? null);
2141
+ record._setRaw("is_deleted", false);
2142
+ if (opts.embedding !== void 0) {
2143
+ record._setRaw("embedding", opts.embedding);
2144
+ record._setRaw("embedding_model", opts.embeddingModel ?? null);
2145
+ }
2146
+ if (opts.sourceChunkIds !== void 0) {
2147
+ record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
2148
+ }
2149
+ record._setRaw("proof_count", opts.proofCount ?? 1);
2150
+ record._setRaw("source", opts.source ?? "manual");
2151
+ if (opts.eventTime) {
2152
+ record._setRaw("event_time_start", opts.eventTime.start ?? null);
2153
+ record._setRaw("event_time_end", opts.eventTime.end ?? null);
2154
+ record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
2155
+ }
2156
+ });
2157
+ await target.update((r) => {
2158
+ r._setRaw("superseded_by", createdRecord.id);
2159
+ r._setRaw("superseded_at", Date.now());
2160
+ });
2161
+ });
2162
+ if (!createdRecord) return { created: null, retired: false };
2163
+ const created = await vaultMemoryToStored(
2164
+ createdRecord,
2165
+ ctx.walletAddress,
2166
+ ctx.signMessage,
2167
+ ctx.embeddedWalletSigner
2168
+ );
2169
+ return { created, retired: true };
2170
+ }
2115
2171
  async function getMemoriesByEventTimeOp(ctx, windowStart, windowEnd) {
2116
2172
  const records = await ctx.vaultMemoryCollection.query(
2117
2173
  ...baseVaultConditions(ctx),
@@ -2251,6 +2307,8 @@ function vaultMemoryRawToStoredRaw(raw) {
2251
2307
  // SQLite stores booleans as 0/1, LokiJS as true/false — coerce both.
2252
2308
  topicsUserManaged: raw.topics_user_managed === true || raw.topics_user_managed === 1,
2253
2309
  topicsExtractedAt: raw.topics_extracted_at ?? null,
2310
+ supersededBy: raw.superseded_by ?? null,
2311
+ supersededAt: raw.superseded_at ?? null,
2254
2312
  createdAt: new Date(raw.created_at),
2255
2313
  updatedAt: new Date(raw.updated_at),
2256
2314
  isDeleted: raw.is_deleted === true || raw.is_deleted === 1
@@ -2292,7 +2350,7 @@ async function getAllVaultMemoryContentsOp(ctx, options) {
2292
2350
  async function updateVaultMemoryOp(ctx, id, opts) {
2293
2351
  try {
2294
2352
  const probe = await ctx.vaultMemoryCollection.find(id);
2295
- if (probe.isDeleted || !isOwnedByCtxUser(ctx, probe)) return null;
2353
+ if (probe.isDeleted || probe.supersededBy || !isOwnedByCtxUser(ctx, probe)) return null;
2296
2354
  const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
2297
2355
  opts.content,
2298
2356
  ctx.walletAddress,
@@ -2303,7 +2361,7 @@ async function updateVaultMemoryOp(ctx, id, opts) {
2303
2361
  const record = probe;
2304
2362
  const originalUpdatedAt = record.updatedAt.getTime();
2305
2363
  await ctx.database.write(async () => {
2306
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
2364
+ if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record)) {
2307
2365
  stale = true;
2308
2366
  return;
2309
2367
  }
@@ -2435,6 +2493,40 @@ async function deleteVaultMemoryOp(ctx, id) {
2435
2493
  return false;
2436
2494
  }
2437
2495
  }
2496
+ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
2497
+ if (id === supersededById) return false;
2498
+ try {
2499
+ const record = await ctx.vaultMemoryCollection.find(id);
2500
+ if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record)) return false;
2501
+ let successor;
2502
+ try {
2503
+ successor = await ctx.vaultMemoryCollection.find(supersededById);
2504
+ } catch {
2505
+ return false;
2506
+ }
2507
+ if (successor.isDeleted || successor.supersededBy || !isOwnedByCtxUser(ctx, successor)) {
2508
+ return false;
2509
+ }
2510
+ let stale = false;
2511
+ await ctx.database.write(async () => {
2512
+ if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record)) {
2513
+ stale = true;
2514
+ return;
2515
+ }
2516
+ if (successor.isDeleted || successor.supersededBy || !isOwnedByCtxUser(ctx, successor)) {
2517
+ stale = true;
2518
+ return;
2519
+ }
2520
+ await record.update((r) => {
2521
+ r._setRaw("superseded_by", supersededById);
2522
+ r._setRaw("superseded_at", Date.now());
2523
+ });
2524
+ });
2525
+ return !stale;
2526
+ } catch {
2527
+ return false;
2528
+ }
2529
+ }
2438
2530
  async function getUnfiledVaultMemoriesOp(ctx) {
2439
2531
  const conditions = [
2440
2532
  Q3.where("folder_id", null),
@@ -5282,7 +5374,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
5282
5374
  legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
5283
5375
  );
5284
5376
  }
5285
- const { recall: recall2 } = await import("./recall-G3CS444F.mjs");
5377
+ const { recall: recall2 } = await import("./recall-IRTSMKYI.mjs");
5286
5378
  const result = await recall2(
5287
5379
  query,
5288
5380
  { vaultCtx, embeddingOptions, vaultCache: cache },
@@ -6008,6 +6100,7 @@ export {
6008
6100
  getMemoriesByEntityNamesOp,
6009
6101
  vaultMemoryToStored,
6010
6102
  createVaultMemoryOp,
6103
+ createSupersedingMemoryOp,
6011
6104
  createVaultMemoriesBatchOp,
6012
6105
  getVaultMemoryOp,
6013
6106
  getAllVaultMemoriesOp,
@@ -6016,6 +6109,7 @@ export {
6016
6109
  setMemoryEntitiesOp,
6017
6110
  clearMemoryTopicsOverrideOp,
6018
6111
  deleteVaultMemoryOp,
6112
+ supersedeVaultMemoryOp,
6019
6113
  getUnfiledVaultMemoriesOp,
6020
6114
  getMemoriesNeedingTopicExtractionOp,
6021
6115
  stampTopicsExtractedAtOp,