@prestyj/agent 4.4.0 → 4.5.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.
package/dist/index.cjs CHANGED
@@ -194,23 +194,51 @@ function isTransportFailure(err) {
194
194
  }
195
195
  return false;
196
196
  }
197
+ function createAbortError() {
198
+ return new DOMException("Aborted", "AbortError");
199
+ }
200
+ function abortablePromise(promise, signal) {
201
+ if (!signal) return promise;
202
+ if (signal.aborted) return Promise.reject(createAbortError());
203
+ return new Promise((resolve, reject) => {
204
+ let settled = false;
205
+ const cleanup = () => signal.removeEventListener("abort", onAbort);
206
+ const resolveOnce = (value) => {
207
+ if (settled) return;
208
+ settled = true;
209
+ cleanup();
210
+ resolve(value);
211
+ };
212
+ const rejectOnce = (err) => {
213
+ if (settled) return;
214
+ settled = true;
215
+ cleanup();
216
+ reject(err instanceof Error ? err : new Error(String(err)));
217
+ };
218
+ const onAbort = () => rejectOnce(createAbortError());
219
+ signal.addEventListener("abort", onAbort, { once: true });
220
+ promise.then(resolveOnce, rejectOnce);
221
+ });
222
+ }
197
223
  function abortableSleep(ms, signal) {
198
- if (signal?.aborted) {
199
- return Promise.reject(new DOMException("Aborted", "AbortError"));
200
- }
224
+ if (signal?.aborted) return Promise.reject(createAbortError());
201
225
  return new Promise((resolve, reject) => {
202
- let onAbort = null;
203
226
  const timer = setTimeout(() => {
204
- if (onAbort) signal?.removeEventListener("abort", onAbort);
227
+ signal?.removeEventListener("abort", onAbort);
205
228
  resolve();
206
229
  }, ms);
207
- onAbort = () => {
230
+ const onAbort = () => {
208
231
  clearTimeout(timer);
209
- reject(new DOMException("Aborted", "AbortError"));
232
+ reject(createAbortError());
210
233
  };
211
234
  signal?.addEventListener("abort", onAbort, { once: true });
212
235
  });
213
236
  }
237
+ function closeIterator(iterator) {
238
+ if (!iterator?.return) return;
239
+ Promise.resolve(iterator.return()).catch(() => {
240
+ });
241
+ }
214
242
  async function* agentLoop(messages, options) {
215
243
  const maxTurns = options.maxTurns ?? DEFAULT_MAX_TURNS;
216
244
  const maxContinuations = options.maxContinuations ?? 5;
@@ -335,6 +363,7 @@ async function* agentLoop(messages, options) {
335
363
  idleTimedOut = true;
336
364
  streamController.abort();
337
365
  }, hardTimeoutMs);
366
+ let streamIterator = null;
338
367
  try {
339
368
  diag("stream_call", { nonStreaming: useNonStreamingFallback });
340
369
  streamCallStart = Date.now();
@@ -374,7 +403,11 @@ async function* agentLoop(messages, options) {
374
403
  streamCallStart = Date.now();
375
404
  lastYieldEndTime = Date.now();
376
405
  resetIdleTimer();
377
- for await (const event of result) {
406
+ streamIterator = result[Symbol.asyncIterator]();
407
+ while (true) {
408
+ const next = await abortablePromise(streamIterator.next(), streamController.signal);
409
+ if (next.done) break;
410
+ const event = next.value;
378
411
  const pullTime = Date.now();
379
412
  const consumerLag = pullTime - lastYieldEndTime;
380
413
  if (streamEventCount > 0 && consumerLag > maxConsumerLagMs) {
@@ -471,8 +504,9 @@ async function* agentLoop(messages, options) {
471
504
  maxConsumerLagMs,
472
505
  eventTypes: eventTypeCounts
473
506
  });
474
- response = await result.response;
507
+ response = await abortablePromise(result.response, streamController.signal);
475
508
  } catch (err) {
509
+ if (streamController.signal.aborted) closeIterator(streamIterator);
476
510
  const errMsg = err instanceof Error ? err.message : String(err);
477
511
  diag("stream_error", {
478
512
  error: errMsg.slice(0, 200),
@@ -872,7 +906,10 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
872
906
  });
873
907
  }
874
908
  };
875
- const raw = await tool.execute(parsed, ctx);
909
+ const raw = await abortablePromise(
910
+ Promise.resolve().then(() => tool.execute(parsed, ctx)),
911
+ ctx.signal
912
+ );
876
913
  const normalized = normalizeToolResult(raw);
877
914
  resultContent = normalized.content;
878
915
  details = normalized.details;