190proof 1.0.101 → 1.0.104

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
@@ -273,6 +273,11 @@ Main function to make requests to any supported AI provider.
273
273
  - `retries`: `number` - Number of retry attempts (default: 5)
274
274
  - `chunkTimeoutMs`: `number` - Timeout for streaming chunks in ms (default: 15000)
275
275
 
276
+ Two optional per-request knobs live on `payload` (`GenericPayload`):
277
+
278
+ - `payload.requestTimeoutMs`: `number` - Per-attempt HTTP timeout in ms (default: 120000), honored by every adapter.
279
+ - `payload.signal`: `AbortSignal` - Caller-supplied cancellation. When it aborts, the in-flight provider request is cancelled and `callWithRetries` **rejects immediately — it does not retry or fall back** (both the retry loop and the fallback branch bail on `signal.aborted`). Threaded to the underlying fetch/axios/SDK call of each provider.
280
+
276
281
  #### Returns
277
282
 
278
283
  `Promise<ParsedResponseMessage>`:
package/dist/index.d.mts CHANGED
@@ -123,6 +123,11 @@ interface GenericMessage {
123
123
  * `redacted_thinking` blocks captured in
124
124
  * `ParsedResponseMessage.reasoningDetails`). Preserves the signatures /
125
125
  * encrypted payloads that providers validate on round-trip.
126
+ *
127
+ * Safe to echo regardless of which provider serves the next call: each
128
+ * serializer keeps only its own provider's block shapes (Anthropic keeps
129
+ * `thinking`/`redacted_thinking`; OpenAI-compat keeps `reasoning.*`), so a
130
+ * cross-provider fallback drops foreign blocks instead of 400ing.
126
131
  */
127
132
  reasoningDetails?: any;
128
133
  }
@@ -265,6 +270,14 @@ interface GenericPayload {
265
270
  * valid response isn't cut short.
266
271
  */
267
272
  requestTimeoutMs?: number;
273
+ /**
274
+ * Optional caller-supplied cancellation signal. When it aborts, the in-flight
275
+ * provider request is cancelled and `callWithRetries` rejects immediately —
276
+ * it does NOT retry or fall back (both retry loop and fallback branch bail on
277
+ * `signal.aborted`). Threaded through every adapter to the underlying
278
+ * fetch/axios/SDK call, mirroring `requestTimeoutMs`.
279
+ */
280
+ signal?: AbortSignal;
268
281
  }
269
282
 
270
283
  declare function parseModelString(model: string): {
package/dist/index.d.ts CHANGED
@@ -123,6 +123,11 @@ interface GenericMessage {
123
123
  * `redacted_thinking` blocks captured in
124
124
  * `ParsedResponseMessage.reasoningDetails`). Preserves the signatures /
125
125
  * encrypted payloads that providers validate on round-trip.
126
+ *
127
+ * Safe to echo regardless of which provider serves the next call: each
128
+ * serializer keeps only its own provider's block shapes (Anthropic keeps
129
+ * `thinking`/`redacted_thinking`; OpenAI-compat keeps `reasoning.*`), so a
130
+ * cross-provider fallback drops foreign blocks instead of 400ing.
126
131
  */
127
132
  reasoningDetails?: any;
128
133
  }
@@ -265,6 +270,14 @@ interface GenericPayload {
265
270
  * valid response isn't cut short.
266
271
  */
267
272
  requestTimeoutMs?: number;
273
+ /**
274
+ * Optional caller-supplied cancellation signal. When it aborts, the in-flight
275
+ * provider request is cancelled and `callWithRetries` rejects immediately —
276
+ * it does NOT retry or fall back (both retry loop and fallback branch bail on
277
+ * `signal.aborted`). Threaded through every adapter to the underlying
278
+ * fetch/axios/SDK call, mirroring `requestTimeoutMs`.
279
+ */
280
+ signal?: AbortSignal;
268
281
  }
269
282
 
