190proof 1.0.100 → 1.0.102

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
@@ -265,6 +265,14 @@ interface GenericPayload {
265
265
  * valid response isn't cut short.
266
266
  */
267
267
  requestTimeoutMs?: number;
268
+ /**
269
+ * Optional caller-supplied cancellation signal. When it aborts, the in-flight
270
+ * provider request is cancelled and `callWithRetries` rejects immediately —
271
+ * it does NOT retry or fall back (both retry loop and fallback branch bail on
272
+ * `signal.aborted`). Threaded through every adapter to the underlying
273
+ * fetch/axios/SDK call, mirroring `requestTimeoutMs`.
274
+ */
275
+ signal?: AbortSignal;
268
276
  }
269
277
 
270
278
  declare function parseModelString(model: string): {
package/dist/index.d.ts CHANGED
@@ -265,6 +265,14 @@ interface GenericPayload {
265
265
  * valid response isn't cut short.
266
266
  */
267
267
  requestTimeoutMs?: number;
268
+ /**
269
+ * Optional caller-supplied cancellation signal. When it aborts, the in-flight
270
+ * provider request is cancelled and `callWithRetries` rejects immediately —
271
+ * it does NOT retry or fall back (both retry loop and fallback branch bail on
272
+ * `signal.aborted`). Threaded through every adapter to the underlying
273
+ * fetch/axios/SDK call, mirroring `requestTimeoutMs`.
274
+ */
275
+ signal?: AbortSignal;
268
276
  }
269
277
 
270
278
  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
  );
@@ -386,7 +393,7 @@ async function prepareOpenAIPayload(identifier, payload) {
386
393
  }
387
394
  return preparedPayload;
388
395
  }
389
- async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs, requestTimeoutMs = 12e4) {
396
+ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs, requestTimeoutMs = 12e4, signal) {
390
397
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
391
398
  const functionNames = openAiPayload.tools ? new Set(openAiPayload.tools.map((fn) => fn.function.name)) : null;
392
399
  const { endpoint, headers } = buildOpenAIRequestConfig(
@@ -406,7 +413,10 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
406
413
  method: "POST",
407
414
  headers,
408
415
  body: JSON.stringify({ ...openAiPayload, stream: true }),
409
- signal: controller.signal
416
+ // Merge (don't overwrite) the internal timeout controller with the caller's
417
+ // cancellation signal so both an internal timeout and an external abort stop
418
+ // the stream.
419
+ signal: signal ? anySignal([controller.signal, signal]) : controller.signal
410
420
  });
411
421
  if (!response.body) {
412
422
  throw new Error("Stream error: no response body");
@@ -496,7 +506,7 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
496
506
  }
497
507
  }
498
508
  }
