@anuma/sdk 7.3.2 → 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.
@@ -709,6 +709,13 @@ var FOREIGN_ENDPOINT_SUFFIX = {
709
709
  chat: "/responses",
710
710
  responses: "/chat/completions"
711
711
  };
712
+ function endpointForTransport(endpoint, transport) {
713
+ const { path, rest } = splitEndpoint(endpoint);
714
+ const foreign = FOREIGN_ENDPOINT_SUFFIX[transport];
715
+ if (!path.endsWith(foreign)) return endpoint;
716
+ const own = FOREIGN_ENDPOINT_SUFFIX[transport === "chat" ? "responses" : "chat"];
717
+ return `${path.slice(0, -foreign.length)}${own}${rest}`;
718
+ }
712
719
  function assertTransportMatchesEndpoint(transport, endpoint) {
713
720
  const foreign = FOREIGN_ENDPOINT_SUFFIX[transport];
714
721
  if (!splitEndpoint(endpoint).path.endsWith(foreign)) return;
@@ -766,10 +773,7 @@ async function callPortalJsonCompletion(req) {
766
773
  throw new Error(overrideValidation.message);
767
774
  }
768
775
  endpoint = overrideValidation.endpoint;
769
- const { path, rest } = splitEndpoint(endpoint);
770
- if (autoUpgraded && path.endsWith("/chat/completions")) {
771
- endpoint = `${path.slice(0, -"/chat/completions".length)}/responses${rest}`;
772
- }
776
+ if (autoUpgraded) endpoint = endpointForTransport(endpoint, transport);
773
777
  assertTransportMatchesEndpoint(transport, endpoint);
774
778
  }
775
779
  const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
@@ -1074,6 +1078,7 @@ export {
1074
1078
  withInternalFlowMarker,
1075
1079
  supportsResponseFormat,
1076
1080
  requiresResponsesTransport,
1081
+ endpointForTransport,
1077
1082
  parseRetryAfterMs,
1078
1083
  resolvePortalAuthHeaders,
1079
1084
  callPortalJsonCompletion,
@@ -1,12 +1,14 @@
1
1
  import {
2
2
  callPortalJsonCompletion,
3
+ endpointForTransport,
3
4
  notifyConsolidationFallback,
5
+ requiresResponsesTransport,
4
6
  resolvePiiRedactor
5
- } from "./chunk-AF37N5Z6.mjs";
7
+ } from "./chunk-XW3LYSDA.mjs";
6
8
  import "./chunk-GYKJOWEO.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);
@@ -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
  });
@@ -18455,7 +18477,12 @@ function createAutoExtractor(options) {
18455
18477
  ...baseUrl !== void 0 && { baseUrl }
18456
18478
  };
18457
18479
  };
18458
- const consolidateOptions = options.consolidate ? { ...options.consolidate, ...subPassAuth(options.consolidate.baseUrl) } : void 0;
18480
+ const consolidateEndpoint = options.consolidate?.endpointOverride ?? options.extract.endpointOverride;
18481
+ const consolidateOptions = options.consolidate ? {
18482
+ ...options.consolidate,
18483
+ ...subPassAuth(options.consolidate.baseUrl),
18484
+ ...consolidateEndpoint !== void 0 && { endpointOverride: consolidateEndpoint }
18485
+ } : void 0;
18459
18486
  const injectionClassifierOptions = options.injectionClassifier ? { ...options.injectionClassifier, ...subPassAuth(options.injectionClassifier.baseUrl) } : void 0;
