@anuma/sdk 3.7.0 → 3.8.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.
@@ -7911,14 +7911,27 @@ function validate2(parsed, newContent, validIds) {
7911
7911
  const c2 = typeof obj.content === "string" ? obj.content.trim() : "";
7912
7912
  return { action: "create", content: c2.length > 0 ? c2 : newContent };
7913
7913
  }
7914
- const targetId = typeof obj.targetId === "string" ? obj.targetId : null;
7915
- if (!targetId || !validIds.has(targetId)) return null;
7916
7914
  if (action === "noop") {
7917
- return { action: "noop", targetId };
7915
+ const targetId2 = typeof obj.targetId === "string" ? obj.targetId : null;
7916
+ if (!targetId2 || !validIds.has(targetId2)) return null;
7917
+ return { action: "noop", targetId: targetId2 };
7918
7918
  }
7919
7919
  const c = typeof obj.content === "string" ? obj.content.trim() : "";
7920
7920
  if (c.length === 0) return null;
7921
- return { action, targetId, content: c };
7921
+ if (action === "supersede") {
7922
+ const rawIds = [
7923
+ ...Array.isArray(obj.targetIds) ? obj.targetIds : [],
7924
+ ...typeof obj.targetId === "string" ? [obj.targetId] : []
7925
+ ];
7926
+ const targetIds = [
7927
+ ...new Set(rawIds.filter((id) => typeof id === "string" && validIds.has(id)))
7928
+ ];
7929
+ if (targetIds.length === 0) return null;
7930
+ return { action: "supersede", targetId: targetIds[0], targetIds, content: c };
7931
+ }
7932
+ const targetId = typeof obj.targetId === "string" ? obj.targetId : null;
7933
+ if (!targetId || !validIds.has(targetId)) return null;
7934
+ return { action: "update", targetId, content: c };
7922
7935
  }
7923
7936
  var DEFAULT_MODEL3, DEFAULT_CONSOLIDATE_ATTEMPTS, DEFAULT_CONSOLIDATE_TOTAL_TIMEOUT_MS, SYSTEM_PROMPT3;
7924
7937
  var init_consolidate = __esm({
@@ -7938,7 +7951,7 @@ Decide one of four actions:
7938
7951
 
7939
7952
  - "create": the new memory describes a distinct fact not covered by any existing memory. Write it as new.
7940
7953
  - "update": the new memory describes the SAME FACET as exactly one existing memory and is COMPATIBLE with it \u2014 it adds detail, fixes an incomplete value, or rephrases the same still-true fact. Return targetId of that existing memory + the consolidated content (richest version of the two).
7941
- - "supersede": the new memory REPLACES a standing fact whose value has CHANGED and is now INCOMPATIBLE with an existing memory \u2014 the old fact was true before but is false now (a state change). Return targetId of the STALE existing memory to retire + content = the NEW fact. The old memory is kept as history, not overwritten or deleted; do not re-state it.
7954
+ - "supersede": the new memory REPLACES a standing fact whose value has CHANGED and is now INCOMPATIBLE with an existing memory \u2014 the old fact was true before but is false now (a state change). Return "targetIds": an array of the ids of EVERY existing candidate that describes the SAME standing attribute now being changed \u2014 retire ALL stale duplicates of the old value, not just one (the candidate list may contain several paraphrases of the same old fact) + content = the NEW fact. The old memories are kept as history, not overwritten or deleted; do not re-state them.
7942
7955
  - "noop": the new memory is already fully captured by an existing memory \u2014 same facet, no new information. Skip the write.
7943
7956
 
7944
7957
  RULES (carry these strictly):
@@ -7954,14 +7967,15 @@ RULES (carry these strictly):
7954
7967
  OUTPUT \u2014 strict JSON, no prose:
7955
7968
  {
7956
7969
  "action": "create" | "update" | "supersede" | "noop",
7957
- "targetId": "<existing memory id \u2014 required for update/supersede/noop, omit for create>",
7970
+ "targetId": "<existing memory id \u2014 required for update/noop, omit for create/supersede>",
7971
+ "targetIds": ["<id>", ...],
7958
7972
  "content": "<content \u2014 required for create/update/supersede, omit for noop>"
7959
7973
  }
7960
7974
 
7961
- For "create": content is the new memory verbatim (or a slight refinement).
7962
- For "update": content is the merged richest-version, \u226480 words.
7963
- For "supersede": content is the NEW fact only (\u226480 words); targetId is the stale memory being retired.
7964
- For "noop": no content (existing memory is already correct).`;
7975
+ For "create": content is the new memory verbatim (or a slight refinement); omit targetId/targetIds.
7976
+ For "update": content is the merged richest-version, \u226480 words; targetId is the single memory to update.
7977
+ For "supersede": content is the NEW fact only (\u226480 words); "targetIds" lists EVERY stale memory being retired (all candidates describing the same now-changed attribute).
7978
+ For "noop": no content (existing memory is already correct); targetId is that memory.`;
7965
7979
  }
7966
7980
  });
