@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.
@@ -1,3 +1,7 @@
1
+ import {
2
+ getLogger
3
+ } from "./chunk-ILAWDQDE.mjs";
4
+
1
5
  // src/lib/pii/patterns.ts
2
6
  function luhnCheck(digits) {
3
7
  let sum = 0;
@@ -637,10 +641,24 @@ 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
  PII_PATTERNS,
642
659
  PiiRedactor,
643
660
  isPiiRedactor,
644
661
  resolvePiiRedactor,
645
- createStreamingDeAnonymizer
662
+ createStreamingDeAnonymizer,
663
+ notifyConsolidationFallback
646
664
  };
@@ -1,9 +1,9 @@
1
1
  import {
2
+ notifyConsolidationFallback,
2
3
  resolvePiiRedactor
3
- } from "./chunk-Y7XT2VNQ.mjs";
4
+ } from "./chunk-WV7C7VHF.mjs";
4
5
  import {
5
- callPortalJsonCompletion,
6
- getLogger
6
+ callPortalJsonCompletion
7
7
  } from "./chunk-ILAWDQDE.mjs";
8
8
  import "./chunk-GYKJOWEO.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) {
@@ -8170,6 +8170,25 @@ var init_searchTool = __esm({
8170
8170
  }
8171
8171
  });
8172
8172
 
8173
+ // src/lib/memory/consolidationFallback.ts
8174
+ function notifyConsolidationFallback(reason, onFallback, detail) {
8175
+ if (detail !== void 0) {
8176
+ getLogger().warn(`memory/consolidate: degraded to create (${reason})`, detail);
8177
+ } else {
8178
+ getLogger().warn(`memory/consolidate: degraded to create (${reason})`);
8179
+ }
8180
+ try {
8181
+ onFallback?.(reason);
8182
+ } catch {
8183
+ }
8184
+ }
8185
+ var init_consolidationFallback = __esm({
8186
+ "src/lib/memory/consolidationFallback.ts"() {
8187
+ "use strict";
8188
+ init_logger();
8189
+ }
8190
+ });
8191
+
8173
8192
  // src/lib/memory/consolidate.ts
8174
8193
  var consolidate_exports = {};