499
- async function callOpenAI(id, openAiPayload, openAiConfig, requestTimeoutMs = 12e4) {
509
+ async function callOpenAI(id, openAiPayload, openAiConfig, requestTimeoutMs = 12e4, signal) {
500
510
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
501
511
  const { endpoint, headers } = buildOpenAIRequestConfig(
502
512
  id,
@@ -511,7 +521,8 @@ async function callOpenAI(id, openAiPayload, openAiConfig, requestTimeoutMs = 12
511
521
  method: "POST",
512
522
  headers,
513
523
  body: JSON.stringify({ ...openAiPayload, stream: false }),
514
- signal: controller.signal
524
+ // Merge the internal timeout controller with the caller's cancellation signal.
525
+ signal: signal ? anySignal([controller.signal, signal]) : controller.signal
515
526
  });
516
527
  if (!response.ok) {
517
528
  const errorData = await response.json();
@@ -574,7 +585,7 @@ async function callOpenAI(id, openAiPayload, openAiConfig, requestTimeoutMs = 12
574
585
  } : null
575
586
  };
576
587
  }
577
- async function callOpenAiWithRetries(id, openAiPayload, openAiConfig, retries = 5, chunkTimeoutMs = 15e3, requestTimeoutMs = 12e4) {
588
+ async function callOpenAiWithRetries(id, openAiPayload, openAiConfig, retries = 5, chunkTimeoutMs = 15e3, requestTimeoutMs = 12e4, signal) {
578
589
  logger_default.log(
579
590
  id,
580
591
  "Calling OpenAI API with retries:",
@@ -593,14 +604,16 @@ async function callOpenAiWithRetries(id, openAiPayload, openAiConfig, retries =
593
604
  openAiPayload,
594
605
  openAiConfig,
595
606
  chunkTimeoutMs,
596
- requestTimeoutMs
607
+ requestTimeoutMs,
608
+ signal
597
609
  );
598
610
  } else {
599
- return callOpenAI(id, openAiPayload, openAiConfig, requestTimeoutMs);
611
+ return callOpenAI(id, openAiPayload, openAiConfig, requestTimeoutMs, signal);
600
612
  }
601
613
  },
602
614
  {
603
615
  retries,
616
+ signal,
604
617
  baseDelayMs: 250,
605
618
  onError: (error2, attempt) => {
606
619
  var _a, _b;
@@ -732,7 +745,7 @@ async function prepareAnthropicPayload(_identifier, payload) {
732
745
  }
733
746
  return preparedPayload;
734
747
  }
735
- async function callAnthropic(id, payload, config, requestTimeoutMs = 12e4) {
748
+ async function callAnthropic(id, payload, config, requestTimeoutMs = 12e4, signal) {
736
749
  var _a, _b, _c;
737
750
  const anthropicMessages = jigAnthropicMessages(payload.messages);
738
751
  const tools = (_a = payload.functions) == null ? void 0 : _a.map((f) => ({
@@ -756,7 +769,8 @@ async function callAnthropic(id, payload, config, requestTimeoutMs = 12e4) {
756
769
  contentType: "application/json",
757
770
  body: JSON.stringify(bedrockPayload),
758
771
  modelId: MODEL_ID
759
- })
772
+ }),
773
+ { abortSignal: signal }
760
774
  );
761
775
  const decodedResponseBody = new TextDecoder().decode(response.body);
762
776
  data = JSON.parse(decodedResponseBody);
@@ -782,7 +796,8 @@ async function callAnthropic(id, payload, config, requestTimeoutMs = 12e4) {
782
796
  "anthropic-version": "2023-06-01",
783
797
  "anthropic-beta": "tools-2024-04-04"
784
798
  },
785
- timeout: requestTimeoutMs
799
+ timeout: requestTimeoutMs,
800
+ signal
786
801
  }
787
802
  );
788
803
  data = response.data;
@@ -852,13 +867,14 @@ ${text}` : text;
852
867
  usage
853
868
  };
854
869
  }
855
- async function callAnthropicWithRetries(id, payload, config, retries = 5, requestTimeoutMs = 12e4) {
870
+ async function callAnthropicWithRetries(id, payload, config, retries = 5, requestTimeoutMs = 12e4, signal) {
856
871
  return withRetries(
857
872
  id,
858
873
  "Anthropic",
859
- () => callAnthropic(id, payload, config, requestTimeoutMs),
874
+ () => callAnthropic(id, payload, config, requestTimeoutMs, signal),
860
875
  {
861
- retries
876
+ retries,
877
+ signal
862
878
  }
863
879
  );
864
880
  }
@@ -976,7 +992,7 @@ async function prepareGoogleAIPayload(_identifier, payload) {
976
992
  }
977
993
  return preparedPayload;
978
994
  }
979
- async function callGoogleAI(id, payload, requestTimeoutMs = 12e4) {
995
+ async function callGoogleAI(id, payload, requestTimeoutMs = 12e4, signal) {
980
996
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
981
997
  const contents = jigGoogleMessages(payload.messages);
982
998
  const requestBody = {
@@ -1000,7 +1016,8 @@ async function callGoogleAI(id, payload, requestTimeoutMs = 12e4) {
1000
1016
  "content-type": "application/json",
1001
1017
  "x-goog-api-key": process.env.GEMINI_API_KEY
1002
1018
  },
1003
- timeout: requestTimeoutMs
1019
+ timeout: requestTimeoutMs,
1020
+ signal
1004
1021
  }
1005
1022
  );
1006
1023
  response = httpResponse.data;
@@ -1099,10 +1116,11 @@ function removeImagesFromGooglePayload(payload) {
1099
1116
  }
1100
1117
  return removedImages;
1101
1118
  }
1102
- async function callGoogleAIWithRetries(id, payload, retries = 5, requestTimeoutMs = 12e4) {
1119
+ async function callGoogleAIWithRetries(id, payload, retries = 5, requestTimeoutMs = 12e4, signal) {
1103
1120
  let hasTriedWithoutImages = false;
1104
- return withRetries(id, "Google AI", () => callGoogleAI(id, payload, requestTimeoutMs), {
1121
+ return withRetries(id, "Google AI", () => callGoogleAI(id, payload, requestTimeoutMs, signal), {
1105
1122
  retries,
1123
+ signal,
1106
1124
  onError: (error2, attempt) => {
1107
1125
  var _a, _b;
1108
1126
  const errorDetails = {
@@ -1228,7 +1246,7 @@ function prepareGroqPayload(payload) {
1228
1246
  temperature: payload.temperature
1229
1247
  };
1230
1248
  }
1231
- async function callGroq(id, payload, requestTimeoutMs = 12e4) {
1249
+ async function callGroq(id, payload, requestTimeoutMs = 12e4, signal) {
1232
1250
  var _a, _b, _c, _d, _e, _f, _g;
1233
1251
  const response = await import_axios.default.post(
1234
1252
  "https://api.groq.com/openai/v1/chat/completions",
@@ -1238,7 +1256,8 @@ async function callGroq(id, payload, requestTimeoutMs = 12e4) {
1238
1256
  "content-type": "application/json",
1239
1257
  Authorization: `Bearer ${process.env.GROQ_API_KEY}`
1240
1258
  },
1241
- timeout: requestTimeoutMs
1259
+ timeout: requestTimeoutMs,
1260
+ signal
1242
1261
  }
1243
1262
  );
1244
1263
  if (response.data.error) {
@@ -1286,9 +1305,10 @@ async function callGroq(id, payload, requestTimeoutMs = 12e4) {
1286
1305
  } : null
1287
1306
  };
1288
1307
  }
1289
- async function callGroqWithRetries(id, payload, retries = 5, requestTimeoutMs = 12e4) {
1290
- return withRetries(id, "Groq", () => callGroq(id, payload, requestTimeoutMs), {
1291
- retries
1308
+ async function callGroqWithRetries(id, payload, retries = 5, requestTimeoutMs = 12e4, signal) {
1309
+ return withRetries(id, "Groq", () => callGroq(id, payload, requestTimeoutMs, signal), {
1310
+ retries,
1311
+ signal
1292
1312
  });
1293
1313
  }
1294
1314
  function prepareOpenRouterPayload(payload) {
@@ -1305,8 +1325,56 @@ function prepareOpenRouterPayload(payload) {
1305
1325
  provider: payload.provider
1306
1326
  };
1307
1327
  }
1308
- async function callOpenRouter(id, payload, requestTimeoutMs = 12e4) {
1309
- var _a, _b, _c, _d, _e, _f, _g, _h;
1328
+ var DSML_ENVELOPE_RE = /<|+DSML|+tool_calls>/;
1329
+ var DSML_DELIMITER_RE = /<\/?|+DSML|+/;
1330
+ var DSML_INVOKE_RE = /<|+DSML|+invoke\s+name="([^"]+)"\s*>([\s\S]*?)<\/|+DSML|+invoke>/g;
1331
+ var DSML_PARAM_RE = /<|+DSML|+parameter\s+name="([^"]+)"(?:\s+string="(true|false)")?\s*>([\s\S]*?)<\/|+DSML|+parameter>/g;
1332
+ var DSML_ANY_TAG_RE = /<\/?|+DSML|+[^>]*>/g;
1333
+ function parseDsmlToolCalls(content) {
1334
+ const calls = [];
1335
+ DSML_INVOKE_RE.lastIndex = 0;
1336
+ let invokeMatch;
1337
+ while ((invokeMatch = DSML_INVOKE_RE.exec(content)) !== null) {
1338
+ const name = invokeMatch[1];
1339
+ const inner = invokeMatch[2];
1340
+ const args = {};
1341
+ let ok = true;
1342
+ DSML_PARAM_RE.lastIndex = 0;
1343
+ let paramMatch;
1344
+ while ((paramMatch = DSML_PARAM_RE.exec(inner)) !== null) {
1345
+ const [, paramName, stringAttr, rawValue] = paramMatch;
1346
+ if (stringAttr === "false") {
1347
+ try {
1348
+ args[paramName] = JSON.parse(rawValue);
1349
+ } catch (e) {
1350
+ ok = false;
1351
+ break;
1352
+ }
1353
+ } else {
1354
+ args[paramName] = rawValue;
1355
+ }
1356
+ }
1357
+ if (ok && name) {
1358
+ calls.push({ id: `call_${calls.length}`, name, arguments: args });
1359
+ }
1360
+ }
1361
+ if (!calls.length) {
1362
+ return { calls, remainingContent: content };
1363
+ }
1364
+ DSML_ANY_TAG_RE.lastIndex = 0;
1365
+ let first = -1;
1366
+ let last = -1;
1367
+ let tag;
1368
+ while ((tag = DSML_ANY_TAG_RE.exec(content)) !== null) {
1369
+ if (first === -1)
1370
+ first = tag.index;
1371
+ last = tag.index + tag[0].length;
1372
+ }
1373
+ const remaining = first === -1 ? content : (content.slice(0, first) + content.slice(last)).trim();
1374
+ return { calls, remainingContent: remaining.length ? remaining : null };
1375
+ }
1376
+ async function callOpenRouter(id, payload, requestTimeoutMs = 12e4, signal) {
1377
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1310
1378
  const response = await import_axios.default.post(
1311
1379
  "https://openrouter.ai/api/v1/chat/completions",
1312
1380
  payload,
@@ -1315,7 +1383,8 @@ async function callOpenRouter(id, payload, requestTimeoutMs = 12e4) {
1315
1383
  "content-type": "application/json",
1316
1384
  Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`
1317
1385
  },
1318
- timeout: requestTimeoutMs
1386
+ timeout: requestTimeoutMs,
1387
+ signal
1319
1388
  }
