@anuma/sdk 3.11.6 → 3.12.1

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,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) {
@@ -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;
@@ -12164,13 +12175,18 @@ Executing tool: ${toolInfo}
12164
12175
  }
12165
12176
  const truncatedToNothing = (acc) => acc.finishReason === "length" && acc.toolCalls.size === 0 && acc.content.trim() === "";
12166
12177
  const TRUNCATION_ERROR = "Model response was truncated at the output-token limit before it produced any usable content or tool call. Retry with a higher `maxOutputTokens`, or prompt for fewer/smaller tool calls per turn.";
12178
+ const terminalStateOf = (acc) => ({
12179
+ ...acc.finishReason !== void 0 && { finishReason: acc.finishReason },
12180
+ finalToolCallCount: acc.toolCalls.size
12181
+ });
12167
12182
  if (toolIteration > 0) {
12168
12183
  if (truncatedToNothing(currentAccumulator)) {
12169
12184
  await fireRunError({ error: TRUNCATION_ERROR, stage: "model" });
12170
12185
  return {
12171
12186
  data: buildResponseFinal(currentAccumulator),
12172
12187
  error: TRUNCATION_ERROR,
12173
- toolsChecksum: currentAccumulator.toolsChecksum
12188
+ toolsChecksum: currentAccumulator.toolsChecksum,
12189
+ terminalState: terminalStateOf(currentAccumulator)
12174
12190
  };
12175
12191
  }
12176
12192
  const finalResponse = buildResponseFinal(currentAccumulator);
@@ -12183,7 +12199,8 @@ Executing tool: ${toolInfo}
12183
12199
  data: finalResponse,
12184
12200
  error: null,
12185
12201
  toolsChecksum: currentAccumulator.toolsChecksum,
12186
- autoExecutedToolResults: accumulatedToolResults
12202
+ autoExecutedToolResults: accumulatedToolResults,
12203
+ terminalState: terminalStateOf(currentAccumulator)
12187
12204
  };
12188
12205
  }
12189
12206
  if (truncatedToNothing(accumulator)) {
@@ -12191,7 +12208,8 @@ Executing tool: ${toolInfo}
12191
12208
  return {
12192
12209
  data: response,
12193
12210
  error: TRUNCATION_ERROR,
12194
- toolsChecksum: accumulator.toolsChecksum
12211
+ toolsChecksum: accumulator.toolsChecksum,
12212
+ terminalState: terminalStateOf(accumulator)
12195
12213
  };
12196
12214
  }
12197
12215
  if (onFinish) onFinish(response);
@@ -12202,7 +12220,8 @@ Executing tool: ${toolInfo}
12202
12220
  return {
12203
12221
  data: response,
12204
12222
  error: null,
12205
- toolsChecksum: accumulator.toolsChecksum
12223
+ toolsChecksum: accumulator.toolsChecksum,
12224
+ terminalState: terminalStateOf(accumulator)
12206
12225
  };
12207
12226
  } catch (err) {
12208
12227
  if (isAbortError(err)) {
@@ -16157,6 +16176,7 @@ init_constants();
16157
16176
  init_embeddings();
16158
16177
  init_vector();
16159
16178
  init_searchTool();
16179
+ init_consolidationFallback();
16160
16180
  var DEFAULT_AUTO_MERGE_THRESHOLD = 0.8;
16161
16181
  var DEFAULT_SCOPE = "private";
16162
16182
  var DEFAULT_CONSOLIDATE_THRESHOLD = 0.55;
@@ -16336,6 +16356,11 @@ async function retain(content, ctx, options = {}) {
16336
16356
  proofCount: 1
16337
16357
  };
16338
16358
  }
16359
+ notifyConsolidationFallback(
16360
+ "target_vanished",
16361
+ options.consolidateOptions?.onFallback,
16362
+ `supersede: primary target ${primaryTargetId} retired or deleted inside the atomic write`
16363
+ );
16339
16364
  }
16340
16365
  const created = await createVaultMemoryOp(ctx.vaultCtx, createOpts);
16341
16366
  ctx.vaultCache.set(created.uniqueId, Float32Array.from(embedding));
