@anuma/sdk 6.7.2 → 6.8.0

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.
Files changed (32) hide show
  1. package/dist/{react/chunk-B5UPJRCU.mjs → expo/chunk-CJ32HO6Q.mjs} +62 -11
  2. package/dist/expo/{chunk-VOMDHMKH.mjs → chunk-OUFITMDL.mjs} +1 -1
  3. package/dist/expo/{chunk-2YHVYDEL.mjs → chunk-YO5UXOC4.mjs} +3 -2
  4. package/dist/{react/consolidate-ZCGS7QUA.mjs → expo/consolidate-4BMNVOL4.mjs} +3 -2
  5. package/dist/expo/index.cjs +101 -18
  6. package/dist/expo/index.d.mts +105 -2
  7. package/dist/expo/index.d.ts +105 -2
  8. package/dist/expo/index.mjs +34 -10
  9. package/dist/expo/{recall-M3JVFTZL.mjs → recall-IEKVX4JL.mjs} +2 -2
  10. package/dist/index.cjs +10 -0
  11. package/dist/index.d.mts +49 -1
  12. package/dist/index.d.ts +49 -1
  13. package/dist/index.mjs +8 -0
  14. package/dist/{expo/chunk-B5UPJRCU.mjs → react/chunk-CJ32HO6Q.mjs} +62 -11
  15. package/dist/react/{chunk-2ARMO2NN.mjs → chunk-DY5VGC6K.mjs} +1 -1
  16. package/dist/react/{chunk-S6WPXD5N.mjs → chunk-POCLKALT.mjs} +3 -2
  17. package/dist/{expo/consolidate-TWE6OSSZ.mjs → react/consolidate-5TP3J6BY.mjs} +3 -2
  18. package/dist/react/index.cjs +101 -18
  19. package/dist/react/index.d.mts +105 -2
  20. package/dist/react/index.d.ts +105 -2
  21. package/dist/react/index.mjs +34 -10
  22. package/dist/react/{recall-ROEK55FJ.mjs → recall-B2AIAPCM.mjs} +2 -2
  23. package/dist/server/{chunk-TD7SMY7C.mjs → chunk-FS6DNUNT.mjs} +3 -2
  24. package/dist/server/{chunk-VHWLLYKO.mjs → chunk-KF5OU4IN.mjs} +62 -11
  25. package/dist/server/{chunk-CR5P3YIK.mjs → chunk-MEQ2PAEX.mjs} +1 -1
  26. package/dist/server/{consolidate-FWYK5KXB.mjs → consolidate-QDWEYFTZ.mjs} +3 -2
  27. package/dist/server/index.cjs +101 -18
  28. package/dist/server/index.d.mts +105 -2
  29. package/dist/server/index.d.ts +105 -2
  30. package/dist/server/index.mjs +34 -10
  31. package/dist/server/{recall-CGDEW2LQ.mjs → recall-2GAPE2XH.mjs} +2 -2
  32. package/package.json +1 -1