270
283
  declare function parseModelString(model: string): {
package/dist/index.js CHANGED
@@ -141,8 +141,13 @@ function isHeicImage(name, mime) {
141
141
  // index.ts
142
142
  var sharp = require("sharp");
143
143
  var decode = require("heic-decode");
144
+ function anySignal(signals) {
145
+ return AbortSignal.any(
146
+ signals
147
+ );
148
+ }
144
149
  async function withRetries(identifier, apiName, fn, options = {}) {
145
- var _a, _b, _c, _d;
150
+ var _a, _b, _c, _d, _e;
146
151
  const { retries = 5, baseDelayMs = 125, onError } = options;
147
152
  logger_default.log(identifier, `Calling ${apiName} API with retries`);
148
153
  let lastError;
@@ -151,19 +156,21 @@ async function withRetries(identifier, apiName, fn, options = {}) {
151
156
  return await fn();
152
157
  } catch (error3) {
153
158
  lastError = error3;
159
+ if ((_a = options.signal) == null ? void 0 : _a.aborted)
160
+ throw error3;
154
161
  if (onError) {
155
162
  onError(error3, attempt);
156
163
  } else {
157
164
  logger_default.error(
158
165
  identifier,
159
166
  `Retry #${attempt} error: ${error3.message}`,
160
- ((_a = error3.response) == null ? void 0 : _a.data) || error3
167
+ ((_b = error3.response) == null ? void 0 : _b.data) || error3
161
168
  );
162
169
  }
163
170
  await timeout(baseDelayMs * attempt);
164
171
  }
165
172
  }
166
- const detail = ((_d = (_c = (_b = lastError == null ? void 0 : lastError.response) == null ? void 0 : _b.data) == null ? void 0 : _c.error) == null ? void 0 : _d.message) || (lastError == null ? void 0 : lastError.message) || String(lastError);
173
+ const detail = ((_e = (_d = (_c = lastError == null ? void 0 : lastError.response) == null ? void 0 : _c.data) == null ? void 0 : _d.error) == null ? void 0 : _e.message) || (lastError == null ? void 0 : lastError.message) || String(lastError);
167
174
  const error2 = new Error(
168
175
  `Failed to call ${apiName} API after ${retries} attempts: ${detail}`
169
176
  );
@@ -313,6 +320,14 @@ function buildOpenAIRequestConfig(identifier, model, config) {
313
320
  }
314
321
  };
315
322
  }
323
+ function filterOpenAICompatReasoningDetails(details) {
324
+ if (!Array.isArray(details))
325
+ return details || void 0;
326
+ const blocks = details.filter(
327
+ (block) => typeof (block == null ? void 0 : block.type) === "string" && block.type.startsWith("reasoning.")
328
+ );
329
+ return blocks.length ? blocks : void 0;
330
+ }
316
331
  async function prepareOpenAIPayload(identifier, payload) {
317
332
  var _a, _b;
318
333
  const preparedPayload = {
@@ -380,13 +395,16 @@ async function prepareOpenAIPayload(identifier, payload) {
380
395
  }
381
396
  if (message.reasoning)
382
397
  outMessage.reasoning = message.reasoning;
383
- if (message.reasoningDetails)
384
- outMessage.reasoning_details = message.reasoningDetails;
398
+ const reasoningDetails = filterOpenAICompatReasoningDetails(
399
+ message.reasoningDetails
400
+ );
401
+ if (reasoningDetails)
402
+ outMessage.reasoning_details = reasoningDetails;
385
403
  preparedPayload.messages.push(outMessage);
386
404
  }
387
405
  return preparedPayload;
388
406
  }
389
- async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs, requestTimeoutMs = 12e4) {
407
+ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs, requestTimeoutMs = 12e4, signal) {
390
408
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
391
409
  const functionNames = openAiPayload.tools ? new Set(openAiPayload.tools.map((fn) => fn.function.name)) : null;
392
410
  const { endpoint, headers } = buildOpenAIRequestConfig(
@@ -406,7 +424,10 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
406
424
  method: "POST",
407
425
  headers,
408
426
  body: JSON.stringify({ ...openAiPayload, stream: true }),
409
- signal: controller.signal
427
+ // Merge (don't overwrite) the internal timeout controller with the caller's
428
+ // cancellation signal so both an internal timeout and an external abort stop
429
+ // the stream.
430
+ signal: signal ? anySignal([controller.signal, signal]) : controller.signal
410
431
  });
411
432
  if (!response.body) {
412
433
  throw new Error("Stream error: no response body");
@@ -496,7 +517,7 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
496
517
  }
497
518
  }
498
519
  }
