@anuma/sdk 7.3.1 → 7.3.3

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.
@@ -807,6 +807,13 @@ function splitEndpoint(endpoint) {
807
807
  rest: cut === -1 ? "" : endpoint.slice(cut)
808
808
  };
809
809
  }
810
+ function endpointForTransport(endpoint, transport) {
811
+ const { path, rest } = splitEndpoint(endpoint);
812
+ const foreign = FOREIGN_ENDPOINT_SUFFIX[transport];
813
+ if (!path.endsWith(foreign)) return endpoint;
814
+ const own = FOREIGN_ENDPOINT_SUFFIX[transport === "chat" ? "responses" : "chat"];
815
+ return `${path.slice(0, -foreign.length)}${own}${rest}`;
816
+ }
810
817
  function assertTransportMatchesEndpoint(transport, endpoint) {
811
818
  const foreign = FOREIGN_ENDPOINT_SUFFIX[transport];
812
819
  if (!splitEndpoint(endpoint).path.endsWith(foreign)) return;
@@ -863,10 +870,7 @@ async function callPortalJsonCompletion(req) {
863
870
  throw new Error(overrideValidation.message);
864
871
  }
865
872
  endpoint = overrideValidation.endpoint;
866
- const { path, rest } = splitEndpoint(endpoint);
867
- if (autoUpgraded && path.endsWith("/chat/completions")) {
868
- endpoint = `${path.slice(0, -"/chat/completions".length)}/responses${rest}`;
869
- }
873
+ if (autoUpgraded) endpoint = endpointForTransport(endpoint, transport);
870
874
  assertTransportMatchesEndpoint(transport, endpoint);
871
875
  }
872
876
  const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
@@ -1212,14 +1216,23 @@ async function consolidateMemory(newContent, candidates, options) {
1212
1216
 
1213
1217
  Existing memories (top ${candidates.length} by cosine):
1214
1218
  ${candidateText}`;
1219
+ const model = options.model ?? DEFAULT_CONSOLIDATION_MODEL;
1220
+ const viaResponses = requiresResponsesTransport(model);
1221
+ const endpointOverride = options.endpointOverride === void 0 ? void 0 : endpointForTransport(options.endpointOverride, viaResponses ? "responses" : "chat");
1215
1222
  let parsed;
1223
+ let failure;
1216
1224
  try {
1217
1225
  parsed = await callPortalJsonCompletion({
1226
+ onFailure: (f) => {
1227
+ failure = f;
1228
+ },
1218
1229
  ...options.apiKey !== void 0 && { apiKey: options.apiKey },
1219
1230
  ...options.getToken !== void 0 && { getToken: options.getToken },
1220
1231
  ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
1232
+ ...endpointOverride !== void 0 && { endpointOverride },
1221
1233
  taskType: "memory_consolidate",
1222
- model: options.model ?? DEFAULT_CONSOLIDATION_MODEL,
1234
+ model,
1235
+ ...viaResponses ? { transport: "responses", reasoning: { effort: "low" } } : { transport: "chat" },
1223
1236
  systemPrompt: SYSTEM_PROMPT3,
1224
1237
  userMessage,
1225
1238
  tag: "memory/consolidate",
@@ -1231,7 +1244,7 @@ ${candidateText}`;
1231
1244
  } catch (err) {
1232
1245
  return degrade("llm_error", fallback, options, err);
1233
1246
  }
1234
- if (parsed === null) return degrade("llm_error", fallback, options);
1247
+ if (parsed === null) return degrade(fallbackReasonFor(failure), fallback, options, failure);
1235
1248
  const validIds = new Set(candidates.map((c) => c.id));
1236
1249
  const result = validate2(parsed, trimmed, validIds);
1237
1250
  if (!result) return degrade("invalid_response", fallback, options);