@@ -53,6 +53,12 @@ function withInternalFlowMarker(systemPrompt) {
53
53
  ${systemPrompt}`;
54
54
  }
55
55
 
56
+ // src/lib/taskType.ts
57
+ var TASK_TYPE_HEADER = "X-Anuma-Task-Type";
58
+ function taskTypeHeader(taskType) {
59
+ return taskType ? { [TASK_TYPE_HEADER]: taskType } : {};
60
+ }
61
+
56
62
  // src/lib/memory/portalLlm.ts
57
63
  function defaultBaseUrl() {
58
64
  return typeof process !== "undefined" && process.env?.ANUMA_PORTAL_BASE_URL || BASE_URL;
@@ -115,9 +121,15 @@ async function callPortalJsonCompletion(req) {
115
121
  const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
116
122
  const startedAt = Date.now();
117
123
  const overBudget = () => req.totalTimeoutMs !== void 0 && Date.now() - startedAt >= req.totalTimeoutMs;
124
+ let lastFailure;
125
+ const giveUp = () => {
126
+ req.onFailure?.(lastFailure ?? { reason: "network", attempts: maxAttempts });
127
+ return null;
128
+ };
118
129
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
119
130
  if (attempt > 1 && overBudget()) {
120
131
  log.warn(`[${req.tag}] over time budget before attempt ${attempt}, giving up`);
132
+ lastFailure = { reason: "time-budget-exhausted", attempts: attempt - 1 };
121
133
  break;
122
134
  }
123
135
  const attemptReq = req.totalTimeoutMs !== void 0 ? {
@@ -129,9 +141,14 @@ async function callPortalJsonCompletion(req) {
129
141
  } : req;
130
142
  const outcome = await attemptPortalJson(attemptReq, endpoint);
131
143
  if (outcome.kind === "ok") return outcome.value;
144
+ lastFailure = {
145
+ reason: outcome.code,
146
+ ...outcome.httpStatus !== void 0 && { httpStatus: outcome.httpStatus },
147
+ attempts: attempt
148
+ };
132
149
  if (outcome.kind === "terminal") {
133
150
  log.warn(`[${req.tag}] ${outcome.reason}`);
134
- return null;
151
+ return giveUp();
135
152
  }
136
153
  if (attempt >= maxAttempts) {
137
154
  log.warn(`[${req.tag}] ${outcome.reason} \u2014 attempt ${attempt}/${maxAttempts}, giving up`);
@@ -143,19 +160,21 @@ async function callPortalJsonCompletion(req) {
143
160
  log.warn(
144
161
  `[${req.tag}] ${outcome.reason} \u2014 attempt ${attempt}/${maxAttempts}, over time budget, giving up`
145
162
  );
163
+ lastFailure = { reason: "time-budget-exhausted", attempts: attempt };
146
164
  break;
147
165
  }
148
166
  log.warn(`[${req.tag}] ${outcome.reason} \u2014 attempt ${attempt}/${maxAttempts}, retrying`);
149
167
  if (delay > 0) await sleep(delay);
150
168
  }
151
- return null;
169
+ return giveUp();
152
170
  }
153
171
  async function attemptPortalJson(req, endpoint) {
154
172
  const baseUrl = req.baseUrl ?? defaultBaseUrl();
155
173
  const fetchImpl = req.fetchFn ?? fetch;
156
174
  const timeoutMs = req.timeoutMs ?? 6e4;
157
175
  const authHeaders = await resolvePortalAuthHeaders(req, req.tag);
158
- if (authHeaders === null) return { kind: "terminal", reason: "auth unavailable (no token)" };
176
+ if (authHeaders === null)
177
+ return { kind: "terminal", code: "auth-unavailable", reason: "auth unavailable (no token)" };
159
178
  const isAnthropic = req.model.startsWith("anthropic/");
160
179
  const prefill = isAnthropic ? "{" : "";
161
180
  const messages = [
@@ -182,37 +201,67 @@ async function attemptPortalJson(req, endpoint) {
182
201
  try {
183
202
  response = await fetchImpl(`${baseUrl}${endpoint}`, {
184
203
  method: "POST",
185
- headers: { ...authHeaders, "Content-Type": "application/json" },
204
+ // Attached HERE, at the one transport every background memory op shares, so
205
+ // a new flow gets the provenance by construction rather than by remembering.
206
+ headers: {
207
+ ...authHeaders,
208
+ ...taskTypeHeader(req.taskType),
209
+ "Content-Type": "application/json"
210
+ },
186
211
  body: JSON.stringify(requestBody),
187
212
  signal: controller.signal
188
213
  });
189
214
  } catch (err) {
190
215
  clearTimeout(timer);
191
- return { kind: "retryable", reason: `fetch failed: ${err.message}` };
216
+ return {
217
+ kind: "retryable",
218
+ code: "network",
219
+ reason: `fetch failed: ${err.message}`
220
+ };
192
221
  }
193
222
  if (!response.ok) {
194
223
  clearTimeout(timer);
195
224
  const reason = `portal returned ${response.status}`;
196
225
  if (response.status === 401) {
197
226
  const tokenAuth = !req.apiKey && !!req.getToken;
198
- return tokenAuth ? { kind: "retryable", reason: `${reason} (token may be expired; refreshing)` } : { kind: "terminal", reason };
227
+ return tokenAuth ? {
228
+ kind: "retryable",
229
+ code: "http-retryable",
230
+ reason: `${reason} (token may be expired; refreshing)`,
231
+ httpStatus: response.status
232
+ } : { kind: "terminal", code: "http-terminal", reason, httpStatus: response.status };
199
233
  }
200
- if (!isRetryableStatus(response.status)) return { kind: "terminal", reason };
234
+ if (!isRetryableStatus(response.status))
235
+ return { kind: "terminal", code: "http-terminal", reason, httpStatus: response.status };
201
236
  const retryAfterMs = parseRetryAfterMs(response.headers.get("retry-after"));
202
- return retryAfterMs !== null ? { kind: "retryable", reason, retryAfterMs } : { kind: "retryable", reason };
237
+ return {
238
+ kind: "retryable",
239
+ code: "http-retryable",
240
+ reason,
241
+ httpStatus: response.status,
242
+ ...retryAfterMs !== null && { retryAfterMs }
243
+ };
203
244
  }
204
245
  let body;
205
246
  try {
206
247
  body = await response.json();
207
248
  } catch (err) {
208
249
  clearTimeout(timer);
209
- return { kind: "retryable", reason: `response body parse failed: ${err.message}` };
250
+ return {
251
+ kind: "retryable",
252
+ code: "body-parse-failed",
253
+ reason: `response body parse failed: ${err.message}`
254
+ };
210
255
  }
211
256
  clearTimeout(timer);
212
257
  logPortalUsage(body, req.tag);
213
258
  const rawContent = extractCompletionContent(body);
214
259
  if (!rawContent) {
215
- return { kind: "retryable", reason: "portal response had no completion content" };
260
+ return {
261
+ kind: "retryable",
262
+ code: "empty-content",
263
+ reason: "portal response had no completion content"
264
+ };
216
265
  }
217
266
  const looksLikeContinuation = prefill && /^\s*"/.test(rawContent);
218
267
  const content = looksLikeContinuation ? prefill + rawContent : rawContent;
@@ -223,11 +272,12 @@ async function attemptPortalJson(req, endpoint) {
223
272
  } catch (err) {
224
273
  return {
225
274
  kind: "retryable",
275
+ code: "invalid-json",
226
276
  reason: `completion was not valid JSON: ${err.message}`
227
277
  };
228
278
  }
229
279
  if (value === null) {
230
- return { kind: "retryable", reason: "completion parsed to null" };
280
+ return { kind: "retryable", code: "null-completion", reason: "completion parsed to null" };
231
281
  }
232
282
  return { kind: "ok", value };
233
283
  }
@@ -305,6 +355,7 @@ export {
305
355
  validateEndpointOverride,
306
356
  INTERNAL_FLOW_MARKER,
307
357
  withInternalFlowMarker,
358
+ taskTypeHeader,
308
359
  supportsResponseFormat,
309
360
  resolvePortalAuthHeaders,
310
361
  callPortalJsonCompletion,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getLogger
3
- } from "./chunk-B5UPJRCU.mjs";
3
+ } from "./chunk-CJ32HO6Q.mjs";
4
4
 
5
5
  // src/lib/pii/patterns.ts
6
6
  function luhnCheck(digits) {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  callPortalJsonCompletion,
3
3
  getLogger
4
- } from "./chunk-B5UPJRCU.mjs";
4
+ } from "./chunk-CJ32HO6Q.mjs";
5
5
  import {
6
6
  BASE_URL,
7
7
  createClientConfig
@@ -6807,7 +6807,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
6807
6807
  subQueries = decomp.subQueries;
6808
6808
  }
6809
6809
  }
6810
- const { recall: recall2 } = await import("./recall-M3JVFTZL.mjs");
6810
+ const { recall: recall2 } = await import("./recall-IEKVX4JL.mjs");
6811
6811
  let recallDegraded = [];
6812
6812
  const result = await recall2(
6813
6813
  query,
@@ -7074,6 +7074,7 @@ Output strict JSON, no prose: { "expand": [<entity names to expand, verbatim fro
7074
7074
  ...options.apiKey !== void 0 && { apiKey: options.apiKey },
7075
7075
  ...options.getToken !== void 0 && { getToken: options.getToken },
7076
7076
  ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
7077
+ taskType: "memory_graph",
7077
7078
  model: options.model ?? DEFAULT_REFINER_MODEL,
7078
7079
  systemPrompt,
7079
7080
  userMessage: `Question: ${query}
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  notifyConsolidationFallback,
3
3
  resolvePiiRedactor
4
- } from "./chunk-2ARMO2NN.mjs";
4
+ } from "./chunk-OUFITMDL.mjs";
5
5
  import {
6
6
  callPortalJsonCompletion
7
- } from "./chunk-B5UPJRCU.mjs";
7
+ } from "./chunk-CJ32HO6Q.mjs";
8
8
  import "./chunk-GYKJOWEO.mjs";
