@agentskit/adapters 0.17.3 → 0.18.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/README.md CHANGED
@@ -258,6 +258,8 @@ const agent = createAgent({ model, tools: [add] })
258
258
  ## Stream guarantees
259
259
 
260
260
  - A stream terminates exactly once with `done` or `error`; terminal errors carry an `Error` in `metadata.error`.
261
+ - Fetch retries use `@agentskit/net` backoff and `Retry-After` parsing; the `fetchWithRetry` and adapter `retry` options keep their 3-attempt defaults. `readSSELines` remains as a deprecated compatibility wrapper; new parsers should consume `parseSSE` events directly.
262
+ - SSE event data preserves whitespace and joins multiple `data:` fields with newlines. NDJSON readers flush a final UTF-8 chunk and accept a last record without a newline.
261
263
  - Provider streams that close before their native completion marker are treated as truncated, not successful.
262
264
  - `abort(reason)` propagates to active fetch readers and SDK requests and terminates with the same error semantics.
263
265
  - Native tool histories preserve call/result correlation. Parallel tool results are encoded in a single provider turn where required.
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var net = require('@agentskit/net');
3
4
  var core = require('@agentskit/core');
4
5
 
5
6
  // src/catalog/schema.ts
@@ -297135,29 +297136,6 @@ function applyOverrides(snapshot, overrides) {
297135
297136
  const providers = snapshot.providers.map((p) => applyToProvider(p, overrides)).filter((p) => p !== void 0);
297136
297137
  return { ...snapshot, providers };
297137
297138
  }
297138
-
297139
- // src/stream-lines.ts
297140
- async function* readSSELines(stream) {
297141
- const reader = stream.getReader();
297142
- const decoder = new TextDecoder();
297143
- let buffer = "";
297144
- try {
297145
- while (true) {
297146
- const { done, value } = await reader.read();
297147
- if (done) break;
297148
- buffer += decoder.decode(value, { stream: true });
297149
- const lines = buffer.split("\n");
297150
- buffer = lines.pop() ?? "";
297151
- for (const line of lines) {
297152
- if (!line.startsWith("data: ")) continue;
297153
- const data = line.slice(6).trim();
297154
- if (data) yield data;
297155
- }
297156
- }
297157
- } finally {
297158
- reader.releaseLock();
297159
- }
297160
- }
297161
297139
  function isAbortError(err) {
297162
297140
  if (err instanceof DOMException && err.name === "AbortError") return true;
297163
297141
  if (err instanceof Error && err.name === "AbortError") return true;
@@ -297233,7 +297211,78 @@ async function cancelBody(body) {
297233
297211
  }
297234
297212
  }
297235
297213
 