18460
18487
  if (!options.memoryStore && options.retainCtx.vaultCtx.entityCtx && !options.entityCtx) {
18461
18488
  getLogger().warn(
@@ -4821,7 +4821,7 @@ type RetainSource = "manual" | "auto-extracted" | "capsule";
4821
4821
  * rate of exactly zero is as likely to mean "the fields are being omitted" as
4822
4822
  * "the mistake never happens". Check compliance before reading zero as health.
4823
4823
  */
4824
- type ConsolidationFallbackReason = "llm_error" | "invalid_response" | "target_vanished"
4824
+ type ConsolidationFallbackReason = "llm_error" | "llm_timeout" | "content_flagged" | "invalid_response" | "target_vanished"
4825
4825
  /**
4826
4826
  * A `supersede` was downgraded to `create` because the model's own stated
4827
4827
  * subjects disagreed: the new fact is about someone other than the fact it
@@ -4860,6 +4860,7 @@ interface RetainOptions {
4860
4860
  consolidateOptions?: PortalLlmAuth & {
4861
4861
  baseUrl?: string;
4862
4862
  model?: string;
4863
+ endpointOverride?: string;
4863
4864
  /**
4864
4865
  * Invoked when the consolidator degrades to its "create" fallback
4865
4866
  * instead of returning a real decision — `llm_error` for network /
@@ -8967,6 +8968,7 @@ interface CreateAutoExtractorOptions {
8967
8968
  baseUrl?: string;
8968
8969
  /** Override the consolidation model. Default: see `consolidate.ts`. */
8969
8970
  model?: string;
8971
+ endpointOverride?: string;
8970
8972
  /**
8971
8973
  * Notified on each degraded create-fallback (LLM failure or
8972
8974
  * schema-violating response). See
@@ -4821,7 +4821,7 @@ type RetainSource = "manual" | "auto-extracted" | "capsule";
4821
4821
  * rate of exactly zero is as likely to mean "the fields are being omitted" as
4822
4822
  * "the mistake never happens". Check compliance before reading zero as health.
4823
4823
  */
4824
- type ConsolidationFallbackReason = "llm_error" | "invalid_response" | "target_vanished"
4824
+ type ConsolidationFallbackReason = "llm_error" | "llm_timeout" | "content_flagged" | "invalid_response" | "target_vanished"
4825
4825
  /**
4826
4826
  * A `supersede` was downgraded to `create` because the model's own stated
4827
4827
  * subjects disagreed: the new fact is about someone other than the fact it
@@ -4860,6 +4860,7 @@ interface RetainOptions {
4860
4860
  consolidateOptions?: PortalLlmAuth & {
4861
4861
  baseUrl?: string;
4862
4862
  model?: string;
4863
+ endpointOverride?: string;
4863
4864
  /**
4864
4865
  * Invoked when the consolidator degrades to its "create" fallback
4865
4866
  * instead of returning a real decision — `llm_error` for network /
@@ -8967,6 +8968,7 @@ interface CreateAutoExtractorOptions {
8967
8968
  baseUrl?: string;
8968
8969
  /** Override the consolidation model. Default: see `consolidate.ts`. */
8969
8970
  model?: string;
8971
+ endpointOverride?: string;
8970
8972
  /**
8971
8973
  * Notified on each degraded create-fallback (LLM failure or
8972
8974
  * schema-violating response). See
@@ -20,7 +20,7 @@ import {
20
20
  taskTypeHeader,
21
21
  validateEndpointOverride,
22
22
  withInternalFlowMarker
23
- } from "./chunk-AF37N5Z6.mjs";
23
+ } from "./chunk-XW3LYSDA.mjs";
24
24
  import {
25
25
  BASE_URL,
26
26
  MCP_R2_DOMAIN,
@@ -16121,7 +16121,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
16121
16121
  content: m.content,
16122
16122
  similarity: m.similarity
16123
16123
  }));
16124
- const { consolidateMemory: doConsolidate } = await import("./consolidate-TOITBD6W.mjs");
16124
+ const { consolidateMemory: doConsolidate } = await import("./consolidate-4CQJYKRK.mjs");
16125
16125
  const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
16126
16126
  if (decision.action === "create") return decision.fallbackReason ? null : { create: true };
16127
16127
  if (decision.action === "supersede" && decision.content) {
@@ -16837,7 +16837,12 @@ function createAutoExtractor(options) {
16837
16837
  ...baseUrl !== void 0 && { baseUrl }
16838
16838
  };
16839
16839
  };
16840
- const consolidateOptions = options.consolidate ? { ...options.consolidate, ...subPassAuth(options.consolidate.baseUrl) } : void 0;
16840
+ const consolidateEndpoint = options.consolidate?.endpointOverride ?? options.extract.endpointOverride;
16841
+ const consolidateOptions = options.consolidate ? {
16842
+ ...options.consolidate,
16843
+ ...subPassAuth(options.consolidate.baseUrl),
16844
+ ...consolidateEndpoint !== void 0 && { endpointOverride: consolidateEndpoint }
16845
+ } : void 0;
16841
16846
  const injectionClassifierOptions = options.injectionClassifier ? { ...options.injectionClassifier, ...subPassAuth(options.injectionClassifier.baseUrl) } : void 0;
16842
16847
  if (!options.memoryStore && options.retainCtx.vaultCtx.entityCtx && !options.entityCtx) {
16843
16848
  getLogger().warn(
@@ -709,6 +709,13 @@ var FOREIGN_ENDPOINT_SUFFIX = {
709
709
  chat: "/responses",
710
710
  responses: "/chat/completions"
711
711
  };
712
+ function endpointForTransport(endpoint, transport) {
713
+ const { path, rest } = splitEndpoint(endpoint);
714
+ const foreign = FOREIGN_ENDPOINT_SUFFIX[transport];
715
+ if (!path.endsWith(foreign)) return endpoint;
716
+ const own = FOREIGN_ENDPOINT_SUFFIX[transport === "chat" ? "responses" : "chat"];
717
+ return `${path.slice(0, -foreign.length)}${own}${rest}`;
718
+ }
712
719
  function assertTransportMatchesEndpoint(transport, endpoint) {
713
720
  const foreign = FOREIGN_ENDPOINT_SUFFIX[transport];
714
721
  if (!splitEndpoint(endpoint).path.endsWith(foreign)) return;
@@ -766,10 +773,7 @@ async function callPortalJsonCompletion(req) {
766
773
  throw new Error(overrideValidation.message);
767
774
  }
768
775
  endpoint = overrideValidation.endpoint;
769
- const { path, rest } = splitEndpoint(endpoint);
770
- if (autoUpgraded && path.endsWith("/chat/completions")) {
771
- endpoint = `${path.slice(0, -"/chat/completions".length)}/responses${rest}`;
772
- }
776
+ if (autoUpgraded) endpoint = endpointForTransport(endpoint, transport);
773
777
  assertTransportMatchesEndpoint(transport, endpoint);
774
778
  }
775
779
  const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
@@ -1073,6 +1077,7 @@ export {
1073
1077
  withInternalFlowMarker,
1074
1078
  supportsResponseFormat,
1075
1079
  requiresResponsesTransport,
1080
+ endpointForTransport,
1076
1081
  parseRetryAfterMs,
1077
1082
  resolvePortalAuthHeaders,
1078
1083
  callPortalJsonCompletion,
@@ -1,12 +1,14 @@
1
1
  import {
2
2
  callPortalJsonCompletion,
3
+ endpointForTransport,
3
4
  notifyConsolidationFallback,
5
+ requiresResponsesTransport,
4
6
  resolvePiiRedactor
5
- } from "./chunk-TGLAOFVA.mjs";
7
+ } from "./chunk-7QX4J7KV.mjs";
6
8
  import "./chunk-GYKJOWEO.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);
@@ -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
  });
@@ -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(
@@ -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,
@@ -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(
@@ -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);
@@ -15674,6 +15674,13 @@ function splitEndpoint(endpoint) {
15674
15674
  rest: cut === -1 ? "" : endpoint.slice(cut)
15675
15675
  };
15676
15676
  }
15677
+ function endpointForTransport(endpoint, transport) {
15678
+ const { path, rest } = splitEndpoint(endpoint);
15679
+ const foreign = FOREIGN_ENDPOINT_SUFFIX[transport];
15680
+ if (!path.endsWith(foreign)) return endpoint;
15681
+ const own = FOREIGN_ENDPOINT_SUFFIX[transport === "chat" ? "responses" : "chat"];
15682
+ return `${path.slice(0, -foreign.length)}${own}${rest}`;
15683
+ }
15677
15684
  function assertTransportMatchesEndpoint(transport, endpoint) {
15678
15685
  const foreign = FOREIGN_ENDPOINT_SUFFIX[transport];
15679
15686
  if (!splitEndpoint(endpoint).path.endsWith(foreign)) return;
@@ -15730,10 +15737,7 @@ async function callPortalJsonCompletion(req) {
15730
15737
  throw new Error(overrideValidation.message);
15731
15738
  }
15732
15739
  endpoint = overrideValidation.endpoint;
15733
- const { path, rest } = splitEndpoint(endpoint);
15734
- if (autoUpgraded && path.endsWith("/chat/completions")) {
15735
- endpoint = `${path.slice(0, -"/chat/completions".length)}/responses${rest}`;
15736
- }
15740
+ if (autoUpgraded) endpoint = endpointForTransport(endpoint, transport);
15737
15741
  assertTransportMatchesEndpoint(transport, endpoint);
15738
15742
  }
15739
15743
  const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
@@ -16079,14 +16083,23 @@ async function consolidateMemory(newContent, candidates, options) {
16079
16083
 
16080
16084
  Existing memories (top ${candidates.length} by cosine):
16081
16085
  ${candidateText}`;
16086
+ const model = options.model ?? DEFAULT_CONSOLIDATION_MODEL;
16087
+ const viaResponses = requiresResponsesTransport(model);
16088
+ const endpointOverride = options.endpointOverride === void 0 ? void 0 : endpointForTransport(options.endpointOverride, viaResponses ? "responses" : "chat");
16082
16089
  let parsed;
16090
+ let failure;
16083
16091
  try {
16084
16092
  parsed = await callPortalJsonCompletion({
16093
+ onFailure: (f) => {
16094
+ failure = f;
16095
+ },
16085
16096
  ...options.apiKey !== void 0 && { apiKey: options.apiKey },
16086
16097
  ...options.getToken !== void 0 && { getToken: options.getToken },
16087
16098
  ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
16099
+ ...endpointOverride !== void 0 && { endpointOverride },
16088
16100
  taskType: "memory_consolidate",
16089
- model: options.model ?? DEFAULT_CONSOLIDATION_MODEL,
16101
+ model,
16102
+ ...viaResponses ? { transport: "responses", reasoning: { effort: "low" } } : { transport: "chat" },
16090
16103
  systemPrompt: SYSTEM_PROMPT3,
16091
16104
  userMessage,
16092
16105
  tag: "memory/consolidate",
@@ -16098,7 +16111,7 @@ ${candidateText}`;
16098
16111
  } catch (err) {
16099
16112
  return degrade("llm_error", fallback, options, err);
16100
16113
  }
16101
- if (parsed === null) return degrade("llm_error", fallback, options);
16114
+ if (parsed === null) return degrade(fallbackReasonFor(failure), fallback, options, failure);
16102
16115
  const validIds = new Set(candidates.map((c) => c.id));
16103
16116
  const result = validate2(parsed, trimmed, validIds);
16104
16117
  if (!result) return degrade("invalid_response", fallback, options);
@@ -16111,6 +16124,11 @@ ${candidateText}`;
16111
16124
  }
16112
16125
  return reportRefusal(result, options);
16113
16126
  }
16127
+ function fallbackReasonFor(failure) {
16128
+ if (failure?.reason === "time-budget-exhausted") return "llm_timeout";
16129
+ if (failure?.reason === "content-flagged") return "content_flagged";
16130
+ return "llm_error";
16131
+ }
16114
16132
  function reportRefusal(result, options) {
16115
16133
  if (result.fallbackReason) {
16116
16134
  notifyConsolidationFallback(result.fallbackReason, options.onFallback);
@@ -16184,7 +16202,7 @@ var init_consolidate = __esm({
16184
16202
  init_redactor();
16185
16203
  init_consolidationFallback();
16186
16204
  init_portalLlm();
16187
- DEFAULT_CONSOLIDATION_MODEL = "inclusionai/ling-2.6-flash";
16205
+ DEFAULT_CONSOLIDATION_MODEL = "openai/gpt-6-luna";
16188
16206
  DEFAULT_CONSOLIDATE_ATTEMPTS = 3;
16189
16207
  DEFAULT_CONSOLIDATE_TOTAL_TIMEOUT_MS = 2e4;
16190
16208
  SYSTEM_PROMPT3 = `You consolidate a new memory against existing memories from the same user.
@@ -16224,7 +16242,11 @@ OUTPUT \u2014 strict JSON, no prose:
16224
16242
  For "create": content is the new memory verbatim (or a slight refinement); omit targetId/targetIds.
16225
16243
  For "update": content is the merged richest-version, \u226480 words; targetId is the single memory to update.
16226
16244
  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.
16227
- For "noop": no content (existing memory is already correct); targetId is that memory.`;
16245
+ For "noop": no content (existing memory is already correct); targetId is that memory.
16246
+
16247
+ 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.
16248
+
16249
+ 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".`;
16228
16250
  USER_SUBJECT_ALIASES = /* @__PURE__ */ new Set(["user", "themselves", "themself", "they", "me", "self"]);
16229
16251
  }
16230
16252
  });