9
9
 
10
10
  // src/lib/memory/consolidate.ts
@@ -77,6 +77,7 @@ ${candidateText}`;
77
77
  ...options.apiKey !== void 0 && { apiKey: options.apiKey },
78
78
  ...options.getToken !== void 0 && { getToken: options.getToken },
79
79
  ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
80
+ taskType: "memory_consolidate",
80
81
  model: options.model ?? DEFAULT_CONSOLIDATION_MODEL,
81
82
  systemPrompt: SYSTEM_PROMPT,
82
83
  userMessage,
@@ -4578,6 +4578,18 @@ var init_internalFlowMarker = __esm({
4578
4578
  }
4579
4579
  });
4580
4580
 
4581
+ // src/lib/taskType.ts
4582
+ function taskTypeHeader(taskType) {
4583
+ return taskType ? { [TASK_TYPE_HEADER]: taskType } : {};
4584
+ }
4585
+ var TASK_TYPE_HEADER;
4586
+ var init_taskType = __esm({
4587
+ "src/lib/taskType.ts"() {
4588
+ "use strict";
4589
+ TASK_TYPE_HEADER = "X-Anuma-Task-Type";
4590
+ }
4591
+ });
4592
+
4581
4593
  // src/lib/db/entities/types.ts
4582
4594
  function normalizeEntityName(name) {
4583
4595
  return name.trim().toLowerCase();
@@ -6151,9 +6163,15 @@ async function callPortalJsonCompletion(req) {
6151
6163
  const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
6152
6164
  const startedAt = Date.now();
6153
6165
  const overBudget = () => req.totalTimeoutMs !== void 0 && Date.now() - startedAt >= req.totalTimeoutMs;
6166
+ let lastFailure;
6167
+ const giveUp = () => {
6168
+ req.onFailure?.(lastFailure ?? { reason: "network", attempts: maxAttempts });
6169
+ return null;
6170
+ };
6154
6171
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
6155
6172
  if (attempt > 1 && overBudget()) {
6156
6173
  log.warn(`[${req.tag}] over time budget before attempt ${attempt}, giving up`);
6174
+ lastFailure = { reason: "time-budget-exhausted", attempts: attempt - 1 };
6157
6175
  break;
6158
6176
  }
6159
6177
  const attemptReq = req.totalTimeoutMs !== void 0 ? {
@@ -6165,9 +6183,14 @@ async function callPortalJsonCompletion(req) {
6165
6183
  } : req;
6166
6184
  const outcome = await attemptPortalJson(attemptReq, endpoint);
6167
6185
  if (outcome.kind === "ok") return outcome.value;
6186
+ lastFailure = {
6187
+ reason: outcome.code,
6188
+ ...outcome.httpStatus !== void 0 && { httpStatus: outcome.httpStatus },
6189
+ attempts: attempt
6190
+ };
6168
6191
  if (outcome.kind === "terminal") {
6169
6192
  log.warn(`[${req.tag}] ${outcome.reason}`);
6170
- return null;
6193
+ return giveUp();
6171
6194
  }
6172
6195
  if (attempt >= maxAttempts) {
6173
6196
  log.warn(`[${req.tag}] ${outcome.reason} \u2014 attempt ${attempt}/${maxAttempts}, giving up`);
@@ -6179,19 +6202,21 @@ async function callPortalJsonCompletion(req) {
6179
6202
  log.warn(
6180
6203
  `[${req.tag}] ${outcome.reason} \u2014 attempt ${attempt}/${maxAttempts}, over time budget, giving up`
6181
6204
  );
6205
+ lastFailure = { reason: "time-budget-exhausted", attempts: attempt };
6182
6206
  break;
6183
6207
  }
6184
6208
  log.warn(`[${req.tag}] ${outcome.reason} \u2014 attempt ${attempt}/${maxAttempts}, retrying`);
6185
6209
  if (delay > 0) await sleep3(delay);
6186
6210
  }
6187
- return null;
6211
+ return giveUp();
6188
6212
  }
6189
6213
  async function attemptPortalJson(req, endpoint) {
6190
6214
  const baseUrl = req.baseUrl ?? defaultBaseUrl();
6191
6215
  const fetchImpl = req.fetchFn ?? fetch;
6192
6216
  const timeoutMs = req.timeoutMs ?? 6e4;
6193
6217
  const authHeaders = await resolvePortalAuthHeaders(req, req.tag);
6194
- if (authHeaders === null) return { kind: "terminal", reason: "auth unavailable (no token)" };
6218
+ if (authHeaders === null)
6219
+ return { kind: "terminal", code: "auth-unavailable", reason: "auth unavailable (no token)" };
6195
6220
  const isAnthropic = req.model.startsWith("anthropic/");
6196
6221
  const prefill = isAnthropic ? "{" : "";
6197
6222
  const messages = [
@@ -6218,37 +6243,67 @@ async function attemptPortalJson(req, endpoint) {
6218
6243
  try {
6219
6244
  response = await fetchImpl(`${baseUrl}${endpoint}`, {
6220
6245
  method: "POST",
6221
- headers: { ...authHeaders, "Content-Type": "application/json" },
6246
+ // Attached HERE, at the one transport every background memory op shares, so
6247
+ // a new flow gets the provenance by construction rather than by remembering.
6248
+ headers: {
6249
+ ...authHeaders,
6250
+ ...taskTypeHeader(req.taskType),
6251
+ "Content-Type": "application/json"
6252
+ },
6222
6253
  body: JSON.stringify(requestBody),
6223
6254
  signal: controller.signal
6224
6255
  });
6225
6256
  } catch (err) {
6226
6257
  clearTimeout(timer);
6227
- return { kind: "retryable", reason: `fetch failed: ${err.message}` };
6258
+ return {
6259
+ kind: "retryable",
6260
+ code: "network",
6261
+ reason: `fetch failed: ${err.message}`
6262
+ };
6228
6263
  }
6229
6264
  if (!response.ok) {
6230
6265
  clearTimeout(timer);
6231
6266
  const reason = `portal returned ${response.status}`;
6232
6267
  if (response.status === 401) {
6233
6268
  const tokenAuth = !req.apiKey && !!req.getToken;
6234
- return tokenAuth ? { kind: "retryable", reason: `${reason} (token may be expired; refreshing)` } : { kind: "terminal", reason };
6235
- }
6236
- if (!isRetryableStatus(response.status)) return { kind: "terminal", reason };
6269
+ return tokenAuth ? {
6270
+ kind: "retryable",
6271
+ code: "http-retryable",
6272
+ reason: `${reason} (token may be expired; refreshing)`,
6273
+ httpStatus: response.status
6274
+ } : { kind: "terminal", code: "http-terminal", reason, httpStatus: response.status };
6275
+ }
6276
+ if (!isRetryableStatus(response.status))
6277
+ return { kind: "terminal", code: "http-terminal", reason, httpStatus: response.status };
6237
6278
  const retryAfterMs = parseRetryAfterMs(response.headers.get("retry-after"));
6238
- return retryAfterMs !== null ? { kind: "retryable", reason, retryAfterMs } : { kind: "retryable", reason };
6279
+ return {
6280
+ kind: "retryable",
6281
+ code: "http-retryable",
6282
+ reason,
6283
+ httpStatus: response.status,
6284
+ ...retryAfterMs !== null && { retryAfterMs }
6285
+ };
6239
6286
  }
6240
6287
  let body;
6241
6288
  try {
6242
6289
  body = await response.json();
6243
6290
  } catch (err) {
6244
6291
  clearTimeout(timer);
6245
- return { kind: "retryable", reason: `response body parse failed: ${err.message}` };
6292
+ return {
6293
+ kind: "retryable",
6294
+ code: "body-parse-failed",
6295
+ reason: `response body parse failed: ${err.message}`
6296
+ };
6246
6297
  }
6247
6298
  clearTimeout(timer);
6248
6299
  logPortalUsage(body, req.tag);
6249
6300
  const rawContent = extractCompletionContent(body);
6250
6301
  if (!rawContent) {
6251
- return { kind: "retryable", reason: "portal response had no completion content" };
6302
+ return {
6303
+ kind: "retryable",
6304
+ code: "empty-content",
6305
+ reason: "portal response had no completion content"
6306
+ };
6252
6307
  }
6253
6308
  const looksLikeContinuation = prefill && /^\s*"/.test(rawContent);
6254
6309
  const content = looksLikeContinuation ? prefill + rawContent : rawContent;
@@ -6259,11 +6314,12 @@ async function attemptPortalJson(req, endpoint) {
6259
6314
  } catch (err) {
6260
6315
  return {
6261
6316
  kind: "retryable",
6317
+ code: "invalid-json",
6262
6318
  reason: `completion was not valid JSON: ${err.message}`
6263
6319
  };
6264
6320
  }
6265
6321
  if (value === null) {
6266
- return { kind: "retryable", reason: "completion parsed to null" };
6322
+ return { kind: "retryable", code: "null-completion", reason: "completion parsed to null" };
6267
6323
  }
6268
6324
  return { kind: "ok", value };
6269
6325
  }
@@ -6340,6 +6396,7 @@ var init_portalLlm = __esm({
6340
6396
  init_endpointOverride();
6341
6397
  init_internalFlowMarker();
6342
6398
  init_logger();
6399
+ init_taskType();
6343
6400
  RESPONSE_FORMAT_OK = /* @__PURE__ */ new Set(["openai", "inclusionai", "deepseek"]);
6344
6401
  RESPONSE_SCHEMA_OK = /* @__PURE__ */ new Set(["openai"]);
6345
6402
  RETRYABLE_HTTP = /* @__PURE__ */ new Set([408, 409, 425, 429]);
@@ -7126,6 +7183,7 @@ Output strict JSON, no prose: { "expand": [<entity names to expand, verbatim fro
7126
7183
  ...options.apiKey !== void 0 && { apiKey: options.apiKey },
7127
7184
  ...options.getToken !== void 0 && { getToken: options.getToken },
7128
7185
  ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
7186
+ taskType: "memory_graph",
7129
7187
  model: options.model ?? DEFAULT_REFINER_MODEL,
7130
7188
  systemPrompt,
7131
7189
  userMessage: `Question: ${query}