297236
- // src/openai-stream.ts
297214
+ // src/retry.ts
297215
+ var DEFAULT_RETRY = {
297216
+ maxAttempts: 3,
297217
+ baseDelayMs: 500,
297218
+ maxDelayMs: 8e3,
297219
+ jitter: true,
297220
+ retryOn: ({ error, response }) => {
297221
+ if (response) return [408, 429, 500, 502, 503, 504].includes(response.status);
297222
+ if (isAbortError(error)) return false;
297223
+ return true;
297224
+ }
297225
+ };
297226
+ var RetryableResponse = class extends Error {
297227
+ constructor(response, retryAfterMs) {
297228
+ super(`HTTP ${response.status}`);
297229
+ this.response = response;
297230
+ this.retryAfterMs = retryAfterMs;
297231
+ }
297232
+ };
297233
+ async function fetchWithRetry(doFetch, signal, retryOpt = {}) {
297234
+ const opts = { ...DEFAULT_RETRY, ...retryOpt };
297235
+ const maxAttempts = Math.floor(opts.maxAttempts);
297236
+ if (!Number.isFinite(maxAttempts) || maxAttempts < 1) {
297237
+ throw new core.AdapterError({
297238
+ code: core.ErrorCodes.AK_CONFIG_INVALID,
297239
+ message: "Retry maxAttempts must be finite and at least 1 after flooring"
297240
+ });
297241
+ }
297242
+ if (signal.aborted) throw new DOMException("Aborted", "AbortError");
297243
+ try {
297244
+ return await net.retry(async ({ attempt }) => {
297245
+ let response;
297246
+ try {
297247
+ response = await doFetch(signal);
297248
+ } catch (error) {
297249
+ if (signal.aborted) throw new DOMException("Aborted", "AbortError");
297250
+ throw error;
297251
+ }
297252
+ if (response.ok || attempt >= maxAttempts || !opts.retryOn({ response, attempt })) return response;
297253
+ const retryAfter = net.parseRetryAfter(response.headers.get("retry-after"));
297254
+ await cancelBody(response.body);
297255
+ throw new RetryableResponse(
297256
+ response,
297257
+ retryAfter === void 0 ? void 0 : Math.min(retryAfter, opts.maxDelayMs)
297258
+ );
297259
+ }, {
297260
+ retries: maxAttempts - 1,
297261
+ minDelayMs: opts.baseDelayMs,
297262
+ maxDelayMs: opts.maxDelayMs,
297263
+ jitter: opts.jitter ? "full" : "none",
297264
+ shouldRetry: (error, attempt) => {
297265
+ if (error instanceof RetryableResponse) return true;
297266
+ if (isAbortError(error)) return false;
297267
+ return opts.retryOn({ error, attempt });
297268
+ },
297269
+ delayFor: (error) => error instanceof RetryableResponse ? error.retryAfterMs : void 0,
297270
+ onRetry: ({ error, attempt, delayMs }) => {
297271
+ retryOpt.onRetry?.({
297272
+ attempt,
297273
+ delayMs,
297274
+ reason: error instanceof Error ? error.message : String(error)
297275
+ });
297276
+ },
297277
+ sleep: retryOpt.sleep ? (ms, retrySignal) => abortableSleep(ms, retrySignal ?? signal, retryOpt.sleep) : net.sleep,
297278
+ signal
297279
+ });
297280
+ } catch (error) {
297281
+ if (signal.aborted) throw new DOMException("Aborted", "AbortError");
297282
+ if (error instanceof RetryableResponse) return error.response;
297283
+ throw error;
297284
+ }
297285
+ }
297237
297286
  var SUCCESS_FINISH_REASONS = /* @__PURE__ */ new Set(["stop", "tool_calls", "function_call"]);