499
- async function callOpenAI(id, openAiPayload, openAiConfig, requestTimeoutMs = 12e4) {
520
+ async function callOpenAI(id, openAiPayload, openAiConfig, requestTimeoutMs = 12e4, signal) {
500
521
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
501
522
  const { endpoint, headers } = buildOpenAIRequestConfig(
502
523
  id,
@@ -511,7 +532,8 @@ async function callOpenAI(id, openAiPayload, openAiConfig, requestTimeoutMs = 12
511
532
  method: "POST",
512
533
  headers,
513
534
  body: JSON.stringify({ ...openAiPayload, stream: false }),
514
- signal: controller.signal
535
+ // Merge the internal timeout controller with the caller's cancellation signal.
536
+ signal: signal ? anySignal([controller.signal, signal]) : controller.signal
515
537
  });
516
538
  if (!response.ok) {
517
539
  const errorData = await response.json();
@@ -574,7 +596,7 @@ async function callOpenAI(id, openAiPayload, openAiConfig, requestTimeoutMs = 12
574
596
  } : null
575
597
  };
576
598
  }
577
- async function callOpenAiWithRetries(id, openAiPayload, openAiConfig, retries = 5, chunkTimeoutMs = 15e3, requestTimeoutMs = 12e4) {
599
+ async function callOpenAiWithRetries(id, openAiPayload, openAiConfig, retries = 5, chunkTimeoutMs = 15e3, requestTimeoutMs = 12e4, signal) {
578
600
  logger_default.log(
579
601
  id,
580
602
  "Calling OpenAI API with retries:",
@@ -593,14 +615,16 @@ async function callOpenAiWithRetries(id, openAiPayload, openAiConfig, retries =
593
615
  openAiPayload,
594
616
  openAiConfig,
595
617
  chunkTimeoutMs,
596
- requestTimeoutMs
618
+ requestTimeoutMs,
619
+ signal
597
620
  );
598
621
  } else {
599
- return callOpenAI(id, openAiPayload, openAiConfig, requestTimeoutMs);
622
+ return callOpenAI(id, openAiPayload, openAiConfig, requestTimeoutMs, signal);
600
623
  }
601
624
  },
602
625
  {
603
626
  retries,
627
+ signal,
604
628
  baseDelayMs: 250,
605
629
  onError: (error2, attempt) => {
606
630
  var _a, _b;
@@ -715,7 +739,9 @@ async function prepareAnthropicPayload(_identifier, payload) {
715
739
  });
716
740
  }
717
741
  }
718
- const leadingBlocks = message.role === "assistant" && Array.isArray(message.reasoningDetails) ? message.reasoningDetails : [];
742
+ const leadingBlocks = message.role === "assistant" && Array.isArray(message.reasoningDetails) ? message.reasoningDetails.filter(
743
+ (block) => (block == null ? void 0 : block.type) === "thinking" || (block == null ? void 0 : block.type) === "redacted_thinking"
744
+ ) : [];
719
745
  const toolUseBlocks = (message.functionCalls || []).map((fc, i) => {
720
746
  var _a;
721
747
  return {
@@ -732,7 +758,7 @@ async function prepareAnthropicPayload(_identifier, payload) {
732
758
  }
733
759
  return preparedPayload;
734
760
  }
735
- async function callAnthropic(id, payload, config, requestTimeoutMs = 12e4) {
761
+ async function callAnthropic(id, payload, config, requestTimeoutMs = 12e4, signal) {
736
762
  var _a, _b, _c;
737
763
  const anthropicMessages = jigAnthropicMessages(payload.messages);
738
764
  const tools = (_a = payload.functions) == null ? void 0 : _a.map((f) => ({
@@ -756,7 +782,8 @@ async function callAnthropic(id, payload, config, requestTimeoutMs = 12e4) {
756
782
  contentType: "application/json",
757
783
  body: JSON.stringify(bedrockPayload),
758
784
  modelId: MODEL_ID
759
- })
785
+ }),
786
+ { abortSignal: signal }
760
787
  );
761
788
  const decodedResponseBody = new TextDecoder().decode(response.body);
762
789
  data = JSON.parse(decodedResponseBody);
@@ -782,7 +809,8 @@ async function callAnthropic(id, payload, config, requestTimeoutMs = 12e4) {
782
809
  "anthropic-version": "2023-06-01",
783
810
  "anthropic-beta": "tools-2024-04-04"
784
811
  },
785
- timeout: requestTimeoutMs
812
+ timeout: requestTimeoutMs,
813
+ signal
786
814
  }
787
815
  );
788
816
  data = response.data;
@@ -852,13 +880,14 @@ ${text}` : text;
852
880
  usage
853
881
  };
854
882
  }
855
- async function callAnthropicWithRetries(id, payload, config, retries = 5, requestTimeoutMs = 12e4) {
883
+ async function callAnthropicWithRetries(id, payload, config, retries = 5, requestTimeoutMs = 12e4, signal) {
856
884
  return withRetries(
857
885
  id,
858
886
  "Anthropic",
859
- () => callAnthropic(id, payload, config, requestTimeoutMs),
887
+ () => callAnthropic(id, payload, config, requestTimeoutMs, signal),
860
888
  {
861
- retries
889
+ retries,
890
+ signal
862
891
  }
863
892
  );
864
893
  }
@@ -976,7 +1005,7 @@ async function prepareGoogleAIPayload(_identifier, payload) {
976
1005
  }
977
1006
  return preparedPayload;
978
1007
  }
979
- async function callGoogleAI(id, payload, requestTimeoutMs = 12e4) {
1008
+ async function callGoogleAI(id, payload, requestTimeoutMs = 12e4, signal) {
980
1009
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
981
1010
  const contents = jigGoogleMessages(payload.messages);
982
1011
  const requestBody = {
@@ -1000,7 +1029,8 @@ async function callGoogleAI(id, payload, requestTimeoutMs = 12e4) {
1000
1029
  "content-type": "application/json",
1001
1030
  "x-goog-api-key": process.env.GEMINI_API_KEY
1002
1031
  },
1003
- timeout: requestTimeoutMs
1032
+ timeout: requestTimeoutMs,
1033
+ signal
1004
1034
  }
1005
1035
  );
1006
1036
  response = httpResponse.data;
@@ -1099,10 +1129,11 @@ function removeImagesFromGooglePayload(payload) {
1099
1129
  }
1100
1130
  return removedImages;
1101
1131
  }
1102
- async function callGoogleAIWithRetries(id, payload, retries = 5, requestTimeoutMs = 12e4) {
1132
+ async function callGoogleAIWithRetries(id, payload, retries = 5, requestTimeoutMs = 12e4, signal) {
1103
1133
  let hasTriedWithoutImages = false;
1104
- return withRetries(id, "Google AI", () => callGoogleAI(id, payload, requestTimeoutMs), {
1134
+ return withRetries(id, "Google AI", () => callGoogleAI(id, payload, requestTimeoutMs, signal), {
1105
1135
  retries,
1136
+ signal,
1106
1137
  onError: (error2, attempt) => {
1107
1138
  var _a, _b;
1108
1139
  const errorDetails = {
@@ -1209,8 +1240,11 @@ function prepareOpenAICompatMessages(messages) {
1209
1240
  }
1210
1241
  if (message.reasoning)
1211
1242
  outMessage.reasoning = message.reasoning;
1212
- if (message.reasoningDetails)
1213
- outMessage.reasoning_details = message.reasoningDetails;
1243
+ const reasoningDetails = filterOpenAICompatReasoningDetails(
1244
+ message.reasoningDetails
1245
+ );
1246
+ if (reasoningDetails)
1247
+ outMessage.reasoning_details = reasoningDetails;
1214
1248
  out.push(outMessage);
1215
1249
  }
1216
1250
  return out;
@@ -1228,7 +1262,7 @@ function prepareGroqPayload(payload) {
1228
1262
  temperature: payload.temperature
1229
1263
  };
1230
1264
  }
1231
- async function callGroq(id, payload, requestTimeoutMs = 12e4) {
1265
+ async function callGroq(id, payload, requestTimeoutMs = 12e4, signal) {
1232
1266
  var _a, _b, _c, _d, _e, _f, _g;
1233
1267
  const response = await import_axios.default.post(
1234
1268
  "https://api.groq.com/openai/v1/chat/completions",
@@ -1238,7 +1272,8 @@ async function callGroq(id, payload, requestTimeoutMs = 12e4) {
1238
1272
  "content-type": "application/json",
1239
1273
  Authorization: `Bearer ${process.env.GROQ_API_KEY}`
1240
1274
  },
1241
- timeout: requestTimeoutMs
1275
+ timeout: requestTimeoutMs,
1276
+ signal
1242
1277
  }
1243
1278
  );
1244
1279
  if (response.data.error) {
@@ -1286,9 +1321,10 @@ async function callGroq(id, payload, requestTimeoutMs = 12e4) {
1286
1321
  } : null
1287
1322
  };
1288
1323
  }
1289
- async function callGroqWithRetries(id, payload, retries = 5, requestTimeoutMs = 12e4) {
1290
- return withRetries(id, "Groq", () => callGroq(id, payload, requestTimeoutMs), {
1291
- retries
1324
+ async function callGroqWithRetries(id, payload, retries = 5, requestTimeoutMs = 12e4, signal) {
1325
+ return withRetries(id, "Groq", () => callGroq(id, payload, requestTimeoutMs, signal), {
1326
+ retries,
1327
+ signal
1292
1328
  });
1293
1329
  }
1294
1330
  function prepareOpenRouterPayload(payload) {
@@ -1353,7 +1389,7 @@ function parseDsmlToolCalls(content) {
1353
1389
  const remaining = first === -1 ? content : (content.slice(0, first) + content.slice(last)).trim();
1354
1390
  return { calls, remainingContent: remaining.length ? remaining : null };
1355
1391
  }
1356
- async function callOpenRouter(id, payload, requestTimeoutMs = 12e4) {
1392
+ async function callOpenRouter(id, payload, requestTimeoutMs = 12e4, signal) {
1357
1393
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1358
1394
  const response = await import_axios.default.post(
1359
1395
  "https://openrouter.ai/api/v1/chat/completions",
@@ -1363,7 +1399,8 @@ async function callOpenRouter(id, payload, requestTimeoutMs = 12e4) {
1363
1399
  "content-type": "application/json",
1364
1400
  Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`
1365
1401
  },
1366
- timeout: requestTimeoutMs
1402
+ timeout: requestTimeoutMs,
1403
+ signal
1367
1404
  }