7967
7981
 
@@ -8963,7 +8977,7 @@ var CompletionsStrategy = class {
8963
8977
  model,
8964
8978
  stream,
8965
8979
  ...temperature !== void 0 && { temperature },
8966
- ...maxOutputTokens !== void 0 && { max_tokens: maxOutputTokens },
8980
+ ...maxOutputTokens !== void 0 && { max_completion_tokens: maxOutputTokens },
8967
8981
  ...tools && { tools },
8968
8982
  ...toolChoice && { tool_choice: toolChoice },
8969
8983
  ...portal && { portal }
@@ -15291,14 +15305,15 @@ init_portalLlm();
15291
15305
 
15292
15306
  // src/lib/memory/retain.ts
15293
15307
  init_operations3();
15308
+ init_logger();
15294
15309
  init_constants();
15295
15310
  init_embeddings();
15296
15311
  init_vector();
15297
15312
  init_searchTool();
15298
- var DEFAULT_AUTO_MERGE_THRESHOLD = 0.85;
15313
+ var DEFAULT_AUTO_MERGE_THRESHOLD = 0.8;
15299
15314
  var DEFAULT_SCOPE = "private";
15300
- var DEFAULT_CONSOLIDATE_THRESHOLD = 0.65;
15301
- var DEFAULT_CONSOLIDATE_TOP_K = 5;
15315
+ var DEFAULT_CONSOLIDATE_THRESHOLD = 0.55;
15316
+ var DEFAULT_CONSOLIDATE_TOP_K = 20;
15302
15317
  async function retain(content, ctx, options = {}) {
15303
15318
  const trimmed = content.trim();
15304
15319
  if (trimmed.length === 0) {
@@ -15307,18 +15322,18 @@ async function retain(content, ctx, options = {}) {
15307
15322
  const enableAutoMerge = options.enableAutoMerge ?? true;
15308
15323
  const threshold = options.autoMergeThreshold ?? DEFAULT_AUTO_MERGE_THRESHOLD;
15309
15324
  const resolvedScope = options.scope ?? DEFAULT_SCOPE;
15310
- let supersedeTargetId;
15325
+ let supersedeTargetIds = [];
15311
15326
  let supersedeContent;
15312
15327
  if (enableAutoMerge) {
15313
15328
  if (options.consolidateOptions) {
15314
15329
  const outcome = await tryConsolidate(trimmed, ctx, options);
15315
15330
  if (outcome) {
15316
15331
  if ("done" in outcome) return outcome.done;
15317
- supersedeTargetId = outcome.supersede;
15332
+ supersedeTargetIds = outcome.supersede;
15318
15333
  supersedeContent = outcome.content;
15319
15334
  }
15320
15335
  }
15321
- if (!supersedeTargetId) {
15336
+ if (supersedeTargetIds.length === 0) {
15322
15337
  const matches = await searchVaultMemories(
15323
15338
  trimmed,
15324
15339
  ctx.vaultCtx,
@@ -15422,18 +15437,42 @@ async function retain(content, ctx, options = {}) {
15422
15437
  // memory's tier. The DB op re-validates against the known set.
15423
15438
  ...options.trustTier !== void 0 && { trustTier: options.trustTier }
15424
15439
  };
15425
- if (supersedeTargetId) {
15440
+ if (supersedeTargetIds.length > 0) {
15441
+ const [primaryTargetId, ...restTargetIds] = supersedeTargetIds;
15426
15442
  const { created: created2, retired } = await createSupersedingMemoryOp(
15427
15443
  ctx.vaultCtx,
15428
15444
  createOpts,
15429
- supersedeTargetId
15445
+ primaryTargetId
15430
15446
  );
15431
15447
  if (created2 && retired) {
15432
15448
  ctx.vaultCache.set(created2.uniqueId, Float32Array.from(embedding));
15449
+ const liveLeftovers = [];
15450
+ for (const staleId of restTargetIds) {
15451
+ let ok = false;
15452
+ try {
15453
+ ok = await supersedeVaultMemoryOp(ctx.vaultCtx, staleId, created2.uniqueId) === true;
15454
+ } catch {
15455
+ }
15456
+ if (ok) continue;
15457
+ const stillLive = await getVaultMemoryOp(ctx.vaultCtx, staleId).catch(() => null);
15458
+ if (stillLive && !stillLive.supersededBy) liveLeftovers.push(staleId);
15459
+ }
15460
+ if (liveLeftovers.length > 0) {
15461
+ getLogger().warn(
15462
+ "[memory/retain] supersede left duplicate row(s) live \u2014 will reconcile at next consolidation",
15463
+ {
15464
+ newMemoryId: created2.uniqueId,
15465
+ leftover: liveLeftovers.length,
15466
+ // Log the specific ids (opaque record ids, not content) so an
15467
+ // operator can identify exactly which rows are still active.
15468
+ leftoverIds: liveLeftovers
15469
+ }
15470
+ );
15471
+ }
15433
15472
  return {
15434
15473
  action: "supersede",
15435
15474
  memoryId: created2.uniqueId,
15436
- targetId: supersedeTargetId,
15475
+ targetId: primaryTargetId,
15437
15476
  proofCount: 1
15438
15477
  };
15439
15478
  }
@@ -15519,10 +15558,16 @@ async function tryConsolidate(trimmed, ctx, options) {
15519
15558
  const { consolidateMemory: doConsolidate } = await Promise.resolve().then(() => (init_consolidate(), consolidate_exports));
15520
15559
  const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
15521
15560
  if (decision.action === "create") return null;
15522
- if (decision.action === "supersede" && decision.targetId && decision.content) {
15523
- const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
15524
- if (!existing || existing.supersededBy) return null;
15525
- return { supersede: decision.targetId, content: decision.content };
15561
+ if (decision.action === "supersede" && decision.content) {
15562
+ const requestedIds = decision.targetIds?.length ? decision.targetIds : decision.targetId ? [decision.targetId] : [];
15563
+ if (requestedIds.length === 0) return null;
15564
+ const valid = [];
15565
+ for (const id of requestedIds) {
15566
+ const existing = await getVaultMemoryOp(ctx.vaultCtx, id);
15567
+ if (existing && !existing.supersededBy) valid.push(id);
15568
+ }
15569
+ if (valid.length === 0) return null;
15570
+ return { supersede: valid, content: decision.content };
15526
15571
  }
15527
15572
  if (decision.action === "noop" && decision.targetId) {
15528
15573
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
@@ -16817,7 +16862,10 @@ ${evidence}`;
16817
16862
  headers: { ...authHeaders, "Content-Type": "application/json" },
16818
16863
  body: JSON.stringify({
16819
16864
  model,
16820
- max_tokens: maxTokens,
16865
+ // Modern OpenAI field; the portal reads only `max_completion_tokens`
16866
+ // (the deprecated `max_tokens` is silently ignored → falls back to the
16867
+ // portal's default output cap and truncates the answer).
16868
+ max_completion_tokens: maxTokens,
16821
16869
  messages: [
16822
16870
  { role: "system", content: systemPrompt },
16823
16871
  { role: "user", content: userMessage }
@@ -920,6 +920,12 @@ type HandlersCreditBalanceResponse = {
920
920
  * Total credits ever received (1 credit = $0.01)
921
921
  */
922
922
  lifetime_credits: number;
923
+ /**
924
+ * NextResetDate is the next monthly credit refill date (ISO8601), keyed on the
925
+ * credit_expiry_day anchor — the same anchor the monthly claim uses, NOT the grant
926
+ * expires_at (which is anchor+1). Display-only; does not affect reset logic.
927
+ */
928
+ next_reset_date?: string;
923
929
  /**
924
930
  * "basic" or "pro"
925
931
  */
@@ -920,6 +920,12 @@ type HandlersCreditBalanceResponse = {
920
920
  * Total credits ever received (1 credit = $0.01)
921
921
  */
922
922
  lifetime_credits: number;
923
+ /**
924
+ * NextResetDate is the next monthly credit refill date (ISO8601), keyed on the
925
+ * credit_expiry_day anchor — the same anchor the monthly claim uses, NOT the grant
926
+ * expires_at (which is anchor+1). Display-only; does not affect reset logic.
927
+ */
928
+ next_reset_date?: string;
923
929
  /**
924
930
  * "basic" or "pro"
925
931
  */
@@ -149,7 +149,7 @@ import {
149
149
  updateVaultMemoryOp,
150
150
  useEncryption,
151
151
  vaultMemoryToStored
152
- } from "./chunk-3VPEZDYL.mjs";
152
+ } from "./chunk-3LUACMDC.mjs";
153
153
  import {
154
154
  PiiRedactor,
155
155
  createStreamingDeAnonymizer,
@@ -720,7 +720,7 @@ var CompletionsStrategy = class {
720
720
  model,
721
721
  stream,
722
722
  ...temperature !== void 0 && { temperature },
723
- ...maxOutputTokens !== void 0 && { max_tokens: maxOutputTokens },
723
+ ...maxOutputTokens !== void 0 && { max_completion_tokens: maxOutputTokens },
724
724
  ...tools && { tools },
725
725
  ...toolChoice && { tool_choice: toolChoice },
726
726
  ...portal && { portal }
@@ -7007,10 +7007,10 @@ function injectionSignatureCatalog() {
7007
7007
  }
7008
7008
 
7009
7009
  // src/lib/memory/retain.ts
7010
- var DEFAULT_AUTO_MERGE_THRESHOLD = 0.85;
7010
+ var DEFAULT_AUTO_MERGE_THRESHOLD = 0.8;
7011
7011
  var DEFAULT_SCOPE = "private";
7012
- var DEFAULT_CONSOLIDATE_THRESHOLD = 0.65;
7013
- var DEFAULT_CONSOLIDATE_TOP_K = 5;
7012
+ var DEFAULT_CONSOLIDATE_THRESHOLD = 0.55;
7013
+ var DEFAULT_CONSOLIDATE_TOP_K = 20;
7014
7014
  async function retain(content, ctx, options = {}) {
7015
7015
  const trimmed = content.trim();
7016
7016
  if (trimmed.length === 0) {
@@ -7019,18 +7019,18 @@ async function retain(content, ctx, options = {}) {
7019
7019
  const enableAutoMerge = options.enableAutoMerge ?? true;
7020
7020
  const threshold = options.autoMergeThreshold ?? DEFAULT_AUTO_MERGE_THRESHOLD;
7021
7021
  const resolvedScope = options.scope ?? DEFAULT_SCOPE;
7022
- let supersedeTargetId;
7022
+ let supersedeTargetIds = [];
7023
7023
  let supersedeContent;
7024
7024
  if (enableAutoMerge) {
7025
7025
  if (options.consolidateOptions) {
7026
7026
  const outcome = await tryConsolidate(trimmed, ctx, options);
7027
7027
  if (outcome) {
7028
7028
  if ("done" in outcome) return outcome.done;
7029
- supersedeTargetId = outcome.supersede;
7029
+ supersedeTargetIds = outcome.supersede;
7030
7030
  supersedeContent = outcome.content;
7031
7031
  }
7032
7032
  }
7033
- if (!supersedeTargetId) {
7033
+ if (supersedeTargetIds.length === 0) {
7034
7034
  const matches = await searchVaultMemories(
7035
7035
  trimmed,
7036
7036
  ctx.vaultCtx,
@@ -7134,18 +7134,42 @@ async function retain(content, ctx, options = {}) {
7134
7134
  // memory's tier. The DB op re-validates against the known set.
7135
7135
  ...options.trustTier !== void 0 && { trustTier: options.trustTier }
7136
7136
  };
7137
- if (supersedeTargetId) {
7137
+ if (supersedeTargetIds.length > 0) {
7138
+ const [primaryTargetId, ...restTargetIds] = supersedeTargetIds;
7138
7139
  const { created: created2, retired } = await createSupersedingMemoryOp(
7139
7140
  ctx.vaultCtx,
7140
7141
  createOpts,
7141
- supersedeTargetId
7142
+ primaryTargetId
7142
7143
  );
7143
7144
  if (created2 && retired) {
7144
7145
  ctx.vaultCache.set(created2.uniqueId, Float32Array.from(embedding));
7146
+ const liveLeftovers = [];
7147
+ for (const staleId of restTargetIds) {
7148
+ let ok = false;
7149
+ try {
7150
+ ok = await supersedeVaultMemoryOp(ctx.vaultCtx, staleId, created2.uniqueId) === true;
7151
+ } catch {
7152
+ }
7153
+ if (ok) continue;
7154
+ const stillLive = await getVaultMemoryOp(ctx.vaultCtx, staleId).catch(() => null);
7155
+ if (stillLive && !stillLive.supersededBy) liveLeftovers.push(staleId);
7156
+ }
7157
+ if (liveLeftovers.length > 0) {
7158
+ getLogger().warn(
7159
+ "[memory/retain] supersede left duplicate row(s) live \u2014 will reconcile at next consolidation",
7160
+ {
7161
+ newMemoryId: created2.uniqueId,
7162
+ leftover: liveLeftovers.length,
7163
+ // Log the specific ids (opaque record ids, not content) so an
7164
+ // operator can identify exactly which rows are still active.
7165
+ leftoverIds: liveLeftovers
7166
+ }
7167
+ );
7168
+ }
7145
7169
  return {
7146
7170
  action: "supersede",
7147
7171
  memoryId: created2.uniqueId,
7148
- targetId: supersedeTargetId,
7172
+ targetId: primaryTargetId,
7149
7173
  proofCount: 1
7150
7174
  };
7151
7175
  }
@@ -7228,13 +7252,19 @@ async function tryConsolidate(trimmed, ctx, options) {
7228
7252
  content: m.content,
7229
7253
  similarity: m.similarity
7230
7254
  }));
7231
- const { consolidateMemory: doConsolidate } = await import("./consolidate-PWJCAPZA.mjs");
7255
+ const { consolidateMemory: doConsolidate } = await import("./consolidate-7UUX56GM.mjs");
7232
7256
  const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
7233
7257
  if (decision.action === "create") return null;
7234
- if (decision.action === "supersede" && decision.targetId && decision.content) {
7235
- const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
7236
- if (!existing || existing.supersededBy) return null;
7237
- return { supersede: decision.targetId, content: decision.content };
7258
+ if (decision.action === "supersede" && decision.content) {
7259
+ const requestedIds = decision.targetIds?.length ? decision.targetIds : decision.targetId ? [decision.targetId] : [];
7260
+ if (requestedIds.length === 0) return null;
7261
+ const valid = [];
7262
+ for (const id of requestedIds) {
7263
+ const existing = await getVaultMemoryOp(ctx.vaultCtx, id);
7264
+ if (existing && !existing.supersededBy) valid.push(id);
7265
+ }
7266
+ if (valid.length === 0) return null;
7267
+ return { supersede: valid, content: decision.content };
7238
7268
  }
7239
7269
  if (decision.action === "noop" && decision.targetId) {
7240
7270
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
@@ -8505,7 +8535,10 @@ ${evidence}`;
8505
8535
  headers: { ...authHeaders, "Content-Type": "application/json" },
8506
8536
  body: JSON.stringify({
8507
8537
  model,
8508
- max_tokens: maxTokens,
8538
+ // Modern OpenAI field; the portal reads only `max_completion_tokens`
8539
+ // (the deprecated `max_tokens` is silently ignored → falls back to the
8540
+ // portal's default output cap and truncates the answer).
8541
+ max_completion_tokens: maxTokens,
8509
8542
  messages: [
8510
8543
  { role: "system", content: systemPrompt },
8511
8544
  { role: "user", content: userMessage }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  recall
3
- } from "./chunk-3VPEZDYL.mjs";
3
+ } from "./chunk-3LUACMDC.mjs";
4
4
  import "./chunk-BOY27A2C.mjs";
5
5
  import "./chunk-GYKJOWEO.mjs";
6
6
  export {
@@ -19,7 +19,7 @@ Decide one of four actions:
19
19
 
20
20
  - "create": the new memory describes a distinct fact not covered by any existing memory. Write it as new.
21
21
  - "update": the new memory describes the SAME FACET as exactly one existing memory and is COMPATIBLE with it \u2014 it adds detail, fixes an incomplete value, or rephrases the same still-true fact. Return targetId of that existing memory + the consolidated content (richest version of the two).
22
- - "supersede": the new memory REPLACES a standing fact whose value has CHANGED and is now INCOMPATIBLE with an existing memory \u2014 the old fact was true before but is false now (a state change). Return targetId of the STALE existing memory to retire + content = the NEW fact. The old memory is kept as history, not overwritten or deleted; do not re-state it.
22
+ - "supersede": the new memory REPLACES a standing fact whose value has CHANGED and is now INCOMPATIBLE with an existing memory \u2014 the old fact was true before but is false now (a state change). Return "targetIds": an array of the ids of EVERY existing candidate that describes the SAME standing attribute now being changed \u2014 retire ALL stale duplicates of the old value, not just one (the candidate list may contain several paraphrases of the same old fact) + content = the NEW fact. The old memories are kept as history, not overwritten or deleted; do not re-state them.
23
23
  - "noop": the new memory is already fully captured by an existing memory \u2014 same facet, no new information. Skip the write.
24
24
 
25
25
  RULES (carry these strictly):
@@ -35,14 +35,15 @@ RULES (carry these strictly):
35
35
  OUTPUT \u2014 strict JSON, no prose:
36
36
  {
37
37
  "action": "create" | "update" | "supersede" | "noop",
38
- "targetId": "<existing memory id \u2014 required for update/supersede/noop, omit for create>",
38
+ "targetId": "<existing memory id \u2014 required for update/noop, omit for create/supersede>",
39
+ "targetIds": ["<id>", ...],
39
40
  "content": "<content \u2014 required for create/update/supersede, omit for noop>"
40
41
  }
41
42
 
42
- For "create": content is the new memory verbatim (or a slight refinement).
43
- For "update": content is the merged richest-version, \u226480 words.
44
- For "supersede": content is the NEW fact only (\u226480 words); targetId is the stale memory being retired.
45
- For "noop": no content (existing memory is already correct).`;
43
+ For "create": content is the new memory verbatim (or a slight refinement); omit targetId/targetIds.
44
+ For "update": content is the merged richest-version, \u226480 words; targetId is the single memory to update.
45
+ For "supersede": content is the NEW fact only (\u226480 words); "targetIds" lists EVERY stale memory being retired (all candidates describing the same now-changed attribute).
46
+ For "noop": no content (existing memory is already correct); targetId is that memory.`;
46
47
  async function consolidateMemory(newContent, candidates, options) {
47
48
  const fallback = {
48
49
  action: "create",
@@ -123,14 +124,27 @@ function validate(parsed, newContent, validIds) {
123
124
  const c2 = typeof obj.content === "string" ? obj.content.trim() : "";
124
125
  return { action: "create", content: c2.length > 0 ? c2 : newContent };
125
126
  }
126
- const targetId = typeof obj.targetId === "string" ? obj.targetId : null;
127
- if (!targetId || !validIds.has(targetId)) return null;
128
127
  if (action === "noop") {
129
- return { action: "noop", targetId };
128
+ const targetId2 = typeof obj.targetId === "string" ? obj.targetId : null;
129
+ if (!targetId2 || !validIds.has(targetId2)) return null;
130
+ return { action: "noop", targetId: targetId2 };
130
131
  }
131
132
  const c = typeof obj.content === "string" ? obj.content.trim() : "";
132
133
  if (c.length === 0) return null;
133
- return { action, targetId, content: c };
134
+ if (action === "supersede") {
135
+ const rawIds = [
136
+ ...Array.isArray(obj.targetIds) ? obj.targetIds : [],
137
+ ...typeof obj.targetId === "string" ? [obj.targetId] : []
138
+ ];
139
+ const targetIds = [
140
+ ...new Set(rawIds.filter((id) => typeof id === "string" && validIds.has(id)))
141
+ ];
142
+ if (targetIds.length === 0) return null;
143
+ return { action: "supersede", targetId: targetIds[0], targetIds, content: c };
144
+ }
145
+ const targetId = typeof obj.targetId === "string" ? obj.targetId : null;
146
+ if (!targetId || !validIds.has(targetId)) return null;
147
+ return { action: "update", targetId, content: c };
134
148
  }
135
149
  export {
136
150
  consolidateMemory
@@ -22458,14 +22458,27 @@ function validate2(parsed, newContent, validIds) {
22458
22458
  const c2 = typeof obj.content === "string" ? obj.content.trim() : "";
22459
22459
  return { action: "create", content: c2.length > 0 ? c2 : newContent };
22460
22460
  }
22461
- const targetId = typeof obj.targetId === "string" ? obj.targetId : null;
22462
- if (!targetId || !validIds.has(targetId)) return null;
22463
22461
  if (action === "noop") {
22464
- return { action: "noop", targetId };
22462
+ const targetId2 = typeof obj.targetId === "string" ? obj.targetId : null;
22463
+ if (!targetId2 || !validIds.has(targetId2)) return null;
22464
+ return { action: "noop", targetId: targetId2 };
22465
22465
  }
22466
22466
  const c = typeof obj.content === "string" ? obj.content.trim() : "";
22467
22467
  if (c.length === 0) return null;
22468
- return { action, targetId, content: c };
22468
+ if (action === "supersede") {
22469
+ const rawIds = [
22470
+ ...Array.isArray(obj.targetIds) ? obj.targetIds : [],
22471
+ ...typeof obj.targetId === "string" ? [obj.targetId] : []
22472
+ ];
22473
+ const targetIds = [
22474
+ ...new Set(rawIds.filter((id) => typeof id === "string" && validIds.has(id)))
22475
+ ];
22476
+ if (targetIds.length === 0) return null;
22477
+ return { action: "supersede", targetId: targetIds[0], targetIds, content: c };
22478
+ }
22479
+ const targetId = typeof obj.targetId === "string" ? obj.targetId : null;
22480
+ if (!targetId || !validIds.has(targetId)) return null;
22481
+ return { action: "update", targetId, content: c };
22469
22482
  }
22470
22483
  var DEFAULT_MODEL3, DEFAULT_CONSOLIDATE_ATTEMPTS, DEFAULT_CONSOLIDATE_TOTAL_TIMEOUT_MS, SYSTEM_PROMPT3;
22471
22484
  var init_consolidate = __esm({
@@ -22485,7 +22498,7 @@ Decide one of four actions:
22485
22498
 
22486
22499
  - "create": the new memory describes a distinct fact not covered by any existing memory. Write it as new.
22487
22500
  - "update": the new memory describes the SAME FACET as exactly one existing memory and is COMPATIBLE with it \u2014 it adds detail, fixes an incomplete value, or rephrases the same still-true fact. Return targetId of that existing memory + the consolidated content (richest version of the two).
22488
- - "supersede": the new memory REPLACES a standing fact whose value has CHANGED and is now INCOMPATIBLE with an existing memory \u2014 the old fact was true before but is false now (a state change). Return targetId of the STALE existing memory to retire + content = the NEW fact. The old memory is kept as history, not overwritten or deleted; do not re-state it.
22501
+ - "supersede": the new memory REPLACES a standing fact whose value has CHANGED and is now INCOMPATIBLE with an existing memory \u2014 the old fact was true before but is false now (a state change). Return "targetIds": an array of the ids of EVERY existing candidate that describes the SAME standing attribute now being changed \u2014 retire ALL stale duplicates of the old value, not just one (the candidate list may contain several paraphrases of the same old fact) + content = the NEW fact. The old memories are kept as history, not overwritten or deleted; do not re-state them.
22489
22502
  - "noop": the new memory is already fully captured by an existing memory \u2014 same facet, no new information. Skip the write.
22490
22503
 
22491
22504
  RULES (carry these strictly):
@@ -22501,14 +22514,15 @@ RULES (carry these strictly):
22501
22514
  OUTPUT \u2014 strict JSON, no prose:
22502
22515
  {
22503
22516
  "action": "create" | "update" | "supersede" | "noop",
22504
- "targetId": "<existing memory id \u2014 required for update/supersede/noop, omit for create>",
22517
+ "targetId": "<existing memory id \u2014 required for update/noop, omit for create/supersede>",
22518
+ "targetIds": ["<id>", ...],
22505
22519
  "content": "<content \u2014 required for create/update/supersede, omit for noop>"
22506
22520
  }
22507
22521
 
22508
- For "create": content is the new memory verbatim (or a slight refinement).
22509
- For "update": content is the merged richest-version, \u226480 words.
22510
- For "supersede": content is the NEW fact only (\u226480 words); targetId is the stale memory being retired.
22511
- For "noop": no content (existing memory is already correct).`;
22522
+ For "create": content is the new memory verbatim (or a slight refinement); omit targetId/targetIds.
22523
+ For "update": content is the merged richest-version, \u226480 words; targetId is the single memory to update.
22524
+ For "supersede": content is the NEW fact only (\u226480 words); "targetIds" lists EVERY stale memory being retired (all candidates describing the same now-changed attribute).
22525
+ For "noop": no content (existing memory is already correct); targetId is that memory.`;
22512
22526
  }
22513
22527
  });
22514
22528
 
@@ -27157,14 +27171,15 @@ init_portalLlm();
27157
27171
 
27158
27172
  // src/lib/memory/retain.ts
27159
27173
  init_operations3();
27174
+ init_logger();
27160
27175
  init_constants();
27161
27176
  init_embeddings();
27162
27177
  init_vector();
27163
27178
  init_searchTool();
27164
- var DEFAULT_AUTO_MERGE_THRESHOLD = 0.85;
27179
+ var DEFAULT_AUTO_MERGE_THRESHOLD = 0.8;
27165
27180
  var DEFAULT_SCOPE = "private";
27166
- var DEFAULT_CONSOLIDATE_THRESHOLD = 0.65;
27167
- var DEFAULT_CONSOLIDATE_TOP_K = 5;
27181
+ var DEFAULT_CONSOLIDATE_THRESHOLD = 0.55;
27182
+ var DEFAULT_CONSOLIDATE_TOP_K = 20;
27168
27183
  async function retain(content, ctx, options = {}) {
27169
27184
  const trimmed = content.trim();
27170
27185
  if (trimmed.length === 0) {
@@ -27173,18 +27188,18 @@ async function retain(content, ctx, options = {}) {
27173
27188
  const enableAutoMerge = options.enableAutoMerge ?? true;
27174
27189
  const threshold = options.autoMergeThreshold ?? DEFAULT_AUTO_MERGE_THRESHOLD;
27175
27190
  const resolvedScope = options.scope ?? DEFAULT_SCOPE;
27176
- let supersedeTargetId;
27191
+ let supersedeTargetIds = [];
27177
27192
  let supersedeContent;
27178
27193
  if (enableAutoMerge) {
27179
27194
  if (options.consolidateOptions) {
27180
27195
  const outcome = await tryConsolidate(trimmed, ctx, options);
27181
27196
  if (outcome) {
27182
27197
  if ("done" in outcome) return outcome.done;
27183
- supersedeTargetId = outcome.supersede;
27198
+ supersedeTargetIds = outcome.supersede;
27184
27199
  supersedeContent = outcome.content;
27185
27200
  }
27186
27201
  }
27187
- if (!supersedeTargetId) {
27202
+ if (supersedeTargetIds.length === 0) {
27188
27203
  const matches = await searchVaultMemories(
27189
27204
  trimmed,
27190
27205
  ctx.vaultCtx,
@@ -27288,18 +27303,42 @@ async function retain(content, ctx, options = {}) {
27288
27303
  // memory's tier. The DB op re-validates against the known set.
27289
27304
  ...options.trustTier !== void 0 && { trustTier: options.trustTier }
27290
27305
  };
27291
- if (supersedeTargetId) {
27306
+ if (supersedeTargetIds.length > 0) {
27307
+ const [primaryTargetId, ...restTargetIds] = supersedeTargetIds;
27292
27308
  const { created: created2, retired } = await createSupersedingMemoryOp(
27293
27309
  ctx.vaultCtx,
27294
27310
  createOpts,
27295
- supersedeTargetId
27311
+ primaryTargetId
27296
27312
  );
27297
27313
  if (created2 && retired) {
27298
27314
  ctx.vaultCache.set(created2.uniqueId, Float32Array.from(embedding));
27315
+ const liveLeftovers = [];
27316
+ for (const staleId of restTargetIds) {
27317
+ let ok = false;
27318
+ try {
27319
+ ok = await supersedeVaultMemoryOp(ctx.vaultCtx, staleId, created2.uniqueId) === true;
27320
+ } catch {
27321
+ }
27322
+ if (ok) continue;
27323
+ const stillLive = await getVaultMemoryOp(ctx.vaultCtx, staleId).catch(() => null);
27324
+ if (stillLive && !stillLive.supersededBy) liveLeftovers.push(staleId);
27325
+ }
27326
+ if (liveLeftovers.length > 0) {
27327
+ getLogger().warn(
27328
+ "[memory/retain] supersede left duplicate row(s) live \u2014 will reconcile at next consolidation",
27329
+ {
27330
+ newMemoryId: created2.uniqueId,
27331
+ leftover: liveLeftovers.length,
27332
+ // Log the specific ids (opaque record ids, not content) so an
27333
+ // operator can identify exactly which rows are still active.
27334
+ leftoverIds: liveLeftovers
27335
+ }
27336
+ );
27337
+ }
27299
27338
  return {
27300
27339
  action: "supersede",
27301
27340
  memoryId: created2.uniqueId,
27302
- targetId: supersedeTargetId,
27341
+ targetId: primaryTargetId,
27303
27342
  proofCount: 1
27304
27343
  };
27305
27344
  }
@@ -27385,10 +27424,16 @@ async function tryConsolidate(trimmed, ctx, options) {
27385
27424
  const { consolidateMemory: doConsolidate } = await Promise.resolve().then(() => (init_consolidate(), consolidate_exports));
27386
27425
  const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
27387
27426
  if (decision.action === "create") return null;
27388
- if (decision.action === "supersede" && decision.targetId && decision.content) {
27389
- const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
27390
- if (!existing || existing.supersededBy) return null;
27391
- return { supersede: decision.targetId, content: decision.content };
27427
+ if (decision.action === "supersede" && decision.content) {
27428
+ const requestedIds = decision.targetIds?.length ? decision.targetIds : decision.targetId ? [decision.targetId] : [];
27429
+ if (requestedIds.length === 0) return null;
27430
+ const valid = [];
27431
+ for (const id of requestedIds) {
27432
+ const existing = await getVaultMemoryOp(ctx.vaultCtx, id);
27433
+ if (existing && !existing.supersededBy) valid.push(id);
27434
+ }
27435
+ if (valid.length === 0) return null;
27436
+ return { supersede: valid, content: decision.content };
27392
27437
  }
27393
27438
  if (decision.action === "noop" && decision.targetId) {
27394
27439
  const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
@@ -28683,7 +28728,10 @@ ${evidence}`;
28683
28728
  headers: { ...authHeaders, "Content-Type": "application/json" },
28684
28729
  body: JSON.stringify({
28685
28730
  model,
28686
- max_tokens: maxTokens,
28731
+ // Modern OpenAI field; the portal reads only `max_completion_tokens`
28732
+ // (the deprecated `max_tokens` is silently ignored → falls back to the
28733
+ // portal's default output cap and truncates the answer).
28734
+ max_completion_tokens: maxTokens,
28687
28735
  messages: [
28688
28736
  { role: "system", content: systemPrompt },
28689
28737
  { role: "user", content: userMessage }
@@ -31842,7 +31890,7 @@ var CompletionsStrategy = class {
31842
31890
  model,
31843
31891
  stream,
31844
31892
  ...temperature !== void 0 && { temperature },
31845
- ...maxOutputTokens !== void 0 && { max_tokens: maxOutputTokens },
31893
+ ...maxOutputTokens !== void 0 && { max_completion_tokens: maxOutputTokens },
31846
31894
  ...tools && { tools },
31847
31895
  ...toolChoice && { tool_choice: toolChoice },
31848
31896
  ...portal && { portal }