@@ -1244,6 +1257,11 @@ ${candidateText}`;
1244
1257
  }
1245
1258
  return reportRefusal(result, options);
1246
1259
  }
1260
+ function fallbackReasonFor(failure) {
1261
+ if (failure?.reason === "time-budget-exhausted") return "llm_timeout";
1262
+ if (failure?.reason === "content-flagged") return "content_flagged";
1263
+ return "llm_error";
1264
+ }
1247
1265
  function reportRefusal(result, options) {
1248
1266
  if (result.fallbackReason) {
1249
1267
  notifyConsolidationFallback(result.fallbackReason, options.onFallback);
@@ -1317,7 +1335,7 @@ var init_consolidate = __esm({
1317
1335
  init_redactor();
1318
1336
  init_consolidationFallback();
1319
1337
  init_portalLlm();
1320
- DEFAULT_CONSOLIDATION_MODEL = "inclusionai/ling-2.6-flash";
1338
+ DEFAULT_CONSOLIDATION_MODEL = "openai/gpt-6-luna";
1321
1339
  DEFAULT_CONSOLIDATE_ATTEMPTS = 3;
1322
1340
  DEFAULT_CONSOLIDATE_TOTAL_TIMEOUT_MS = 2e4;
1323
1341
  SYSTEM_PROMPT3 = `You consolidate a new memory against existing memories from the same user.
@@ -1357,7 +1375,11 @@ OUTPUT \u2014 strict JSON, no prose:
1357
1375
  For "create": content is the new memory verbatim (or a slight refinement); omit targetId/targetIds.
1358
1376
  For "update": content is the merged richest-version, \u226480 words; targetId is the single memory to update.
1359
1377
  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). You MUST also name the subjects: "newSubject" for the new memory, and one entry in "targetSubjects" for EACH memory you are retiring (use "targetSubject" as well when you retire a single memory). List a subject ONLY for the memories you are actually retiring, not for every candidate you were shown. Write the plain subject, not a sentence: "the user", "the user's sister", "the user's manager", "Biscuit the dog". Rule 1a means a supersede is only valid when every one of those subjects is the SAME as "newSubject"; name them and check them against each other before you commit to the action. If ANY of them differs, the answer is "create" \u2014 do not retire the ones that match and keep the rest, because a group that mixes subjects was grouped wrongly in the first place. A subjectless fact ("Lives in Denver", "Works at Riverbend") is about "the user" \u2014 the extractor omits the subject when it is the user, so treat the absence of a subject as the user, never as unknown.
1360
- For "noop": no content (existing memory is already correct); targetId is that memory.`;
1378
+ For "noop": no content (existing memory is already correct); targetId is that memory.
1379
+
1380
+ ADDING TO AN INTRODUCED ENTITY (check this before choosing "create"): when an existing memory only introduces or names someone or something in the user's life ("User has a cat named Mochi", "User's sister is called Ana") and the new memory gives an attribute of that SAME entity that the existing memory does not state yet (its age, breed, job, home city), choose "update": targetId is that memory and content folds both into one sentence ("User has a cat named Mochi, who is four years old."). The "dog's name vs dog's age" example above means two memories that each already state a different attribute stay separate; a memory that only introduces the entity absorbs the next attribute about it. If the existing memory already states a value and the new memory changes it, that is "supersede" (rule 4), not this.
1381
+
1382
+ CARRY FORWARD UNCHANGED DETAILS (every "update" and "supersede"): a memory can hold several details at once, such as one folded from an introduction and an attribute ("User's sister Ana lives in Paris"). content replaces ONLY the value that changed and keeps every other detail of the memory it replaces, the subject's relation to the user and name above all: "Ana lives in London" against "User's sister Ana lives in Paris" is "supersede" with content "User's sister Ana lives in London", never just "Ana lives in London". Name the subject the same way on both sides: here "newSubject" and "targetSubjects" are both "the user's sister Ana".`;
1361
1383
  USER_SUBJECT_ALIASES = /* @__PURE__ */ new Set(["user", "themselves", "themself", "they", "me", "self"]);
1362
1384
  }
1363
1385
  });