@@ -9209,6 +9267,7 @@ ${candidateText}`;
9209
9267
  ...options.apiKey !== void 0 && { apiKey: options.apiKey },
9210
9268
  ...options.getToken !== void 0 && { getToken: options.getToken },
9211
9269
  ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
9270
+ taskType: "memory_consolidate",
9212
9271
  model: options.model ?? DEFAULT_CONSOLIDATION_MODEL,
9213
9272
  systemPrompt: SYSTEM_PROMPT3,
9214
9273
  userMessage,
@@ -14042,6 +14101,7 @@ async function deleteConversationSummaryOp(ctx, conversationId) {
14042
14101
  // src/lib/chat/summarize.ts
14043
14102
  init_internalFlowMarker();
14044
14103
  init_logger();
14104
+ init_taskType();
14045
14105
  var DEFAULT_SUMMARY_TOKEN_THRESHOLD = 4e3;
14046
14106
  var DEFAULT_SUMMARY_MIN_WINDOW_MESSAGES = 4;
14047
14107
  var DEFAULT_SUMMARY_MODEL = "cerebras/qwen-3-235b-a22b-instruct-2507";
@@ -14228,7 +14288,12 @@ async function callSummarizationLlm(prompt, model, token, baseUrl) {
14228
14288
  method: "POST",
14229
14289
  headers: {
14230
14290
  "Content-Type": "application/json",
14231
- Authorization: `Bearer ${token}`
14291
+ Authorization: `Bearer ${token}`,
14292
+ // Names the task so the portal can own this prompt server-side instead of
14293
+ // trusting the one we build. Summarization is the archetypal Class-B flow:
14294
+ // one fixed purpose, no conversation, and today its instructions are ours
14295
+ // to reword.
14296
+ ...taskTypeHeader("summarize")
14232
14297
  },
14233
14298
  body: JSON.stringify({
14234
14299
  model,
@@ -15861,6 +15926,7 @@ async function classifyInjectionCandidates(candidates, options) {
15861
15926
  ...options.apiKey !== void 0 && { apiKey: options.apiKey },
15862
15927
  ...options.getToken !== void 0 && { getToken: options.getToken },
15863
15928
  ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
15929
+ taskType: "memory_injection_check",
15864
15930
  model: options.model ?? DEFAULT_MODEL,
15865
15931
  systemPrompt: SYSTEM_PROMPT,
15866
15932
  userMessage: `Candidate facts:
