@anuma/sdk 6.30.1 → 6.30.2

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.
@@ -74,13 +74,21 @@ function responsesExtra(extra) {
74
74
  }
75
75
  return out;
76
76
  }
77
+ function splitEndpoint(endpoint) {
78
+ const cut = endpoint.search(/[?#]/);
79
+ const rawPath = cut === -1 ? endpoint : endpoint.slice(0, cut);
80
+ return {
81
+ path: rawPath.replace(/\/+$/, ""),
82
+ rest: cut === -1 ? "" : endpoint.slice(cut)
83
+ };
84
+ }
77
85
  var FOREIGN_ENDPOINT_SUFFIX = {
78
86
  chat: "/responses",
79
87
  responses: "/chat/completions"
80
88
  };
81
89
  function assertTransportMatchesEndpoint(transport, endpoint) {
82
90
  const foreign = FOREIGN_ENDPOINT_SUFFIX[transport];
83
- if (!endpoint.endsWith(foreign)) return;
91
+ if (!splitEndpoint(endpoint).path.endsWith(foreign)) return;
84
92
  throw new Error(
85
93
  `endpointOverride "${endpoint}" is the other transport's endpoint, but transport is "${transport}". The request body is built for the transport, so this sends the wrong shape and 400s without retry.`
86
94
  );
@@ -126,14 +134,20 @@ async function resolvePortalAuthHeaders(auth, tag) {
126
134
  }
127
135
  async function callPortalJsonCompletion(req) {
128
136
  const log = getLogger();
129
- let endpoint = req.transport === "responses" ? "/api/v1/responses" : "/api/v1/chat/completions";
137
+ const transport = req.transport ?? (requiresResponsesTransport(req.model) ? "responses" : "chat");
138
+ const autoUpgraded = req.transport === void 0 && transport === "responses";
139
+ let endpoint = transport === "responses" ? "/api/v1/responses" : "/api/v1/chat/completions";
130
140
  if (req.endpointOverride !== void 0) {
131
141
  const overrideValidation = validateEndpointOverride(req.endpointOverride);
132
142
  if (!overrideValidation.valid) {
133
143
  throw new Error(overrideValidation.message);
134
144
  }
135
145
  endpoint = overrideValidation.endpoint;
136
- assertTransportMatchesEndpoint(req.transport ?? "chat", endpoint);
146
+ const { path, rest } = splitEndpoint(endpoint);
147
+ if (autoUpgraded && path.endsWith("/chat/completions")) {
148
+ endpoint = `${path.slice(0, -"/chat/completions".length)}/responses${rest}`;
149
+ }
150
+ assertTransportMatchesEndpoint(transport, endpoint);
137
151
  }
138
152
  const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
139
153
  const startedAt = Date.now();
@@ -158,7 +172,10 @@ async function callPortalJsonCompletion(req) {
158
172
  ),
159
173
  ...reinforce && { reinforceJsonContract: true }
160
174
  } : reinforce ? { ...req, reinforceJsonContract: true } : req;
161
- const outcome = await attemptPortalJson(attemptReq, endpoint);
175
+ const outcome = await attemptPortalJson(
176
+ { ...attemptReq, transport },
177
+ endpoint
178
+ );
162
179
  if (outcome.kind === "ok") {
163
180
  req.onAttempt?.({ attempt, ok: true });
164
181
  return outcome.value;
@@ -310,6 +327,13 @@ async function attemptPortalJson(req, endpoint) {
310
327
  }
311
328
  clearTimeout(timer);
312
329
  logPortalUsage(body, req.tag);
330
+ if (isModerationResponse(body)) {
331
+ return {
332
+ kind: "terminal",
333
+ code: "content-flagged",
334
+ reason: "portal moderation refused the request"
335
+ };
336
+ }
313
337
  const rawContent = extractCompletionContent(body);
314
338
  if (!rawContent) {
315
339
  return {
@@ -395,6 +419,9 @@ function logPortalUsage(body, tag) {
395
419
  } catch {
396
420
  }
397
421
  }
422
+ function isModerationResponse(body) {
423
+ return typeof body === "object" && body !== null && body.id === "moderation";
424
+ }
398
425
  function extractCompletionContent(body) {
399
426
  if (typeof body !== "object" || body === null) return null;
400
427
  const responsesText = extractResponsesContent(body);
@@ -2,7 +2,7 @@ import {
2
2
  callPortalJsonCompletion,
3
3
  notifyConsolidationFallback,
4
4
  resolvePiiRedactor
5
- } from "./chunk-Z2QBL4HB.mjs";
5
+ } from "./chunk-7GHESNOH.mjs";
6
6
  import "./chunk-3RPGXXPZ.mjs";
7
7
 
8
8
  // src/lib/memory/consolidate.ts
@@ -15076,9 +15076,17 @@ function responsesExtra(extra) {
15076
15076
  }
15077
15077
  return out;
15078
15078
  }
15079
+ function splitEndpoint(endpoint) {
15080
+ const cut = endpoint.search(/[?#]/);
15081
+ const rawPath = cut === -1 ? endpoint : endpoint.slice(0, cut);
15082
+ return {
15083
+ path: rawPath.replace(/\/+$/, ""),
15084
+ rest: cut === -1 ? "" : endpoint.slice(cut)
15085
+ };
15086
+ }
15079
15087
  function assertTransportMatchesEndpoint(transport, endpoint) {
15080
15088
  const foreign = FOREIGN_ENDPOINT_SUFFIX[transport];
15081
- if (!endpoint.endsWith(foreign)) return;
15089
+ if (!splitEndpoint(endpoint).path.endsWith(foreign)) return;
15082
15090
  throw new Error(
15083
15091
  `endpointOverride "${endpoint}" is the other transport's endpoint, but transport is "${transport}". The request body is built for the transport, so this sends the wrong shape and 400s without retry.`
15084
15092
  );
@@ -15123,14 +15131,20 @@ async function resolvePortalAuthHeaders(auth, tag) {
15123
15131
  }
15124
15132
  async function callPortalJsonCompletion(req) {
15125
15133
  const log = getLogger();
15126
- let endpoint = req.transport === "responses" ? "/api/v1/responses" : "/api/v1/chat/completions";
15134
+ const transport = req.transport ?? (requiresResponsesTransport(req.model) ? "responses" : "chat");
15135
+ const autoUpgraded = req.transport === void 0 && transport === "responses";
15136
+ let endpoint = transport === "responses" ? "/api/v1/responses" : "/api/v1/chat/completions";
15127
15137
  if (req.endpointOverride !== void 0) {
15128
15138
  const overrideValidation = validateEndpointOverride(req.endpointOverride);
15129
15139
  if (!overrideValidation.valid) {
15130
15140
  throw new Error(overrideValidation.message);
15131
15141
  }
15132
15142
  endpoint = overrideValidation.endpoint;
15133
- assertTransportMatchesEndpoint(req.transport ?? "chat", endpoint);
15143
+ const { path, rest } = splitEndpoint(endpoint);
15144
+ if (autoUpgraded && path.endsWith("/chat/completions")) {
15145
+ endpoint = `${path.slice(0, -"/chat/completions".length)}/responses${rest}`;
15146
+ }
15147
+ assertTransportMatchesEndpoint(transport, endpoint);
15134
15148
  }
15135
15149
  const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
15136
15150
  const startedAt = Date.now();
@@ -15155,7 +15169,10 @@ async function callPortalJsonCompletion(req) {
15155
15169
  ),
15156
15170
  ...reinforce && { reinforceJsonContract: true }
15157
15171
  } : reinforce ? { ...req, reinforceJsonContract: true } : req;
15158
- const outcome = await attemptPortalJson(attemptReq, endpoint);
15172
+ const outcome = await attemptPortalJson(
15173
+ { ...attemptReq, transport },
15174
+ endpoint
15175
+ );
15159
15176
  if (outcome.kind === "ok") {
15160
15177
  req.onAttempt?.({ attempt, ok: true });
15161
15178
  return outcome.value;
@@ -15307,6 +15324,13 @@ async function attemptPortalJson(req, endpoint) {
15307
15324
  }
15308
15325
  clearTimeout(timer);
15309
15326
  logPortalUsage(body, req.tag);
15327
+ if (isModerationResponse(body)) {
15328
+ return {
15329
+ kind: "terminal",
15330
+ code: "content-flagged",
15331
+ reason: "portal moderation refused the request"
15332
+ };
15333
+ }
15310
15334
  const rawContent = extractCompletionContent(body);
15311
15335
  if (!rawContent) {
15312
15336
  return {
@@ -15392,6 +15416,9 @@ function logPortalUsage(body, tag) {
15392
15416
  } catch {
15393
15417
  }
15394
15418
  }
15419
+ function isModerationResponse(body) {
15420
+ return typeof body === "object" && body !== null && body.id === "moderation";
15421
+ }
15395
15422
  function extractCompletionContent(body) {
15396
15423
  if (typeof body !== "object" || body === null) return null;
15397
15424
  const responsesText = extractResponsesContent(body);
@@ -32417,6 +32444,28 @@ var BatchFailureError = class extends Error {
32417
32444
  this.terminal = terminal;
32418
32445
  }
32419
32446
  };
32447
+ var FlaggedBatchError = class extends Error {
32448
+ };
32449
+ function extracted(result) {
32450
+ return result.failedCount === 0 && result.outcome !== "empty-after-retry";
32451
+ }
32452
+ function batchError(result) {
32453
+ const failure = result.failure;
32454
+ if (failure?.reason === "http-terminal") {
32455
+ const status = failure.httpStatus;
32456
+ if (status !== void 0 && REQUEST_REJECTED_STATUSES.has(status))
32457
+ return new BatchFailureError(
32458
+ `Extraction rejected the batch (HTTP ${status}); not retried this session`,
32459
+ true
32460
+ );
32461
+ return new AccountFailureError(
32462
+ `Extraction refused for the account (HTTP ${status ?? "unknown"}); retried next session`
32463
+ );
32464
+ }
32465
+ if (result.failedCount > 0 || failure !== void 0 && CONTENT_FAILURE_REASONS.has(failure.reason))
32466
+ return new BatchFailureError("Extraction batch incomplete; retained for retry", false);
32467
+ return new Error("Extraction batch incomplete; retained for retry");
32468
+ }
32420
32469
  var AccountFailureError = class extends Error {
32421
32470
  };
32422
32471
  var LockedSourcesError = class extends Error {
@@ -32425,6 +32474,16 @@ var LockedSourcesError = class extends Error {
32425
32474
  this.persistentIds = persistentIds;
32426
32475
  }
32427
32476
  };
32477
+ function splitTurns(messages) {
32478
+ const turns = [];
32479
+ for (const message of messages) {
32480
+ const last = turns[turns.length - 1];
32481
+ if (!last || message.role === "user" && last.some((m) => m.role === "user"))
32482
+ turns.push([message]);
32483
+ else last.push(message);
32484
+ }
32485
+ return turns;
32486
+ }
32428
32487
  function idsOf(job) {
32429
32488
  return JSON.parse(String(job._getRaw("message_ids")));
32430
32489
  }
@@ -32575,6 +32634,10 @@ function createDurableAutoExtractor(options) {
32575
32634
  skippedThisSession.add(job.id);
32576
32635
  return false;
32577
32636
  }
32637
+ if (error instanceof FlaggedBatchError) {
32638
+ await acknowledge(job, ids, loaded, true);
32639
+ return true;
32640
+ }
32578
32641
  const counted = error instanceof BatchFailureError || error instanceof LockedSourcesError && error.persistentIds.length > 0;
32579
32642
  if (!counted) return false;
32580
32643
  const prior = sessionFailures.get(job.id);
@@ -32701,37 +32764,50 @@ function createDurableAutoExtractor(options) {
32701
32764
  const messages = loaded.flatMap(
32702
32765
  (m) => m && m.conversationId === conversationId && (m.role === "user" || m.role === "assistant") ? [{ id: m.uniqueId, role: m.role, content: m.content }] : []
32703
32766
  );
32704
- let success = messages.length === 0;
32705
- let result;
32706
- if (messages.length) {
32707
- result = await extractBatch(
32708
- messages,
32767
+ const jobScope = currentScope() === "private" ? "private" : String(job._getRaw("scope"));
32768
+ const jobFolderId = job._getRaw("folder_id") ?? null;
32769
+ const runExtraction = async (batch, batchIds) => {
32770
+ const result = await extractBatch(
32771
+ batch,
32709
32772
  conversationId,
32710
- ids,
32711
- currentScope() === "private" ? "private" : String(job._getRaw("scope")),
32712
- job._getRaw("folder_id") ?? null
32773
+ batchIds,
32774
+ jobScope,
32775
+ jobFolderId
32713
32776
  );
32714
- success = result.failedCount === 0 && result.outcome !== "empty-after-retry";
32715
32777
  options.onTurnComplete?.(result);
32716
- }
32717
- if (!success) {
32718
- const failure = result?.failure;
32719
- if (failure?.reason === "http-terminal") {
32720
- const status = failure.httpStatus;
32721
- if (status !== void 0 && REQUEST_REJECTED_STATUSES.has(status))
32722
- throw new BatchFailureError(
32723
- `Extraction rejected the batch (HTTP ${status}); not retried this session`,
32724
- true
32778
+ return result;
32779
+ };
32780
+ const flaggedIds = /* @__PURE__ */ new Set();
32781
+ if (messages.length) {
32782
+ const result = await runExtraction(messages, ids);
32783
+ if (result.failure?.reason === "content-flagged") {
32784
+ const turns = splitTurns(messages);
32785
+ if (turns.length < 2)
32786
+ throw new FlaggedBatchError("Extraction batch refused by moderation; abandoned");
32787
+ for (const turn of turns) {
32788
+ const turnResult = await runExtraction(
32789
+ turn,
32790
+ turn.map((m) => m.id)
32725
32791
  );
32726
- throw new AccountFailureError(
32727
- `Extraction refused for the account (HTTP ${status ?? "unknown"}); retried next session`
32728
- );
32729
- }
32730
- if ((result?.failedCount ?? 0) > 0 || failure !== void 0 && CONTENT_FAILURE_REASONS.has(failure.reason))
32731
- throw new BatchFailureError("Extraction batch incomplete; retained for retry", false);
32732
- throw new Error("Extraction batch incomplete; retained for retry");
32792
+ if (turnResult.failure?.reason === "content-flagged")
32793
+ for (const m of turn) flaggedIds.add(m.id);
32794
+ else if (!extracted(turnResult)) throw batchError(turnResult);
32795
+ }
32796
+ if (flaggedIds.size)
32797
+ reportError(
32798
+ new Error(
32799
+ `Dropped ${flaggedIds.size} source id(s) of an extraction batch refused by moderation`
32800
+ ),
32801
+ conversationId
32802
+ );
32803
+ } else if (!extracted(result)) throw batchError(result);
32733
32804
  }
32734
- await acknowledge(job, ids, loaded, false);
32805
+ await acknowledge(
32806
+ job,
32807
+ ids,
32808
+ loaded,
32809
+ ids.slice(-2).some((id) => flaggedIds.has(id))
32810
+ );
32735
32811
  scheduleAfterSuccess = true;
32736
32812
  } catch (error) {
32737
32813
  attempts.set(job.id, attempted + 1);
@@ -4988,7 +4988,12 @@ type PortalLlmFailureReason =
4988
4988
  /** Content parsed to a literal `null`, which is never a valid response. */
4989
4989
  | "null-completion"
4990
4990
  /** `totalTimeoutMs` was spent before the next attempt could run. */
4991
- | "time-budget-exhausted";
4991
+ | "time-budget-exhausted"
4992
+ /**
4993
+ * The portal's moderation gate refused the request. Terminal: the same input
4994
+ * is flagged again on every retry. See {@link isModerationResponse}.
4995
+ */
4996
+ | "content-flagged";
4992
4997
  /**
4993
4998
  * One attempt of a {@link callPortalJsonCompletion} call, reported to
4994
4999
  * `onAttempt` as it settles — success included. The wire-level diagnostic the
@@ -6338,7 +6343,9 @@ interface ExtractFactsOptions extends PortalLlmAuth {
6338
6343
  * Optional per-call request path override, forwarded to
6339
6344
  * {@link callPortalJsonCompletion}. When set, the extraction call POSTs to
6340
6345
  * `baseUrl + endpointOverride` instead of the default
6341
- * `/api/v1/chat/completions` — path only, body unchanged. Lets callers route
6346
+ * `/api/v1/chat/completions`. The body follows the transport, not the path: a
6347
+ * model that needs the Responses API is moved from a `.../chat/completions`
6348
+ * override to its sibling `.../responses` with a Responses-shaped body. Lets callers route
6342
6349
  * this internal-utility pass to a dedicated endpoint. Invalid values throw at
6343
6350
  * call time (see {@link validateEndpointOverride}).
6344
6351
  *
@@ -9768,7 +9775,9 @@ interface TopicExtractOptions extends PortalLlmAuth {
9768
9775
  * Optional per-call request path override, forwarded to
9769
9776
  * {@link callPortalJsonCompletion}. When set, topic extraction POSTs to
9770
9777
  * `baseUrl + endpointOverride` instead of the default
9771
- * `/api/v1/chat/completions` — path only, body unchanged. Lets callers route
9778
+ * `/api/v1/chat/completions`. The body follows the transport, not the path: a
9779
+ * model that needs the Responses API is moved from a `.../chat/completions`
9780
+ * override to its sibling `.../responses` with a Responses-shaped body. Lets callers route
9772
9781
  * this internal-utility pass to a dedicated endpoint. Invalid values throw at
9773
9782
  * call time (see {@link validateEndpointOverride}).
9774
9783
  */
@@ -4988,7 +4988,12 @@ type PortalLlmFailureReason =
4988
4988
  /** Content parsed to a literal `null`, which is never a valid response. */
4989
4989
  | "null-completion"
4990
4990
  /** `totalTimeoutMs` was spent before the next attempt could run. */
4991
- | "time-budget-exhausted";
4991
+ | "time-budget-exhausted"
4992
+ /**
4993
+ * The portal's moderation gate refused the request. Terminal: the same input
4994
+ * is flagged again on every retry. See {@link isModerationResponse}.
4995
+ */
4996
+ | "content-flagged";
4992
4997
  /**
4993
4998
  * One attempt of a {@link callPortalJsonCompletion} call, reported to
4994
4999
  * `onAttempt` as it settles — success included. The wire-level diagnostic the
@@ -6338,7 +6343,9 @@ interface ExtractFactsOptions extends PortalLlmAuth {
6338
6343
  * Optional per-call request path override, forwarded to
6339
6344
  * {@link callPortalJsonCompletion}. When set, the extraction call POSTs to
6340
6345
  * `baseUrl + endpointOverride` instead of the default
6341
- * `/api/v1/chat/completions` — path only, body unchanged. Lets callers route
6346
+ * `/api/v1/chat/completions`. The body follows the transport, not the path: a
6347
+ * model that needs the Responses API is moved from a `.../chat/completions`
6348
+ * override to its sibling `.../responses` with a Responses-shaped body. Lets callers route
6342
6349
  * this internal-utility pass to a dedicated endpoint. Invalid values throw at
6343
6350
  * call time (see {@link validateEndpointOverride}).
6344
6351
  *
@@ -9768,7 +9775,9 @@ interface TopicExtractOptions extends PortalLlmAuth {
9768
9775
  * Optional per-call request path override, forwarded to
9769
9776
  * {@link callPortalJsonCompletion}. When set, topic extraction POSTs to
9770
9777
  * `baseUrl + endpointOverride` instead of the default
9771
- * `/api/v1/chat/completions` — path only, body unchanged. Lets callers route
9778
+ * `/api/v1/chat/completions`. The body follows the transport, not the path: a
9779
+ * model that needs the Responses API is moved from a `.../chat/completions`
9780
+ * override to its sibling `.../responses` with a Responses-shaped body. Lets callers route
9772
9781
  * this internal-utility pass to a dedicated endpoint. Invalid values throw at
9773
9782
  * call time (see {@link validateEndpointOverride}).
9774
9783
  */
@@ -13,7 +13,7 @@ import {
13
13
  taskTypeHeader,
14
14
  validateEndpointOverride,
15
15
  withInternalFlowMarker
16
- } from "./chunk-Z2QBL4HB.mjs";
16
+ } from "./chunk-7GHESNOH.mjs";
17
17
  import {
18
18
  BASE_URL,
19
19
  __commonJS,
@@ -28020,7 +28020,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
28020
28020
  content: m.content,
28021
28021
  similarity: m.similarity
28022
28022
  }));
28023
- const { consolidateMemory: doConsolidate } = await import("./consolidate-QWVI25WQ.mjs");
28023
+ const { consolidateMemory: doConsolidate } = await import("./consolidate-3RNRDM75.mjs");
28024
28024
  const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
28025
28025
  if (decision.action === "create") return decision.fallbackReason ? null : { create: true };
28026
28026
  if (decision.action === "supersede" && decision.content) {
@@ -30682,6 +30682,28 @@ var BatchFailureError = class extends Error {
30682
30682
  this.terminal = terminal;
30683
30683
  }
30684
30684
  };
30685
+ var FlaggedBatchError = class extends Error {
30686
+ };
30687
+ function extracted(result) {
30688
+ return result.failedCount === 0 && result.outcome !== "empty-after-retry";
30689
+ }
30690
+ function batchError(result) {
30691
+ const failure = result.failure;
30692
+ if (failure?.reason === "http-terminal") {
30693
+ const status = failure.httpStatus;
30694
+ if (status !== void 0 && REQUEST_REJECTED_STATUSES.has(status))
30695
+ return new BatchFailureError(
30696
+ `Extraction rejected the batch (HTTP ${status}); not retried this session`,
30697
+ true
30698
+ );
30699
+ return new AccountFailureError(
30700
+ `Extraction refused for the account (HTTP ${status ?? "unknown"}); retried next session`
30701
+ );
30702
+ }
30703
+ if (result.failedCount > 0 || failure !== void 0 && CONTENT_FAILURE_REASONS.has(failure.reason))
30704
+ return new BatchFailureError("Extraction batch incomplete; retained for retry", false);
30705
+ return new Error("Extraction batch incomplete; retained for retry");
30706
+ }
30685
30707
  var AccountFailureError = class extends Error {
30686
30708
  };
30687
30709
  var LockedSourcesError = class extends Error {
@@ -30690,6 +30712,16 @@ var LockedSourcesError = class extends Error {
30690
30712
  this.persistentIds = persistentIds;
30691
30713
  }
30692
30714
  };
30715
+ function splitTurns(messages) {
30716
+ const turns = [];
30717
+ for (const message of messages) {
30718
+ const last = turns[turns.length - 1];
30719
+ if (!last || message.role === "user" && last.some((m) => m.role === "user"))
30720
+ turns.push([message]);
30721
+ else last.push(message);
30722
+ }
30723
+ return turns;
30724
+ }
30693
30725
  function idsOf(job) {
30694
30726
  return JSON.parse(String(job._getRaw("message_ids")));
30695
30727
  }
@@ -30840,6 +30872,10 @@ function createDurableAutoExtractor(options) {
30840
30872
  skippedThisSession.add(job.id);
30841
30873
  return false;
30842
30874
  }
30875
+ if (error instanceof FlaggedBatchError) {
30876
+ await acknowledge(job, ids, loaded, true);
30877
+ return true;
30878
+ }
30843
30879
  const counted = error instanceof BatchFailureError || error instanceof LockedSourcesError && error.persistentIds.length > 0;
30844
30880
  if (!counted) return false;
30845
30881
  const prior = sessionFailures.get(job.id);
@@ -30966,37 +31002,50 @@ function createDurableAutoExtractor(options) {
30966
31002
  const messages = loaded.flatMap(
30967
31003
  (m) => m && m.conversationId === conversationId && (m.role === "user" || m.role === "assistant") ? [{ id: m.uniqueId, role: m.role, content: m.content }] : []
30968
31004
  );
30969
- let success = messages.length === 0;
30970
- let result;
30971
- if (messages.length) {
30972
- result = await extractBatch(
30973
- messages,
31005
+ const jobScope = currentScope() === "private" ? "private" : String(job._getRaw("scope"));
31006
+ const jobFolderId = job._getRaw("folder_id") ?? null;
31007
+ const runExtraction = async (batch, batchIds) => {
31008
+ const result = await extractBatch(
31009
+ batch,
30974
31010
  conversationId,
30975
- ids,
30976
- currentScope() === "private" ? "private" : String(job._getRaw("scope")),
30977
- job._getRaw("folder_id") ?? null
31011
+ batchIds,
31012
+ jobScope,
31013
+ jobFolderId
30978
31014
  );
30979
- success = result.failedCount === 0 && result.outcome !== "empty-after-retry";
30980
31015
  options.onTurnComplete?.(result);
30981
- }
30982
- if (!success) {
30983
- const failure = result?.failure;
30984
- if (failure?.reason === "http-terminal") {
30985
- const status = failure.httpStatus;
30986
- if (status !== void 0 && REQUEST_REJECTED_STATUSES.has(status))
30987
- throw new BatchFailureError(
30988
- `Extraction rejected the batch (HTTP ${status}); not retried this session`,
30989
- true
31016
+ return result;
31017
+ };
31018
+ const flaggedIds = /* @__PURE__ */ new Set();
31019
+ if (messages.length) {
31020
+ const result = await runExtraction(messages, ids);
31021
+ if (result.failure?.reason === "content-flagged") {
31022
+ const turns = splitTurns(messages);
31023
+ if (turns.length < 2)
31024
+ throw new FlaggedBatchError("Extraction batch refused by moderation; abandoned");
31025
+ for (const turn of turns) {
31026
+ const turnResult = await runExtraction(
31027
+ turn,
31028
+ turn.map((m) => m.id)
30990
31029
  );
30991
- throw new AccountFailureError(
30992
- `Extraction refused for the account (HTTP ${status ?? "unknown"}); retried next session`
30993
- );
30994
- }
30995
- if ((result?.failedCount ?? 0) > 0 || failure !== void 0 && CONTENT_FAILURE_REASONS.has(failure.reason))
30996
- throw new BatchFailureError("Extraction batch incomplete; retained for retry", false);
30997
- throw new Error("Extraction batch incomplete; retained for retry");
31030
+ if (turnResult.failure?.reason === "content-flagged")
31031
+ for (const m of turn) flaggedIds.add(m.id);
31032
+ else if (!extracted(turnResult)) throw batchError(turnResult);
31033
+ }
31034
+ if (flaggedIds.size)
31035
+ reportError(
31036
+ new Error(
31037
+ `Dropped ${flaggedIds.size} source id(s) of an extraction batch refused by moderation`
31038
+ ),
31039
+ conversationId
31040
+ );
31041
+ } else if (!extracted(result)) throw batchError(result);
30998
31042
  }
30999
- await acknowledge(job, ids, loaded, false);
31043
+ await acknowledge(
31044
+ job,
31045
+ ids,
31046
+ loaded,
31047
+ ids.slice(-2).some((id) => flaggedIds.has(id))
31048
+ );
31000
31049
  scheduleAfterSuccess = true;
31001
31050
  } catch (error) {
31002
31051
  attempts.set(job.id, attempted + 1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anuma/sdk",
3
- "version": "6.30.1",
3
+ "version": "6.30.2",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",