@@ -33697,7 +33719,12 @@ function createAutoExtractor(options) {
33697
33719
  ...baseUrl !== void 0 && { baseUrl }
33698
33720
  };
33699
33721
  };
33700
- const consolidateOptions = options.consolidate ? { ...options.consolidate, ...subPassAuth(options.consolidate.baseUrl) } : void 0;
33722
+ const consolidateEndpoint = options.consolidate?.endpointOverride ?? options.extract.endpointOverride;
33723
+ const consolidateOptions = options.consolidate ? {
33724
+ ...options.consolidate,
33725
+ ...subPassAuth(options.consolidate.baseUrl),
33726
+ ...consolidateEndpoint !== void 0 && { endpointOverride: consolidateEndpoint }
33727
+ } : void 0;
33701
33728
  const injectionClassifierOptions = options.injectionClassifier ? { ...options.injectionClassifier, ...subPassAuth(options.injectionClassifier.baseUrl) } : void 0;
33702
33729
  if (!options.memoryStore && options.retainCtx.vaultCtx.entityCtx && !options.entityCtx) {
33703
33730
  getLogger().warn(
@@ -4503,7 +4503,7 @@ type RetainSource = "manual" | "auto-extracted" | "capsule";
4503
4503
  * rate of exactly zero is as likely to mean "the fields are being omitted" as
4504
4504
  * "the mistake never happens". Check compliance before reading zero as health.
4505
4505
  */
4506
- type ConsolidationFallbackReason = "llm_error" | "invalid_response" | "target_vanished"
4506
+ type ConsolidationFallbackReason = "llm_error" | "llm_timeout" | "content_flagged" | "invalid_response" | "target_vanished"
4507
4507
  /**
4508
4508
  * A `supersede` was downgraded to `create` because the model's own stated
4509
4509
  * subjects disagreed: the new fact is about someone other than the fact it
@@ -4542,6 +4542,7 @@ interface RetainOptions {
4542
4542
  consolidateOptions?: PortalLlmAuth & {
4543
4543
  baseUrl?: string;
4544
4544
  model?: string;
4545
+ endpointOverride?: string;
4545
4546
  /**
4546
4547
  * Invoked when the consolidator degrades to its "create" fallback
4547
4548
  * instead of returning a real decision — `llm_error` for network /
@@ -9174,6 +9175,7 @@ interface CreateAutoExtractorOptions {
9174
9175
  baseUrl?: string;
9175
9176
  /** Override the consolidation model. Default: see `consolidate.ts`. */
9176
9177
  model?: string;
9178
+ endpointOverride?: string;
9177
9179
  /**
9178
9180
  * Notified on each degraded create-fallback (LLM failure or
9179
9181
  * schema-violating response). See
@@ -4503,7 +4503,7 @@ type RetainSource = "manual" | "auto-extracted" | "capsule";
4503
4503
  * rate of exactly zero is as likely to mean "the fields are being omitted" as
4504
4504
  * "the mistake never happens". Check compliance before reading zero as health.
4505
4505
  */
4506
- type ConsolidationFallbackReason = "llm_error" | "invalid_response" | "target_vanished"
4506
+ type ConsolidationFallbackReason = "llm_error" | "llm_timeout" | "content_flagged" | "invalid_response" | "target_vanished"
4507
4507
  /**
4508
4508
  * A `supersede` was downgraded to `create` because the model's own stated
4509
4509
  * subjects disagreed: the new fact is about someone other than the fact it
@@ -4542,6 +4542,7 @@ interface RetainOptions {
4542
4542
  consolidateOptions?: PortalLlmAuth & {
4543
4543
  baseUrl?: string;
4544
4544
  model?: string;
4545
+ endpointOverride?: string;
4545
4546
  /**
4546
4547
  * Invoked when the consolidator degrades to its "create" fallback
4547
4548
  * instead of returning a real decision — `llm_error` for network /
@@ -9174,6 +9175,7 @@ interface CreateAutoExtractorOptions {
9174
9175
  baseUrl?: string;
9175
9176
  /** Override the consolidation model. Default: see `consolidate.ts`. */
9176
9177
  model?: string;
9178
+ endpointOverride?: string;
9177
9179
  /**
9178
9180
  * Notified on each degraded create-fallback (LLM failure or
9179
9181
  * schema-violating response). See
@@ -13,7 +13,7 @@ import {
13
13
  taskTypeHeader,
14
14
  validateEndpointOverride,
15
15
  withInternalFlowMarker
16
- } from "./chunk-WCG5BFI6.mjs";
16
+ } from "./chunk-AU3Z7NBC.mjs";
17
17
  import {
18
18
  BASE_URL,
19
19
  __commonJS,
@@ -31273,7 +31273,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
31273
31273
  content: m.content,
31274
31274
  similarity: m.similarity
31275
31275
  }));
31276
- const { consolidateMemory: doConsolidate } = await import("./consolidate-WY6BHODK.mjs");
31276
+ const { consolidateMemory: doConsolidate } = await import("./consolidate-B6OSCZU4.mjs");
31277
31277
  const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
31278
31278
  if (decision.action === "create") return decision.fallbackReason ? null : { create: true };
31279
31279
  if (decision.action === "supersede" && decision.content) {
@@ -31989,7 +31989,12 @@ function createAutoExtractor(options) {
31989
31989
  ...baseUrl !== void 0 && { baseUrl }
31990
31990
  };
31991
31991
  };
31992
- const consolidateOptions = options.consolidate ? { ...options.consolidate, ...subPassAuth(options.consolidate.baseUrl) } : void 0;
31992
+ const consolidateEndpoint = options.consolidate?.endpointOverride ?? options.extract.endpointOverride;
31993
+ const consolidateOptions = options.consolidate ? {
31994
+ ...options.consolidate,
31995
+ ...subPassAuth(options.consolidate.baseUrl),
31996
+ ...consolidateEndpoint !== void 0 && { endpointOverride: consolidateEndpoint }
31997
+ } : void 0;
31993
31998
  const injectionClassifierOptions = options.injectionClassifier ? { ...options.injectionClassifier, ...subPassAuth(options.injectionClassifier.baseUrl) } : void 0;
31994
31999
  if (!options.memoryStore && options.retainCtx.vaultCtx.entityCtx && !options.entityCtx) {
31995
32000
  getLogger().warn(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anuma/sdk",
3
- "version": "7.3.2",
3
+ "version": "7.3.3",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",