@@ -16562,10 +16628,15 @@ async function extractFacts(messages, options) {
16562
16628
  }
16563
16629
  const transcript = transcriptLines.join("\n");
16564
16630
  const today = formatLocalDate(options.now ?? Date.now());
16631
+ let failure;
16565
16632
  const parsed = await callPortalJsonCompletion({
16633
+ onFailure: (f) => {
16634
+ failure = f;
16635
+ },
16566
16636
  ...options.apiKey !== void 0 && { apiKey: options.apiKey },
16567
16637
  ...options.getToken !== void 0 && { getToken: options.getToken },
16568
16638
  ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
16639
+ taskType: "memory_extract",
16569
16640
  ...options.endpointOverride !== void 0 && {
16570
16641
  endpointOverride: options.endpointOverride
16571
16642
  },
@@ -16585,7 +16656,7 @@ Extract durable user facts.`,
16585
16656
  ...options.backoffMs && { backoffMs: options.backoffMs }
16586
16657
  });
16587
16658
  if (parsed === null) {
16588
- options.onExhaustedEmpty?.();
16659
+ options.onExhaustedEmpty?.(failure ?? { reason: "empty-content", attempts: 1 });
16589
16660
  return [];
16590
16661
  }
16591
16662
  const fallbackSourceId = [...messages].reverse().find((m) => m.role === "user")?.id;
@@ -16629,14 +16700,16 @@ async function extractAndRetain(messages, retainCtx, options) {
16629
16700
  ...resolvedConsolidatePii !== void 0 && { piiRedaction: resolvedConsolidatePii }
16630
16701
  } : void 0;
16631
16702
  let exhaustedEmpty = false;
16703
+ let exhaustedFailure;
16632
16704
  let droppedAfterRedaction = false;
16633
16705
  const callerOnExhaustedEmpty = options.extract.onExhaustedEmpty;
16634
16706
  const callerOnCandidatesDropped = options.extract.onCandidatesDropped;
16635
16707
  const candidates = await extractFacts(messages, {
16636
16708
  ...options.extract,
16637
- onExhaustedEmpty: () => {
16709
+ onExhaustedEmpty: (failure) => {
16638
16710
  exhaustedEmpty = true;
16639
- callerOnExhaustedEmpty?.();
16711
+ exhaustedFailure = failure;
16712
+ callerOnExhaustedEmpty?.(failure);
16640
16713
  },
16641
16714
  onCandidatesDropped: () => {
16642
16715
  droppedAfterRedaction = true;
@@ -16755,12 +16828,19 @@ async function extractAndRetain(messages, retainCtx, options) {
16755
16828
  results,
16756
16829
  failedCount: failedWrites,
16757
16830
  outcome,
16758
- quarantined: quarantinedInfo
16831
+ quarantined: quarantinedInfo,
16832
+ // Only meaningful alongside `outcome: "empty-after-retry"`. Returned as well
16833
+ // as pushed through the callback so a consumer that only inspects the result
16834
+ // (rather than wiring a hook) can still report WHY.
16835
+ ...exhaustedFailure !== void 0 && { failure: exhaustedFailure }
16759
16836
  };
16760
16837
  }
16838
+ var UTTERANCE_ECHO_RE = /^(?:said|says|asked|answered|replied|guessed|typed)\s*:\s*(?:'[^']*'|"[^"]*"|‘[^’]*’|“[^”]*”)[\s.!?]*$/iu;
16761
16839
  function isLowSignalContent(content, ownNames) {
16762
- const normalized = content.trim().replace(/[.!?]+$/, "").toLowerCase();
16840
+ const trimmed = content.trim();
16841
+ const normalized = trimmed.replace(/[.!?]+$/, "").toLowerCase();
16763
16842
  if (normalized.length < MIN_CONTENT_LENGTH) return true;
16843
+ if (UTTERANCE_ECHO_RE.test(trimmed)) return true;
16764
16844
  if (ownNames.some(
16765
16845
  (n) => normalized === n.trim().replace(/[.!?]+$/, "").toLowerCase()
16766
16846
  )) {
@@ -17125,6 +17205,7 @@ function createLlmDecayClassifier(options) {
17125
17205
  ...options.apiKey !== void 0 && { apiKey: options.apiKey },
17126
17206
  ...options.getToken !== void 0 && { getToken: options.getToken },
17127
17207
  ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
17208
+ taskType: "memory_decay",
17128
17209
  model: options.model ?? DEFAULT_MODEL3,
17129
17210
  systemPrompt: SYSTEM_PROMPT5,
17130
17211
  userMessage: `Memory content:
@@ -18282,6 +18363,7 @@ When a memory refers to one of these, reuse the EXACT existing name (same spelli
18282
18363
  ...options.apiKey !== void 0 && { apiKey: options.apiKey },
18283
18364
  ...options.getToken !== void 0 && { getToken: options.getToken },
18284
18365
  ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
18366
+ taskType: "memory_topic",
18285
18367
  ...options.endpointOverride !== void 0 && {
18286
18368
  endpointOverride: options.endpointOverride
18287
18369
  },
@@ -18475,6 +18557,7 @@ ${evidence}`);
18475
18557
  ...options.apiKey !== void 0 && { apiKey: options.apiKey },
18476
18558
  ...options.getToken !== void 0 && { getToken: options.getToken },
18477
18559
  ...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
18560
+ taskType: "memory_verify_support",
18478
18561
  model: options.model ?? DEFAULT_MODEL5,
18479
18562
  systemPrompt: SYSTEM_PROMPT7,
18480
18563
  userMessage: `Stored facts and their sources: