@anuma/sdk 6.39.2 → 6.39.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.
@@ -6702,6 +6702,93 @@ function composeHooks(hooks) {
6702
6702
  };
6703
6703
  }
6704
6704
 
6705
+ // src/lib/chat/streamIdleTimeout.ts
6706
+ var StreamIdleTimeoutError = class extends Error {
6707
+ constructor(idleTimeoutMs) {
6708
+ super(`Stream timed out after ${idleTimeoutMs} ms without activity.`);
6709
+ this.name = "StreamIdleTimeoutError";
6710
+ this.idleTimeoutMs = idleTimeoutMs;
6711
+ }
6712
+ };
6713
+ function withStreamIdleTimeout(transport, idleTimeoutMs) {
6714
+ if (!(idleTimeoutMs > 0) || idleTimeoutMs === Infinity) return transport;
6715
+ return (options) => ({
6716
+ stream: (async function* () {
6717
+ const controller = new AbortController();
6718
+ let timer;
6719
+ let settled = false;
6720
+ let completed = false;
6721
+ let iterator;
6722
+ let interruption;
6723
+ let rejectPending;
6724
+ const disarm = () => {
6725
+ if (timer !== void 0) clearTimeout(timer);
6726
+ timer = void 0;
6727
+ };
6728
+ const interrupt = (error) => {
6729
+ if (interruption) return;
6730
+ interruption = error;
6731
+ rejectPending?.(error);
6732
+ controller.abort();
6733
+ };
6734
+ const arm = () => {
6735
+ if (settled || controller.signal.aborted) return;
6736
+ disarm();
6737
+ timer = setTimeout(() => {
6738
+ interrupt(new StreamIdleTimeoutError(idleTimeoutMs));
6739
+ }, idleTimeoutMs);
6740
+ };
6741
+ const onAbort = () => {
6742
+ controller.abort();
6743
+ };
6744
+ options.signal?.addEventListener("abort", onAbort, { once: true });
6745
+ try {
6746
+ if (options.signal?.aborted) {
6747
+ const error = new Error("Request aborted");
6748
+ error.name = "AbortError";
6749
+ throw error;
6750
+ }
6751
+ arm();
6752
+ iterator = transport({
6753
+ ...options,
6754
+ signal: controller.signal,
6755
+ onActivity: () => {
6756
+ arm();
6757
+ options.onActivity?.();
6758
+ }
6759
+ }).stream[Symbol.asyncIterator]();
6760
+ while (true) {
6761
+ if (interruption) throw interruption;
6762
+ const next = await new Promise((resolve, reject) => {
6763
+ rejectPending = reject;
6764
+ Promise.resolve(iterator.next()).then(resolve, reject);
6765
+ });
6766
+ rejectPending = void 0;
6767
+ if (next.done) {
6768
+ completed = true;
6769
+ break;
6770
+ }
6771
+ arm();
6772
+ yield next.value;
6773
+ }
6774
+ } finally {
6775
+ settled = true;
6776
+ rejectPending = void 0;
6777
+ disarm();
6778
+ options.signal?.removeEventListener("abort", onAbort);
6779
+ if (!completed) {
6780
+ controller.abort();
6781
+ try {
6782
+ void iterator?.return?.().catch(() => {
6783
+ });
6784
+ } catch {
6785
+ }
6786
+ }
6787
+ }
6788
+ })()
6789
+ });
6790
+ }
6791
+
6705
6792
  // src/lib/chat/useChat/utils.ts
6706
6793
  var import_jsonrepair = require("jsonrepair");
6707
6794
  init_logger();
@@ -8892,7 +8979,20 @@ var defaultTransport = (options) => {
8892
8979
  } catch {
8893
8980
  }
8894
8981
  }
8895
- return response;
8982
+ if (!response.body || !options.onActivity) return response;
8983
+ const body = response.body.pipeThrough(
8984
+ new TransformStream({
8985
+ transform(chunk, controller) {
8986
+ if (chunk.byteLength > 0) options.onActivity?.();
8987
+ controller.enqueue(chunk);
8988
+ }
8989
+ })
8990
+ );
8991
+ return new Response(body, {
8992
+ status: response.status,
8993
+ statusText: response.statusText,
8994
+ headers: response.headers
8995
+ });
8896
8996
  };
8897
8997
  return createSseClient({
8898
8998
  method: options.method ?? "POST",
@@ -8949,6 +9049,7 @@ async function runToolLoop(options) {
8949
9049
  conversationId,
8950
9050
  smoothing,
8951
9051
  signal,
9052
+ idleTimeoutMs = 12e4,
8952
9053
  resumable,
8953
9054
  detachSignal,
8954
9055
  onStreamMeta,
@@ -8962,13 +9063,14 @@ async function runToolLoop(options) {
8962
9063
  onStepFinish,
8963
9064
  onRequest,
8964
9065
  onStreamRetry,
8965
- transport: makeStreamingRequest = defaultTransport,
9066
+ transport = defaultTransport,
8966
9067
  preProcessors,
8967
9068
  maxConnectorCalls = 2,
8968
9069
  hooks: hooksOption,
8969
9070
  piiRedaction,
8970
9071
  onPiiRedacted
8971
9072
  } = options;
9073
+ const makeStreamingRequest = withStreamIdleTimeout(transport, idleTimeoutMs);
8972
9074
  const hooks = Array.isArray(hooksOption) ? composeHooks(hooksOption) : hooksOption;
8973
9075
  const runId = generateRunId();
8974
9076
  let messages = options.messages;
@@ -2592,12 +2592,10 @@ type StreamingTransportOptions = {
2592
2592
  inferenceId: string;
2593
2593
  }) => void;
2594
2594
  /**
2595
- * Fires whenever bytes arrive on the wire — data frames AND the keep-alive
2596
- * comment lines (`: ...`) the SSE parser otherwise discards. A pure liveness
2597
- * signal: a consumer running an idle watchdog uses it to tell a slow-but-alive
2598
- * stream (the server still heart-beating through a long reasoning silence)
2599
- * apart from a dead connection (no bytes at all). Not every transport emits it
2600
- * — the xhr transport does; treat its absence as "no extra liveness info".
2595
+ * Fires when the transport receives bytes, including SSE keep-alive comments.
2596
+ * Consumers can use this callback to reset the idle timeout.
2597
+ * The fetch and XHR transports emit it.
2598
+ * Custom transports can omit it if they cannot report byte activity.
2601
2599
  */
2602
2600
  onActivity?: () => void;
2603
2601
  };
@@ -2592,12 +2592,10 @@ type StreamingTransportOptions = {
2592
2592
  inferenceId: string;
2593
2593
  }) => void;
2594
2594
  /**
2595
- * Fires whenever bytes arrive on the wire — data frames AND the keep-alive
2596
- * comment lines (`: ...`) the SSE parser otherwise discards. A pure liveness
2597
- * signal: a consumer running an idle watchdog uses it to tell a slow-but-alive
2598
- * stream (the server still heart-beating through a long reasoning silence)
2599
- * apart from a dead connection (no bytes at all). Not every transport emits it
2600
- * — the xhr transport does; treat its absence as "no extra liveness info".
2595
+ * Fires when the transport receives bytes, including SSE keep-alive comments.
2596
+ * Consumers can use this callback to reset the idle timeout.
2597
+ * The fetch and XHR transports emit it.
2598
+ * Custom transports can omit it if they cannot report byte activity.
2601
2599
  */
2602
2600
  onActivity?: () => void;
2603
2601
  };
@@ -5115,6 +5115,93 @@ function composeHooks(hooks) {
5115
5115
  };
5116
5116
  }
5117
5117
 
5118
+ // src/lib/chat/streamIdleTimeout.ts
5119
+ var StreamIdleTimeoutError = class extends Error {
5120
+ constructor(idleTimeoutMs) {
5121
+ super(`Stream timed out after ${idleTimeoutMs} ms without activity.`);
5122
+ this.name = "StreamIdleTimeoutError";
5123
+ this.idleTimeoutMs = idleTimeoutMs;
5124
+ }
5125
+ };
5126
+ function withStreamIdleTimeout(transport, idleTimeoutMs) {
5127
+ if (!(idleTimeoutMs > 0) || idleTimeoutMs === Infinity) return transport;
5128
+ return (options) => ({
5129
+ stream: (async function* () {
5130
+ const controller = new AbortController();
5131
+ let timer;
5132
+ let settled = false;
5133
+ let completed = false;
5134
+ let iterator;
5135
+ let interruption;
5136
+ let rejectPending;
5137
+ const disarm = () => {
5138
+ if (timer !== void 0) clearTimeout(timer);
5139
+ timer = void 0;
5140
+ };
5141
+ const interrupt = (error) => {
5142
+ if (interruption) return;
5143
+ interruption = error;
5144
+ rejectPending?.(error);
5145
+ controller.abort();
5146
+ };
5147
+ const arm = () => {
5148
+ if (settled || controller.signal.aborted) return;
5149
+ disarm();
5150
+ timer = setTimeout(() => {
5151
+ interrupt(new StreamIdleTimeoutError(idleTimeoutMs));
5152
+ }, idleTimeoutMs);
5153
+ };
5154
+ const onAbort = () => {
5155
+ controller.abort();
5156
+ };
5157
+ options.signal?.addEventListener("abort", onAbort, { once: true });
5158
+ try {
5159
+ if (options.signal?.aborted) {
5160
+ const error = new Error("Request aborted");
5161
+ error.name = "AbortError";
5162
+ throw error;
5163
+ }
5164
+ arm();
5165
+ iterator = transport({
5166
+ ...options,
5167
+ signal: controller.signal,
5168
+ onActivity: () => {
5169
+ arm();
5170
+ options.onActivity?.();
5171
+ }
5172
+ }).stream[Symbol.asyncIterator]();
5173
+ while (true) {
5174
+ if (interruption) throw interruption;
5175
+ const next = await new Promise((resolve, reject) => {
5176
+ rejectPending = reject;
5177
+ Promise.resolve(iterator.next()).then(resolve, reject);
5178
+ });
5179
+ rejectPending = void 0;
5180
+ if (next.done) {
5181
+ completed = true;
5182
+ break;
5183
+ }
5184
+ arm();
5185
+ yield next.value;
5186
+ }
5187
+ } finally {
5188
+ settled = true;
5189
+ rejectPending = void 0;
5190
+ disarm();
5191
+ options.signal?.removeEventListener("abort", onAbort);
5192
+ if (!completed) {
5193
+ controller.abort();
5194
+ try {
5195
+ void iterator?.return?.().catch(() => {
5196
+ });
5197
+ } catch {
5198
+ }
5199
+ }
5200
+ }
5201
+ })()
5202
+ });
5203
+ }
5204
+
5118
5205
  // src/lib/chat/useChat/utils.ts
5119
5206
  import { jsonrepair } from "jsonrepair";
5120
5207
  function parseToolArguments(raw) {
@@ -7304,7 +7391,20 @@ var defaultTransport = (options) => {
7304
7391
  } catch {
7305
7392
  }
7306
7393
  }
7307
- return response;
7394
+ if (!response.body || !options.onActivity) return response;
7395
+ const body = response.body.pipeThrough(
7396
+ new TransformStream({
7397
+ transform(chunk, controller) {
7398
+ if (chunk.byteLength > 0) options.onActivity?.();
7399
+ controller.enqueue(chunk);
7400
+ }
7401
+ })
7402
+ );
7403
+ return new Response(body, {
7404
+ status: response.status,
7405
+ statusText: response.statusText,
7406
+ headers: response.headers
7407
+ });
7308
7408
  };
7309
7409
  return createSseClient({
7310
7410
  method: options.method ?? "POST",
@@ -7361,6 +7461,7 @@ async function runToolLoop(options) {
7361
7461
  conversationId,
7362
7462
  smoothing,
7363
7463
  signal,
7464
+ idleTimeoutMs = 12e4,
7364
7465
  resumable,
7365
7466
  detachSignal,
7366
7467
  onStreamMeta,
@@ -7374,13 +7475,14 @@ async function runToolLoop(options) {
7374
7475
  onStepFinish,
7375
7476
  onRequest,
7376
7477
  onStreamRetry,
7377
- transport: makeStreamingRequest = defaultTransport,
7478
+ transport = defaultTransport,
7378
7479
  preProcessors,
7379
7480
  maxConnectorCalls = 2,
7380
7481
  hooks: hooksOption,
7381
7482
  piiRedaction,
7382
7483
  onPiiRedacted
7383
7484
  } = options;
7485
+ const makeStreamingRequest = withStreamIdleTimeout(transport, idleTimeoutMs);
7384
7486
  const hooks = Array.isArray(hooksOption) ? composeHooks(hooksOption) : hooksOption;
7385
7487
  const runId = generateRunId();
7386
7488
  let messages = options.messages;
@@ -8741,6 +8741,93 @@ function composeHooks(hooks) {
8741
8741
  };
8742
8742
  }
8743
8743
 
8744
+ // src/lib/chat/streamIdleTimeout.ts
8745
+ var StreamIdleTimeoutError = class extends Error {
8746
+ constructor(idleTimeoutMs) {
8747
+ super(`Stream timed out after ${idleTimeoutMs} ms without activity.`);
8748
+ this.name = "StreamIdleTimeoutError";
8749
+ this.idleTimeoutMs = idleTimeoutMs;
8750
+ }
8751
+ };
8752
+ function withStreamIdleTimeout(transport, idleTimeoutMs) {
8753
+ if (!(idleTimeoutMs > 0) || idleTimeoutMs === Infinity) return transport;
8754
+ return (options) => ({
8755
+ stream: (async function* () {
8756
+ const controller = new AbortController();
8757
+ let timer;
8758
+ let settled = false;
8759
+ let completed = false;
8760
+ let iterator;
8761
+ let interruption;
8762
+ let rejectPending;
8763
+ const disarm = () => {
8764
+ if (timer !== void 0) clearTimeout(timer);
8765
+ timer = void 0;
8766
+ };
8767
+ const interrupt = (error) => {
8768
+ if (interruption) return;
8769
+ interruption = error;
8770
+ rejectPending?.(error);
8771
+ controller.abort();
8772
+ };
8773
+ const arm = () => {
8774
+ if (settled || controller.signal.aborted) return;
8775
+ disarm();
8776
+ timer = setTimeout(() => {
8777
+ interrupt(new StreamIdleTimeoutError(idleTimeoutMs));
8778
+ }, idleTimeoutMs);
8779
+ };
8780
+ const onAbort = () => {
8781
+ controller.abort();
8782
+ };
8783
+ options.signal?.addEventListener("abort", onAbort, { once: true });
8784
+ try {
8785
+ if (options.signal?.aborted) {
8786
+ const error = new Error("Request aborted");
8787
+ error.name = "AbortError";
8788
+ throw error;
8789
+ }
8790
+ arm();
8791
+ iterator = transport({
8792
+ ...options,
8793
+ signal: controller.signal,
8794
+ onActivity: () => {
8795
+ arm();
8796
+ options.onActivity?.();
8797
+ }
8798
+ }).stream[Symbol.asyncIterator]();
8799
+ while (true) {
8800
+ if (interruption) throw interruption;
8801
+ const next = await new Promise((resolve, reject) => {
8802
+ rejectPending = reject;
8803
+ Promise.resolve(iterator.next()).then(resolve, reject);
8804
+ });
8805
+ rejectPending = void 0;
8806
+ if (next.done) {
8807
+ completed = true;
8808
+ break;
8809
+ }
8810
+ arm();
8811
+ yield next.value;
8812
+ }
8813
+ } finally {
8814
+ settled = true;
8815
+ rejectPending = void 0;
8816
+ disarm();
8817
+ options.signal?.removeEventListener("abort", onAbort);
8818
+ if (!completed) {
8819
+ controller.abort();
8820
+ try {
8821
+ void iterator?.return?.().catch(() => {
8822
+ });
8823
+ } catch {
8824
+ }
8825
+ }
8826
+ }
8827
+ })()
8828
+ });
8829
+ }
8830
+
8744
8831
  // src/lib/chat/useChat/utils.ts
8745
8832
  var import_jsonrepair = require("jsonrepair");
8746
8833
  init_logger();
@@ -10931,7 +11018,20 @@ var defaultTransport = (options) => {
10931
11018
  } catch {
10932
11019
  }
10933
11020
  }
10934
- return response;
11021
+ if (!response.body || !options.onActivity) return response;
11022
+ const body = response.body.pipeThrough(
11023
+ new TransformStream({
11024
+ transform(chunk, controller) {
11025
+ if (chunk.byteLength > 0) options.onActivity?.();
11026
+ controller.enqueue(chunk);
11027
+ }
11028
+ })
11029
+ );
11030
+ return new Response(body, {
11031
+ status: response.status,
11032
+ statusText: response.statusText,
11033
+ headers: response.headers
11034
+ });
10935
11035
  };
10936
11036
  return createSseClient({
10937
11037
  method: options.method ?? "POST",
@@ -10988,6 +11088,7 @@ async function runToolLoop(options) {
10988
11088
  conversationId,
10989
11089
  smoothing,
10990
11090
  signal,
11091
+ idleTimeoutMs = 12e4,
10991
11092
  resumable,
10992
11093
  detachSignal,
10993
11094
  onStreamMeta,
@@ -11001,13 +11102,14 @@ async function runToolLoop(options) {
11001
11102
  onStepFinish,
11002
11103
  onRequest,
11003
11104
  onStreamRetry,
11004
- transport: makeStreamingRequest = defaultTransport,
11105
+ transport = defaultTransport,
11005
11106
  preProcessors,
11006
11107
  maxConnectorCalls = 2,
11007
11108
  hooks: hooksOption,
11008
11109
  piiRedaction,
11009
11110
  onPiiRedacted
11010
11111
  } = options;
11112
+ const makeStreamingRequest = withStreamIdleTimeout(transport, idleTimeoutMs);
11011
11113
  const hooks = Array.isArray(hooksOption) ? composeHooks(hooksOption) : hooksOption;
11012
11114
  const runId = generateRunId();
11013
11115
  let messages = options.messages;
@@ -3247,12 +3247,10 @@ type StreamingTransportOptions = {
3247
3247
  inferenceId: string;
3248
3248
  }) => void;
3249
3249
  /**
3250
- * Fires whenever bytes arrive on the wire — data frames AND the keep-alive
3251
- * comment lines (`: ...`) the SSE parser otherwise discards. A pure liveness
3252
- * signal: a consumer running an idle watchdog uses it to tell a slow-but-alive
3253
- * stream (the server still heart-beating through a long reasoning silence)
3254
- * apart from a dead connection (no bytes at all). Not every transport emits it
3255
- * — the xhr transport does; treat its absence as "no extra liveness info".
3250
+ * Fires when the transport receives bytes, including SSE keep-alive comments.
3251
+ * Consumers can use this callback to reset the idle timeout.
3252
+ * The fetch and XHR transports emit it.
3253
+ * Custom transports can omit it if they cannot report byte activity.
3256
3254
  */
3257
3255
  onActivity?: () => void;
3258
3256
  };
@@ -3247,12 +3247,10 @@ type StreamingTransportOptions = {
3247
3247
  inferenceId: string;
3248
3248
  }) => void;
3249
3249
  /**
3250
- * Fires whenever bytes arrive on the wire — data frames AND the keep-alive
3251
- * comment lines (`: ...`) the SSE parser otherwise discards. A pure liveness
3252
- * signal: a consumer running an idle watchdog uses it to tell a slow-but-alive
3253
- * stream (the server still heart-beating through a long reasoning silence)
3254
- * apart from a dead connection (no bytes at all). Not every transport emits it
3255
- * — the xhr transport does; treat its absence as "no extra liveness info".
3250
+ * Fires when the transport receives bytes, including SSE keep-alive comments.
3251
+ * Consumers can use this callback to reset the idle timeout.
3252
+ * The fetch and XHR transports emit it.
3253
+ * Custom transports can omit it if they cannot report byte activity.
3256
3254
  */
3257
3255
  onActivity?: () => void;
3258
3256
  };
@@ -6889,6 +6889,93 @@ function composeHooks(hooks) {
6889
6889
  };
6890
6890
  }
6891
6891
 
6892
+ // src/lib/chat/streamIdleTimeout.ts
6893
+ var StreamIdleTimeoutError = class extends Error {
6894
+ constructor(idleTimeoutMs) {
6895
+ super(`Stream timed out after ${idleTimeoutMs} ms without activity.`);
6896
+ this.name = "StreamIdleTimeoutError";
6897
+ this.idleTimeoutMs = idleTimeoutMs;
6898
+ }
6899
+ };
6900
+ function withStreamIdleTimeout(transport, idleTimeoutMs) {
6901
+ if (!(idleTimeoutMs > 0) || idleTimeoutMs === Infinity) return transport;
6902
+ return (options) => ({
6903
+ stream: (async function* () {
6904
+ const controller = new AbortController();
6905
+ let timer;
6906
+ let settled = false;
6907
+ let completed = false;
6908
+ let iterator;
6909
+ let interruption;
6910
+ let rejectPending;
6911
+ const disarm = () => {
6912
+ if (timer !== void 0) clearTimeout(timer);
6913
+ timer = void 0;
6914
+ };
6915
+ const interrupt = (error) => {
6916
+ if (interruption) return;
6917
+ interruption = error;
6918
+ rejectPending?.(error);
6919
+ controller.abort();
6920
+ };
6921
+ const arm = () => {
6922
+ if (settled || controller.signal.aborted) return;
6923
+ disarm();
6924
+ timer = setTimeout(() => {
6925
+ interrupt(new StreamIdleTimeoutError(idleTimeoutMs));
6926
+ }, idleTimeoutMs);
6927
+ };
6928
+ const onAbort = () => {
6929
+ controller.abort();
6930
+ };
6931
+ options.signal?.addEventListener("abort", onAbort, { once: true });
6932
+ try {
6933
+ if (options.signal?.aborted) {
6934
+ const error = new Error("Request aborted");
6935
+ error.name = "AbortError";
6936
+ throw error;
6937
+ }
6938
+ arm();
6939
+ iterator = transport({
6940
+ ...options,
6941
+ signal: controller.signal,
6942
+ onActivity: () => {
6943
+ arm();
6944
+ options.onActivity?.();
6945
+ }
6946
+ }).stream[Symbol.asyncIterator]();
6947
+ while (true) {
6948
+ if (interruption) throw interruption;
6949
+ const next = await new Promise((resolve, reject) => {
6950
+ rejectPending = reject;
6951
+ Promise.resolve(iterator.next()).then(resolve, reject);
6952
+ });
6953
+ rejectPending = void 0;
6954
+ if (next.done) {
6955
+ completed = true;
6956
+ break;
6957
+ }
6958
+ arm();
6959
+ yield next.value;
6960
+ }
6961
+ } finally {
6962
+ settled = true;
6963
+ rejectPending = void 0;
6964
+ disarm();
6965
+ options.signal?.removeEventListener("abort", onAbort);
6966
+ if (!completed) {
6967
+ controller.abort();
6968
+ try {
6969
+ void iterator?.return?.().catch(() => {
6970
+ });
6971
+ } catch {
6972
+ }
6973
+ }
6974
+ }
6975
+ })()
6976
+ });
6977
+ }
6978
+
6892
6979
  // src/lib/chat/useChat/utils.ts
6893
6980
  import { jsonrepair } from "jsonrepair";
6894
6981
  function parseToolArguments(raw) {
@@ -9078,7 +9165,20 @@ var defaultTransport = (options) => {
9078
9165
  } catch {
9079
9166
  }
9080
9167
  }
9081
- return response;
9168
+ if (!response.body || !options.onActivity) return response;
9169
+ const body = response.body.pipeThrough(
9170
+ new TransformStream({
9171
+ transform(chunk, controller) {
9172
+ if (chunk.byteLength > 0) options.onActivity?.();
9173
+ controller.enqueue(chunk);
9174
+ }
9175
+ })
9176
+ );
9177
+ return new Response(body, {
9178
+ status: response.status,
9179
+ statusText: response.statusText,
9180
+ headers: response.headers
9181
+ });
9082
9182
  };
