@qoniai/qoni 0.4.0 → 0.4.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.
package/dist/index.cjs CHANGED
@@ -25,8 +25,7 @@ __export(index_exports, {
25
25
  InteractionStatuses: () => InteractionStatuses,
26
26
  InteractionTypes: () => InteractionTypes,
27
27
  MonitorHandle: () => MonitorHandle,
28
- Qoni: () => QoniAgentKit,
29
- QoniAgentKit: () => QoniAgentKit,
28
+ Qoni: () => Qoni,
30
29
  QoniAuthError: () => QoniAuthError,
31
30
  QoniDelegationRequiredError: () => QoniDelegationRequiredError,
32
31
  QoniError: () => QoniError,
@@ -817,11 +816,11 @@ var RunHandle = class {
817
816
  }
818
817
  /** Drive the run to a terminal state and return the settled result. */
819
818
  async wait(opts = {}) {
820
- const { signal, timedOut } = withTimeout(opts.signal, opts.timeoutMs);
819
+ const { signal, timedOut, dispose } = withTimeout(opts.signal, opts.timeoutMs);
821
820
  let lastEventId;
822
821
  let eventIdAtLastClose;
823
822
  let sawCleanClose = false;
824
- let terminalPayload;
823
+ let terminalDetail;
825
824
  let terminalDoneReason;
826
825
  let screenshotIndex = 0;
827
826
  try {
@@ -829,24 +828,28 @@ var RunHandle = class {
829
828
  for await (const event of this.events({
830
829
  signal,
831
830
  lastEventId,
832
- onWireEvent: opts.onWireEvent,
831
+ onWireEvent: (wire) => waitWithSignal(() => {
832
+ if (wire.id !== void 0) lastEventId = wire.id;
833
+ return opts.onWireEvent?.(wire);
834
+ }, signal),
833
835
  onReconnect: opts.onReconnect
834
836
  })) {
835
- if (event.raw.id) lastEventId = event.raw.id;
836
- await opts.onEvent?.(event);
837
+ await waitWithSignal(() => opts.onEvent?.(event), signal);
837
838
  if (event.type === "screenshot") {
838
- await opts.onScreenshot?.(event.image, screenshotIndex++);
839
+ await waitWithSignal(() => opts.onScreenshot?.(event.image, screenshotIndex++), signal);
839
840
  } else if (event.type === "interaction") {
840
- await opts.onInteraction?.(this.interactionHandle(event.data), event);
841
+ await waitWithSignal(() => opts.onInteraction?.(this.interactionHandle(event.data), event), signal);
841
842
  }
842
843
  if (event.isTerminal) {
843
- terminalPayload = isJsonObject(event.raw.data) ? event.raw.data : void 0;
844
844
  if (event.type === "done") terminalDoneReason = event.data.terminalReason || void 0;
845
845
  break settled;
846
846
  }
847
847
  }
848
- const detail2 = await this.ops.getDetail();
849
- if (isTerminalRunStatus(detail2.status)) break;
848
+ const detail2 = await waitWithSignal(() => this.ops.getDetail(signal), signal);
849
+ if (isTerminalRunStatus(normalizeRunStatus(this.id, detail2).status)) {
850
+ terminalDetail = detail2;
851
+ break;
852
+ }
850
853
  if (sawCleanClose && lastEventId === eventIdAtLastClose) {
851
854
  throw new QoniError(
852
855
  `run event stream ended before a terminal event while the run is still "${String(detail2.status)}" \u2014 re-attach or poll status()`,
@@ -856,6 +859,11 @@ var RunHandle = class {
856
859
  sawCleanClose = true;
857
860
  eventIdAtLastClose = lastEventId;
858
861
  }
862
+ const detail = terminalDetail ?? await waitWithSignal(() => this.ops.getDetail(signal), signal);
863
+ this.#adoptSessionRef(detail);
864
+ const result = settleRunResult(this.id, detail, [], terminalDoneReason);
865
+ result.artifacts = this.ops.listArtifacts ? await waitWithSignal(() => this.ops.listArtifacts(signal), signal) : [];
866
+ return result;
859
867
  } catch (err) {
860
868
  if (timedOut() && !opts.signal?.aborted) {
861
869
  throw new QoniTimeoutError(
@@ -864,17 +872,9 @@ var RunHandle = class {
864
872
  );
865
873
  }
866
874
  throw err;
875
+ } finally {
876
+ dispose();
867
877
  }
868
- let detail;
869
- try {
870
- detail = await this.ops.getDetail();
871
- } catch (err) {
872
- if (!terminalPayload) throw err;
873
- detail = terminalPayload;
874
- }
875
- this.#adoptSessionRef(detail);
876
- const artifacts = this.ops.listArtifacts ? await this.ops.listArtifacts() : [];
877
- return settleRunResult(this.id, detail, artifacts, terminalDoneReason);
878
878
  }
879
879
  /**
880
880
  * Wrap an {@link Interaction} (from `event.data` of an `interaction` event)
@@ -927,15 +927,12 @@ function normalizeRunStatus(id, detail) {
927
927
  function settleRunResult(runId, detail, artifacts, fallbackTerminalReason) {
928
928
  const terminalReason = (typeof detail.terminal_reason === "string" ? detail.terminal_reason : void 0) ?? fallbackTerminalReason;
929
929
  const isTaskSuccessful = typeof detail.is_task_successful === "boolean" ? detail.is_task_successful : void 0;
930
- let status;
931
- if (isTerminalRunStatus(detail.status)) {
932
- status = detail.status;
933
- } else if (terminalReason === "canceled") {
934
- status = "canceled";
935
- } else if (terminalReason === "failed" || terminalReason === "expired" || isTaskSuccessful === false) {
936
- status = "failed";
937
- } else {
938
- status = "succeeded";
930
+ const status = normalizeRunStatus(runId, detail).status;
931
+ if (!isTerminalRunStatus(status)) {
932
+ throw new QoniError(
933
+ "run detail did not confirm a terminal state \u2014 re-attach or poll status()",
934
+ { code: "upstream.failed", retryable: true, body: detail }
935
+ );
939
936
  }
940
937
  return {
941
938
  runId,
@@ -962,19 +959,40 @@ function isVideoFrame(wire) {
962
959
  return type === "browser_video_frame" || type === "run.browser_video_frame";
963
960
  }
964
961
  function withTimeout(signal, timeoutMs) {
965
- if (!timeoutMs) return { signal, timedOut: () => false };
962
+ if (!timeoutMs) return { signal, timedOut: () => false, dispose: () => {
963
+ } };
966
964
  const controller = new AbortController();
967
965
  let fired = false;
968
966
  const timer = setTimeout(() => {
969
967
  fired = true;
970
968
  controller.abort();
971
969
  }, timeoutMs);
972
- controller.signal.addEventListener("abort", () => clearTimeout(timer), { once: true });
970
+ const onAbort = () => controller.abort(signal?.reason);
971
+ const dispose = () => {
972
+ clearTimeout(timer);
973
+ signal?.removeEventListener("abort", onAbort);
974
+ };
975
+ controller.signal.addEventListener("abort", dispose, { once: true });
973
976
  if (signal) {
974
- if (signal.aborted) controller.abort();
975
- else signal.addEventListener("abort", () => controller.abort(), { once: true });
977
+ if (signal.aborted) onAbort();
978
+ else signal.addEventListener("abort", onAbort, { once: true });
976
979
  }
977
- return { signal: controller.signal, timedOut: () => fired };
980
+ return { signal: controller.signal, timedOut: () => fired, dispose };
981
+ }
982
+ function waitWithSignal(operation, signal) {
983
+ if (!signal) return Promise.resolve().then(operation);
984
+ return new Promise((resolve, reject) => {
985
+ const onAbort = () => reject(signal.reason ?? new DOMException("Aborted", "AbortError"));
986
+ if (signal.aborted) {
987
+ onAbort();
988
+ return;
989
+ }
990
+ signal.addEventListener("abort", onAbort, { once: true });
991
+ Promise.resolve().then(() => {
992
+ signal.throwIfAborted();
993
+ return operation();
994
+ }).then(resolve, reject).finally(() => signal.removeEventListener("abort", onAbort));
995
+ });
978
996
  }
979
997
 
980
998
  // src/deep-research.ts
@@ -989,6 +1007,7 @@ function createDeepResearchNamespace(transport) {
989
1007
  `/deep_research/runs/${encodeURIComponent(input.runId)}`,
990
1008
  input.token,
991
1009
  {
1010
+ signal: input.signal,
992
1011
  requiredScopes: ["webagent.deep_research:read"]
993
1012
  }
994
1013
  ),
@@ -1034,6 +1053,7 @@ function createDeepResearchNamespace(transport) {
1034
1053
  `/deep_research/runs/${encodeURIComponent(input.runId)}/artifacts`,
1035
1054
  input.token,
1036
1055
  {
1056
+ signal: input.signal,
1037
1057
  requiredScopes: ["webagent.deep_research:read"]
1038
1058
  }
1039
1059
  ),
@@ -1048,7 +1068,7 @@ function createDeepResearchNamespace(transport) {
1048
1068
  };
1049
1069
  function buildOps(token, runId) {
1050
1070
  return {
1051
- getDetail: async () => asRecord((await api.get({ token, runId })).data),
1071
+ getDetail: async (signal) => asRecord((await api.get({ token, runId, signal })).data),
1052
1072
  streamEvents: (opts) => api.events({
1053
1073
  token,
1054
1074
  runId,
@@ -1068,8 +1088,8 @@ function createDeepResearchNamespace(transport) {
1068
1088
  );
1069
1089
  },
1070
1090
  cancel: async () => asRecord((await api.cancel({ token, runId })).data),
1071
- listArtifacts: async () => {
1072
- const res = await api.listArtifacts({ token, runId });
1091
+ listArtifacts: async (signal) => {
1092
+ const res = await api.listArtifacts({ token, runId, signal });
1073
1093
  const items = Array.isArray(res.data?.items) ? res.data.items : [];
1074
1094
  return items.filter(isJsonObject).map((item) => toArtifact(item, token, runId));
1075
1095
  }
@@ -1189,6 +1209,7 @@ function createDoAnythingNamespace(transport) {
1189
1209
  `/do_anything/runs/${encodeURIComponent(input.runId)}`,
1190
1210
  input.token,
1191
1211
  {
1212
+ signal: input.signal,
1192
1213
  requiredScopes: ["webagent.do_anything:read"]
1193
1214
  }
1194
1215
  ),
@@ -1246,7 +1267,7 @@ function createDoAnythingNamespace(transport) {
1246
1267
  };
1247
1268
  function buildOps(token, runId, capture) {
1248
1269
  return {
1249
- getDetail: async () => asRecord2((await api.getRun({ token, runId })).data),
1270
+ getDetail: async (signal) => asRecord2((await api.getRun({ token, runId, signal })).data),
1250
1271
  streamEvents: (opts) => api.events({
1251
1272
  token,
1252
1273
  runId,
@@ -1840,6 +1861,7 @@ function createWebSearchNamespace(transport) {
1840
1861
  `/web_search/runs/${encodeURIComponent(input.runId)}`,
1841
1862
  input.token,
1842
1863
  {
1864
+ signal: input.signal,
1843
1865
  requiredScopes: ["webagent.web_search:read"]
1844
1866
  }
1845
1867
  ),
@@ -1865,7 +1887,7 @@ function createWebSearchNamespace(transport) {
1865
1887
  };
1866
1888
  function buildOps(token, runId) {
1867
1889
  return {
1868
- getDetail: async () => asRecord4((await api.get({ token, runId })).data),
1890
+ getDetail: async (signal) => asRecord4((await api.get({ token, runId, signal })).data),
1869
1891
  streamEvents: (opts) => api.events({
1870
1892
  token,
1871
1893
  runId,
@@ -1958,8 +1980,8 @@ function renameKeys5(value, mapping) {
1958
1980
  }
1959
1981
 
1960
1982
  // src/client.ts
1961
- var DEFAULT_QONI_HOST = "https://anima.eazo.ai/dashboard";
1962
- var QoniAgentKit = class {
1983
+ var DEFAULT_QONI_HOST = "https://dashboard.qoni.ai";
1984
+ var Qoni = class {
1963
1985
  constructor(options) {
1964
1986
  this.options = options;
1965
1987
  const accessKey = options.accessKey ?? options.accessKeyId;
@@ -2138,7 +2160,9 @@ var QoniAgentKit = class {
2138
2160
  }
2139
2161
  }
2140
2162
  async webAgentJson(method, path, token, payload = {}) {
2163
+ payload.signal?.throwIfAborted();
2141
2164
  const runtimeToken = await this.productTokenFor("webagent", token, payload.requiredScopes);
2165
+ payload.signal?.throwIfAborted();
2142
2166
  const baseUrl = await this.baseUrlFor("webagent");
2143
2167
  return this.jsonRequest(
2144
2168
  baseUrl,
@@ -2149,9 +2173,11 @@ var QoniAgentKit = class {
2149
2173
  // Binary GET against the WebAgent API — artifact content downloads. JSON
2150
2174
  // error payloads still map to typed QoniErrors.
2151
2175
  async webAgentBytes(path, token, payload = {}) {
2176
+ payload.signal?.throwIfAborted();
2152
2177
  const runtimeToken = await this.productTokenFor("webagent", token, payload.requiredScopes);
2178
+ payload.signal?.throwIfAborted();
2153
2179
  const baseUrl = await this.baseUrlFor("webagent");
2154
- const response = await this.fetchWithTimeout(
2180
+ return this.fetchWithTimeout(
2155
2181
  urlWithBasePath(baseUrl, this.webAgentPath(runtimeToken, path), payload.query),
2156
2182
  {
2157
2183
  method: "GET",
@@ -2160,20 +2186,22 @@ var QoniAgentKit = class {
2160
2186
  authorization: `Bearer ${runtimeToken}`,
2161
2187
  ...payload.headers || {}
2162
2188
  }
2163
- }
2189
+ },
2190
+ async (response, signal) => {
2191
+ if (!response.ok) {
2192
+ throw errorFromPayload(
2193
+ response.status,
2194
+ await readJson(response, signal),
2195
+ `Qoni request failed with HTTP ${response.status}`
2196
+ );
2197
+ }
2198
+ return {
2199
+ bytes: await readBody(response, signal),
2200
+ mime: response.headers.get("content-type") || "application/octet-stream"
2201
+ };
2202
+ },
2203
+ payload.signal
2164
2204
  );
2165
- if (!response.ok) {
2166
- throw errorFromPayload(
2167
- response.status,
2168
- await readJson(response),
2169
- `Qoni request failed with HTTP ${response.status}`
2170
- );
2171
- }
2172
- const buffer = await response.arrayBuffer();
2173
- return {
2174
- bytes: new Uint8Array(buffer),
2175
- mime: response.headers.get("content-type") || "application/octet-stream"
2176
- };
2177
2205
  }
2178
2206
  async *webAgentSSE(path, token, payload = {}) {
2179
2207
  const runtimeToken = await this.productTokenFor("webagent", token, payload.requiredScopes);
@@ -2213,15 +2241,16 @@ var QoniAgentKit = class {
2213
2241
  });
2214
2242
  }
2215
2243
  async jsonRequest(baseUrl, pathname, options) {
2216
- const response = await this.fetchWithTimeout(
2244
+ const { response, payload } = await this.fetchWithTimeout(
2217
2245
  urlWithBasePath(baseUrl, pathname, options.query),
2218
2246
  {
2219
2247
  method: options.method,
2220
2248
  headers: requestHeaders(options),
2221
2249
  body: requestBody(options.body)
2222
- }
2250
+ },
2251
+ async (response2, signal) => ({ response: response2, payload: await readJson(response2, signal) }),
2252
+ options.signal
2223
2253
  );
2224
- const payload = await readJson(response);
2225
2254
  if (!response.ok) {
2226
2255
  throw errorFromPayload(
2227
2256
  response.status,
@@ -2271,45 +2300,55 @@ var QoniAgentKit = class {
2271
2300
  }
2272
2301
  }
2273
2302
  async *sseConnectOnce(baseUrl, pathname, options) {
2274
- const response = await this.fetchWithTimeout(
2275
- urlWithBasePath(baseUrl, pathname, options.query),
2276
- {
2277
- method: "GET",
2278
- headers: {
2279
- accept: "text/event-stream",
2280
- authorization: `Bearer ${options.token}`,
2281
- ...options.headers || {},
2282
- ...options.lastEventId ? { "last-event-id": options.lastEventId } : {}
2283
- }
2284
- },
2285
- options.signal,
2286
- { streamBody: true }
2287
- );
2288
- if (!response.ok) {
2289
- throw errorFromPayload(
2290
- response.status,
2291
- await readJson(response),
2292
- `Qoni stream failed with HTTP ${response.status}`
2293
- );
2294
- }
2295
- if (!response.body) {
2296
- throw errorFromPayload(502, void 0, "Qoni stream response has no body");
2297
- }
2298
- const reader = response.body.getReader();
2303
+ let cleanup;
2304
+ let reader;
2305
+ const onAbort = () => {
2306
+ void reader?.cancel(options.signal?.reason).catch(() => void 0);
2307
+ };
2299
2308
  const decoder = new TextDecoder();
2300
2309
  let buffer = "";
2301
2310
  try {
2311
+ const response = await this.fetchWithTimeout(
2312
+ urlWithBasePath(baseUrl, pathname, options.query),
2313
+ {
2314
+ method: "GET",
2315
+ headers: {
2316
+ accept: "text/event-stream",
2317
+ authorization: `Bearer ${options.token}`,
2318
+ ...options.headers || {},
2319
+ ...options.lastEventId ? { "last-event-id": options.lastEventId } : {}
2320
+ }
2321
+ },
2322
+ async (response2, signal) => {
2323
+ if (!response2.ok) {
2324
+ throw errorFromPayload(
2325
+ response2.status,
2326
+ await readJson(response2, signal),
2327
+ `Qoni stream failed with HTTP ${response2.status}`
2328
+ );
2329
+ }
2330
+ return response2;
2331
+ },
2332
+ options.signal,
2333
+ { streamCleanup: (dispose) => {
2334
+ cleanup = dispose;
2335
+ } }
2336
+ );
2337
+ if (!response.body) {
2338
+ throw errorFromPayload(502, void 0, "Qoni stream response has no body");
2339
+ }
2340
+ reader = response.body.getReader();
2341
+ options.signal?.addEventListener("abort", onAbort, { once: true });
2302
2342
  while (true) {
2303
- if (options.signal?.aborted) {
2304
- await reader.cancel().catch(() => void 0);
2305
- throw options.signal.reason || new DOMException("Aborted", "AbortError");
2306
- }
2343
+ options.signal?.throwIfAborted();
2307
2344
  const { done, value } = await reader.read();
2345
+ options.signal?.throwIfAborted();
2308
2346
  if (done) break;
2309
2347
  buffer += decoder.decode(value, { stream: true });
2310
2348
  const chunks = buffer.split(/\r?\n\r?\n/);
2311
2349
  buffer = chunks.pop() || "";
2312
2350
  for (const chunk of chunks) {
2351
+ options.signal?.throwIfAborted();
2313
2352
  const event = parseSSEEvent(chunk);
2314
2353
  if (event) yield event;
2315
2354
  }
@@ -2317,10 +2356,16 @@ var QoniAgentKit = class {
2317
2356
  const finalEvent = parseSSEEvent(buffer);
2318
2357
  if (finalEvent) yield finalEvent;
2319
2358
  } finally {
2320
- reader.releaseLock();
2359
+ cleanup?.();
2360
+ options.signal?.removeEventListener("abort", onAbort);
2361
+ void reader?.cancel().catch(() => void 0);
2362
+ try {
2363
+ reader?.releaseLock();
2364
+ } catch {
2365
+ }
2321
2366
  }
2322
2367
  }
2323
- async fetchWithTimeout(input, init, signal, opts) {
2368
+ async fetchWithTimeout(input, init, consume, signal, opts) {
2324
2369
  if (signal?.aborted) throw signal.reason || new DOMException("Aborted", "AbortError");
2325
2370
  const controller = new AbortController();
2326
2371
  const resolved = resolveLocalGenauthRequest(input);
@@ -2335,24 +2380,46 @@ var QoniAgentKit = class {
2335
2380
  didTimeout = true;
2336
2381
  controller.abort();
2337
2382
  }, this.timeoutMs);
2383
+ let response;
2338
2384
  try {
2339
- return await this.fetchImpl(resolved.url, { ...requestInit, signal: controller.signal });
2385
+ response = await new Promise((resolve, reject) => {
2386
+ const onAbort = () => reject(controller.signal.reason);
2387
+ controller.signal.addEventListener("abort", onAbort, { once: true });
2388
+ Promise.resolve().then(() => {
2389
+ controller.signal.throwIfAborted();
2390
+ return this.fetchImpl(resolved.url, { ...requestInit, signal: controller.signal });
2391
+ }).then((response2) => {
2392
+ if (controller.signal.aborted) {
2393
+ void response2.body?.cancel(controller.signal.reason).catch(() => void 0);
2394
+ reject(controller.signal.reason);
2395
+ } else {
2396
+ resolve(response2);
2397
+ }
2398
+ }, reject).finally(() => controller.signal.removeEventListener("abort", onAbort));
2399
+ });
2400
+ const result = await consume(response, controller.signal);
2401
+ controller.signal.throwIfAborted();
2402
+ return result;
2340
2403
  } catch (error) {
2341
- if (isAbortError(error) && didTimeout || isConnectTimeoutError(error)) {
2404
+ void response?.body?.cancel().catch(() => void 0);
2405
+ if (signal?.aborted) throw signal.reason;
2406
+ if (didTimeout || isConnectTimeoutError(error)) {
2342
2407
  throw timeoutError(error);
2343
2408
  }
2344
2409
  if (isFetchNetworkError(error)) throw networkError(error);
2345
2410
  throw error;
2346
2411
  } finally {
2347
2412
  clearTimeout(timeout);
2348
- if (!opts?.streamBody) signal?.removeEventListener("abort", abortFromSignal);
2413
+ const cleanup = () => signal?.removeEventListener("abort", abortFromSignal);
2414
+ if (opts?.streamCleanup) opts.streamCleanup(cleanup);
2415
+ else cleanup();
2349
2416
  }
2350
2417
  }
2351
2418
  async baseUrlFor(service) {
2352
2419
  const explicit = this.explicitBaseUrlFor(service);
2353
2420
  if (explicit) return explicit;
2354
- const runtime = await this.runtimeConfig();
2355
2421
  if (service === "qoni") return this.host;
2422
+ const runtime = await this.runtimeConfig();
2356
2423
  const hostOrigin = originBaseUrl(this.host);
2357
2424
  if (service === "genauth") return runtime.genauthBaseUrl ?? hostOrigin;
2358
2425
  if (service === "gumem") return runtime.gumemBaseUrl ?? hostOrigin;
@@ -2401,7 +2468,7 @@ var QoniAgentKit = class {
2401
2468
  pathname,
2402
2469
  {}
2403
2470
  );
2404
- const response = await this.fetchWithTimeout(
2471
+ const { response, payload } = await this.fetchWithTimeout(
2405
2472
  urlWithBasePath(this.host, pathname),
2406
2473
  {
2407
2474
  method: "GET",
@@ -2409,9 +2476,9 @@ var QoniAgentKit = class {
2409
2476
  accept: "application/json",
2410
2477
  ...headers
2411
2478
  }
2412
- }
2479
+ },
2480
+ async (response2, signal) => ({ response: response2, payload: await readJson(response2, signal) })
2413
2481
  );
2414
- const payload = await readJson(response);
2415
2482
  if (!response.ok) {
2416
2483
  throw errorFromPayload(
2417
2484
  response.status,
@@ -2505,18 +2572,52 @@ function requestBody(body) {
2505
2572
  function isBodyInit(value) {
2506
2573
  return typeof value === "string" || value instanceof ArrayBuffer || value instanceof Blob || value instanceof FormData || value instanceof URLSearchParams;
2507
2574
  }
2508
- async function readJson(response) {
2575
+ async function readBody(response, signal) {
2576
+ if (!response.body) {
2577
+ signal.throwIfAborted();
2578
+ return new Uint8Array();
2579
+ }
2580
+ const reader = response.body.getReader();
2581
+ const onAbort = () => {
2582
+ void reader.cancel(signal.reason).catch(() => void 0);
2583
+ };
2584
+ signal.addEventListener("abort", onAbort, { once: true });
2585
+ try {
2586
+ const chunks = [];
2587
+ let size = 0;
2588
+ for (; ; ) {
2589
+ signal.throwIfAborted();
2590
+ const { done, value } = await reader.read();
2591
+ signal.throwIfAborted();
2592
+ if (done) break;
2593
+ chunks.push(value);
2594
+ size += value.byteLength;
2595
+ }
2596
+ const bytes = new Uint8Array(size);
2597
+ let offset = 0;
2598
+ for (const chunk of chunks) {
2599
+ bytes.set(chunk, offset);
2600
+ offset += chunk.byteLength;
2601
+ }
2602
+ return bytes;
2603
+ } finally {
2604
+ signal.removeEventListener("abort", onAbort);
2605
+ void reader.cancel().catch(() => void 0);
2606
+ reader.releaseLock();
2607
+ }
2608
+ }
2609
+ async function readJson(response, signal) {
2509
2610
  const contentType = response.headers.get("content-type")?.toLowerCase() || "";
2510
- if (contentType.includes("ndjson") || contentType.includes("jsonl")) {
2511
- const body = await response.text();
2512
- if (!body.trim()) return [];
2513
- try {
2611
+ const body = new TextDecoder().decode(await readBody(response, signal));
2612
+ try {
2613
+ if (contentType.includes("ndjson") || contentType.includes("jsonl")) {
2614
+ if (!body.trim()) return [];
2514
2615
  return body.split(/\r?\n/).filter((line) => line.trim().length > 0).map((line) => JSON.parse(line));
2515
- } catch {
2516
- return void 0;
2517
2616
  }
2617
+ return JSON.parse(body);
2618
+ } catch {
2619
+ return void 0;
2518
2620
  }
2519
- return response.json().catch(() => void 0);
2520
2621
  }
2521
2622
  function normalizeResponse(payload, _service) {
2522
2623
  if (isJsonObject(payload) && ("data" in payload || "meta" in payload)) {
@@ -2759,6 +2860,7 @@ function isRetryableStreamError(err) {
2759
2860
  if (err && typeof err === "object") {
2760
2861
  const e = err;
2761
2862
  if (e.name === "AbortError") return false;
2863
+ if (e.status === 408) return true;
2762
2864
  if (typeof e.retryable === "boolean") return e.retryable;
2763
2865
  if (typeof e.status === "number") {
2764
2866
  return e.status >= 500 || e.status === 408 || e.status === 429;
@@ -2865,9 +2967,6 @@ function normalizeDelegateAgentTokenResponse(response) {
2865
2967
  }
2866
2968
  };
2867
2969
  }
2868
- function isAbortError(error) {
2869
- return error instanceof DOMException && error.name === "AbortError";
2870
- }
2871
2970
  function isConnectTimeoutError(error) {
2872
2971
  const cause = errorCause(error);
2873
2972
  return errorCode(cause) === "UND_ERR_CONNECT_TIMEOUT" || errorName(cause) === "ConnectTimeoutError";
@@ -2894,7 +2993,6 @@ function errorName(error) {
2894
2993
  InteractionTypes,
2895
2994
  MonitorHandle,
2896
2995
  Qoni,
2897
- QoniAgentKit,
2898
2996
  QoniAuthError,
2899
2997
  QoniDelegationRequiredError,
2900
2998
  QoniError,