@@ -16387,6 +16412,10 @@ function pickFactTypeUpdate(existing, incoming) {
16387
16412
  function resurrectFields(existing) {
16388
16413
  return typeof existing.archivedAt === "number" ? { restore: true } : { preserveUpdatedAt: true };
16389
16414
  }
16415
+ function abandonToRace(options, detail) {
16416
+ notifyConsolidationFallback("target_vanished", options.consolidateOptions?.onFallback, detail);
16417
+ return null;
16418
+ }
16390
16419
  async function tryConsolidate(trimmed, ctx, options, prepared) {
16391
16420
  const consolidateOptions = options.consolidateOptions;
16392
16421
  if (!consolidateOptions) return null;
@@ -16419,12 +16448,22 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
16419
16448
  const existing = await getVaultMemoryOp(ctx.vaultCtx, id);
16420
16449
  if (existing && !existing.supersededBy) valid.push(id);
16421
16450
  }
16422
- 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
+ }
16423
16457
  return { supersede: valid, content: decision.content };
16424
16458
  }
16425
16459
  if (decision.action === "noop" && decision.targetId) {
16426
16460
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
16427
- 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
+ }
16428
16467
  const mergedSourceIds = unionStrings(
16429
16468
  existing.sourceChunkIds ?? [],
16430
16469
  options.sourceChunkIds ?? []
@@ -16449,7 +16488,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
16449
16488
  });
16450
16489
  if (!updated) {
16451
16490
  await assertMergeTargetGoneOrThrow(ctx, decision.targetId);
16452
- return null;
16491
+ return abandonToRace(
16492
+ options,
16493
+ `noop: target ${decision.targetId} deleted mid-write (proof-count bump lost)`
16494
+ );
16453
16495
  }
16454
16496
  return {
16455
16497
  done: {
@@ -16462,7 +16504,12 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
16462
16504
  }
16463
16505
  if (decision.action === "update" && decision.targetId && decision.content) {
16464
16506
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
16465
- 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
+ }
16466
16513
  const mergedSourceIds = unionStrings(
16467
16514
  existing.sourceChunkIds ?? [],
16468
16515
  options.sourceChunkIds ?? []
@@ -16493,7 +16540,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
16493
16540
  });
16494
16541
  if (!updated) {
16495
16542
  await assertMergeTargetGoneOrThrow(ctx, decision.targetId);
16496
- return null;
16543
+ return abandonToRace(
16544
+ options,
16545
+ `update: target ${decision.targetId} deleted mid-write (consolidated rewrite lost)`
16546
+ );
16497
16547
  }
16498
16548
  ctx.vaultCache.set(decision.targetId, Float32Array.from(newEmbedding));
16499
16549
  return {
@@ -16505,6 +16555,11 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
16505
16555
  }
16506
16556
  };
16507
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
+ );
16508
16563
  return null;
16509
16564
  }
16510
16565
  async function assertMergeTargetGoneOrThrow(ctx, targetId) {
@@ -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[];
@@ -6612,7 +6630,8 @@ interface RetainOptions {
6612
6630
  * Returns `action: 'suppressed'` with the matched `tombstoneId`.
6613
6631
  */
6614
6632
  respectTombstones?: boolean;
6615
- /** Cosine similarity threshold for auto-merge. Default: 0.85. */
6633
+ /** Cosine similarity threshold for auto-merge. Default: 0.8
6634
+ * (`DEFAULT_AUTO_MERGE_THRESHOLD` in retain.ts — the source of truth). */
6616
6635
  autoMergeThreshold?: number;
6617
6636
  /**
6618
6637
  * When provided, runs an LLM-based consolidation pass against the top-K
@@ -6640,9 +6659,13 @@ interface RetainOptions {
6640
6659
  */
6641
6660
  piiRedaction?: boolean | PiiRedactor;
6642
6661
  };
6643
- /** Cosine similarity floor for the consolidator candidate set. Default: 0.65. */
6662
+ /** Cosine similarity floor for the consolidator candidate set. Default: 0.55
6663
+ * (`DEFAULT_CONSOLIDATE_THRESHOLD` in retain.ts — the source of truth). */
6644
6664
  consolidateThreshold?: number;
6645
- /** Top-K consolidation candidates to feed the LLM. Default: 5. */
6665
+ /** Top-K consolidation candidates to feed the LLM. Default: 20
6666
+ * (`DEFAULT_CONSOLIDATE_TOP_K` in retain.ts — the source of truth). Widened
6667
+ * from 5 so a value change can find and retire ALL stale duplicates of the
6668
+ * old value in one pass, not just the nearest few. */
6646
6669
  consolidateTopK?: number;
6647
6670
  /**
6648
6671
  * W6 temporal lane — when the event in this fact occurred. Persisted to
@@ -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[];
@@ -6612,7 +6630,8 @@ interface RetainOptions {
6612
6630
  * Returns `action: 'suppressed'` with the matched `tombstoneId`.
6613
6631
  */
6614
6632
  respectTombstones?: boolean;
6615
- /** Cosine similarity threshold for auto-merge. Default: 0.85. */
6633
+ /** Cosine similarity threshold for auto-merge. Default: 0.8
6634
+ * (`DEFAULT_AUTO_MERGE_THRESHOLD` in retain.ts — the source of truth). */
6616
6635
  autoMergeThreshold?: number;
6617
6636
  /**
6618
6637
  * When provided, runs an LLM-based consolidation pass against the top-K
@@ -6640,9 +6659,13 @@ interface RetainOptions {
6640
6659
  */
6641
6660
  piiRedaction?: boolean | PiiRedactor;
6642
6661
  };