9083
9183
  return createSseClient({
9084
9184
  method: options.method ?? "POST",
@@ -9135,6 +9235,7 @@ async function runToolLoop(options) {
9135
9235
  conversationId,
9136
9236
  smoothing,
9137
9237
  signal,
9238
+ idleTimeoutMs = 12e4,
9138
9239
  resumable,
9139
9240
  detachSignal,
9140
9241
  onStreamMeta,
@@ -9148,13 +9249,14 @@ async function runToolLoop(options) {
9148
9249
  onStepFinish,
9149
9250
  onRequest,
9150
9251
  onStreamRetry,
9151
- transport: makeStreamingRequest = defaultTransport,
9252
+ transport = defaultTransport,
9152
9253
  preProcessors,
9153
9254
  maxConnectorCalls = 2,
9154
9255
  hooks: hooksOption,
9155
9256
  piiRedaction,
9156
9257
  onPiiRedacted
9157
9258
  } = options;
9259
+ const makeStreamingRequest = withStreamIdleTimeout(transport, idleTimeoutMs);
9158
9260
  const hooks = Array.isArray(hooksOption) ? composeHooks(hooksOption) : hooksOption;
9159
9261
  const runId = generateRunId();
9160
9262
  let messages = options.messages;
@@ -21152,6 +21152,93 @@ function composeHooks(hooks) {
21152
21152
  };
21153
21153
  }
21154
21154
 
21155
+ // src/lib/chat/streamIdleTimeout.ts
21156
+ var StreamIdleTimeoutError = class extends Error {
21157
+ constructor(idleTimeoutMs) {
21158
+ super(`Stream timed out after ${idleTimeoutMs} ms without activity.`);
21159
+ this.name = "StreamIdleTimeoutError";
21160
+ this.idleTimeoutMs = idleTimeoutMs;
21161
+ }
21162
+ };
21163
+ function withStreamIdleTimeout(transport, idleTimeoutMs) {
21164
+ if (!(idleTimeoutMs > 0) || idleTimeoutMs === Infinity) return transport;
21165
+ return (options) => ({
21166
+ stream: (async function* () {
21167
+ const controller = new AbortController();
21168
+ let timer;
21169
+ let settled = false;
21170
+ let completed = false;
21171
+ let iterator;
21172
+ let interruption;
21173
+ let rejectPending;
21174
+ const disarm = () => {
21175
+ if (timer !== void 0) clearTimeout(timer);
21176
+ timer = void 0;
21177
+ };
21178
+ const interrupt = (error) => {
21179
+ if (interruption) return;
21180
+ interruption = error;
21181
+ rejectPending?.(error);
21182
+ controller.abort();
21183
+ };
21184
+ const arm = () => {
21185
+ if (settled || controller.signal.aborted) return;
21186
+ disarm();
21187
+ timer = setTimeout(() => {
21188
+ interrupt(new StreamIdleTimeoutError(idleTimeoutMs));
21189
+ }, idleTimeoutMs);
21190
+ };
21191
+ const onAbort = () => {
21192
+ controller.abort();
21193
+ };
21194
+ options.signal?.addEventListener("abort", onAbort, { once: true });
21195
+ try {
21196
+ if (options.signal?.aborted) {
21197
+ const error = new Error("Request aborted");
21198
+ error.name = "AbortError";
21199
+ throw error;
21200
+ }
21201
+ arm();
21202
+ iterator = transport({
21203
+ ...options,
21204
+ signal: controller.signal,
21205
+ onActivity: () => {
21206
+ arm();
21207
+ options.onActivity?.();
21208
+ }
21209
+ }).stream[Symbol.asyncIterator]();
21210
+ while (true) {
21211
+ if (interruption) throw interruption;
21212
+ const next = await new Promise((resolve, reject) => {
21213
+ rejectPending = reject;
21214
+ Promise.resolve(iterator.next()).then(resolve, reject);
21215
+ });
21216
+ rejectPending = void 0;
21217
+ if (next.done) {
21218
+ completed = true;
21219
+ break;
21220
+ }
21221
+ arm();
21222
+ yield next.value;
21223
+ }
21224
+ } finally {
21225
+ settled = true;
21226
+ rejectPending = void 0;
21227
+ disarm();
21228
+ options.signal?.removeEventListener("abort", onAbort);
21229
+ if (!completed) {
21230
+ controller.abort();
21231
+ try {
21232
+ void iterator?.return?.().catch(() => {
21233
+ });
21234
+ } catch {
21235
+ }
21236
+ }
21237
+ }
21238
+ })()
21239
+ });
21240
+ }
21241
+
21155
21242
  // src/lib/chat/useChat/utils.ts
21156
21243
  var import_jsonrepair = require("jsonrepair");
21157
21244
  init_logger();
@@ -23316,7 +23403,20 @@ var defaultTransport = (options) => {
23316
23403
  } catch {
23317
23404
  }
23318
23405
  }
23319
- return response;
23406
+ if (!response.body || !options.onActivity) return response;
23407
+ const body = response.body.pipeThrough(
23408
+ new TransformStream({
23409
+ transform(chunk, controller) {
23410
+ if (chunk.byteLength > 0) options.onActivity?.();
23411
+ controller.enqueue(chunk);
23412
+ }
23413
+ })
23414
+ );
23415
+ return new Response(body, {
23416
+ status: response.status,
23417
+ statusText: response.statusText,
23418
+ headers: response.headers
23419
+ });
23320
23420
  };