@@ -1837,7 +1859,7 @@ function onKeyAvailable(address, callback) {
1837
1859
  callbacks.add(callback);
1838
1860
  return () => {
1839
1861
  callbacks.delete(callback);
1840
- if (callbacks.size === 0) {
1862
+ if (callbacks.size === 0 && keyAvailableCallbacks.get(address) === callbacks) {
1841
1863
  keyAvailableCallbacks.delete(address);
1842
1864
  }
1843
1865
  };
@@ -20732,7 +20754,12 @@ function createAutoExtractor(options) {
20732
20754
  ...baseUrl !== void 0 && { baseUrl }
20733
20755
  };
20734
20756
  };
20735
- const consolidateOptions = options.consolidate ? { ...options.consolidate, ...subPassAuth(options.consolidate.baseUrl) } : void 0;
20757
+ const consolidateEndpoint = options.consolidate?.endpointOverride ?? options.extract.endpointOverride;
20758
+ const consolidateOptions = options.consolidate ? {
20759
+ ...options.consolidate,
20760
+ ...subPassAuth(options.consolidate.baseUrl),
20761
+ ...consolidateEndpoint !== void 0 && { endpointOverride: consolidateEndpoint }
20762
+ } : void 0;
20736
20763
  const injectionClassifierOptions = options.injectionClassifier ? { ...options.injectionClassifier, ...subPassAuth(options.injectionClassifier.baseUrl) } : void 0;
20737
20764
  if (!options.memoryStore && options.retainCtx.vaultCtx.entityCtx && !options.entityCtx) {
20738
20765
  getLogger().warn(
@@ -26119,10 +26146,20 @@ function batchError(result) {
26119
26146
  var AccountFailureError = class extends Error {
26120
26147
  };
26121
26148
  var LockedSourcesError = class extends Error {
26122
- constructor(persistentIds) {
26123
- super("Source messages are locked; retained for retry");
26149
+ constructor(persistentIds, locked) {
26150
+ const counts = /* @__PURE__ */ new Map();
26151
+ for (const message of locked) {
26152
+ const version = /^enc:(v\d+):/.exec(message.content)?.[1] ?? "unknown";
26153
+ const key = `${message.decryptionStatus ?? "no_status"}:${version}`;
26154
+ counts.set(key, (counts.get(key) ?? 0) + 1);
26155
+ }
26156
+ const summary = [...counts].map(([key, count2]) => `${key}=${count2}`).join(", ");
26157
+ super(`Source messages are locked; retained for retry (${summary})`);
26124
26158
  this.persistentIds = persistentIds;
26125
26159
  }
26160
+ get awaitingKey() {
26161
+ return this.persistentIds.length === 0;
26162
+ }
26126
26163
  };
26127
26164
  function splitTurns(messages) {
26128
26165
  const turns = [];
@@ -26176,6 +26213,8 @@ function createDurableAutoExtractor(options) {
26176
26213
  const attempts = /* @__PURE__ */ new Map();
26177
26214
  const sessionFailures = /* @__PURE__ */ new Map();
26178
26215
  const skippedThisSession = /* @__PURE__ */ new Set();
26216
+ const awaitingKey = /* @__PURE__ */ new Set();
26217
+ let keyEpoch = 0;
26179
26218
  const clock = options.now ?? Date.now;
26180
26219
  const reportError = (error, conversationId) => {
26181
26220
  try {
@@ -26369,13 +26408,15 @@ function createDurableAutoExtractor(options) {
26369
26408
  for (const job of pending) {
26370
26409
  if (disposed) break;
26371
26410
  const attempted = attempts.get(job.id) ?? 0;
26372
- if (attempted >= MAX_ATTEMPTS || skippedThisSession.has(job.id)) continue;
26411
+ if (attempted >= MAX_ATTEMPTS || skippedThisSession.has(job.id) || awaitingKey.has(job.id))
26412
+ continue;
26373
26413
  if (processed >= MAX_JOBS_PER_PASS) {
26374
26414
  scheduleAfterSuccess = true;
26375
26415
  break;
26376
26416
  }
26377
26417
  processed++;
26378
26418
  const conversationId = String(job._getRaw("conversation_id"));
26419
+ const epochAtRead = keyEpoch;
26379
26420
  let ids = [];
26380
26421
  let loaded = [];
26381
26422
  try {
@@ -26429,12 +26470,15 @@ function createDurableAutoExtractor(options) {
26429
26470
  );
26430
26471
  continue;
26431
26472
  }
26432
- const locked = loaded.filter((message) => message && isEncrypted(message.content));
26473
+ const locked = loaded.filter(
26474
+ (message) => !!message && isEncrypted(message.content)
26475
+ );
26433
26476
  if (locked.length) {
26434
26477
  throw new LockedSourcesError(
26435
26478
  locked.flatMap(
26436
26479
  (message) => message.decryptionStatus === "auth_mismatch" || message.decryptionStatus === "invalid_payload" ? [message.uniqueId] : []
26437
- )
26480
+ ),
26481
+ locked
26438
26482
  );
26439
26483
  }
26440
26484
  const messages = loaded.flatMap(
@@ -26488,6 +26532,12 @@ function createDurableAutoExtractor(options) {
26488
26532
  scheduleAfterSuccess = true;
26489
26533
  } catch (error) {
26490
26534
  if (disposed) break;
26535
+ if (error instanceof LockedSourcesError && error.awaitingKey) {
26536
+ reportError(error, conversationId);
26537
+ if (keyEpoch === epochAtRead) awaitingKey.add(job.id);
26538
+ else scheduleAfterSuccess = true;
26539
+ continue;
26540
+ }
26491
26541
  attempts.set(job.id, attempted + 1);
26492
26542
  retry = true;
26493
26543
  reportError(error, conversationId);
@@ -26515,7 +26565,18 @@ function createDurableAutoExtractor(options) {
26515
26565
  activeBatch?.abort(options.signal?.reason);
26516
26566
  if (timer !== void 0) clearTimeout(timer);
26517
26567
  options.signal?.removeEventListener("abort", dispose);
26568
+ unsubscribeKey?.();
26518
26569
  }
26570
+ const unsubscribeKey = vault.walletAddress ? onKeyAvailable(vault.walletAddress, () => {
26571
+ keyEpoch++;
26572
+ if (!awaitingKey.size) return;
26573
+ awaitingKey.clear();
26574
+ if (timer !== void 0) {
26575
+ clearTimeout(timer);
26576
+ timer = void 0;
26577
+ }
26578
+ schedule(0);
26579
+ }) : void 0;
26519
26580
  if (options.signal?.aborted) dispose();
26520
26581
  else options.signal?.addEventListener("abort", dispose, { once: true });
26521
26582
  schedule(0);
@@ -26605,6 +26666,7 @@ function createDurableAutoExtractor(options) {
26605
26666
  (r) => r._setRaw("message_ids", JSON.stringify([.../* @__PURE__ */ new Set([...idsOf(job), ...fresh])]))
26606
26667
  );
26607
26668
  attempts.delete(job.id);
26669
+ awaitingKey.delete(job.id);
26608
26670
  } else {
26609
26671
  await jobs.create((r) => {
26610
26672
  r._setRaw("owner_key", owner);
@@ -5337,7 +5337,7 @@ type RetainSource = "manual" | "auto-extracted" | "capsule";
5337
5337
  * rate of exactly zero is as likely to mean "the fields are being omitted" as
5338
5338
  * "the mistake never happens". Check compliance before reading zero as health.
5339
5339
  */
5340
- type ConsolidationFallbackReason = "llm_error" | "invalid_response" | "target_vanished"
5340
+ type ConsolidationFallbackReason = "llm_error" | "llm_timeout" | "content_flagged" | "invalid_response" | "target_vanished"
5341
5341
  /**
5342
5342
  * A `supersede` was downgraded to `create` because the model's own stated
5343
5343
  * subjects disagreed: the new fact is about someone other than the fact it
@@ -5376,6 +5376,7 @@ interface RetainOptions {
5376
5376
  consolidateOptions?: PortalLlmAuth & {
5377
5377
  baseUrl?: string;
5378
5378
  model?: string;
5379
+ endpointOverride?: string;
5379
5380
  /**
5380
5381
  * Invoked when the consolidator degrades to its "create" fallback
5381
5382
  * instead of returning a real decision — `llm_error` for network /
@@ -10700,6 +10701,7 @@ interface CreateAutoExtractorOptions {
10700
10701
  baseUrl?: string;
10701
10702
  /** Override the consolidation model. Default: see `consolidate.ts`. */
10702
10703
  model?: string;
10704
+ endpointOverride?: string;
10703
10705
  /**
10704
10706
  * Notified on each degraded create-fallback (LLM failure or
10705
10707
  * schema-violating response). See
@@ -5337,7 +5337,7 @@ type RetainSource = "manual" | "auto-extracted" | "capsule";
5337
5337
  * rate of exactly zero is as likely to mean "the fields are being omitted" as
5338
5338
  * "the mistake never happens". Check compliance before reading zero as health.
5339
5339
  */
5340
- type ConsolidationFallbackReason = "llm_error" | "invalid_response" | "target_vanished"
5340
+ type ConsolidationFallbackReason = "llm_error" | "llm_timeout" | "content_flagged" | "invalid_response" | "target_vanished"
5341
5341
  /**
5342
5342
  * A `supersede` was downgraded to `create` because the model's own stated
5343
5343
  * subjects disagreed: the new fact is about someone other than the fact it
@@ -5376,6 +5376,7 @@ interface RetainOptions {
5376
5376
  consolidateOptions?: PortalLlmAuth & {
5377
5377
  baseUrl?: string;
5378
5378
  model?: string;
5379
+ endpointOverride?: string;
5379
5380
  /**
5380
5381
  * Invoked when the consolidator degrades to its "create" fallback
5381
5382
  * instead of returning a real decision — `llm_error` for network /
@@ -10700,6 +10701,7 @@ interface CreateAutoExtractorOptions {
10700
10701
  baseUrl?: string;
10701
10702
  /** Override the consolidation model. Default: see `consolidate.ts`. */
10702
10703
  model?: string;
10704
+ endpointOverride?: string;
10703
10705
  /**
10704
10706
  * Notified on each degraded create-fallback (LLM failure or
10705
10707
  * schema-violating response). See
@@ -19,7 +19,7 @@ import {
19
19
  taskTypeHeader,
20
20
  validateEndpointOverride,
21
21
  withInternalFlowMarker
22
- } from "./chunk-TGLAOFVA.mjs";
22
+ } from "./chunk-7QX4J7KV.mjs";
23
23
  import {
24
24
  BASE_URL,
25
25
  MCP_R2_DOMAIN,
@@ -69,7 +69,7 @@ function onKeyAvailable(address, callback) {
69
69
  callbacks.add(callback);
70
70
  return () => {
71
71
  callbacks.delete(callback);
72
- if (callbacks.size === 0) {
72
+ if (callbacks.size === 0 && keyAvailableCallbacks.get(address) === callbacks) {
73
73
  keyAvailableCallbacks.delete(address);
74
74
  }
75
75
  };
@@ -18190,7 +18190,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
18190
18190
  content: m.content,
18191
18191
  similarity: m.similarity
18192
18192
  }));
18193
- const { consolidateMemory: doConsolidate } = await import("./consolidate-ZEINV2LX.mjs");
18193
+ const { consolidateMemory: doConsolidate } = await import("./consolidate-WLDYJF6J.mjs");
18194
18194
  const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
18195
18195
  if (decision.action === "create") return decision.fallbackReason ? null : { create: true };
18196
18196
  if (decision.action === "supersede" && decision.content) {
@@ -18906,7 +18906,12 @@ function createAutoExtractor(options) {
18906
18906
  ...baseUrl !== void 0 && { baseUrl }
18907
18907
  };
18908
18908
  };
18909
- const consolidateOptions = options.consolidate ? { ...options.consolidate, ...subPassAuth(options.consolidate.baseUrl) } : void 0;
18909
+ const consolidateEndpoint = options.consolidate?.endpointOverride ?? options.extract.endpointOverride;
18910
+ const consolidateOptions = options.consolidate ? {
18911
+ ...options.consolidate,
18912
+ ...subPassAuth(options.consolidate.baseUrl),
18913
+ ...consolidateEndpoint !== void 0 && { endpointOverride: consolidateEndpoint }
18914
+ } : void 0;
18910
18915
  const injectionClassifierOptions = options.injectionClassifier ? { ...options.injectionClassifier, ...subPassAuth(options.injectionClassifier.baseUrl) } : void 0;
18911
18916
  if (!options.memoryStore && options.retainCtx.vaultCtx.entityCtx && !options.entityCtx) {
18912
18917
  getLogger().warn(
@@ -24266,10 +24271,20 @@ function batchError(result) {
24266
24271
  var AccountFailureError = class extends Error {
24267
24272
  };
24268
24273
  var LockedSourcesError = class extends Error {
24269
- constructor(persistentIds) {
24270
- super("Source messages are locked; retained for retry");
24274
+ constructor(persistentIds, locked) {
24275
+ const counts = /* @__PURE__ */ new Map();
24276
+ for (const message of locked) {
24277
+ const version = /^enc:(v\d+):/.exec(message.content)?.[1] ?? "unknown";
24278
+ const key = `${message.decryptionStatus ?? "no_status"}:${version}`;
24279
+ counts.set(key, (counts.get(key) ?? 0) + 1);
24280
+ }
24281
+ const summary = [...counts].map(([key, count2]) => `${key}=${count2}`).join(", ");
24282
+ super(`Source messages are locked; retained for retry (${summary})`);
24271
24283
  this.persistentIds = persistentIds;
24272
24284
  }
24285
+ get awaitingKey() {
24286
+ return this.persistentIds.length === 0;
24287
+ }
24273
24288
  };
24274
24289
  function splitTurns(messages) {
24275
24290
  const turns = [];
@@ -24323,6 +24338,8 @@ function createDurableAutoExtractor(options) {
24323
24338
  const attempts = /* @__PURE__ */ new Map();
24324
24339
  const sessionFailures = /* @__PURE__ */ new Map();
24325
24340
  const skippedThisSession = /* @__PURE__ */ new Set();
24341
+ const awaitingKey = /* @__PURE__ */ new Set();
24342
+ let keyEpoch = 0;
24326
24343
  const clock = options.now ?? Date.now;
24327
24344
  const reportError = (error, conversationId) => {
24328
24345
  try {
@@ -24516,13 +24533,15 @@ function createDurableAutoExtractor(options) {
24516
24533
  for (const job of pending) {
24517
24534
  if (disposed) break;
24518
24535
  const attempted = attempts.get(job.id) ?? 0;
24519
- if (attempted >= MAX_ATTEMPTS || skippedThisSession.has(job.id)) continue;
24536
+ if (attempted >= MAX_ATTEMPTS || skippedThisSession.has(job.id) || awaitingKey.has(job.id))
24537
+ continue;
24520
24538
  if (processed >= MAX_JOBS_PER_PASS) {
24521
24539
  scheduleAfterSuccess = true;
24522
24540
  break;
24523
24541
  }
24524
24542
  processed++;
24525
24543
  const conversationId = String(job._getRaw("conversation_id"));
24544
+ const epochAtRead = keyEpoch;
24526
24545
  let ids = [];
24527
24546
  let loaded = [];
24528
24547
  try {
@@ -24576,12 +24595,15 @@ function createDurableAutoExtractor(options) {
24576
24595
  );
24577
24596
  continue;
24578
24597
  }
24579
- const locked = loaded.filter((message) => message && isEncrypted(message.content));
24598
+ const locked = loaded.filter(
24599
+ (message) => !!message && isEncrypted(message.content)
24600
+ );
24580
24601
  if (locked.length) {
24581
24602
  throw new LockedSourcesError(
24582
24603
  locked.flatMap(
24583
24604
  (message) => message.decryptionStatus === "auth_mismatch" || message.decryptionStatus === "invalid_payload" ? [message.uniqueId] : []
24584
- )
24605
+ ),
24606
+ locked
24585
24607
  );
24586
24608
  }
24587
24609
  const messages = loaded.flatMap(
@@ -24635,6 +24657,12 @@ function createDurableAutoExtractor(options) {
24635
24657
  scheduleAfterSuccess = true;
24636
24658
  } catch (error) {
24637
24659
  if (disposed) break;
24660
+ if (error instanceof LockedSourcesError && error.awaitingKey) {
24661
+ reportError(error, conversationId);
24662
+ if (keyEpoch === epochAtRead) awaitingKey.add(job.id);
24663
+ else scheduleAfterSuccess = true;
24664
+ continue;
24665
+ }
24638
24666
  attempts.set(job.id, attempted + 1);
24639
24667
  retry = true;
24640
24668
  reportError(error, conversationId);
@@ -24662,7 +24690,18 @@ function createDurableAutoExtractor(options) {
24662
24690
  activeBatch?.abort(options.signal?.reason);
24663
24691
  if (timer !== void 0) clearTimeout(timer);
24664
24692
  options.signal?.removeEventListener("abort", dispose);
24693
+ unsubscribeKey?.();
24665
24694
  }
24695
+ const unsubscribeKey = vault.walletAddress ? onKeyAvailable(vault.walletAddress, () => {
24696
+ keyEpoch++;
24697
+ if (!awaitingKey.size) return;
24698
+ awaitingKey.clear();
24699
+ if (timer !== void 0) {
24700
+ clearTimeout(timer);
24701
+ timer = void 0;
24702
+ }
24703
+ schedule(0);
24704
+ }) : void 0;
24666
24705
  if (options.signal?.aborted) dispose();
24667
24706
  else options.signal?.addEventListener("abort", dispose, { once: true });
24668
24707
  schedule(0);
@@ -24752,6 +24791,7 @@ function createDurableAutoExtractor(options) {
24752
24791
  (r) => r._setRaw("message_ids", JSON.stringify([.../* @__PURE__ */ new Set([...idsOf(job), ...fresh])]))
24753
24792
  );
24754
24793
  attempts.delete(job.id);
24794
+ awaitingKey.delete(job.id);
24755
24795
  } else {
24756
24796
  await jobs.create((r) => {
24757
24797
  r._setRaw("owner_key", owner);
@@ -696,6 +696,13 @@ var FOREIGN_ENDPOINT_SUFFIX = {
696
696
  chat: "/responses",
697
697
  responses: "/chat/completions"
698
698
  };
699
+ function endpointForTransport(endpoint, transport) {
700
+ const { path, rest } = splitEndpoint(endpoint);
701
+ const foreign = FOREIGN_ENDPOINT_SUFFIX[transport];
702
+ if (!path.endsWith(foreign)) return endpoint;
703
+ const own = FOREIGN_ENDPOINT_SUFFIX[transport === "chat" ? "responses" : "chat"];
704
+ return `${path.slice(0, -foreign.length)}${own}${rest}`;
705
+ }
699
706
  function assertTransportMatchesEndpoint(transport, endpoint) {
700
707
  const foreign = FOREIGN_ENDPOINT_SUFFIX[transport];
701
708
  if (!splitEndpoint(endpoint).path.endsWith(foreign)) return;
@@ -753,10 +760,7 @@ async function callPortalJsonCompletion(req) {
753
760
  throw new Error(overrideValidation.message);
754
761
  }
755
762
  endpoint = overrideValidation.endpoint;
756
- const { path, rest } = splitEndpoint(endpoint);
757
- if (autoUpgraded && path.endsWith("/chat/completions")) {
758
- endpoint = `${path.slice(0, -"/chat/completions".length)}/responses${rest}`;
759
- }
763
+ if (autoUpgraded) endpoint = endpointForTransport(endpoint, transport);
760
764
  assertTransportMatchesEndpoint(transport, endpoint);
761
765
  }
762
766
  const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
@@ -1055,6 +1059,7 @@ export {
1055
1059
  withInternalFlowMarker,
1056
1060
  supportsResponseFormat,
1057
1061
  requiresResponsesTransport,
1062
+ endpointForTransport,
1058
1063
  resolvePortalAuthHeaders,
1059
1064
  callPortalJsonCompletion,
1060
1065
  extractJsonCandidate,
@@ -1,12 +1,14 @@
1
1
  import {
2
2
  callPortalJsonCompletion,
3
+ endpointForTransport,
3
4
  notifyConsolidationFallback,
5
+ requiresResponsesTransport,
4
6
  resolvePiiRedactor
5
- } from "./chunk-WCG5BFI6.mjs";
7
+ } from "./chunk-AU3Z7NBC.mjs";
6
8
  import "./chunk-3RPGXXPZ.mjs";
7
9
 
8
10
  // src/lib/memory/consolidate.ts
9
- var DEFAULT_CONSOLIDATION_MODEL = "inclusionai/ling-2.6-flash";
11
+ var DEFAULT_CONSOLIDATION_MODEL = "openai/gpt-6-luna";
10
12
  var DEFAULT_CONSOLIDATE_ATTEMPTS = 3;
11
13
  var DEFAULT_CONSOLIDATE_TOTAL_TIMEOUT_MS = 2e4;
12
14
  var SYSTEM_PROMPT = `You consolidate a new memory against existing memories from the same user.
@@ -46,7 +48,11 @@ OUTPUT \u2014 strict JSON, no prose:
46
48
  For "create": content is the new memory verbatim (or a slight refinement); omit targetId/targetIds.
47
49
  For "update": content is the merged richest-version, \u226480 words; targetId is the single memory to update.
48
50
  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). You MUST also name the subjects: "newSubject" for the new memory, and one entry in "targetSubjects" for EACH memory you are retiring (use "targetSubject" as well when you retire a single memory). List a subject ONLY for the memories you are actually retiring, not for every candidate you were shown. Write the plain subject, not a sentence: "the user", "the user's sister", "the user's manager", "Biscuit the dog". Rule 1a means a supersede is only valid when every one of those subjects is the SAME as "newSubject"; name them and check them against each other before you commit to the action. If ANY of them differs, the answer is "create" \u2014 do not retire the ones that match and keep the rest, because a group that mixes subjects was grouped wrongly in the first place. A subjectless fact ("Lives in Denver", "Works at Riverbend") is about "the user" \u2014 the extractor omits the subject when it is the user, so treat the absence of a subject as the user, never as unknown.
49
- For "noop": no content (existing memory is already correct); targetId is that memory.`;
51
+ For "noop": no content (existing memory is already correct); targetId is that memory.
52
+
53
+ ADDING TO AN INTRODUCED ENTITY (check this before choosing "create"): when an existing memory only introduces or names someone or something in the user's life ("User has a cat named Mochi", "User's sister is called Ana") and the new memory gives an attribute of that SAME entity that the existing memory does not state yet (its age, breed, job, home city), choose "update": targetId is that memory and content folds both into one sentence ("User has a cat named Mochi, who is four years old."). The "dog's name vs dog's age" example above means two memories that each already state a different attribute stay separate; a memory that only introduces the entity absorbs the next attribute about it. If the existing memory already states a value and the new memory changes it, that is "supersede" (rule 4), not this.
54
+
55
+ CARRY FORWARD UNCHANGED DETAILS (every "update" and "supersede"): a memory can hold several details at once, such as one folded from an introduction and an attribute ("User's sister Ana lives in Paris"). content replaces ONLY the value that changed and keeps every other detail of the memory it replaces, the subject's relation to the user and name above all: "Ana lives in London" against "User's sister Ana lives in Paris" is "supersede" with content "User's sister Ana lives in London", never just "Ana lives in London". Name the subject the same way on both sides: here "newSubject" and "targetSubjects" are both "the user's sister Ana".`;
50
56
  async function consolidateMemory(newContent, candidates, options) {
51
57
  const fallback = {
52
58
  action: "create",
@@ -69,14 +75,23 @@ async function consolidateMemory(newContent, candidates, options) {
69
75
 
70
76
  Existing memories (top ${candidates.length} by cosine):
71
77
  ${candidateText}`;
78
+ const model = options.model ?? DEFAULT_CONSOLIDATION_MODEL;
79
+ const viaResponses = requiresResponsesTransport(model);
80
+ const endpointOverride = options.endpointOverride === void 0 ? void 0 : endpointForTransport(options.endpointOverride, viaResponses ? "responses" : "chat");
72
81
  let parsed;
82
+ let failure;
73
83
  try {
74
84
  parsed = await callPortalJsonCompletion({
85
+ onFailure: (f) => {
86
+ failure = f;
87
+ },
75
88
  ...options.apiKey !== void 0 && { apiKey: options.apiKey },
76
89
  ...options.getToken !== void 0 && { getToken: options.getToken },
77
90
  ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
91
+ ...endpointOverride !== void 0 && { endpointOverride },
78
92
  taskType: "memory_consolidate",
79
- model: options.model ?? DEFAULT_CONSOLIDATION_MODEL,
93
+ model,
94
+ ...viaResponses ? { transport: "responses", reasoning: { effort: "low" } } : { transport: "chat" },
80
95
  systemPrompt: SYSTEM_PROMPT,
81
96
  userMessage,
82
97
  tag: "memory/consolidate",
@@ -88,7 +103,7 @@ ${candidateText}`;
88
103
  } catch (err) {
89
104
  return degrade("llm_error", fallback, options, err);
90
105
  }
91
- if (parsed === null) return degrade("llm_error", fallback, options);
106
+ if (parsed === null) return degrade(fallbackReasonFor(failure), fallback, options, failure);
92
107
  const validIds = new Set(candidates.map((c) => c.id));
93
108
  const result = validate(parsed, trimmed, validIds);
94
109
  if (!result) return degrade("invalid_response", fallback, options);
@@ -101,6 +116,11 @@ ${candidateText}`;
101
116
  }
102
117
  return reportRefusal(result, options);
103
118
  }
119
+ function fallbackReasonFor(failure) {
120
+ if (failure?.reason === "time-budget-exhausted") return "llm_timeout";
121
+ if (failure?.reason === "content-flagged") return "content_flagged";
122
+ return "llm_error";
123
+ }
104
124
  function reportRefusal(result, options) {
105
125
  if (result.fallbackReason) {
106
126
  notifyConsolidationFallback(result.fallbackReason, options.onFallback);