1320
1389
  );
1321
1390
  if (response.data.error) {
@@ -1338,38 +1407,47 @@ async function callOpenRouter(id, payload, requestTimeoutMs = 12e4) {
1338
1407
  });
1339
1408
  }
1340
1409
  }
1341
- if (!answer.content && !functionCalls.length) {
1410
+ let content = (_e = answer.content) != null ? _e : null;
1411
+ if (!functionCalls.length && content && DSML_ENVELOPE_RE.test(content)) {
1412
+ const { calls, remainingContent } = parseDsmlToolCalls(content);
1413
+ if (calls.length) {
1414
+ functionCalls.push(...calls);
1415
+ content = remainingContent;
1416
+ }
1417
+ }
1418
+ const hasUnparsedDsml = !!content && DSML_DELIMITER_RE.test(content);
1419
+ if (!functionCalls.length && (!content || hasUnparsedDsml)) {
1342
1420
  logger_default.error(
1343
1421
  id,
1344
- "OpenRouter: received message without content or function_call:",
1422
+ "OpenRouter: empty or unparseable completion:",
1345
1423
  JSON.stringify(response.data)
1346
1424
  );
1347
1425
  throw new Error(
1348
- "OpenRouter: received message without content or function_call"
1426
+ "OpenRouter: received message without usable content or function_call"
1349
1427
  );
1350
1428
  }
1351
1429
  return {
1352
1430
  role: "assistant",
1353
- content: answer.content || null,
1431
+ content: content || null,
1354
1432
  function_call: functionCalls[0] || null,
1355
1433
  function_calls: functionCalls,
1356
1434
  files: [],
1357
- reasoning: (_e = answer.reasoning) != null ? _e : void 0,
1358
- reasoningDetails: (_f = answer.reasoning_details) != null ? _f : void 0,
1435
+ reasoning: (_f = answer.reasoning) != null ? _f : void 0,
1436
+ reasoningDetails: (_g = answer.reasoning_details) != null ? _g : void 0,
1359
1437
  usage: response.data.usage ? {
1360
1438
  prompt_tokens: response.data.usage.prompt_tokens,
1361
1439
  completion_tokens: response.data.usage.completion_tokens,
1362
1440
  total_tokens: response.data.usage.total_tokens,
1363
- cached_tokens: (_h = (_g = response.data.usage.prompt_tokens_details) == null ? void 0 : _g.cached_tokens) != null ? _h : 0
1441
+ cached_tokens: (_i = (_h = response.data.usage.prompt_tokens_details) == null ? void 0 : _h.cached_tokens) != null ? _i : 0
1364
1442
  } : null
1365
1443
  };
1366
1444
  }
