@anuma/sdk 3.12.0 → 3.12.2

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.
@@ -8471,6 +8471,25 @@ var init_searchTool = __esm({
8471
8471
  }
8472
8472
  });
8473
8473
 
8474
+ // src/lib/memory/consolidationFallback.ts
8475
+ function notifyConsolidationFallback(reason, onFallback, detail) {
8476
+ if (detail !== void 0) {
8477
+ getLogger().warn(`memory/consolidate: degraded to create (${reason})`, detail);
8478
+ } else {
8479
+ getLogger().warn(`memory/consolidate: degraded to create (${reason})`);
8480
+ }
8481
+ try {
8482
+ onFallback?.(reason);
8483
+ } catch {
8484
+ }
8485
+ }
8486
+ var init_consolidationFallback = __esm({
8487
+ "src/lib/memory/consolidationFallback.ts"() {
8488
+ "use strict";
8489
+ init_logger();
8490
+ }
8491
+ });
8492
+
8474
8493
  // src/lib/memory/consolidate.ts
8475
8494
  var consolidate_exports = {};
8476
8495
  __export(consolidate_exports, {
@@ -8535,15 +8554,7 @@ ${candidateText}`;
8535
8554
  return result;
8536
8555
  }
8537
8556
  function degrade(reason, fallback, options, detail) {
8538
- if (detail !== void 0) {
8539
- getLogger().warn(`memory/consolidate: degraded to create (${reason})`, detail);
8540
- } else {
8541
- getLogger().warn(`memory/consolidate: degraded to create (${reason})`);
8542
- }
8543
- try {
8544
- options.onFallback?.(reason);
8545
- } catch {
8546
- }
8557
+ notifyConsolidationFallback(reason, options.onFallback, detail);
8547
8558
  return { ...fallback, fallbackReason: reason };
8548
8559
  }
8549
8560
  function validate2(parsed, newContent, validIds) {
@@ -8583,8 +8594,8 @@ var DEFAULT_CONSOLIDATION_MODEL, DEFAULT_CONSOLIDATE_ATTEMPTS, DEFAULT_CONSOLIDA
8583
8594
  var init_consolidate = __esm({
8584
8595
  "src/lib/memory/consolidate.ts"() {
8585
8596
  "use strict";
8586
- init_logger();
8587
8597
  init_redactor();
8598
+ init_consolidationFallback();
8588
8599
  init_portalLlm();
8589
8600
  DEFAULT_CONSOLIDATION_MODEL = "inclusionai/ling-2.6-flash";
8590
8601
  DEFAULT_CONSOLIDATE_ATTEMPTS = 3;
@@ -16165,6 +16176,7 @@ init_constants();
16165
16176
  init_embeddings();
16166
16177
  init_vector();
16167
16178
  init_searchTool();
16179
+ init_consolidationFallback();
16168
16180
  var DEFAULT_AUTO_MERGE_THRESHOLD = 0.8;
16169
16181
  var DEFAULT_SCOPE = "private";
16170
16182
  var DEFAULT_CONSOLIDATE_THRESHOLD = 0.55;
@@ -16344,6 +16356,11 @@ async function retain(content, ctx, options = {}) {
16344
16356
  proofCount: 1
16345
16357
  };
16346
16358
  }
16359
+ notifyConsolidationFallback(
16360
+ "target_vanished",
16361
+ options.consolidateOptions?.onFallback,
16362
+ `supersede: primary target ${primaryTargetId} retired or deleted inside the atomic write`
16363
+ );
16347
16364
  }
16348
16365
  const created = await createVaultMemoryOp(ctx.vaultCtx, createOpts);
16349
16366
  ctx.vaultCache.set(created.uniqueId, Float32Array.from(embedding));
@@ -16395,6 +16412,10 @@ function pickFactTypeUpdate(existing, incoming) {
16395
16412
  function resurrectFields(existing) {
16396
16413
  return typeof existing.archivedAt === "number" ? { restore: true } : { preserveUpdatedAt: true };
16397
16414
  }
16415
+ function abandonToRace(options, detail) {
16416
+ notifyConsolidationFallback("target_vanished", options.consolidateOptions?.onFallback, detail);
16417
+ return null;
16418
+ }
16398
16419
  async function tryConsolidate(trimmed, ctx, options, prepared) {
16399
16420
  const consolidateOptions = options.consolidateOptions;
16400
16421
  if (!consolidateOptions) return null;
@@ -16427,12 +16448,22 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
16427
16448
  const existing = await getVaultMemoryOp(ctx.vaultCtx, id);
16428
16449
  if (existing && !existing.supersededBy) valid.push(id);
16429
16450
  }
16430
- if (valid.length === 0) return null;
16451
+ if (valid.length === 0) {
16452
+ return abandonToRace(
16453
+ options,
16454
+ `supersede: all ${requestedIds.length} target(s) deleted or already superseded`
16455
+ );
16456
+ }
16431
16457
  return { supersede: valid, content: decision.content };
16432
16458
  }
16433
16459
  if (decision.action === "noop" && decision.targetId) {
16434
16460
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
16435
- if (!existing || existing.supersededBy) return null;
16461
+ if (!existing || existing.supersededBy) {
16462
+ return abandonToRace(
16463
+ options,
16464
+ `noop: target ${decision.targetId} ${existing ? "superseded" : "deleted"} before the write`
16465
+ );
16466
+ }
16436
16467
  const mergedSourceIds = unionStrings(
16437
16468
  existing.sourceChunkIds ?? [],
16438
16469
  options.sourceChunkIds ?? []
@@ -16457,7 +16488,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
16457
16488
  });
16458
16489
  if (!updated) {
16459
16490
  await assertMergeTargetGoneOrThrow(ctx, decision.targetId);
16460
- return null;
16491
+ return abandonToRace(
16492
+ options,
16493
+ `noop: target ${decision.targetId} deleted mid-write (proof-count bump lost)`
16494
+ );
16461
16495
  }
16462
16496
  return {
16463
16497
  done: {
@@ -16470,7 +16504,12 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
16470
16504
  }
16471
16505
  if (decision.action === "update" && decision.targetId && decision.content) {
16472
16506
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
16473
- if (!existing || existing.supersededBy) return null;
16507
+ if (!existing || existing.supersededBy) {
16508
+ return abandonToRace(
16509
+ options,
16510
+ `update: target ${decision.targetId} ${existing ? "superseded" : "deleted"} before the write`
16511
+ );
16512
+ }
16474
16513
  const mergedSourceIds = unionStrings(
16475
16514
  existing.sourceChunkIds ?? [],
16476
16515
  options.sourceChunkIds ?? []
@@ -16501,7 +16540,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
16501
16540
  });
16502
16541
  if (!updated) {
16503
16542
  await assertMergeTargetGoneOrThrow(ctx, decision.targetId);
16504
- return null;
16543
+ return abandonToRace(
16544
+ options,
16545
+ `update: target ${decision.targetId} deleted mid-write (consolidated rewrite lost)`
16546
+ );
16505
16547
  }
16506
16548
  ctx.vaultCache.set(decision.targetId, Float32Array.from(newEmbedding));
16507
16549
  return {
@@ -16513,6 +16555,11 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
16513
16555
  }
16514
16556
  };
16515
16557
  }
16558
+ notifyConsolidationFallback(
16559
+ "invalid_response",
16560
+ options.consolidateOptions?.onFallback,
16561
+ `unapplicable ${decision.action} decision reached the applier \u2014 validate() should have rejected it`
16562
+ );
16516
16563
  return null;
16517
16564
  }
16518
16565
  async function assertMergeTargetGoneOrThrow(ctx, targetId) {
@@ -17095,7 +17142,6 @@ function createAutoExtractor(options) {
17095
17142
  return true;
17096
17143
  }
17097
17144
  function drainPending() {
17098
- if (disposed) return;
17099
17145
  for (const [conversationId, state] of conversations) {
17100
17146
  if (state.pending) {
17101
17147
  const messages = state.pending;
@@ -17110,7 +17156,7 @@ function createAutoExtractor(options) {
17110
17156
  isProcessing: () => inflight > 0,
17111
17157
  dispose: () => {
17112
17158
  disposed = true;
17113
- for (const state of conversations.values()) state.pending = void 0;
17159
+ if (inflight === 0) drainPending();
17114
17160
  }
17115
17161
  };
17116
17162
  }
@@ -6595,8 +6595,26 @@ interface RecallDiagnostics {
6595
6595
  }
6596
6596
  type RetainAction = "create" | "merge" | "update" | "skip" | "suppressed" | "supersede";
6597
6597
  type RetainSource = "manual" | "auto-extracted" | "capsule";
6598
- /** Why the consolidator fell back to "create" instead of a real decision. */
6599
- type ConsolidationFallbackReason = "llm_error" | "invalid_response";
6598
+ /**
6599
+ * Why a retain fell back to "create" instead of applying a consolidation
6600
+ * decision. Each value names a DIFFERENT thing to go fix, which is the point of
6601
+ * keeping them apart:
6602
+ *
6603
+ * - `llm_error` — the consolidation call never produced a response (network,
6604
+ * timeout, 5xx, 429, empty completion, or missing credentials). Look at the
6605
+ * portal and the auth config.
6606
+ * - `invalid_response` — the model answered, but with something unusable: an
6607
+ * unknown action, a targetId that was not in the candidate set, an `update` or
6608
+ * `supersede` with empty content, a `noop` with no target. Look at the prompt
6609
+ * and the model.
6610
+ * - `target_vanished` — the model returned a decision that was valid when it was
6611
+ * made, and the row it named was deleted or superseded by a concurrent writer
6612
+ * before the write landed. Nothing is broken in the consolidator; a sustained
6613
+ * rate points at write contention (for example an auto-extraction worker and a
6614
+ * manual write racing over the same vault), which quietly costs you the
6615
+ * dedup that decision would have performed.
6616
+ */
6617
+ type ConsolidationFallbackReason = "llm_error" | "invalid_response" | "target_vanished";
6600
6618
  interface RetainOptions {
6601
6619
  source?: RetainSource;
6602
6620
  sourceChunkIds?: string[];
@@ -7841,7 +7859,11 @@ interface AutoExtractor {
7841
7859
  processTurn(messages: AutoExtractMessage[], conversationId?: string): boolean;
7842
7860
  /** True while a turn's extraction is in flight. */
7843
7861
  isProcessing(): boolean;
7844
- /** Stop accepting new turns. In-flight work continues to completion. */
7862
+ /**
7863
+ * Stop accepting new turns. In-flight work continues to completion, and any
7864
+ * turn already queued (coalesced while an extraction was in flight) is still
7865
+ * flushed — never dropped — so a turn sent right before unmount isn't lost.
7866
+ */
7845
7867
  dispose(): void;
7846
7868
  }
7847
7869
  /**
@@ -6595,8 +6595,26 @@ interface RecallDiagnostics {
6595
6595
  }
6596
6596
  type RetainAction = "create" | "merge" | "update" | "skip" | "suppressed" | "supersede";
6597
6597
  type RetainSource = "manual" | "auto-extracted" | "capsule";
6598
- /** Why the consolidator fell back to "create" instead of a real decision. */
6599
- type ConsolidationFallbackReason = "llm_error" | "invalid_response";
6598
+ /**
6599
+ * Why a retain fell back to "create" instead of applying a consolidation
6600
+ * decision. Each value names a DIFFERENT thing to go fix, which is the point of
6601
+ * keeping them apart:
6602
+ *
6603
+ * - `llm_error` — the consolidation call never produced a response (network,
6604
+ * timeout, 5xx, 429, empty completion, or missing credentials). Look at the
6605
+ * portal and the auth config.
6606
+ * - `invalid_response` — the model answered, but with something unusable: an
6607
+ * unknown action, a targetId that was not in the candidate set, an `update` or
6608
+ * `supersede` with empty content, a `noop` with no target. Look at the prompt
6609
+ * and the model.
6610
+ * - `target_vanished` — the model returned a decision that was valid when it was
6611
+ * made, and the row it named was deleted or superseded by a concurrent writer
6612
+ * before the write landed. Nothing is broken in the consolidator; a sustained
6613
+ * rate points at write contention (for example an auto-extraction worker and a
6614
+ * manual write racing over the same vault), which quietly costs you the
6615
+ * dedup that decision would have performed.
6616
+ */
6617
+ type ConsolidationFallbackReason = "llm_error" | "invalid_response" | "target_vanished";
6600
6618
  interface RetainOptions {
6601
6619
  source?: RetainSource;
6602
6620
  sourceChunkIds?: string[];
@@ -7841,7 +7859,11 @@ interface AutoExtractor {
7841
7859
  processTurn(messages: AutoExtractMessage[], conversationId?: string): boolean;
7842
7860
  /** True while a turn's extraction is in flight. */
7843
7861
  isProcessing(): boolean;
7844
- /** Stop accepting new turns. In-flight work continues to completion. */
7862
+ /**
7863
+ * Stop accepting new turns. In-flight work continues to completion, and any
7864
+ * turn already queued (coalesced while an extraction was in flight) is still
7865
+ * flushed — never dropped — so a turn sent right before unmount isn't lost.
7866
+ */
7845
7867
  dispose(): void;
7846
7868
  }
7847
7869
  /**
@@ -164,8 +164,9 @@ import {
164
164
  PiiRedactor,
165
165
  createStreamingDeAnonymizer,
166
166
  isPiiRedactor,
167
+ notifyConsolidationFallback,
167
168
  resolvePiiRedactor
168
- } from "./chunk-TP6CJZ25.mjs";
169
+ } from "./chunk-3NPDZZGO.mjs";
169
170
  import {
170
171
  callPortalJsonCompletion,
171
172
  consoleLogger,
@@ -7400,6 +7401,11 @@ async function retain(content, ctx, options = {}) {
7400
7401
  proofCount: 1
7401
7402
  };
7402
7403
  }
7404
+ notifyConsolidationFallback(
7405
+ "target_vanished",
7406
+ options.consolidateOptions?.onFallback,
7407
+ `supersede: primary target ${primaryTargetId} retired or deleted inside the atomic write`
7408
+ );
7403
7409
  }
7404
7410
  const created = await createVaultMemoryOp(ctx.vaultCtx, createOpts);
7405
7411
  ctx.vaultCache.set(created.uniqueId, Float32Array.from(embedding));
@@ -7451,6 +7457,10 @@ function pickFactTypeUpdate(existing, incoming) {
7451
7457
  function resurrectFields(existing) {
7452
7458
  return typeof existing.archivedAt === "number" ? { restore: true } : { preserveUpdatedAt: true };
7453
7459
  }
7460
+ function abandonToRace(options, detail) {
7461
+ notifyConsolidationFallback("target_vanished", options.consolidateOptions?.onFallback, detail);
7462
+ return null;
7463
+ }
7454
7464
  async function tryConsolidate(trimmed, ctx, options, prepared) {
7455
7465
  const consolidateOptions = options.consolidateOptions;
7456
7466
  if (!consolidateOptions) return null;
@@ -7472,7 +7482,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
7472
7482
  content: m.content,
7473
7483
  similarity: m.similarity
7474
7484
  }));
7475
- const { consolidateMemory: doConsolidate } = await import("./consolidate-DOY3ZWTE.mjs");
7485
+ const { consolidateMemory: doConsolidate } = await import("./consolidate-R6FH7XMV.mjs");
7476
7486
  const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
7477
7487
  if (decision.action === "create") return null;
7478
7488
  if (decision.action === "supersede" && decision.content) {
@@ -7483,12 +7493,22 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
7483
7493
  const existing = await getVaultMemoryOp(ctx.vaultCtx, id);
7484
7494
  if (existing && !existing.supersededBy) valid.push(id);
7485
7495
  }
7486
- if (valid.length === 0) return null;
7496
+ if (valid.length === 0) {
7497
+ return abandonToRace(
7498
+ options,
7499
+ `supersede: all ${requestedIds.length} target(s) deleted or already superseded`
7500
+ );
7501
+ }
7487
7502
  return { supersede: valid, content: decision.content };
7488
7503
  }
7489
7504
  if (decision.action === "noop" && decision.targetId) {
7490
7505
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
7491
- if (!existing || existing.supersededBy) return null;
7506
+ if (!existing || existing.supersededBy) {
7507
+ return abandonToRace(
7508
+ options,
7509
+ `noop: target ${decision.targetId} ${existing ? "superseded" : "deleted"} before the write`
7510
+ );
7511
+ }
7492
7512
  const mergedSourceIds = unionStrings(
7493
7513
  existing.sourceChunkIds ?? [],
7494
7514
  options.sourceChunkIds ?? []
@@ -7513,7 +7533,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
7513
7533
  });
7514
7534
  if (!updated) {
7515
7535
  await assertMergeTargetGoneOrThrow(ctx, decision.targetId);
7516
- return null;
7536
+ return abandonToRace(
7537
+ options,
7538
+ `noop: target ${decision.targetId} deleted mid-write (proof-count bump lost)`
7539
+ );
7517
7540
  }
7518
7541
  return {
7519
7542
  done: {
@@ -7526,7 +7549,12 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
7526
7549
  }
7527
7550
  if (decision.action === "update" && decision.targetId && decision.content) {
7528
7551
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
7529
- if (!existing || existing.supersededBy) return null;
7552
+ if (!existing || existing.supersededBy) {
7553
+ return abandonToRace(
7554
+ options,
7555
+ `update: target ${decision.targetId} ${existing ? "superseded" : "deleted"} before the write`
7556
+ );
7557
+ }
7530
7558
  const mergedSourceIds = unionStrings(
7531
7559
  existing.sourceChunkIds ?? [],
7532
7560
  options.sourceChunkIds ?? []
@@ -7557,7 +7585,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
7557
7585
  });
7558
7586
  if (!updated) {
7559
7587
  await assertMergeTargetGoneOrThrow(ctx, decision.targetId);
7560
- return null;
7588
+ return abandonToRace(
7589
+ options,
7590
+ `update: target ${decision.targetId} deleted mid-write (consolidated rewrite lost)`
7591
+ );
7561
7592
  }
7562
7593
  ctx.vaultCache.set(decision.targetId, Float32Array.from(newEmbedding));
7563
7594
  return {
@@ -7569,6 +7600,11 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
7569
7600
  }
7570
7601
  };
7571
7602
  }
7603
+ notifyConsolidationFallback(
7604
+ "invalid_response",
7605
+ options.consolidateOptions?.onFallback,
7606
+ `unapplicable ${decision.action} decision reached the applier \u2014 validate() should have rejected it`
7607
+ );
7572
7608
  return null;
7573
7609
  }
7574
7610
  async function assertMergeTargetGoneOrThrow(ctx, targetId) {
@@ -8149,7 +8185,6 @@ function createAutoExtractor(options) {
8149
8185
  return true;
8150
8186
  }
8151
8187
  function drainPending() {
8152
- if (disposed) return;
8153
8188
  for (const [conversationId, state] of conversations) {
8154
8189
  if (state.pending) {
8155
8190
  const messages = state.pending;
@@ -8164,7 +8199,7 @@ function createAutoExtractor(options) {
8164
8199
  isProcessing: () => inflight > 0,
8165
8200
  dispose: () => {
8166
8201
  disposed = true;
8167
- for (const state of conversations.values()) state.pending = void 0;
8202
+ if (inflight === 0) drainPending();
8168
8203
  }
8169
8204
  };
8170
8205
  }
@@ -1,3 +1,7 @@
1
+ import {
2
+ getLogger
3
+ } from "./chunk-OBDRKQQI.mjs";
4
+
1
5
  // src/lib/pii/patterns.ts
2
6
  function luhnCheck(digits) {
3
7
  let sum = 0;
@@ -637,7 +641,21 @@ function createStreamingDeAnonymizer(redactor, emit) {
637
641
  };
638
642
  }
639
643
 
644
+ // src/lib/memory/consolidationFallback.ts
645
+ function notifyConsolidationFallback(reason, onFallback, detail) {
646
+ if (detail !== void 0) {
647
+ getLogger().warn(`memory/consolidate: degraded to create (${reason})`, detail);
648
+ } else {
649
+ getLogger().warn(`memory/consolidate: degraded to create (${reason})`);
650
+ }
651
+ try {
652
+ onFallback?.(reason);
653
+ } catch {
654
+ }
655
+ }
656
+
640
657
  export {
641
658
  resolvePiiRedactor,
642
- createStreamingDeAnonymizer
659
+ createStreamingDeAnonymizer,
660
+ notifyConsolidationFallback
643
661
  };
@@ -1,9 +1,9 @@
1
1
  import {
2
+ notifyConsolidationFallback,
2
3
  resolvePiiRedactor
3
- } from "./chunk-PXN5Q3MD.mjs";
4
+ } from "./chunk-RT75PNSJ.mjs";
4
5
  import {
5
- callPortalJsonCompletion,
6
- getLogger
6
+ callPortalJsonCompletion
7
7
  } from "./chunk-OBDRKQQI.mjs";
8
8
  import "./chunk-3RPGXXPZ.mjs";
9
9
 
@@ -102,15 +102,7 @@ ${candidateText}`;
102
102
  return result;
103
103
  }
104
104
  function degrade(reason, fallback, options, detail) {
105
- if (detail !== void 0) {
106
- getLogger().warn(`memory/consolidate: degraded to create (${reason})`, detail);
107
- } else {
108
- getLogger().warn(`memory/consolidate: degraded to create (${reason})`);
109
- }
110
- try {
111
- options.onFallback?.(reason);
112
- } catch {
113
- }
105
+ notifyConsolidationFallback(reason, options.onFallback, detail);
114
106
  return { ...fallback, fallbackReason: reason };
115
107
  }
116
108
  function validate(parsed, newContent, validIds) {
@@ -22995,6 +22995,25 @@ var init_redactor = __esm({
22995
22995
  }
22996
22996
  });
22997
22997
 
22998
+ // src/lib/memory/consolidationFallback.ts
22999
+ function notifyConsolidationFallback(reason, onFallback, detail) {
23000
+ if (detail !== void 0) {
23001
+ getLogger().warn(`memory/consolidate: degraded to create (${reason})`, detail);
23002
+ } else {
23003
+ getLogger().warn(`memory/consolidate: degraded to create (${reason})`);
23004
+ }
23005
+ try {
23006
+ onFallback?.(reason);
23007
+ } catch {
23008
+ }
23009
+ }
23010
+ var init_consolidationFallback = __esm({
23011
+ "src/lib/memory/consolidationFallback.ts"() {
23012
+ "use strict";
23013
+ init_logger();
23014
+ }
23015
+ });
23016
+
22998
23017
  // src/lib/memory/consolidate.ts
22999
23018
  var consolidate_exports = {};
23000
23019
  __export(consolidate_exports, {
@@ -23059,15 +23078,7 @@ ${candidateText}`;
23059
23078
  return result;
23060
23079
  }
23061
23080
  function degrade(reason, fallback, options, detail) {
23062
- if (detail !== void 0) {
23063
- getLogger().warn(`memory/consolidate: degraded to create (${reason})`, detail);
23064
- } else {
23065
- getLogger().warn(`memory/consolidate: degraded to create (${reason})`);
23066
- }
23067
- try {
23068
- options.onFallback?.(reason);
23069
- } catch {
23070
- }
23081
+ notifyConsolidationFallback(reason, options.onFallback, detail);
23071
23082
  return { ...fallback, fallbackReason: reason };
23072
23083
  }
23073
23084
  function validate2(parsed, newContent, validIds) {
@@ -23107,8 +23118,8 @@ var DEFAULT_CONSOLIDATION_MODEL, DEFAULT_CONSOLIDATE_ATTEMPTS, DEFAULT_CONSOLIDA
23107
23118
  var init_consolidate = __esm({
23108
23119
  "src/lib/memory/consolidate.ts"() {
23109
23120
  "use strict";
23110
- init_logger();
23111
23121
  init_redactor();
23122
+ init_consolidationFallback();
23112
23123
  init_portalLlm();
23113
23124
  DEFAULT_CONSOLIDATION_MODEL = "inclusionai/ling-2.6-flash";
23114
23125
  DEFAULT_CONSOLIDATE_ATTEMPTS = 3;
@@ -27822,6 +27833,7 @@ init_constants();
27822
27833
  init_embeddings();
27823
27834
  init_vector();
27824
27835
  init_searchTool();
27836
+ init_consolidationFallback();
27825
27837
  var DEFAULT_AUTO_MERGE_THRESHOLD = 0.8;
27826
27838
  var DEFAULT_SCOPE = "private";
27827
27839
  var DEFAULT_CONSOLIDATE_THRESHOLD = 0.55;
@@ -28001,6 +28013,11 @@ async function retain(content, ctx, options = {}) {
28001
28013
  proofCount: 1
28002
28014
  };
28003
28015
  }
28016
+ notifyConsolidationFallback(
28017
+ "target_vanished",
28018
+ options.consolidateOptions?.onFallback,
28019
+ `supersede: primary target ${primaryTargetId} retired or deleted inside the atomic write`
28020
+ );
28004
28021
  }
28005
28022
  const created = await createVaultMemoryOp(ctx.vaultCtx, createOpts);
28006
28023
  ctx.vaultCache.set(created.uniqueId, Float32Array.from(embedding));
@@ -28052,6 +28069,10 @@ function pickFactTypeUpdate(existing, incoming) {
28052
28069
  function resurrectFields(existing) {
28053
28070
  return typeof existing.archivedAt === "number" ? { restore: true } : { preserveUpdatedAt: true };
28054
28071
  }
28072
+ function abandonToRace(options, detail) {
28073
+ notifyConsolidationFallback("target_vanished", options.consolidateOptions?.onFallback, detail);
28074
+ return null;
28075
+ }
28055
28076
  async function tryConsolidate(trimmed, ctx, options, prepared) {
28056
28077
  const consolidateOptions = options.consolidateOptions;
28057
28078
  if (!consolidateOptions) return null;
@@ -28084,12 +28105,22 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
28084
28105
  const existing = await getVaultMemoryOp(ctx.vaultCtx, id);
28085
28106
  if (existing && !existing.supersededBy) valid.push(id);
28086
28107
  }
28087
- if (valid.length === 0) return null;
28108
+ if (valid.length === 0) {
28109
+ return abandonToRace(
28110
+ options,
28111
+ `supersede: all ${requestedIds.length} target(s) deleted or already superseded`
28112
+ );
28113
+ }
28088
28114
  return { supersede: valid, content: decision.content };
28089
28115
  }
28090
28116
  if (decision.action === "noop" && decision.targetId) {
28091
28117
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
28092
- if (!existing || existing.supersededBy) return null;
28118
+ if (!existing || existing.supersededBy) {
28119
+ return abandonToRace(
28120
+ options,
28121
+ `noop: target ${decision.targetId} ${existing ? "superseded" : "deleted"} before the write`
28122
+ );
28123
+ }
28093
28124
  const mergedSourceIds = unionStrings(
28094
28125
  existing.sourceChunkIds ?? [],
28095
28126
  options.sourceChunkIds ?? []
@@ -28114,7 +28145,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
28114
28145
  });
28115
28146
  if (!updated) {
28116
28147
  await assertMergeTargetGoneOrThrow(ctx, decision.targetId);
28117
- return null;
28148
+ return abandonToRace(
28149
+ options,
28150
+ `noop: target ${decision.targetId} deleted mid-write (proof-count bump lost)`
28151
+ );
28118
28152
  }
28119
28153
  return {
28120
28154
  done: {
@@ -28127,7 +28161,12 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
28127
28161
  }
28128
28162
  if (decision.action === "update" && decision.targetId && decision.content) {
28129
28163
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
28130
- if (!existing || existing.supersededBy) return null;
28164
+ if (!existing || existing.supersededBy) {
28165
+ return abandonToRace(
28166
+ options,
28167
+ `update: target ${decision.targetId} ${existing ? "superseded" : "deleted"} before the write`
28168
+ );
28169
+ }
28131
28170
  const mergedSourceIds = unionStrings(
28132
28171
  existing.sourceChunkIds ?? [],
28133
28172
  options.sourceChunkIds ?? []
@@ -28158,7 +28197,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
28158
28197
  });
28159
28198
  if (!updated) {
28160
28199
  await assertMergeTargetGoneOrThrow(ctx, decision.targetId);
28161
- return null;
28200
+ return abandonToRace(
28201
+ options,
28202
+ `update: target ${decision.targetId} deleted mid-write (consolidated rewrite lost)`
28203
+ );
28162
28204
  }
28163
28205
  ctx.vaultCache.set(decision.targetId, Float32Array.from(newEmbedding));
28164
28206
  return {
@@ -28170,6 +28212,11 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
28170
28212
  }
28171
28213
  };
28172
28214
  }
28215
+ notifyConsolidationFallback(
28216
+ "invalid_response",
28217
+ options.consolidateOptions?.onFallback,
28218
+ `unapplicable ${decision.action} decision reached the applier \u2014 validate() should have rejected it`
28219
+ );
28173
28220
  return null;
28174
28221
  }
28175
28222
  async function assertMergeTargetGoneOrThrow(ctx, targetId) {
@@ -28752,7 +28799,6 @@ function createAutoExtractor(options) {
28752
28799
  return true;
28753
28800
  }
28754
28801
  function drainPending() {
28755
- if (disposed) return;
28756
28802
  for (const [conversationId, state] of conversations) {
28757
28803
  if (state.pending) {
28758
28804
  const messages = state.pending;
@@ -28767,7 +28813,7 @@ function createAutoExtractor(options) {
28767
28813
  isProcessing: () => inflight > 0,
28768
28814
  dispose: () => {
28769
28815
  disposed = true;
28770
- for (const state of conversations.values()) state.pending = void 0;
28816
+ if (inflight === 0) drainPending();
28771
28817
  }
28772
28818
  };
28773
28819
  }
@@ -5254,8 +5254,26 @@ interface RecallDiagnostics {
5254
5254
  }
5255
5255
  type RetainAction = "create" | "merge" | "update" | "skip" | "suppressed" | "supersede";
5256
5256
  type RetainSource = "manual" | "auto-extracted" | "capsule";
5257
- /** Why the consolidator fell back to "create" instead of a real decision. */
5258
- type ConsolidationFallbackReason = "llm_error" | "invalid_response";
5257
+ /**
5258
+ * Why a retain fell back to "create" instead of applying a consolidation
5259
+ * decision. Each value names a DIFFERENT thing to go fix, which is the point of
5260
+ * keeping them apart:
5261
+ *
5262
+ * - `llm_error` — the consolidation call never produced a response (network,
5263
+ * timeout, 5xx, 429, empty completion, or missing credentials). Look at the
5264
+ * portal and the auth config.
5265
+ * - `invalid_response` — the model answered, but with something unusable: an
5266
+ * unknown action, a targetId that was not in the candidate set, an `update` or
5267
+ * `supersede` with empty content, a `noop` with no target. Look at the prompt
5268
+ * and the model.
5269
+ * - `target_vanished` — the model returned a decision that was valid when it was
5270
+ * made, and the row it named was deleted or superseded by a concurrent writer
5271
+ * before the write landed. Nothing is broken in the consolidator; a sustained
5272
+ * rate points at write contention (for example an auto-extraction worker and a
5273
+ * manual write racing over the same vault), which quietly costs you the
5274
+ * dedup that decision would have performed.
5275
+ */
5276
+ type ConsolidationFallbackReason = "llm_error" | "invalid_response" | "target_vanished";
5259
5277
  interface RetainOptions {
5260
5278
  source?: RetainSource;
5261
5279
  sourceChunkIds?: string[];
@@ -7250,7 +7268,11 @@ interface AutoExtractor {
7250
7268
  processTurn(messages: AutoExtractMessage[], conversationId?: string): boolean;
7251
7269
  /** True while a turn's extraction is in flight. */
7252
7270
  isProcessing(): boolean;
7253
- /** Stop accepting new turns. In-flight work continues to completion. */
7271
+ /**
7272
+ * Stop accepting new turns. In-flight work continues to completion, and any
7273
+ * turn already queued (coalesced while an extraction was in flight) is still
7274
+ * flushed — never dropped — so a turn sent right before unmount isn't lost.
7275
+ */
7254
7276
  dispose(): void;
7255
7277
  }
7256
7278
  /**