190proof 1.0.72 → 1.0.74

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,16 +1,17 @@
1
1
  # 190proof
2
2
 
3
- A unified interface for interacting with multiple AI providers including **OpenAI**, **Anthropic**, **Google**, and **Groq**. This package provides a consistent API for making requests to different LLM providers while handling retries, streaming, and multimodal inputs.
3
+ A unified interface for interacting with multiple AI providers including **OpenAI**, **Anthropic**, **Google**, **Groq**, 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
 
7
7
  Fully-local unified interface across multiple AI providers that includes:
8
8
 
9
- - 🖼️ Image format & size normalization
10
- - 🛠️ Consistent function calling
9
+ - 🛠️ Consistent function/tool calling across all providers
11
10
  - 💬 Consistent message alternation & system instructions
11
+ - 🖼️ Image format & size normalization
12
12
  - 🔄 Automatic retries with configurable attempts
13
13
  - 📡 Streaming by default
14
+ - ☁️ Cloud service providers supported (Azure, AWS Bedrock)
14
15
 
15
16
  ## Installation
16
17
 
@@ -27,7 +28,7 @@ import { callWithRetries } from "190proof";
27
28
  import { GPTModel, GenericPayload } from "190proof/interfaces";
28
29
 
29
30
  const payload: GenericPayload = {
30
- model: GPTModel.O1_MINI,
31
+ model: GPTModel.GPT4O_MINI,
31
32
  messages: [
32
33
  {
33
34
  role: "user",
@@ -40,11 +41,43 @@ const response = await callWithRetries("my-request-id", payload);
40
41
  console.log(response.content);
41
42
  ```
42
43
 
44
+ ### Using Different Providers
45
+
46
+ ```typescript
47
+ import { callWithRetries } from "190proof";
48
+ import {
49
+ ClaudeModel,
50
+ GeminiModel,
51
+ GroqModel,
52
+ GenericPayload,
53
+ } from "190proof/interfaces";
54
+
55
+ // Anthropic
56
+ const claudePayload: GenericPayload = {
57
+ model: ClaudeModel.SONNET_4,
58
+ messages: [{ role: "user", content: "Hello!" }],
59
+ };
60
+
61
+ // Google
62
+ const geminiPayload: GenericPayload = {
63
+ model: GeminiModel.GEMINI_2_0_FLASH,
64
+ messages: [{ role: "user", content: "Hello!" }],
65
+ };
66
+
67
+ // Groq
68
+ const groqPayload: GenericPayload = {
69
+ model: GroqModel.LLAMA_3_70B_8192,
70
+ messages: [{ role: "user", content: "Hello!" }],
71
+ };
72
+
73
+ const response = await callWithRetries("request-id", claudePayload);
74
+ ```
75
+
43
76
  ### With Function Calling
44
77
 
45
78
  ```typescript
46
79
  const payload: GenericPayload = {
47
- model: GPTModel.O1_MINI,
80
+ model: GPTModel.GPT4O,
48
81
  messages: [
49
82
  {
50
83
  role: "user",
@@ -70,13 +103,14 @@ const payload: GenericPayload = {
70
103
  };
71
104
 
72
105
  const response = await callWithRetries("function-call-example", payload);
106
+ // response.function_call contains { name: string, arguments: Record<string, any> }
73
107
  ```
74
108
 
75
109
  ### With Images
76
110
 
77
111
  ```typescript
78
112
  const payload: GenericPayload = {
79
- model: GPTModel.O1_MINI,
113
+ model: ClaudeModel.SONNET_4,
80
114
  messages: [
81
115
  {
82
116
  role: "user",
@@ -98,7 +132,7 @@ const response = await callWithRetries("image-example", payload);
98
132
 
99
133
  ```typescript
100
134
  const payload: GenericPayload = {
101
- model: GPTModel.O1_MINI,
135
+ model: GeminiModel.GEMINI_2_0_FLASH,
102
136
  messages: [
103
137
  {
104
138
  role: "system",
@@ -128,35 +162,122 @@ const response = await callWithRetries("system-message-example", payload);
128
162
  - `gpt-4o-mini`
129
163
  - `o1-preview`
130
164
  - `o1-mini`
165
+ - `o3-mini`
166
+ - `gpt-4.1`
167
+ - `gpt-4.1-mini`
168
+ - `gpt-4.1-nano`
169
+ - `gpt-5`
170
+ - `gpt-5-mini`
131
171
 
132
172
  ### Anthropic Models
133
173
 
134
174
  - `claude-3-haiku-20240307`
135
175
  - `claude-3-sonnet-20240229`
136
176
  - `claude-3-opus-20240229`
177
+ - `claude-3-5-haiku-20241022`
137
178
  - `claude-3-5-sonnet-20241022`
179
+ - `claude-sonnet-4-20250514`
180
+ - `claude-opus-4-20250514`
181
+ - `claude-opus-4-1`
182
+ - `claude-haiku-4-5`
183
+ - `claude-sonnet-4-5`
184
+ - `claude-opus-4-5`
138
185
 
139
186
  ### Google Models
140
187
 
141
188
  - `gemini-1.5-pro-latest`
189
+ - `gemini-exp-1206`
190
+ - `gemini-2.0-flash`
191
+ - `gemini-2.0-flash-exp-image-generation`
192
+ - `gemini-2.0-flash-thinking-exp`
193
+ - `gemini-2.0-flash-thinking-exp-01-21`
194
+ - `gemini-2.5-flash-preview-04-17`
195
+ - `gemini-3-flash-preview`
142
196
 
143
197
  ### Groq Models
144
198
 
145
199
  - `llama3-70b-8192`
200
+ - `deepseek-r1-distill-llama-70b`
201
+
202
+ ## Environment Variables
203
+
204
+ Set the following environment variables for the providers you want to use:
205
+
206
+ ```bash
207
+ # OpenAI
208
+ OPENAI_API_KEY=your-openai-api-key
209
+
210
+ # Anthropic
211
+ ANTHROPIC_API_KEY=your-anthropic-api-key
212
+
213
+ # Google
214
+ GEMINI_API_KEY=your-gemini-api-key
215
+
216
+ # Groq
217
+ GROQ_API_KEY=your-groq-api-key
218
+
219
+ # AWS Bedrock (for Anthropic via Bedrock)
220
+ AWS_ACCESS_KEY_ID=your-aws-access-key
221
+ AWS_SECRET_ACCESS_KEY=your-aws-secret-key
222
+ ```
146
223
 
147
224
  ## API Reference
148
225
 
149
- ### `callWithRetries(identifier: string, payload: GenericPayload, config?: Config, retries?: number, chunkTimeoutMs?: number)`
226
+ ### `callWithRetries(identifier, payload, config?, retries?, chunkTimeoutMs?)`
150
227
 
151
228
  Main function to make requests to any supported AI provider.
152
229
 
153
230
  #### Parameters
154
231
 
155
- - `identifier`: Unique identifier for the request
156
- - `payload`: Request payload containing model, messages, and optional functions
157
- - `config`: Optional configuration for the specific provider
158
- - `retries`: Number of retry attempts (default: 5)
159
- - `chunkTimeoutMs`: Timeout for streaming chunks (default: 15000)
232
+ - `identifier`: `string | string[]` - Unique identifier for the request (used for logging)
233
+ - `payload`: `GenericPayload` - Request payload containing model, messages, and optional functions
234
+ - `config`: `OpenAIConfig | AnthropicAIConfig` - Optional configuration for the specific provider
235
+ - `retries`: `number` - Number of retry attempts (default: 5)
236
+ - `chunkTimeoutMs`: `number` - Timeout for streaming chunks in ms (default: 15000)
237
+
238
+ #### Returns
239
+
240
+ `Promise<ParsedResponseMessage>`:
241
+
242
+ ```typescript
243
+ interface ParsedResponseMessage {
244
+ role: "assistant";
245
+ content: string | null;
246
+ function_call: FunctionCall | null;
247
+ files: File[]; // For models that return files (e.g., image generation)
248
+ }
249
+ ```
250
+
251
+ ### Configuration Options
252
+
253
+ #### OpenAI Config
254
+
255
+ ```typescript
256
+ interface OpenAIConfig {
257
+ service: "azure" | "openai";
258
+ apiKey: string;
259
+ baseUrl: string;
260
+ orgId?: string;
261
+ modelConfigMap?: Record<
262
+ GPTModel,
263
+ {
264
+ resource: string;
265
+ deployment: string;
266
+ apiVersion: string;
267
+ apiKey: string;
268
+ endpoint?: string;
269
+ }
270
+ >;
271
+ }
272
+ ```
273
+
274
+ #### Anthropic Config
275
+
276
+ ```typescript
277
+ interface AnthropicAIConfig {
278
+ service: "anthropic" | "bedrock";
279
+ }
280
+ ```
160
281
 
161
282
  ## License
162
283
 
package/dist/index.d.mts CHANGED
@@ -2,9 +2,12 @@ declare enum ClaudeModel {
2
2
  HAIKU_3 = "claude-3-haiku-20240307",
3
3
  SONNET_3 = "claude-3-sonnet-20240229",
4
4
  OPUS_3 = "claude-3-opus-20240229",
5
+ HAIKU_3_5 = "claude-3-5-haiku-20241022",
5
6
  SONNET_3_5 = "claude-3-5-sonnet-20241022",
6
7
  SONNET_4 = "claude-sonnet-4-20250514",
7
8
  OPUS_4 = "claude-opus-4-20250514",
9
+ OPUS_4_1 = "claude-opus-4-1",
10
+ HAIKU_4_5 = "claude-haiku-4-5",
8
11
  SONNET_4_5 = "claude-sonnet-4-5",
9
12
  OPUS_4_5 = "claude-opus-4-5"
10
13
  }
package/dist/index.d.ts CHANGED
@@ -2,9 +2,12 @@ declare enum ClaudeModel {
2
2
  HAIKU_3 = "claude-3-haiku-20240307",
3
3
  SONNET_3 = "claude-3-sonnet-20240229",
4
4
  OPUS_3 = "claude-3-opus-20240229",
5
+ HAIKU_3_5 = "claude-3-5-haiku-20241022",
5
6
  SONNET_3_5 = "claude-3-5-sonnet-20241022",
6
7
  SONNET_4 = "claude-sonnet-4-20250514",
7
8
  OPUS_4 = "claude-opus-4-20250514",
9
+ OPUS_4_1 = "claude-opus-4-1",
10
+ HAIKU_4_5 = "claude-haiku-4-5",
8
11
  SONNET_4_5 = "claude-sonnet-4-5",
9
12
  OPUS_4_5 = "claude-opus-4-5"
10
13
  }
package/dist/index.js CHANGED
@@ -43,9 +43,12 @@ var ClaudeModel = /* @__PURE__ */ ((ClaudeModel2) => {
43
43
  ClaudeModel2["HAIKU_3"] = "claude-3-haiku-20240307";
44
44
  ClaudeModel2["SONNET_3"] = "claude-3-sonnet-20240229";
45
45
  ClaudeModel2["OPUS_3"] = "claude-3-opus-20240229";
46
+ ClaudeModel2["HAIKU_3_5"] = "claude-3-5-haiku-20241022";
46
47
  ClaudeModel2["SONNET_3_5"] = "claude-3-5-sonnet-20241022";
47
48
  ClaudeModel2["SONNET_4"] = "claude-sonnet-4-20250514";
48
49
  ClaudeModel2["OPUS_4"] = "claude-opus-4-20250514";
50
+ ClaudeModel2["OPUS_4_1"] = "claude-opus-4-1";
51
+ ClaudeModel2["HAIKU_4_5"] = "claude-haiku-4-5";
49
52
  ClaudeModel2["SONNET_4_5"] = "claude-sonnet-4-5";
50
53
  ClaudeModel2["OPUS_4_5"] = "claude-opus-4-5";
51
54
  return ClaudeModel2;
@@ -144,7 +147,11 @@ function parseStreamedResponse(identifier, paragraph, functionCallName, function
144
147
  arguments: JSON.parse(functionCallArgs)
145
148
  };
146
149
  } catch (error2) {
147
- logger_default.error(identifier, "Error parsing functionCallArgs:", functionCallArgs);
150
+ logger_default.error(
151
+ identifier,
152
+ "Error parsing functionCallArgs:",
153
+ functionCallArgs
154
+ );
148
155
  throw error2;
149
156
  }
150
157
  }
@@ -195,7 +202,10 @@ async function callOpenAiWithRetries(identifier, openAiPayload, openAiConfig, re
195
202
  );
196
203
  const errorCode = (_b = error2.data) == null ? void 0 : _b.code;
197
204
  if (errorCode === "content_policy_violation") {
198
- logger_default.log(identifier, "Removing images due to content policy violation error");
205
+ logger_default.log(
206
+ identifier,
207
+ "Removing images due to content policy violation error"
208
+ );
199
209
  openAiPayload.messages.forEach((message) => {
200
210
  if (Array.isArray(message.content)) {
201
211
  message.content = message.content.filter(
@@ -205,18 +215,27 @@ async function callOpenAiWithRetries(identifier, openAiPayload, openAiConfig, re
205
215
  });
206
216
  }
207
217
  if (i >= 2 && (openAiConfig == null ? void 0 : openAiConfig.service) === "azure" && errorCode === "content_filter") {
208
- logger_default.log(identifier, "Switching to OpenAI service due to content filter error");
218
+ logger_default.log(
219
+ identifier,
220
+ "Switching to OpenAI service due to content filter error"
221
+ );
209
222
  openAiConfig.service = "openai";
210
223
  }
211
224
  if (i === 3) {
212
225
  if ((openAiConfig == null ? void 0 : openAiConfig.service) === "azure") {
213
- logger_default.log(identifier, "Switching to OpenAI service due to Azure service error");
226
+ logger_default.log(
227
+ identifier,
228
+ "Switching to OpenAI service due to Azure service error"
229
+ );
214
230
  openAiConfig.service = "openai";
215
231
  }
216
232
  }
217
233
  if (i === 4) {
218
234
  if (openAiPayload.tools) {
219
- logger_default.log(identifier, "Switching to no tool choice due to persistent error");
235
+ logger_default.log(
236
+ identifier,
237
+ "Switching to no tool choice due to persistent error"
238
+ );
220
239
  openAiPayload.tool_choice = "none";
221
240
  }
222
241
  }
@@ -267,7 +286,11 @@ async function callOpenAIStream(identifier, openAiPayload, openAiConfig, chunkTi
267
286
  });
268
287
  const parsedPayload = JSON.parse(stringifiedPayload);
269
288
  } catch (error2) {
270
- logger_default.error(identifier, "Stream error: Azure OpenAI JSON parsing error:", error2);
289
+ logger_default.error(
290
+ identifier,
291
+ "Stream error: Azure OpenAI JSON parsing error:",
292
+ error2
293
+ );
271
294
  }
272
295
  response = await fetch(endpoint, {
273
296
  method: "POST",
@@ -323,7 +346,10 @@ async function callOpenAIStream(identifier, openAiPayload, openAiConfig, chunkTi
323
346
  const { done, value } = await reader.read();
324
347
  clearTimeout(abortTimeout2);
325
348
  if (done) {
326
- logger_default.error(identifier, `Stream ended prematurely after ${chunkIndex + 1} chunks`);
349
+ logger_default.error(
350
+ identifier,
351
+ `Stream ended prematurely after ${chunkIndex + 1} chunks`
352
+ );
327
353
  throw new Error("Stream error: ended prematurely");
328
354
  }
329
355
  let chunk = new TextDecoder().decode(value);
@@ -605,7 +631,11 @@ async function callAnthropic(identifier, AiPayload, AiConfig) {
605
631
  /<thinking>|<\/thinking>|<answer>|<\/answer>/gs,
606
632
  ""
607
633
  );
608
- logger_default.log(identifier, "No text in answer, returning text within tags:", text);
634
+ logger_default.log(
635
+ identifier,
636
+ "No text in answer, returning text within tags:",
637
+ text
638
+ );
609
639
  }
610
640
  if (textResponse) {
611
641
  textResponse += `
@@ -623,7 +653,11 @@ ${text}`;
623
653
  }
624
654
  }
625
655
  if (!textResponse && !functionCalls.length) {
626
- logger_default.error(identifier, "Missing text & fns in Anthropic API response:", data);
656
+ logger_default.error(
657
+ identifier,
658
+ "Missing text & fns in Anthropic API response:",
659
+ data
660
+ );
627
661
  throw new Error("Missing text & fns in Anthropic API response");
628
662
  }
629
663
  return {
@@ -733,7 +767,10 @@ async function prepareGoogleAIPayload(payload) {
733
767
  }
734
768
  for (const file of message.files || []) {
735
769
  if (!((_a = file.mimeType) == null ? void 0 : _a.startsWith("image"))) {
736
- logger_default.warn("payload", "Google AI API does not support non-image file types. Skipping file.");
770
+ logger_default.warn(
771
+ "payload",
772
+ "Google AI API does not support non-image file types. Skipping file."
773
+ );
737
774
  continue;
738
775
  }
739
776
  if (file.url) {
@@ -771,7 +808,6 @@ async function prepareGoogleAIPayload(payload) {
771
808
  }
772
809
  async function callGoogleAI(identifier, payload) {
773
810
  var _a, _b, _c;
774
- logger_default.log(identifier, "Calling Google AI API");
775
811
  const googleMessages = jigGoogleMessages(payload.messages);
776
812
  const history = googleMessages.slice(0, -1);
777
813
  const lastMessage = googleMessages.slice(-1)[0];
@@ -815,7 +851,11 @@ async function callGoogleAI(identifier, payload) {
815
851
  };
816
852
  });
817
853
  if (!text && !(parsedFunctionCalls == null ? void 0 : parsedFunctionCalls.length) && !files.length) {
818
- logger_default.error(identifier, "Missing text & fns in Google AI API response:", response);
854
+ logger_default.error(
855
+ identifier,
856
+ "Missing text & fns in Google AI API response:",
857
+ response
858
+ );
819
859
  throw new Error("Missing text & fns in Google AI API response");
820
860
  }
821
861
  return {
@@ -846,7 +886,6 @@ async function callGoogleAIWithRetries(identifier, payload, retries = 5) {
846
886
  async function callWithRetries(identifier, aiPayload, aiConfig, retries = 5, chunkTimeoutMs = 15e3) {
847
887
  const id = identifier;
848
888
  if (isAnthropicPayload(aiPayload)) {
849
- logger_default.log(id, "Delegating call to Anthropic API");
850
889
  return await callAnthropicWithRetries(
851
890
  id,
852
891
  await prepareAnthropicPayload(aiPayload),
@@ -854,7 +893,6 @@ async function callWithRetries(identifier, aiPayload, aiConfig, retries = 5, chu
854
893
  retries
855
894
  );
856
895
  } else if (isOpenAiPayload(aiPayload)) {
857
- logger_default.log(id, "Delegating call to OpenAI API");
858
896
  return await callOpenAiWithRetries(
859
897
  id,
860
898
  await prepareOpenAIPayload(aiPayload),
@@ -863,13 +901,8 @@ async function callWithRetries(identifier, aiPayload, aiConfig, retries = 5, chu
863
901
  chunkTimeoutMs
864
902
  );
865
903
  } else if (isGroqPayload(aiPayload)) {
866
- logger_default.log(id, "Delegating call to Groq API");
867
- return await callGroqWithRetries(
868
- id,
869
- await prepareGroqPayload(aiPayload)
870
- );
904
+ return await callGroqWithRetries(id, await prepareGroqPayload(aiPayload));
871
905
  } else if (isGoogleAIPayload(aiPayload)) {
872
- logger_default.log(id, "Delegating call to Google AI API");
873
906
  return await callGoogleAIWithRetries(
874
907
  id,
875
908
  await prepareGoogleAIPayload(aiPayload),
@@ -904,7 +937,10 @@ async function prepareAnthropicPayload(payload) {
904
937
  }
905
938
  for (const file of message.files || []) {
906
939
  if (!((_a = file.mimeType) == null ? void 0 : _a.startsWith("image"))) {
907
- logger_default.warn("payload", "Anthropic API does not support non-image file types. Skipping file.");
940
+ logger_default.warn(
941
+ "payload",
942
+ "Anthropic API does not support non-image file types. Skipping file."
943
+ );
908
944
  continue;
909
945
  }
910
946
  if (file.url) {
@@ -994,7 +1030,11 @@ async function prepareOpenAIPayload(payload) {
994
1030
  });
995
1031
  }
996
1032
  } else {
997
- logger_default.warn("payload", "Skipping file in message. File or image type not supported by OpenAI API:", file.mimeType);
1033
+ logger_default.warn(
1034
+ "payload",
1035
+ "Skipping file in message. File or image type not supported by OpenAI API:",
1036
+ file.mimeType
1037
+ );
998
1038
  }
999
1039
  }
1000
1040
  preparedPayload.messages.push({
@@ -1074,7 +1114,11 @@ async function callGroqWithRetries(identifier, payload, retries = 5) {
1074
1114
  lastResponse = await callGroq(identifier, payload);
1075
1115
  return lastResponse;
1076
1116
  } catch (e) {
1077
- logger_default.error(identifier, `Retry #${i} error: ${e.message}`, ((_a = e.response) == null ? void 0 : _a.data) || e);
1117
+ logger_default.error(
1118
+ identifier,
1119
+ `Retry #${i} error: ${e.message}`,
1120
+ ((_a = e.response) == null ? void 0 : _a.data) || e
1121
+ );
1078
1122
  await timeout(125 * i);
1079
1123
  }
1080
1124
  }