297238
297287
  async function* parseOpenAIStream(stream) {
297239
297288
  const pendingToolCalls = /* @__PURE__ */ new Map();
@@ -297265,7 +297314,7 @@ async function* parseOpenAIStream(stream) {
297265
297314
  pendingToolCalls.clear();
297266
297315
  return true;
297267
297316
  };
297268
- for await (const data of readSSELines(stream)) {
297317
+ for await (const { data } of net.parseSSE(stream)) {
297269
297318
  if (data === "[DONE]") {
297270
297319
  if (finishReason !== void 0 && !SUCCESS_FINISH_REASONS.has(finishReason)) {
297271
297320
  pendingToolCalls.clear();
@@ -297368,80 +297417,16 @@ function toProviderMessages(messages) {
297368
297417
  }
297369
297418
  return output;
297370
297419
  }
297371
- var DEFAULT_RETRY = {
297372
- maxAttempts: 3,
297373
- baseDelayMs: 500,
297374
- maxDelayMs: 8e3,
297375
- jitter: true,
297376
- retryOn: ({ error, response }) => {
297377
- if (response) {
297378
- return [408, 429, 500, 502, 503, 504].includes(response.status);
297379
- }
297380
- if (isAbortError(error)) return false;
297381
- return true;
297382
- }
297383
- };
297384
- function defaultSleep(ms) {
297385
- return new Promise((resolve) => setTimeout(resolve, ms));
297386
- }
297387
- function computeDelay(attempt, opts) {
297388
- const exp = Math.min(opts.maxDelayMs, opts.baseDelayMs * Math.pow(2, attempt - 1));
297389
- if (!opts.jitter) return exp;
297390
- return Math.floor(Math.random() * exp);
297391
- }
297392
- function parseRetryAfter(value, maxDelayMs) {
297393
- if (!value) return void 0;
297394
- const n = Number(value);
297395
- if (Number.isFinite(n) && n >= 0) return Math.min(n * 1e3, maxDelayMs);
297396
- const date = Date.parse(value);
297397
- if (!Number.isNaN(date)) return Math.min(maxDelayMs, Math.max(0, date - Date.now()));
297398
- return void 0;
297399
- }
297400
- async function fetchWithRetry(doFetch, signal, retryOpt = {}) {
297401
- const opts = {
297402
- ...DEFAULT_RETRY,
297403
- ...retryOpt
297404
- };
297405
- const sleep = retryOpt.sleep ?? defaultSleep;
297406
- let lastError;
297407
- for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {
297408
- if (signal.aborted) throw new DOMException("Aborted", "AbortError");
297409
- try {
297410
- const response = await doFetch(signal);
297411
- if (response.ok) return response;
297412
- if (attempt >= opts.maxAttempts || !opts.retryOn({ response, attempt })) {
297413
- return response;
297414
- }
297415
- const retryAfterMs = parseRetryAfter(response.headers.get("retry-after"), opts.maxDelayMs);
297416
- const delay = retryAfterMs ?? computeDelay(attempt, opts);
297417
- retryOpt.onRetry?.({ attempt, delayMs: delay, reason: `HTTP ${response.status}` });
297418
- await cancelBody(response.body);
297419
- await abortableSleep(delay, signal, sleep);
297420
- } catch (err) {
297421
- lastError = err;
297422
- if (isAbortError(err)) throw err;
297423
- if (attempt >= opts.maxAttempts || !opts.retryOn({ error: err, attempt })) throw err;
297424
- const delay = computeDelay(attempt, opts);
297425
- retryOpt.onRetry?.({
297426
- attempt,
297427
- delayMs: delay,
297428
- reason: err instanceof Error ? err.message : String(err)
297429
- });
297430
- await abortableSleep(delay, signal, sleep);
297431
- }
297432
- }
297433
- throw lastError ?? new Error("fetchWithRetry: exhausted attempts");
297434
- }
297435
297420
 
297436
297421
  // src/stream-source.ts
297437
- function createStreamSource(doFetch, parse, errorLabel, retry) {
297422
+ function createStreamSource(doFetch, parse, errorLabel, retry2) {
297438
297423
  let abortController = new AbortController();
297439
297424
  return {
297440
297425
  stream: async function* () {
297441
297426
  const controller = abortController;
297442
297427
  if (!controller) return;
297443
297428
  try {
297444
- const response = await fetchWithRetry(doFetch, controller.signal, retry ?? {});
297429
+ const response = await fetchWithRetry(doFetch, controller.signal, retry2 ?? {});
297445
297430
  if (!response.ok) {
297446
297431
  await cancelBody(response.body);
297447
297432
  yield adapterErrorChunk(`${errorLabel} error: ${response.status}`);
@@ -297470,7 +297455,7 @@ function createStreamSource(doFetch, parse, errorLabel, retry) {
297470
297455
 
297471
297456
  // src/openai.ts
297472
297457
  function openai(config) {
297473
- const { apiKey, model, baseUrl = "https://api.openai.com", retry } = config;
297458
+ const { apiKey, model, baseUrl = "https://api.openai.com", retry: retry2 } = config;
297474
297459
  const apiRoot = baseUrl.replace(/\/v1\/?$/, "");
297475
297460
  const isCanonicalOpenAI = (() => {
297476
297461
  try {
@@ -297520,7 +297505,7 @@ function openai(config) {
297520
297505
  }),
297521
297506
  parseOpenAIStream,
297522
297507
  "OpenAI API",
297523
- retry
297508
+ retry2
297524
297509
  );
297525
297510
  }
297526
297511
  };