6643
- /** Cosine similarity floor for the consolidator candidate set. Default: 0.65. */
6662
+ /** Cosine similarity floor for the consolidator candidate set. Default: 0.55
6663
+ * (`DEFAULT_CONSOLIDATE_THRESHOLD` in retain.ts — the source of truth). */
6644
6664
  consolidateThreshold?: number;
6645
- /** Top-K consolidation candidates to feed the LLM. Default: 5. */
6665
+ /** Top-K consolidation candidates to feed the LLM. Default: 20
6666
+ * (`DEFAULT_CONSOLIDATE_TOP_K` in retain.ts — the source of truth). Widened
6667
+ * from 5 so a value change can find and retire ALL stale duplicates of the
6668
+ * old value in one pass, not just the nearest few. */
6646
6669
  consolidateTopK?: number;
6647
6670
  /**
6648
6671
  * W6 temporal lane — when the event in this fact occurred. Persisted to
@@ -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,
@@ -3266,13 +3267,18 @@ Executing tool: ${toolInfo}
3266
3267
  }
3267
3268
  const truncatedToNothing = (acc) => acc.finishReason === "length" && acc.toolCalls.size === 0 && acc.content.trim() === "";
3268
3269
  const TRUNCATION_ERROR = "Model response was truncated at the output-token limit before it produced any usable content or tool call. Retry with a higher `maxOutputTokens`, or prompt for fewer/smaller tool calls per turn.";
3270
+ const terminalStateOf = (acc) => ({
3271
+ ...acc.finishReason !== void 0 && { finishReason: acc.finishReason },
3272
+ finalToolCallCount: acc.toolCalls.size
3273
+ });
3269
3274
  if (toolIteration > 0) {
3270
3275
  if (truncatedToNothing(currentAccumulator)) {
3271
3276
  await fireRunError({ error: TRUNCATION_ERROR, stage: "model" });
3272
3277
  return {
3273
3278
  data: buildResponseFinal(currentAccumulator),
3274
3279
  error: TRUNCATION_ERROR,
3275
- toolsChecksum: currentAccumulator.toolsChecksum
3280
+ toolsChecksum: currentAccumulator.toolsChecksum,
3281
+ terminalState: terminalStateOf(currentAccumulator)
3276
3282
  };
3277
3283
  }
3278
3284
  const finalResponse = buildResponseFinal(currentAccumulator);
@@ -3285,7 +3291,8 @@ Executing tool: ${toolInfo}
3285
3291
  data: finalResponse,
3286
3292
  error: null,
3287
3293
  toolsChecksum: currentAccumulator.toolsChecksum,
3288
- autoExecutedToolResults: accumulatedToolResults
3294
+ autoExecutedToolResults: accumulatedToolResults,
3295
+ terminalState: terminalStateOf(currentAccumulator)
3289
3296
  };
3290
3297
  }
3291
3298
  if (truncatedToNothing(accumulator)) {
@@ -3293,7 +3300,8 @@ Executing tool: ${toolInfo}
3293
3300
  return {
3294
3301
  data: response,
3295
3302
  error: TRUNCATION_ERROR,
3296
- toolsChecksum: accumulator.toolsChecksum
3303
+ toolsChecksum: accumulator.toolsChecksum,
3304
+ terminalState: terminalStateOf(accumulator)
3297
3305
  };
3298
3306
  }
3299
3307
  if (onFinish) onFinish(response);
@@ -3304,7 +3312,8 @@ Executing tool: ${toolInfo}
3304
3312
  return {
3305
3313
  data: response,
3306
3314
  error: null,
3307
- toolsChecksum: accumulator.toolsChecksum
3315
+ toolsChecksum: accumulator.toolsChecksum,
3316
+ terminalState: terminalStateOf(accumulator)
3308
3317
  };
3309
3318
  } catch (err) {
3310
3319
  if (isAbortError(err)) {
@@ -7392,6 +7401,11 @@ async function retain(content, ctx, options = {}) {
7392
7401
  proofCount: 1
7393
7402
  };
7394
7403
  }
7404
+ notifyConsolidationFallback(
7405
+ "target_vanished",
7406
+ options.consolidateOptions?.onFallback,
7407
+ `supersede: primary target ${primaryTargetId} retired or deleted inside the atomic write`
7408
+ );
7395
7409
  }
7396
7410
  const created = await createVaultMemoryOp(ctx.vaultCtx, createOpts);
7397
7411
  ctx.vaultCache.set(created.uniqueId, Float32Array.from(embedding));
@@ -7443,6 +7457,10 @@ function pickFactTypeUpdate(existing, incoming) {
7443
7457
  function resurrectFields(existing) {
7444
7458
  return typeof existing.archivedAt === "number" ? { restore: true } : { preserveUpdatedAt: true };
7445
7459
  }
7460
+ function abandonToRace(options, detail) {
7461
+ notifyConsolidationFallback("target_vanished", options.consolidateOptions?.onFallback, detail);
7462
+ return null;
7463
+ }
7446
7464
  async function tryConsolidate(trimmed, ctx, options, prepared) {
7447
7465
  const consolidateOptions = options.consolidateOptions;
7448
7466
  if (!consolidateOptions) return null;
@@ -7464,7 +7482,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
7464
7482
  content: m.content,
7465
7483
  similarity: m.similarity
7466
7484
  }));
7467
- const { consolidateMemory: doConsolidate } = await import("./consolidate-DOY3ZWTE.mjs");
7485
+ const { consolidateMemory: doConsolidate } = await import("./consolidate-R6FH7XMV.mjs");
7468
7486
  const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
7469
7487
  if (decision.action === "create") return null;
7470
7488
  if (decision.action === "supersede" && decision.content) {
@@ -7475,12 +7493,22 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
7475
7493
  const existing = await getVaultMemoryOp(ctx.vaultCtx, id);
7476
7494
  if (existing && !existing.supersededBy) valid.push(id);
7477
7495
  }
7478
- 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
+ }
7479
7502
  return { supersede: valid, content: decision.content };
7480
7503
  }
7481
7504
  if (decision.action === "noop" && decision.targetId) {
7482
7505
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
7483
- 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
+ }
7484
7512
  const mergedSourceIds = unionStrings(
7485
7513
  existing.sourceChunkIds ?? [],
7486
7514
  options.sourceChunkIds ?? []
@@ -7505,7 +7533,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
7505
7533
  });
7506
7534
  if (!updated) {
7507
7535
  await assertMergeTargetGoneOrThrow(ctx, decision.targetId);
7508
- return null;
7536
+ return abandonToRace(
7537
+ options,
7538
+ `noop: target ${decision.targetId} deleted mid-write (proof-count bump lost)`
7539
+ );
7509
7540
  }
7510
7541
  return {
7511
7542
  done: {
@@ -7518,7 +7549,12 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
7518
7549
  }
7519
7550
  if (decision.action === "update" && decision.targetId && decision.content) {
7520
7551
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
7521
- 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
+ }
7522
7558
  const mergedSourceIds = unionStrings(
7523
7559
  existing.sourceChunkIds ?? [],
7524
7560
  options.sourceChunkIds ?? []
@@ -7549,7 +7585,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
7549
7585
  });
7550
7586
  if (!updated) {
7551
7587
  await assertMergeTargetGoneOrThrow(ctx, decision.targetId);
7552
- return null;
7588
+ return abandonToRace(
7589
+ options,
7590
+ `update: target ${decision.targetId} deleted mid-write (consolidated rewrite lost)`
7591
+ );
7553
7592
  }
7554
7593
  ctx.vaultCache.set(decision.targetId, Float32Array.from(newEmbedding));
7555
7594
  return {
@@ -7561,6 +7600,11 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
7561
7600
  }
7562
7601
  };
7563
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
+ );
7564
7608
  return null;
7565
7609
  }
7566
7610
  async function assertMergeTargetGoneOrThrow(ctx, targetId) {
@@ -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) {