8175
8194
  __export(consolidate_exports, {
@@ -8234,15 +8253,7 @@ ${candidateText}`;
8234
8253
  return result;
8235
8254
  }
8236
8255
  function degrade(reason, fallback, options, detail) {
8237
- if (detail !== void 0) {
8238
- getLogger().warn(`memory/consolidate: degraded to create (${reason})`, detail);
8239
- } else {
8240
- getLogger().warn(`memory/consolidate: degraded to create (${reason})`);
8241
- }
8242
- try {
8243
- options.onFallback?.(reason);
8244
- } catch {
8245
- }
8256
+ notifyConsolidationFallback(reason, options.onFallback, detail);
8246
8257
  return { ...fallback, fallbackReason: reason };
8247
8258
  }
8248
8259
  function validate2(parsed, newContent, validIds) {
@@ -8282,8 +8293,8 @@ var DEFAULT_CONSOLIDATION_MODEL, DEFAULT_CONSOLIDATE_ATTEMPTS, DEFAULT_CONSOLIDA
8282
8293
  var init_consolidate = __esm({
8283
8294
  "src/lib/memory/consolidate.ts"() {
8284
8295
  "use strict";
8285
- init_logger();
8286
8296
  init_redactor();
8297
+ init_consolidationFallback();
8287
8298
  init_portalLlm();
8288
8299
  DEFAULT_CONSOLIDATION_MODEL = "inclusionai/ling-2.6-flash";
8289
8300
  DEFAULT_CONSOLIDATE_ATTEMPTS = 3;
@@ -14848,6 +14859,7 @@ init_constants();
14848
14859
  init_embeddings();
14849
14860
  init_vector();
14850
14861
  init_searchTool();
14862
+ init_consolidationFallback();
14851
14863
  var DEFAULT_AUTO_MERGE_THRESHOLD = 0.8;
14852
14864
  var DEFAULT_SCOPE = "private";
14853
14865
  var DEFAULT_CONSOLIDATE_THRESHOLD = 0.55;
@@ -15027,6 +15039,11 @@ async function retain(content, ctx, options = {}) {
15027
15039
  proofCount: 1
15028
15040
  };
15029
15041
  }
15042
+ notifyConsolidationFallback(
15043
+ "target_vanished",
15044
+ options.consolidateOptions?.onFallback,
15045
+ `supersede: primary target ${primaryTargetId} retired or deleted inside the atomic write`
15046
+ );
15030
15047
  }
15031
15048
  const created = await createVaultMemoryOp(ctx.vaultCtx, createOpts);
15032
15049
  ctx.vaultCache.set(created.uniqueId, Float32Array.from(embedding));
@@ -15078,6 +15095,10 @@ function pickFactTypeUpdate(existing, incoming) {
15078
15095
  function resurrectFields(existing) {
15079
15096
  return typeof existing.archivedAt === "number" ? { restore: true } : { preserveUpdatedAt: true };
15080
15097
  }
15098
+ function abandonToRace(options, detail) {
15099
+ notifyConsolidationFallback("target_vanished", options.consolidateOptions?.onFallback, detail);
15100
+ return null;
15101
+ }
15081
15102
  async function tryConsolidate(trimmed, ctx, options, prepared) {
15082
15103
  const consolidateOptions = options.consolidateOptions;
15083
15104
  if (!consolidateOptions) return null;
@@ -15110,12 +15131,22 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
15110
15131
  const existing = await getVaultMemoryOp(ctx.vaultCtx, id);
15111
15132
  if (existing && !existing.supersededBy) valid.push(id);
15112
15133
  }
15113
- if (valid.length === 0) return null;
15134
+ if (valid.length === 0) {
15135
+ return abandonToRace(
15136
+ options,
15137
+ `supersede: all ${requestedIds.length} target(s) deleted or already superseded`
15138
+ );
15139
+ }
15114
15140
  return { supersede: valid, content: decision.content };
15115
15141
  }
15116
15142
  if (decision.action === "noop" && decision.targetId) {
15117
15143
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
15118
- if (!existing || existing.supersededBy) return null;
15144
+ if (!existing || existing.supersededBy) {
15145
+ return abandonToRace(
15146
+ options,
15147
+ `noop: target ${decision.targetId} ${existing ? "superseded" : "deleted"} before the write`
15148
+ );
15149
+ }
15119
15150
  const mergedSourceIds = unionStrings(
15120
15151
  existing.sourceChunkIds ?? [],
15121
15152
  options.sourceChunkIds ?? []
@@ -15140,7 +15171,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
15140
15171
  });
15141
15172
  if (!updated) {
15142
15173
  await assertMergeTargetGoneOrThrow(ctx, decision.targetId);
15143
- return null;
15174
+ return abandonToRace(
15175
+ options,
15176
+ `noop: target ${decision.targetId} deleted mid-write (proof-count bump lost)`
15177
+ );
15144
15178
  }
15145
15179
  return {
15146
15180
  done: {
@@ -15153,7 +15187,12 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
15153
15187
  }
15154
15188
  if (decision.action === "update" && decision.targetId && decision.content) {
15155
15189
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
15156
- if (!existing || existing.supersededBy) return null;
15190
+ if (!existing || existing.supersededBy) {
15191
+ return abandonToRace(
15192
+ options,
15193
+ `update: target ${decision.targetId} ${existing ? "superseded" : "deleted"} before the write`
15194
+ );
15195
+ }
15157
15196
  const mergedSourceIds = unionStrings(
15158
15197
  existing.sourceChunkIds ?? [],
15159
15198
  options.sourceChunkIds ?? []
@@ -15184,7 +15223,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
15184
15223
  });
15185
15224
  if (!updated) {
15186
15225
  await assertMergeTargetGoneOrThrow(ctx, decision.targetId);
15187
- return null;
15226
+ return abandonToRace(
15227
+ options,
15228
+ `update: target ${decision.targetId} deleted mid-write (consolidated rewrite lost)`
15229
+ );
15188
15230
  }
15189
15231
  ctx.vaultCache.set(decision.targetId, Float32Array.from(newEmbedding));
15190
15232
  return {
@@ -15196,6 +15238,11 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
15196
15238
  }
15197
15239
  };
15198
15240
  }
15241
+ notifyConsolidationFallback(
15242
+ "invalid_response",
15243
+ options.consolidateOptions?.onFallback,
15244
+ `unapplicable ${decision.action} decision reached the applier \u2014 validate() should have rejected it`
15245
+ );
15199
15246
  return null;
15200
15247
  }
15201
15248
  async function assertMergeTargetGoneOrThrow(ctx, targetId) {
@@ -15778,7 +15825,6 @@ function createAutoExtractor(options) {
15778
15825
  return true;
15779
15826
  }
15780
15827
  function drainPending() {
15781
- if (disposed) return;
15782
15828
  for (const [conversationId, state] of conversations) {
15783
15829
  if (state.pending) {
15784
15830
  const messages = state.pending;
@@ -15793,7 +15839,7 @@ function createAutoExtractor(options) {
15793
15839
  isProcessing: () => inflight > 0,
15794
15840
  dispose: () => {
15795
15841
  disposed = true;
15796
- for (const state of conversations.values()) state.pending = void 0;
15842
+ if (inflight === 0) drainPending();
15797
15843
  }
15798
15844
  };
15799
15845
  }
@@ -5322,8 +5322,26 @@ interface RecallDiagnostics {
5322
5322
  }
5323
5323
  type RetainAction = "create" | "merge" | "update" | "skip" | "suppressed" | "supersede";
5324
5324
  type RetainSource = "manual" | "auto-extracted" | "capsule";
5325
- /** Why the consolidator fell back to "create" instead of a real decision. */
5326
- type ConsolidationFallbackReason = "llm_error" | "invalid_response";
5325
+ /**
5326
+ * Why a retain fell back to "create" instead of applying a consolidation
5327
+ * decision. Each value names a DIFFERENT thing to go fix, which is the point of
5328
+ * keeping them apart:
5329
+ *
5330
+ * - `llm_error` — the consolidation call never produced a response (network,
5331
+ * timeout, 5xx, 429, empty completion, or missing credentials). Look at the
5332
+ * portal and the auth config.
5333
+ * - `invalid_response` — the model answered, but with something unusable: an
5334
+ * unknown action, a targetId that was not in the candidate set, an `update` or
5335
+ * `supersede` with empty content, a `noop` with no target. Look at the prompt
5336
+ * and the model.
5337
+ * - `target_vanished` — the model returned a decision that was valid when it was
5338
+ * made, and the row it named was deleted or superseded by a concurrent writer
5339
+ * before the write landed. Nothing is broken in the consolidator; a sustained
5340
+ * rate points at write contention (for example an auto-extraction worker and a
5341
+ * manual write racing over the same vault), which quietly costs you the
5342
+ * dedup that decision would have performed.
5343
+ */
5344
+ type ConsolidationFallbackReason = "llm_error" | "invalid_response" | "target_vanished";
5327
5345
  interface RetainOptions {
5328
5346
  source?: RetainSource;
5329
5347
  sourceChunkIds?: string[];
@@ -6614,7 +6632,11 @@ interface AutoExtractor {
6614
6632
  processTurn(messages: AutoExtractMessage[], conversationId?: string): boolean;
6615
6633
  /** True while a turn's extraction is in flight. */
6616
6634
  isProcessing(): boolean;
6617
- /** Stop accepting new turns. In-flight work continues to completion. */
6635
+ /**
6636
+ * Stop accepting new turns. In-flight work continues to completion, and any
6637
+ * turn already queued (coalesced while an extraction was in flight) is still
6638
+ * flushed — never dropped — so a turn sent right before unmount isn't lost.
6639
+ */
6618
6640
  dispose(): void;
6619
6641
  }
6620
6642
  /**
@@ -5322,8 +5322,26 @@ interface RecallDiagnostics {
5322
5322
  }
5323
5323
  type RetainAction = "create" | "merge" | "update" | "skip" | "suppressed" | "supersede";
5324
5324
  type RetainSource = "manual" | "auto-extracted" | "capsule";
5325
- /** Why the consolidator fell back to "create" instead of a real decision. */
5326
- type ConsolidationFallbackReason = "llm_error" | "invalid_response";
5325
+ /**
5326
+ * Why a retain fell back to "create" instead of applying a consolidation
5327
+ * decision. Each value names a DIFFERENT thing to go fix, which is the point of
5328
+ * keeping them apart:
5329
+ *
5330
+ * - `llm_error` — the consolidation call never produced a response (network,
5331
+ * timeout, 5xx, 429, empty completion, or missing credentials). Look at the
5332
+ * portal and the auth config.
5333
+ * - `invalid_response` — the model answered, but with something unusable: an
5334
+ * unknown action, a targetId that was not in the candidate set, an `update` or
5335
+ * `supersede` with empty content, a `noop` with no target. Look at the prompt
5336
+ * and the model.
5337
+ * - `target_vanished` — the model returned a decision that was valid when it was
5338
+ * made, and the row it named was deleted or superseded by a concurrent writer
5339
+ * before the write landed. Nothing is broken in the consolidator; a sustained
5340
+ * rate points at write contention (for example an auto-extraction worker and a
5341
+ * manual write racing over the same vault), which quietly costs you the
5342
+ * dedup that decision would have performed.
5343
+ */
5344
+ type ConsolidationFallbackReason = "llm_error" | "invalid_response" | "target_vanished";
5327
5345
  interface RetainOptions {
5328
5346
  source?: RetainSource;
5329
5347
  sourceChunkIds?: string[];
@@ -6614,7 +6632,11 @@ interface AutoExtractor {
6614
6632
  processTurn(messages: AutoExtractMessage[], conversationId?: string): boolean;
6615
6633
  /** True while a turn's extraction is in flight. */
6616
6634
  isProcessing(): boolean;
6617
- /** Stop accepting new turns. In-flight work continues to completion. */
6635
+ /**
6636
+ * Stop accepting new turns. In-flight work continues to completion, and any
6637
+ * turn already queued (coalesced while an extraction was in flight) is still
6638
+ * flushed — never dropped — so a turn sent right before unmount isn't lost.
6639
+ */
6618
6640
  dispose(): void;
6619
6641
  }
6620
6642
  /**
@@ -120,8 +120,9 @@ import {
120
120
  PiiRedactor,
121
121
  createStreamingDeAnonymizer,
122
122
  isPiiRedactor,
123
+ notifyConsolidationFallback,
123
124
  resolvePiiRedactor
124
- } from "./chunk-Y7XT2VNQ.mjs";
125
+ } from "./chunk-WV7C7VHF.mjs";
125
126
  import {
126
127
  callPortalJsonCompletion,
127
128
  consoleLogger,
@@ -6583,6 +6584,11 @@ async function retain(content, ctx, options = {}) {
6583
6584
  proofCount: 1
6584
6585
  };
6585
6586
  }
6587
+ notifyConsolidationFallback(
6588
+ "target_vanished",
6589
+ options.consolidateOptions?.onFallback,
6590
+ `supersede: primary target ${primaryTargetId} retired or deleted inside the atomic write`
6591
+ );
6586
6592
  }
6587
6593
  const created = await createVaultMemoryOp(ctx.vaultCtx, createOpts);
6588
6594
  ctx.vaultCache.set(created.uniqueId, Float32Array.from(embedding));
@@ -6634,6 +6640,10 @@ function pickFactTypeUpdate(existing, incoming) {
6634
6640
  function resurrectFields(existing) {
6635
6641
  return typeof existing.archivedAt === "number" ? { restore: true } : { preserveUpdatedAt: true };
6636
6642
  }
6643
+ function abandonToRace(options, detail) {
6644
+ notifyConsolidationFallback("target_vanished", options.consolidateOptions?.onFallback, detail);
6645
+ return null;
6646
+ }
6637
6647
  async function tryConsolidate(trimmed, ctx, options, prepared) {
6638
6648
  const consolidateOptions = options.consolidateOptions;
6639
6649
  if (!consolidateOptions) return null;
@@ -6655,7 +6665,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
6655
6665
  content: m.content,
6656
6666
  similarity: m.similarity
6657
6667
  }));
6658
- const { consolidateMemory: doConsolidate } = await import("./consolidate-HYIEFPFA.mjs");
6668
+ const { consolidateMemory: doConsolidate } = await import("./consolidate-AURTG64H.mjs");
6659
6669
  const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
6660
6670
  if (decision.action === "create") return null;
6661
6671
  if (decision.action === "supersede" && decision.content) {
@@ -6666,12 +6676,22 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
6666
6676
  const existing = await getVaultMemoryOp(ctx.vaultCtx, id);
6667
6677
  if (existing && !existing.supersededBy) valid.push(id);
6668
6678
  }
6669
- if (valid.length === 0) return null;
6679
+ if (valid.length === 0) {
6680
+ return abandonToRace(
6681
+ options,
6682
+ `supersede: all ${requestedIds.length} target(s) deleted or already superseded`
6683
+ );
6684
+ }
6670
6685
  return { supersede: valid, content: decision.content };
6671
6686
  }
6672
6687
  if (decision.action === "noop" && decision.targetId) {
6673
6688
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
6674
- if (!existing || existing.supersededBy) return null;
6689
+ if (!existing || existing.supersededBy) {
6690
+ return abandonToRace(
6691
+ options,
6692
+ `noop: target ${decision.targetId} ${existing ? "superseded" : "deleted"} before the write`
6693
+ );
6694
+ }
6675
6695
  const mergedSourceIds = unionStrings(
6676
6696
  existing.sourceChunkIds ?? [],
6677
6697
  options.sourceChunkIds ?? []
@@ -6696,7 +6716,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
6696
6716
  });
6697
6717
  if (!updated) {
6698
6718
  await assertMergeTargetGoneOrThrow(ctx, decision.targetId);
6699
- return null;
6719
+ return abandonToRace(
6720
+ options,
6721
+ `noop: target ${decision.targetId} deleted mid-write (proof-count bump lost)`
6722
+ );
6700
6723
  }
6701
6724
  return {
6702
6725
  done: {
@@ -6709,7 +6732,12 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
6709
6732
  }
6710
6733
  if (decision.action === "update" && decision.targetId && decision.content) {
6711
6734
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
6712
- if (!existing || existing.supersededBy) return null;
6735
+ if (!existing || existing.supersededBy) {
6736
+ return abandonToRace(
6737
+ options,
6738
+ `update: target ${decision.targetId} ${existing ? "superseded" : "deleted"} before the write`
6739
+ );
6740
+ }
6713
6741
  const mergedSourceIds = unionStrings(
6714
6742
  existing.sourceChunkIds ?? [],
6715
6743
  options.sourceChunkIds ?? []
@@ -6740,7 +6768,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
6740
6768
  });
6741
6769
  if (!updated) {
6742
6770
  await assertMergeTargetGoneOrThrow(ctx, decision.targetId);
6743
- return null;
6771
+ return abandonToRace(
6772
+ options,
6773
+ `update: target ${decision.targetId} deleted mid-write (consolidated rewrite lost)`
6774
+ );
6744
6775
  }
6745
6776
  ctx.vaultCache.set(decision.targetId, Float32Array.from(newEmbedding));
6746
6777
  return {
@@ -6752,6 +6783,11 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
6752
6783
  }
6753
6784
  };
6754
6785
  }
6786
+ notifyConsolidationFallback(
6787
+ "invalid_response",
6788
+ options.consolidateOptions?.onFallback,
6789
+ `unapplicable ${decision.action} decision reached the applier \u2014 validate() should have rejected it`
6790
+ );
6755
6791
  return null;
6756
6792
  }
6757
6793
  async function assertMergeTargetGoneOrThrow(ctx, targetId) {
@@ -7332,7 +7368,6 @@ function createAutoExtractor(options) {
7332
7368
  return true;
7333
7369
  }
7334
7370
  function drainPending() {
7335
- if (disposed) return;
7336
7371
  for (const [conversationId, state] of conversations) {
7337
7372
  if (state.pending) {
7338
7373
  const messages = state.pending;
@@ -7347,7 +7382,7 @@ function createAutoExtractor(options) {
7347
7382
  isProcessing: () => inflight > 0,
7348
7383
  dispose: () => {
7349
7384
  disposed = true;
7350
- for (const state of conversations.values()) state.pending = void 0;
7385
+ if (inflight === 0) drainPending();
7351
7386
  }
7352
7387
  };
7353
7388
  }
@@ -1,3 +1,7 @@
1
+ import {
2
+ getLogger
3
+ } from "./chunk-ILAWDQDE.mjs";
4
+
1
5
  // src/lib/pii/patterns.ts
2
6
  function luhnCheck(digits) {
3
7
  let sum = 0;
@@ -637,9 +641,23 @@ 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
  PiiRedactor,
642
659
  isPiiRedactor,
643
660
  resolvePiiRedactor,
644
- createStreamingDeAnonymizer
661
+ createStreamingDeAnonymizer,
662
+ notifyConsolidationFallback
645
663
  };
@@ -1,9 +1,9 @@
1
1
  import {
2
+ notifyConsolidationFallback,
2
3
  resolvePiiRedactor
3
- } from "./chunk-TP6CJZ25.mjs";
4
+ } from "./chunk-3NPDZZGO.mjs";
4
5
  import {
5
- callPortalJsonCompletion,
6
- getLogger
6
+ callPortalJsonCompletion
7
7
  } from "./chunk-ILAWDQDE.mjs";
8
8
  import "./chunk-GYKJOWEO.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) {