23321
23421
  return createSseClient({
23322
23422
  method: options.method ?? "POST",
@@ -23373,6 +23473,7 @@ async function runToolLoop(options) {
23373
23473
  conversationId,
23374
23474
  smoothing,
23375
23475
  signal,
23476
+ idleTimeoutMs = 12e4,
23376
23477
  resumable,
23377
23478
  detachSignal,
23378
23479
  onStreamMeta,
@@ -23386,13 +23487,14 @@ async function runToolLoop(options) {
23386
23487
  onStepFinish,
23387
23488
  onRequest,
23388
23489
  onStreamRetry,
23389
- transport: makeStreamingRequest = defaultTransport,
23490
+ transport = defaultTransport,
23390
23491
  preProcessors,
23391
23492
  maxConnectorCalls = 2,
23392
23493
  hooks: hooksOption,
23393
23494
  piiRedaction,
23394
23495
  onPiiRedacted
23395
23496
  } = options;
23497
+ const makeStreamingRequest = withStreamIdleTimeout(transport, idleTimeoutMs);
23396
23498
  const hooks = Array.isArray(hooksOption) ? composeHooks(hooksOption) : hooksOption;
23397
23499
  const runId = generateRunId();
23398
23500
  let messages = options.messages;
@@ -2041,6 +2041,12 @@ type RunToolLoopOptions = {
2041
2041
  smoothing?: StreamSmoothingConfig | boolean;
2042
2042
  /** AbortSignal to cancel the request. */
2043
2043
  signal?: AbortSignal;
2044
+ /**
2045
+ * Maximum interval without stream activity, in milliseconds, for each request attempt.
2046
+ * Data chunks and keep-alive bytes reset the interval. Set 0 or Infinity to disable.
2047
+ * @default 120000
2048
+ */
2049
+ idleTimeoutMs?: number;
2044
2050
  /**
2045
2051
  * Opt into resumable streaming. Sends `X-Stream-Resumable: 1` on every
2046
2052
  * streaming request so the portal keeps generating into its buffer after a
@@ -2275,12 +2281,10 @@ type StreamingTransportOptions = {
2275
2281
  inferenceId: string;
2276
2282
  }) => void;
2277
2283
  /**
2278
- * Fires whenever bytes arrive on the wire — data frames AND the keep-alive
2279
- * comment lines (`: ...`) the SSE parser otherwise discards. A pure liveness
2280
- * signal: a consumer running an idle watchdog uses it to tell a slow-but-alive
2281
- * stream (the server still heart-beating through a long reasoning silence)
2282
- * apart from a dead connection (no bytes at all). Not every transport emits it
2283
- * — the xhr transport does; treat its absence as "no extra liveness info".
2284
+ * Fires when the transport receives bytes, including SSE keep-alive comments.
2285
+ * Consumers can use this callback to reset the idle timeout.
2286
+ * The fetch and XHR transports emit it.
2287
+ * Custom transports can omit it if they cannot report byte activity.
2284
2288
  */
2285
2289
  onActivity?: () => void;
2286
2290
  };
@@ -2041,6 +2041,12 @@ type RunToolLoopOptions = {
2041
2041
  smoothing?: StreamSmoothingConfig | boolean;
2042
2042
  /** AbortSignal to cancel the request. */
2043
2043
  signal?: AbortSignal;
2044
+ /**
2045
+ * Maximum interval without stream activity, in milliseconds, for each request attempt.
2046
+ * Data chunks and keep-alive bytes reset the interval. Set 0 or Infinity to disable.
2047
+ * @default 120000
2048
+ */
2049
+ idleTimeoutMs?: number;
2044
2050
  /**
2045
2051
  * Opt into resumable streaming. Sends `X-Stream-Resumable: 1` on every
2046
2052
  * streaming request so the portal keeps generating into its buffer after a
@@ -2275,12 +2281,10 @@ type StreamingTransportOptions = {
2275
2281
  inferenceId: string;
2276
2282
  }) => void;
2277
2283
  /**
2278
- * Fires whenever bytes arrive on the wire — data frames AND the keep-alive
2279
- * comment lines (`: ...`) the SSE parser otherwise discards. A pure liveness
2280
- * signal: a consumer running an idle watchdog uses it to tell a slow-but-alive
2281
- * stream (the server still heart-beating through a long reasoning silence)
2282
- * apart from a dead connection (no bytes at all). Not every transport emits it
2283
- * — the xhr transport does; treat its absence as "no extra liveness info".
2284
+ * Fires when the transport receives bytes, including SSE keep-alive comments.
2285
+ * Consumers can use this callback to reset the idle timeout.
2286
+ * The fetch and XHR transports emit it.
2287
+ * Custom transports can omit it if they cannot report byte activity.
2284
2288
  */
2285
2289
  onActivity?: () => void;
2286
2290
  };
@@ -19482,6 +19482,93 @@ function composeHooks(hooks) {
19482
19482
  };
19483
19483
  }
19484
19484
 
19485
+ // src/lib/chat/streamIdleTimeout.ts
19486
+ var StreamIdleTimeoutError = class extends Error {
19487
+ constructor(idleTimeoutMs) {
19488
+ super(`Stream timed out after ${idleTimeoutMs} ms without activity.`);
19489
+ this.name = "StreamIdleTimeoutError";
19490
+ this.idleTimeoutMs = idleTimeoutMs;
19491
+ }
19492
+ };
19493
+ function withStreamIdleTimeout(transport, idleTimeoutMs) {
19494
+ if (!(idleTimeoutMs > 0) || idleTimeoutMs === Infinity) return transport;
19495
+ return (options) => ({
19496
+ stream: (async function* () {
19497
+ const controller = new AbortController();
19498
+ let timer;
19499
+ let settled = false;
19500
+ let completed = false;
19501
+ let iterator;
19502
+ let interruption;
19503
+ let rejectPending;
19504
+ const disarm = () => {
19505
+ if (timer !== void 0) clearTimeout(timer);
19506
+ timer = void 0;
19507
+ };
19508
+ const interrupt = (error) => {
19509
+ if (interruption) return;
19510
+ interruption = error;
19511
+ rejectPending?.(error);
19512
+ controller.abort();
19513
+ };
19514
+ const arm = () => {
19515
+ if (settled || controller.signal.aborted) return;
19516
+ disarm();
19517
+ timer = setTimeout(() => {
19518
+ interrupt(new StreamIdleTimeoutError(idleTimeoutMs));
19519
+ }, idleTimeoutMs);
19520
+ };
19521
+ const onAbort = () => {
19522
+ controller.abort();
19523
+ };
19524
+ options.signal?.addEventListener("abort", onAbort, { once: true });
19525
+ try {
19526
+ if (options.signal?.aborted) {
19527
+ const error = new Error("Request aborted");
19528
+ error.name = "AbortError";
19529
+ throw error;
19530
+ }
19531
+ arm();
19532
+ iterator = transport({
19533
+ ...options,
19534
+ signal: controller.signal,
19535
+ onActivity: () => {
19536
+ arm();
19537
+ options.onActivity?.();
19538
+ }
19539
+ }).stream[Symbol.asyncIterator]();
19540
+ while (true) {
19541
+ if (interruption) throw interruption;
19542
+ const next = await new Promise((resolve, reject) => {
19543
+ rejectPending = reject;
19544
+ Promise.resolve(iterator.next()).then(resolve, reject);
19545
+ });
19546
+ rejectPending = void 0;
19547
+ if (next.done) {
19548
+ completed = true;
19549
+ break;
19550
+ }
19551
+ arm();
19552
+ yield next.value;
19553
+ }
19554
+ } finally {
19555
+ settled = true;
19556
+ rejectPending = void 0;
19557
+ disarm();
19558
+ options.signal?.removeEventListener("abort", onAbort);
19559
+ if (!completed) {
19560
+ controller.abort();
19561
+ try {
19562
+ void iterator?.return?.().catch(() => {
19563
+ });
19564
+ } catch {
19565
+ }
19566
+ }
19567
+ }
19568
+ })()
19569
+ });
19570
+ }
19571
+
19485
19572
  // src/lib/chat/useChat/utils.ts
19486
19573
  import { jsonrepair } from "jsonrepair";
19487
19574
  function parseToolArguments(raw) {
@@ -21645,7 +21732,20 @@ var defaultTransport = (options) => {
21645
21732
  } catch {
21646
21733
  }
21647
21734
  }
21648
- return response;
21735
+ if (!response.body || !options.onActivity) return response;
21736
+ const body = response.body.pipeThrough(
21737
+ new TransformStream({
21738
+ transform(chunk, controller) {
21739
+ if (chunk.byteLength > 0) options.onActivity?.();
21740
+ controller.enqueue(chunk);
21741
+ }
21742
+ })
21743
+ );
21744
+ return new Response(body, {
21745
+ status: response.status,
21746
+ statusText: response.statusText,
21747
+ headers: response.headers
21748
+ });
21649
21749
  };
21650
21750
  return createSseClient({
21651
21751
  method: options.method ?? "POST",
@@ -21702,6 +21802,7 @@ async function runToolLoop(options) {
21702
21802
  conversationId,
21703
21803
  smoothing,
21704
21804
  signal,
21805
+ idleTimeoutMs = 12e4,
21705
21806
  resumable,
21706
21807
  detachSignal,
21707
21808
  onStreamMeta,
@@ -21715,13 +21816,14 @@ async function runToolLoop(options) {
21715
21816
  onStepFinish,
21716
21817
  onRequest,
21717
21818
  onStreamRetry,
21718
- transport: makeStreamingRequest = defaultTransport,
21819
+ transport = defaultTransport,
21719
21820
  preProcessors,
21720
21821
  maxConnectorCalls = 2,
21721
21822
  hooks: hooksOption,
21722
21823
  piiRedaction,
21723
21824
  onPiiRedacted
21724
21825
  } = options;
21826
+ const makeStreamingRequest = withStreamIdleTimeout(transport, idleTimeoutMs);
21725
21827
  const hooks = Array.isArray(hooksOption) ? composeHooks(hooksOption) : hooksOption;
21726
21828
  const runId = generateRunId();
21727
21829
  let messages = options.messages;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anuma/sdk",
3
- "version": "6.39.2",
3
+ "version": "6.39.3",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",