1368
1405
  );
1369
1406
  if (response.data.error) {
@@ -1421,12 +1458,12 @@ async function callOpenRouter(id, payload, requestTimeoutMs = 12e4) {
1421
1458
  } : null
1422
1459
  };
1423
1460
  }
1424
- async function callOpenRouterWithRetries(id, payload, retries = 5, requestTimeoutMs = 12e4) {
1461
+ async function callOpenRouterWithRetries(id, payload, retries = 5, requestTimeoutMs = 12e4, signal) {
1425
1462
  return withRetries(
1426
1463
  id,
1427
1464
  "OpenRouter",
1428
- () => callOpenRouter(id, payload, requestTimeoutMs),
1429
- { retries }
1465
+ () => callOpenRouter(id, payload, requestTimeoutMs, signal),
1466
+ { retries, signal }
1430
1467
  );
1431
1468
  }
1432
1469
  var VALID_PROVIDERS = ["openai", "anthropic", "google", "groq", "openrouter"];
@@ -1467,11 +1504,12 @@ function parseModelString(model) {
1467
1504
  );
1468
1505
  }
1469
1506
  async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeoutMs = 15e3) {
1470
- var _a;
1507
+ var _a, _b;
1471
1508
  try {
1472
1509
  const { provider, modelId } = parseModelString(aiPayload.model);
1473
1510
  const routingPayload = { ...aiPayload, model: modelId };
1474
1511
  const requestTimeoutMs = (_a = aiPayload.requestTimeoutMs) != null ? _a : 12e4;
1512
+ const signal = aiPayload.signal;
1475
1513
  switch (provider) {
1476
1514
  case "anthropic":
1477
1515
  return await callAnthropicWithRetries(
@@ -1479,7 +1517,8 @@ async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeou
1479
1517
  await prepareAnthropicPayload(id, routingPayload),
1480
1518
  aiConfig,
1481
1519
  retries,
1482
- requestTimeoutMs
1520
+ requestTimeoutMs,
1521
+ signal
1483
1522
  );
1484
1523
  case "openai":
1485
1524
  return await callOpenAiWithRetries(
@@ -1488,31 +1527,37 @@ async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeou
1488
1527
  aiConfig,
1489
1528
  retries,
1490
1529
  chunkTimeoutMs,
1491
- requestTimeoutMs
1530
+ requestTimeoutMs,
1531
+ signal
1492
1532
  );
1493
1533
  case "groq":
1494
1534
  return await callGroqWithRetries(
1495
1535
  id,
1496
1536
  prepareGroqPayload(routingPayload),
1497
1537
  retries,
1498
- requestTimeoutMs
1538
+ requestTimeoutMs,
1539
+ signal
1499
1540
  );
1500
1541
  case "google":
1501
1542
  return await callGoogleAIWithRetries(
1502
1543
  id,
1503
1544
  await prepareGoogleAIPayload(id, routingPayload),
1504
1545
  retries,
1505
- requestTimeoutMs
1546
+ requestTimeoutMs,
1547
+ signal
1506
1548
  );
1507
1549
  case "openrouter":
1508
1550
  return await callOpenRouterWithRetries(
1509
1551
  id,
1510
1552
  prepareOpenRouterPayload(routingPayload),
1511
1553
  retries,
1512
- requestTimeoutMs
1554
+ requestTimeoutMs,
1555
+ signal
1513
1556
  );
1514
1557
  }
1515
1558
  } catch (error2) {
1559
+ if ((_b = aiPayload.signal) == null ? void 0 : _b.aborted)
1560
+ throw error2;
1516
1561
  if (aiPayload.fallbackModel) {
1517
1562
  logger_default.error(
1518
1563
  id,