190proof 1.0.105 → 1.0.107

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
@@ -1,6 +1,6 @@
1
1
  # 190proof
2
2
 
3
- A unified interface for interacting with multiple AI providers including **OpenAI**, **Anthropic**, **Google**, **Groq**, **OpenRouter**, and **AWS Bedrock**. This package provides a consistent API for making requests to different LLM providers while handling retries, streaming, and multimodal inputs.
3
+ An opinionated unified interface for interacting with multiple AI providers including **OpenAI**, **Anthropic**, **Google**, **Groq**, **OpenRouter**, and **AWS Bedrock**. This package provides a consistent API for making requests to different LLM providers while handling retries, streaming, and multimodal inputs.
4
4
 
5
5
  ## Features
6
6
 
package/dist/index.js CHANGED
@@ -28,8 +28,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
 
30
30
  // index.ts
31
- var proof_exports = {};
32
- __export(proof_exports, {
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
33
  ClaudeModel: () => ClaudeModel,
34
34
  GPTModel: () => GPTModel,
35
35
  GeminiModel: () => GeminiModel,
@@ -38,7 +38,7 @@ __export(proof_exports, {
38
38
  callWithRetries: () => callWithRetries,
39
39
  parseModelString: () => parseModelString
40
40
  });
41
- module.exports = __toCommonJS(proof_exports);
41
+ module.exports = __toCommonJS(index_exports);
42
42
 
43
43
  // interfaces.ts
44
44
  var ClaudeModel = /* @__PURE__ */ ((ClaudeModel2) => {
@@ -146,6 +146,19 @@ function anySignal(signals) {
146
146
  signals
147
147
  );
148
148
  }
149
+ async function withRequestDeadline(apiName, requestTimeoutMs, signal, fn) {
150
+ const deadline = AbortSignal.timeout(requestTimeoutMs);
151
+ try {
152
+ return await fn(signal ? anySignal([signal, deadline]) : deadline);
153
+ } catch (error2) {
154
+ if (deadline.aborted && !(signal == null ? void 0 : signal.aborted)) {
155
+ throw new Error(
156
+ `${apiName} request exceeded hard deadline of ${requestTimeoutMs}ms`
157
+ );
158
+ }
159
+ throw error2;
160
+ }
161
+ }
149
162
  async function withRetries(identifier, apiName, fn, options = {}) {
150
163
  var _a, _b, _c, _d, _e;
151
164
  const { retries = 5, baseDelayMs = 125, onError } = options;
@@ -156,8 +169,7 @@ async function withRetries(identifier, apiName, fn, options = {}) {
156
169
  return await fn();
157
170
  } catch (error3) {
158
171
  lastError = error3;
159
- if ((_a = options.signal) == null ? void 0 : _a.aborted)
160
- throw error3;
172
+ if ((_a = options.signal) == null ? void 0 : _a.aborted) throw error3;
161
173
  if (onError) {
162
174
  onError(error3, attempt);
163
175
  } else {
@@ -181,8 +193,7 @@ function parseStreamedResponse(identifier, paragraph, toolCallAccumulators, allo
181
193
  const functionCalls = [];
182
194
  for (let i = 0; i < toolCallAccumulators.length; i++) {
183
195
  const acc = toolCallAccumulators[i];
184
- if (!acc.name || !acc.arguments)
185
- continue;
196
+ if (!acc.name || !acc.arguments) continue;
186
197
  if (allowedFunctionNames && !allowedFunctionNames.has(acc.name)) {
187
198
  throw new Error(
188
199
  `Stream error: received function call with unknown name: ${acc.name}`
@@ -321,8 +332,7 @@ function buildOpenAIRequestConfig(identifier, model, config) {
321
332
  };
322
333
  }
323
334
  function filterOpenAICompatReasoningDetails(details) {
324
- if (!Array.isArray(details))
325
- return details || void 0;
335
+ if (!Array.isArray(details)) return details || void 0;
326
336
  const blocks = details.filter(
327
337
  (block) => typeof (block == null ? void 0 : block.type) === "string" && block.type.startsWith("reasoning.")
328
338
  );
@@ -393,13 +403,11 @@ async function prepareOpenAIPayload(identifier, payload) {
393
403
  };
394
404
  });
395
405
  }
396
- if (message.reasoning)
397
- outMessage.reasoning = message.reasoning;
406
+ if (message.reasoning) outMessage.reasoning = message.reasoning;
398
407
  const reasoningDetails = filterOpenAICompatReasoningDetails(
399
408
  message.reasoningDetails
400
409
  );
401
- if (reasoningDetails)
402
- outMessage.reasoning_details = reasoningDetails;
410
+ if (reasoningDetails) outMessage.reasoning_details = reasoningDetails;
403
411
  preparedPayload.messages.push(outMessage);
404
412
  }
405
413
  return preparedPayload;
@@ -461,8 +469,7 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
461
469
  }
462
470
  const jsonStrings = chunk.split(/^data: /gm);
463
471
  for (const jsonString of jsonStrings) {
464
- if (!jsonString)
465
- continue;
472
+ if (!jsonString) continue;
466
473
  if (jsonString.includes("[DONE]")) {
467
474
  clearTimeout(overallTimeout);
468
475
  return parseStreamedResponse(
@@ -500,8 +507,7 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
500
507
  while (toolCallAccumulators.length <= idx) {
501
508
  toolCallAccumulators.push({ name: "", arguments: "" });
502
509
  }
503
- if (toolCall.id)
504
- toolCallAccumulators[idx].id = toolCall.id;
510
+ if (toolCall.id) toolCallAccumulators[idx].id = toolCall.id;
505
511
  if ((_e = toolCall.function) == null ? void 0 : _e.name)
506
512
  toolCallAccumulators[idx].name += toolCall.function.name;
507
513
  if ((_f = toolCall.function) == null ? void 0 : _f.arguments)
@@ -509,11 +515,9 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
509
515
  }
510
516
  }
511
517
  const text = (_h = (_g = json.choices[0]) == null ? void 0 : _g.delta) == null ? void 0 : _h.content;
512
- if (text)
513
- paragraph += text;
518
+ if (text) paragraph += text;
514
519
  const reasoningDelta = (_j = (_i = json.choices[0]) == null ? void 0 : _i.delta) == null ? void 0 : _j.reasoning;
515
- if (reasoningDelta)
516
- reasoning += reasoningDelta;
520
+ if (reasoningDelta) reasoning += reasoningDelta;
517
521
  }
518
522
  }
519
523
  }
@@ -658,8 +662,7 @@ function jigAnthropicMessages(messages) {
658
662
  ];
659
663
  }
660
664
  jiggedMessages = jiggedMessages.reduce((acc, message) => {
661
- if (acc.length === 0)
662
- return [message];
665
+ if (acc.length === 0) return [message];
663
666
  const lastMessage = acc[acc.length - 1];
664
667
  if (lastMessage.role === message.role) {
665
668
  const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
@@ -796,28 +799,33 @@ async function callAnthropic(id, payload, config, requestTimeoutMs = 12e4, signa
796
799
  ...tools.slice(0, -1),
797
800
  { ...tools[tools.length - 1], cache_control: { type: "ephemeral" } }
798
801
  ] : tools;
799
- const response = await import_axios.default.post(
800
- "https://api.anthropic.com/v1/messages",
801
- {
802
- model: payload.model,
803
- messages: anthropicMessages,
804
- tools: cachedTools,
805
- // tool_choice requires tools in the request; drop it otherwise.
806
- tool_choice: (cachedTools == null ? void 0 : cachedTools.length) ? payload.tool_choice : void 0,
807
- temperature: payload.temperature,
808
- system: payload.system,
809
- max_tokens: 4096
810
- },
811
- {
812
- headers: {
813
- "content-type": "application/json",
814
- "x-api-key": process.env.ANTHROPIC_API_KEY,
815
- "anthropic-version": "2023-06-01",
816
- "anthropic-beta": "tools-2024-04-04"
802
+ const response = await withRequestDeadline(
803
+ "Anthropic",
804
+ requestTimeoutMs,
805
+ signal,
806
+ (mergedSignal) => import_axios.default.post(
807
+ "https://api.anthropic.com/v1/messages",
808
+ {
809
+ model: payload.model,
810
+ messages: anthropicMessages,
811
+ tools: cachedTools,
812
+ // tool_choice requires tools in the request; drop it otherwise.
813
+ tool_choice: (cachedTools == null ? void 0 : cachedTools.length) ? payload.tool_choice : void 0,
814
+ temperature: payload.temperature,
815
+ system: payload.system,
816
+ max_tokens: 4096
817
817
  },
818
- timeout: requestTimeoutMs,
819
- signal
820
- }
818
+ {
819
+ headers: {
820
+ "content-type": "application/json",
821
+ "x-api-key": process.env.ANTHROPIC_API_KEY,
822
+ "anthropic-version": "2023-06-01",
823
+ "anthropic-beta": "tools-2024-04-04"
824
+ },
825
+ timeout: requestTimeoutMs,
826
+ signal: mergedSignal
827
+ }
828
+ )
821
829
  );
822
830
  data = response.data;
823
831
  }
@@ -908,8 +916,7 @@ function jigGoogleMessages(messages) {
908
916
  ];
909
917
  }
910
918
  jiggedMessages = jiggedMessages.reduce((acc, message) => {
911
- if (acc.length === 0)
912
- return [message];
919
+ if (acc.length === 0) return [message];
913
920
  const lastMessage = acc[acc.length - 1];
914
921
  if (lastMessage.role === message.role) {
915
922
  lastMessage.parts = [...lastMessage.parts, ...message.parts];
@@ -947,8 +954,7 @@ async function prepareGoogleAIPayload(_identifier, payload) {
947
954
  const toolNameById = /* @__PURE__ */ new Map();
948
955
  for (const m of payload.messages) {
949
956
  for (const fc of m.functionCalls || []) {
950
- if (fc.id)
951
- toolNameById.set(fc.id, fc.name);
957
+ if (fc.id) toolNameById.set(fc.id, fc.name);
952
958
  }
953
959
  }
954
960
  for (const message of payload.messages) {
@@ -1025,8 +1031,7 @@ async function callGoogleAI(id, payload, requestTimeoutMs = 12e4, signal) {
1025
1031
  contents,
1026
1032
  generationConfig: { responseModalities: ["TEXT"] }
1027
1033
  };
1028
- if (payload.tools)
1029
- requestBody.tools = [payload.tools];
1034
+ if (payload.tools) requestBody.tools = [payload.tools];
1030
1035
  if (payload.tools && payload.toolConfig) {
1031
1036
  requestBody.toolConfig = payload.toolConfig;
1032
1037
  }
@@ -1037,17 +1042,22 @@ async function callGoogleAI(id, payload, requestTimeoutMs = 12e4, signal) {
1037
1042
  }
1038
1043
  let response;
1039
1044
  try {
1040
- const httpResponse = await import_axios.default.post(
1041
- `https://generativelanguage.googleapis.com/v1beta/models/${payload.model}:generateContent`,
1042
- requestBody,
1043
- {
1044
- headers: {
1045
- "content-type": "application/json",
1046
- "x-goog-api-key": process.env.GEMINI_API_KEY
1047
- },
1048
- timeout: requestTimeoutMs,
1049
- signal
1050
- }
1045
+ const httpResponse = await withRequestDeadline(
1046
+ "Google AI",
1047
+ requestTimeoutMs,
1048
+ signal,
1049
+ (mergedSignal) => import_axios.default.post(
1050
+ `https://generativelanguage.googleapis.com/v1beta/models/${payload.model}:generateContent`,
1051
+ requestBody,
1052
+ {
1053
+ headers: {
1054
+ "content-type": "application/json",
1055
+ "x-goog-api-key": process.env.GEMINI_API_KEY
1056
+ },
1057
+ timeout: requestTimeoutMs,
1058
+ signal: mergedSignal
1059
+ }
1060
+ )
1051
1061
  );
1052
1062
  response = httpResponse.data;
1053
1063
  } catch (err) {
@@ -1079,8 +1089,7 @@ async function callGoogleAI(id, payload, requestTimeoutMs = 12e4, signal) {
1079
1089
  });
1080
1090
  continue;
1081
1091
  }
1082
- if (part.text)
1083
- text += part.text;
1092
+ if (part.text) text += part.text;
1084
1093
  if ((_m = part.inlineData) == null ? void 0 : _m.data) {
1085
1094
  files.push({ mimeType: "image/png", data: part.inlineData.data });
1086
1095
  }
@@ -1157,21 +1166,15 @@ async function callGoogleAIWithRetries(id, payload, retries = 5, requestTimeoutM
1157
1166
  finishReason: error2.finishReason,
1158
1167
  modelVersion: error2.modelVersion
1159
1168
  };
1160
- if (error2.safetyRatings)
1161
- errorDetails.safetyRatings = error2.safetyRatings;
1162
- if (error2.usageMetadata)
1163
- errorDetails.usageMetadata = error2.usageMetadata;
1169
+ if (error2.safetyRatings) errorDetails.safetyRatings = error2.safetyRatings;
1170
+ if (error2.usageMetadata) errorDetails.usageMetadata = error2.usageMetadata;
1164
1171
  if (error2.promptFeedback)
1165
1172
  errorDetails.promptFeedback = error2.promptFeedback;
1166
- if (error2.status)
1167
- errorDetails.httpStatus = error2.status;
1168
- if (error2.code)
1169
- errorDetails.errorCode = error2.code;
1170
- if (error2.details)
1171
- errorDetails.errorDetails = error2.details;
1173
+ if (error2.status) errorDetails.httpStatus = error2.status;
1174
+ if (error2.code) errorDetails.errorCode = error2.code;
1175
+ if (error2.details) errorDetails.errorDetails = error2.details;
1172
1176
  const fileUris = payload.messages.flatMap((m) => m.parts).filter((p) => "fileData" in p).map((p) => p.fileData.fileUri);
1173
- if (fileUris.length)
1174
- errorDetails.fileUris = fileUris;
1177
+ if (fileUris.length) errorDetails.fileUris = fileUris;
1175
1178
  logger_default.error(
1176
1179
  id,
1177
1180
  `Retry #${attempt} error: ${error2.message}`,
@@ -1251,16 +1254,13 @@ function prepareOpenAICompatMessages(messages) {
1251
1254
  }
1252
1255
  };
1253
1256
  });
1254
- if (!message.content)
1255
- outMessage.content = null;
1257
+ if (!message.content) outMessage.content = null;
1256
1258
  }
1257
- if (message.reasoning)
1258
- outMessage.reasoning = message.reasoning;
1259
+ if (message.reasoning) outMessage.reasoning = message.reasoning;
1259
1260
  const reasoningDetails = filterOpenAICompatReasoningDetails(
1260
1261
  message.reasoningDetails
1261
1262
  );
1262
- if (reasoningDetails)
1263
- outMessage.reasoning_details = reasoningDetails;
1263
+ if (reasoningDetails) outMessage.reasoning_details = reasoningDetails;
1264
1264
  out.push(outMessage);
1265
1265
  }
1266
1266
  return out;
@@ -1280,17 +1280,22 @@ function prepareGroqPayload(payload) {
1280
1280
  }
1281
1281
  async function callGroq(id, payload, requestTimeoutMs = 12e4, signal) {
1282
1282
  var _a, _b, _c, _d, _e, _f, _g;
1283
- const response = await import_axios.default.post(
1284
- "https://api.groq.com/openai/v1/chat/completions",
1285
- payload,
1286
- {
1287
- headers: {
1288
- "content-type": "application/json",
1289
- Authorization: `Bearer ${process.env.GROQ_API_KEY}`
1290
- },
1291
- timeout: requestTimeoutMs,
1292
- signal
1293
- }
1283
+ const response = await withRequestDeadline(
1284
+ "Groq",
1285
+ requestTimeoutMs,
1286
+ signal,
1287
+ (mergedSignal) => import_axios.default.post(
1288
+ "https://api.groq.com/openai/v1/chat/completions",
1289
+ payload,
1290
+ {
1291
+ headers: {
1292
+ "content-type": "application/json",
1293
+ Authorization: `Bearer ${process.env.GROQ_API_KEY}`
1294
+ },
1295
+ timeout: requestTimeoutMs,
1296
+ signal: mergedSignal
1297
+ }
1298
+ )
1294
1299
  );
1295
1300
  if (response.data.error) {
1296
1301
  logger_default.error(id, "Groq error:", response.data.error);
@@ -1398,8 +1403,7 @@ function parseDsmlToolCalls(content) {
1398
1403
  let last = -1;
1399
1404
  let tag;
1400
1405
  while ((tag = DSML_ANY_TAG_RE.exec(content)) !== null) {
1401
- if (first === -1)
1402
- first = tag.index;
1406
+ if (first === -1) first = tag.index;
1403
1407
  last = tag.index + tag[0].length;
1404
1408
  }
1405
1409
  const remaining = first === -1 ? content : (content.slice(0, first) + content.slice(last)).trim();
@@ -1407,17 +1411,23 @@ function parseDsmlToolCalls(content) {
1407
1411
  }
1408
1412
  async function callOpenRouter(id, payload, requestTimeoutMs = 12e4, signal) {
1409
1413
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1410
- const response = await import_axios.default.post(
1411
- "https://openrouter.ai/api/v1/chat/completions",
1412
- payload,
1413
- {
1414
- headers: {
1415
- "content-type": "application/json",
1416
- Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`
1417
- },
1418
- timeout: requestTimeoutMs,
1419
- signal
1420
- }
1414
+ const response = await withRequestDeadline(
1415
+ "OpenRouter",
1416
+ requestTimeoutMs,
1417
+ signal,
1418
+ (mergedSignal) => import_axios.default.post(
1419
+ // Override point for tests (deadline behavior needs a local server).
1420
+ `${process.env.OPENROUTER_BASE_URL || "https://openrouter.ai"}/api/v1/chat/completions`,
1421
+ payload,
1422
+ {
1423
+ headers: {
1424
+ "content-type": "application/json",
1425
+ Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`
1426
+ },
1427
+ timeout: requestTimeoutMs,
1428
+ signal: mergedSignal
1429
+ }
1430
+ )
1421
1431
  );
1422
1432
  if (response.data.error) {
1423
1433
  logger_default.error(id, "OpenRouter error:", response.data.error);
@@ -1583,8 +1593,7 @@ async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeou
1583
1593
  (_b = result.provider) != null ? _b : result.provider = provider;
1584
1594
  return result;
1585
1595
  } catch (error2) {
1586
- if ((_c = aiPayload.signal) == null ? void 0 : _c.aborted)
1587
- throw error2;
1596
+ if ((_c = aiPayload.signal) == null ? void 0 : _c.aborted) throw error2;
1588
1597
  if (aiPayload.fallbackModel) {
1589
1598
  logger_default.error(
1590
1599
  id,