1367
- async function callOpenRouterWithRetries(id, payload, retries = 5, requestTimeoutMs = 12e4) {
1445
+ async function callOpenRouterWithRetries(id, payload, retries = 5, requestTimeoutMs = 12e4, signal) {
1368
1446
  return withRetries(
1369
1447
  id,
1370
1448
  "OpenRouter",
1371
- () => callOpenRouter(id, payload, requestTimeoutMs),
1372
- { retries }
1449
+ () => callOpenRouter(id, payload, requestTimeoutMs, signal),
1450
+ { retries, signal }
1373
1451
  );
1374
1452
  }
1375
1453
  var VALID_PROVIDERS = ["openai", "anthropic", "google", "groq", "openrouter"];
@@ -1410,11 +1488,12 @@ function parseModelString(model) {
1410
1488
  );
1411
1489
  }
1412
1490
  async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeoutMs = 15e3) {
1413
- var _a;
1491
+ var _a, _b;
1414
1492
  try {
1415
1493
  const { provider, modelId } = parseModelString(aiPayload.model);
1416
1494
  const routingPayload = { ...aiPayload, model: modelId };
1417
1495
  const requestTimeoutMs = (_a = aiPayload.requestTimeoutMs) != null ? _a : 12e4;
1496
+ const signal = aiPayload.signal;
1418
1497
  switch (provider) {
1419
1498
  case "anthropic":
1420
1499
  return await callAnthropicWithRetries(
@@ -1422,7 +1501,8 @@ async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeou
1422
1501
  await prepareAnthropicPayload(id, routingPayload),
1423
1502
  aiConfig,
1424
1503
  retries,
1425
- requestTimeoutMs
1504
+ requestTimeoutMs,
1505
+ signal
1426
1506
  );
1427
1507
  case "openai":
1428
1508
  return await callOpenAiWithRetries(
@@ -1431,31 +1511,37 @@ async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeou
1431
1511
  aiConfig,
1432
1512
  retries,
1433
1513
  chunkTimeoutMs,
1434
- requestTimeoutMs
1514
+ requestTimeoutMs,
1515
+ signal
1435
1516
  );
1436
1517
  case "groq":
1437
1518
  return await callGroqWithRetries(
1438
1519
  id,
1439
1520
  prepareGroqPayload(routingPayload),
1440
1521
  retries,
1441
- requestTimeoutMs
1522
+ requestTimeoutMs,
1523
+ signal
1442
1524
  );
1443
1525
  case "google":
1444
1526
  return await callGoogleAIWithRetries(
1445
1527
  id,
1446
1528
  await prepareGoogleAIPayload(id, routingPayload),
1447
1529
  retries,
1448
- requestTimeoutMs
1530
+ requestTimeoutMs,
1531
+ signal
1449
1532
  );
1450
1533
  case "openrouter":
1451
1534
  return await callOpenRouterWithRetries(
1452
1535
  id,
1453
1536
  prepareOpenRouterPayload(routingPayload),
1454
1537
  retries,
1455
- requestTimeoutMs
1538
+ requestTimeoutMs,
1539
+ signal
1456
1540
  );
1457
1541
  }
1458
1542
  } catch (error2) {
1543
+ if ((_b = aiPayload.signal) == null ? void 0 : _b.aborted)
1544
+ throw error2;
1459
1545
  if (aiPayload.fallbackModel) {
1460
1546
  logger_default.error(
1461
1547
  id,