190proof 1.0.76 → 1.0.77
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/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +519 -788
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +519 -788
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -101,15 +101,42 @@ function isHeicImage(name, mime) {
|
|
|
101
101
|
|
|
102
102
|
// index.ts
|
|
103
103
|
import { GoogleGenAI } from "@google/genai";
|
|
104
|
-
var { GoogleGenerativeAI } = __require("@google/generative-ai");
|
|
105
104
|
var sharp = __require("sharp");
|
|
106
105
|
var decode = __require("heic-decode");
|
|
106
|
+
async function withRetries(identifier, apiName, fn, options = {}) {
|
|
107
|
+
var _a;
|
|
108
|
+
const { retries = 5, baseDelayMs = 125, onError } = options;
|
|
109
|
+
logger_default.log(identifier, `Calling ${apiName} API with retries`);
|
|
110
|
+
let lastError;
|
|
111
|
+
for (let attempt = 0; attempt < retries; attempt++) {
|
|
112
|
+
try {
|
|
113
|
+
return await fn();
|
|
114
|
+
} catch (error3) {
|
|
115
|
+
lastError = error3;
|
|
116
|
+
if (onError) {
|
|
117
|
+
onError(error3, attempt);
|
|
118
|
+
} else {
|
|
119
|
+
logger_default.error(
|
|
120
|
+
identifier,
|
|
121
|
+
`Retry #${attempt} error: ${error3.message}`,
|
|
122
|
+
((_a = error3.response) == null ? void 0 : _a.data) || error3
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
await timeout(baseDelayMs * attempt);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const error2 = new Error(
|
|
129
|
+
`Failed to call ${apiName} API after ${retries} attempts`
|
|
130
|
+
);
|
|
131
|
+
error2.cause = lastError;
|
|
132
|
+
throw error2;
|
|
133
|
+
}
|
|
107
134
|
function parseStreamedResponse(identifier, paragraph, functionCallName, functionCallArgs, allowedFunctionNames) {
|
|
108
135
|
let functionCall = null;
|
|
109
136
|
if (functionCallName && functionCallArgs) {
|
|
110
137
|
if (allowedFunctionNames && !allowedFunctionNames.has(functionCallName)) {
|
|
111
138
|
throw new Error(
|
|
112
|
-
|
|
139
|
+
`Stream error: received function call with unknown name: ${functionCallName}`
|
|
113
140
|
);
|
|
114
141
|
}
|
|
115
142
|
try {
|
|
@@ -120,7 +147,7 @@ function parseStreamedResponse(identifier, paragraph, functionCallName, function
|
|
|
120
147
|
} catch (error2) {
|
|
121
148
|
logger_default.error(
|
|
122
149
|
identifier,
|
|
123
|
-
"Error parsing
|
|
150
|
+
"Error parsing function call arguments:",
|
|
124
151
|
functionCallArgs
|
|
125
152
|
);
|
|
126
153
|
throw error2;
|
|
@@ -129,7 +156,7 @@ function parseStreamedResponse(identifier, paragraph, functionCallName, function
|
|
|
129
156
|
if (!paragraph && !functionCall) {
|
|
130
157
|
logger_default.error(
|
|
131
158
|
identifier,
|
|
132
|
-
"Stream error: received message without content or function_call
|
|
159
|
+
"Stream error: received message without content or function_call:",
|
|
133
160
|
JSON.stringify({ paragraph, functionCallName, functionCallArgs })
|
|
134
161
|
);
|
|
135
162
|
throw new Error(
|
|
@@ -143,328 +170,252 @@ function parseStreamedResponse(identifier, paragraph, functionCallName, function
|
|
|
143
170
|
files: []
|
|
144
171
|
};
|
|
145
172
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
openAiConfig,
|
|
165
|
-
chunkTimeoutMs
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
} catch (error2) {
|
|
169
|
-
logger_default.error(
|
|
170
|
-
identifier,
|
|
171
|
-
`Retry #${i} error: ${error2.message}`,
|
|
172
|
-
((_a = error2.response) == null ? void 0 : _a.data) || error2.data || error2
|
|
173
|
-
);
|
|
174
|
-
const errorCode = (_b = error2.data) == null ? void 0 : _b.code;
|
|
175
|
-
if (errorCode === "content_policy_violation") {
|
|
176
|
-
logger_default.log(
|
|
177
|
-
identifier,
|
|
178
|
-
"Removing images due to content policy violation error"
|
|
179
|
-
);
|
|
180
|
-
openAiPayload.messages.forEach((message) => {
|
|
181
|
-
if (Array.isArray(message.content)) {
|
|
182
|
-
message.content = message.content.filter(
|
|
183
|
-
(content) => content.type === "text"
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
if (i >= 2 && (openAiConfig == null ? void 0 : openAiConfig.service) === "azure" && errorCode === "content_filter") {
|
|
189
|
-
logger_default.log(
|
|
190
|
-
identifier,
|
|
191
|
-
"Switching to OpenAI service due to content filter error"
|
|
192
|
-
);
|
|
193
|
-
openAiConfig.service = "openai";
|
|
194
|
-
}
|
|
195
|
-
if (i === 3) {
|
|
196
|
-
if ((openAiConfig == null ? void 0 : openAiConfig.service) === "azure") {
|
|
197
|
-
logger_default.log(
|
|
198
|
-
identifier,
|
|
199
|
-
"Switching to OpenAI service due to Azure service error"
|
|
200
|
-
);
|
|
201
|
-
openAiConfig.service = "openai";
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
if (i === 4) {
|
|
205
|
-
if (openAiPayload.tools) {
|
|
206
|
-
logger_default.log(
|
|
207
|
-
identifier,
|
|
208
|
-
"Switching to no tool choice due to persistent error"
|
|
209
|
-
);
|
|
210
|
-
openAiPayload.tool_choice = "none";
|
|
173
|
+
function truncatePayload(payload) {
|
|
174
|
+
return JSON.stringify(
|
|
175
|
+
{
|
|
176
|
+
...payload,
|
|
177
|
+
messages: payload.messages.map((message) => {
|
|
178
|
+
const truncatedMessage = { ...message };
|
|
179
|
+
if (typeof truncatedMessage.content === "string") {
|
|
180
|
+
truncatedMessage.content = truncatedMessage.content.slice(0, 100);
|
|
181
|
+
} else if (Array.isArray(truncatedMessage.content)) {
|
|
182
|
+
truncatedMessage.content = truncatedMessage.content.map((block) => {
|
|
183
|
+
if (block.type === "image_url") {
|
|
184
|
+
return {
|
|
185
|
+
...block,
|
|
186
|
+
image_url: { url: block.image_url.url.slice(0, 100) }
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
return block;
|
|
190
|
+
});
|
|
211
191
|
}
|
|
192
|
+
return truncatedMessage;
|
|
193
|
+
})
|
|
194
|
+
},
|
|
195
|
+
null,
|
|
196
|
+
2
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
async function getNormalizedBase64PNG(url, mime) {
|
|
200
|
+
const response = await axios.get(url, { responseType: "arraybuffer" });
|
|
201
|
+
let imageBuffer = Buffer.from(response.data);
|
|
202
|
+
let sharpOptions = {};
|
|
203
|
+
if (isHeicImage(url, mime)) {
|
|
204
|
+
const imageData = await decode({ buffer: imageBuffer });
|
|
205
|
+
imageBuffer = Buffer.from(imageData.data);
|
|
206
|
+
sharpOptions = {
|
|
207
|
+
raw: {
|
|
208
|
+
width: imageData.width,
|
|
209
|
+
height: imageData.height,
|
|
210
|
+
channels: 4
|
|
212
211
|
}
|
|
213
|
-
|
|
214
|
-
}
|
|
212
|
+
};
|
|
215
213
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
`Failed to call OpenAI API after ${retries} attempts. Please lookup OpenAI status for active issues.`,
|
|
219
|
-
errorObj
|
|
220
|
-
);
|
|
221
|
-
throw new Error(
|
|
222
|
-
`${identifier}: Failed to call OpenAI API after ${retries} attempts. Please lookup OpenAI status for active issues.`
|
|
223
|
-
);
|
|
214
|
+
const resizedBuffer = await sharp(imageBuffer, sharpOptions).withMetadata().resize(1024, 1024, { fit: "inside", withoutEnlargement: true }).png().toBuffer();
|
|
215
|
+
return resizedBuffer.toString("base64");
|
|
224
216
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
217
|
+
var ALLOWED_IMAGE_MIME_TYPES = [
|
|
218
|
+
"image/png",
|
|
219
|
+
"image/jpeg",
|
|
220
|
+
"image/gif",
|
|
221
|
+
"image/webp"
|
|
222
|
+
];
|
|
223
|
+
function buildOpenAIRequestConfig(identifier, model, config) {
|
|
224
|
+
if (!config) {
|
|
225
|
+
config = {
|
|
230
226
|
service: "openai",
|
|
231
227
|
apiKey: process.env.OPENAI_API_KEY,
|
|
232
228
|
baseUrl: ""
|
|
233
229
|
};
|
|
234
230
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
logger_default.log(identifier, "Using Azure OpenAI service", openAiPayload.model);
|
|
239
|
-
const model = openAiPayload.model;
|
|
240
|
-
if (!openAiConfig.modelConfigMap) {
|
|
231
|
+
if (config.service === "azure") {
|
|
232
|
+
logger_default.log(identifier, "Using Azure OpenAI service:", model);
|
|
233
|
+
if (!config.modelConfigMap) {
|
|
241
234
|
throw new Error(
|
|
242
235
|
"OpenAI config modelConfigMap is required when using Azure OpenAI service."
|
|
243
236
|
);
|
|
244
237
|
}
|
|
245
|
-
const azureConfig =
|
|
246
|
-
|
|
247
|
-
if (azureConfig.endpoint) {
|
|
248
|
-
endpoint = `${azureConfig.endpoint}/openai/deployments/${azureConfig.deployment}/chat/completions?api-version=${azureConfig.apiVersion}`;
|
|
249
|
-
} else {
|
|
238
|
+
const azureConfig = config.modelConfigMap[model];
|
|
239
|
+
if (!(azureConfig == null ? void 0 : azureConfig.endpoint)) {
|
|
250
240
|
throw new Error("Azure OpenAI endpoint is required in modelConfigMap.");
|
|
251
241
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
stream: true
|
|
257
|
-
});
|
|
258
|
-
const parsedPayload = JSON.parse(stringifiedPayload);
|
|
259
|
-
} catch (error2) {
|
|
260
|
-
logger_default.error(
|
|
261
|
-
identifier,
|
|
262
|
-
"Stream error: Azure OpenAI JSON parsing error:",
|
|
263
|
-
error2
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
|
-
response = await fetch(endpoint, {
|
|
267
|
-
method: "POST",
|
|
242
|
+
const endpoint = `${azureConfig.endpoint}/openai/deployments/${azureConfig.deployment}/chat/completions?api-version=${azureConfig.apiVersion}`;
|
|
243
|
+
logger_default.log(identifier, "Using endpoint:", endpoint);
|
|
244
|
+
return {
|
|
245
|
+
endpoint,
|
|
268
246
|
headers: {
|
|
269
247
|
"Content-Type": "application/json",
|
|
270
248
|
"api-key": azureConfig.apiKey
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
logger_default.log(identifier, "Using OpenAI service:", model);
|
|
253
|
+
if (config.orgId) {
|
|
254
|
+
logger_default.log(identifier, "Using orgId:", config.orgId);
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
endpoint: "https://api.openai.com/v1/chat/completions",
|
|
258
|
+
headers: {
|
|
259
|
+
"Content-Type": "application/json",
|
|
260
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
261
|
+
...config.orgId ? { "OpenAI-Organization": config.orgId } : {}
|
|
283
262
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
async function prepareOpenAIPayload(identifier, payload) {
|
|
266
|
+
var _a;
|
|
267
|
+
const preparedPayload = {
|
|
268
|
+
model: payload.model,
|
|
269
|
+
messages: [],
|
|
270
|
+
tools: (_a = payload.functions) == null ? void 0 : _a.map((fn) => ({
|
|
271
|
+
type: "function",
|
|
272
|
+
function: fn
|
|
273
|
+
})),
|
|
274
|
+
tool_choice: payload.function_call ? typeof payload.function_call === "string" ? payload.function_call : { type: "function", function: payload.function_call } : void 0
|
|
275
|
+
};
|
|
276
|
+
for (const message of payload.messages) {
|
|
277
|
+
const contentBlocks = [];
|
|
278
|
+
if (message.content) {
|
|
279
|
+
contentBlocks.push({ type: "text", text: message.content });
|
|
280
|
+
}
|
|
281
|
+
for (const file of message.files || []) {
|
|
282
|
+
if (ALLOWED_IMAGE_MIME_TYPES.includes(file.mimeType)) {
|
|
283
|
+
if (file.url) {
|
|
284
|
+
contentBlocks.push({
|
|
285
|
+
type: "image_url",
|
|
286
|
+
image_url: { url: file.url }
|
|
287
|
+
});
|
|
288
|
+
contentBlocks.push({ type: "text", text: `Image (${file.url})` });
|
|
289
|
+
} else if (file.data) {
|
|
290
|
+
contentBlocks.push({
|
|
291
|
+
type: "image_url",
|
|
292
|
+
image_url: { url: `data:${file.mimeType};base64,${file.data}` }
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
} else if (file.url) {
|
|
296
|
+
contentBlocks.push({
|
|
297
|
+
type: "text",
|
|
298
|
+
text: `File (${file.url})`
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
preparedPayload.messages.push({
|
|
303
|
+
role: message.role,
|
|
304
|
+
content: contentBlocks
|
|
296
305
|
});
|
|
297
306
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
307
|
+
return preparedPayload;
|
|
308
|
+
}
|
|
309
|
+
async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs) {
|
|
310
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
311
|
+
const functionNames = openAiPayload.tools ? new Set(openAiPayload.tools.map((fn) => fn.function.name)) : null;
|
|
312
|
+
const { endpoint, headers } = buildOpenAIRequestConfig(
|
|
313
|
+
id,
|
|
314
|
+
openAiPayload.model,
|
|
315
|
+
openAiConfig
|
|
316
|
+
);
|
|
317
|
+
const controller = new AbortController();
|
|
318
|
+
const response = await fetch(endpoint, {
|
|
319
|
+
method: "POST",
|
|
320
|
+
headers,
|
|
321
|
+
body: JSON.stringify({ ...openAiPayload, stream: true }),
|
|
322
|
+
signal: controller.signal
|
|
323
|
+
});
|
|
324
|
+
if (!response.body) {
|
|
325
|
+
throw new Error("Stream error: no response body");
|
|
326
|
+
}
|
|
327
|
+
let paragraph = "";
|
|
328
|
+
let functionCallName = "";
|
|
329
|
+
let functionCallArgs = "";
|
|
330
|
+
const reader = response.body.getReader();
|
|
331
|
+
let partialChunk = "";
|
|
332
|
+
let chunkIndex = -1;
|
|
333
|
+
const createAbortTimeout = () => setTimeout(() => {
|
|
334
|
+
logger_default.error(id, `Stream timeout after ${chunkTimeoutMs}ms`);
|
|
335
|
+
controller.abort();
|
|
336
|
+
}, chunkTimeoutMs);
|
|
337
|
+
while (true) {
|
|
338
|
+
chunkIndex++;
|
|
339
|
+
const abortTimeout = createAbortTimeout();
|
|
340
|
+
const { done, value } = await reader.read();
|
|
341
|
+
clearTimeout(abortTimeout);
|
|
342
|
+
if (done) {
|
|
343
|
+
logger_default.error(id, `Stream ended prematurely after ${chunkIndex + 1} chunks`);
|
|
344
|
+
throw new Error("Stream error: ended prematurely");
|
|
345
|
+
}
|
|
346
|
+
let chunk = new TextDecoder().decode(value);
|
|
347
|
+
if (partialChunk) {
|
|
348
|
+
chunk = partialChunk + chunk;
|
|
349
|
+
partialChunk = "";
|
|
350
|
+
}
|
|
351
|
+
const jsonStrings = chunk.split(/^data: /gm);
|
|
352
|
+
for (const jsonString of jsonStrings) {
|
|
353
|
+
if (!jsonString)
|
|
354
|
+
continue;
|
|
355
|
+
if (jsonString.includes("[DONE]")) {
|
|
356
|
+
return parseStreamedResponse(
|
|
357
|
+
id,
|
|
358
|
+
paragraph,
|
|
359
|
+
functionCallName,
|
|
360
|
+
functionCallArgs,
|
|
361
|
+
functionNames
|
|
323
362
|
);
|
|
324
|
-
throw new Error("Stream error: ended prematurely");
|
|
325
363
|
}
|
|
326
|
-
let
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
partialChunk =
|
|
364
|
+
let json;
|
|
365
|
+
try {
|
|
366
|
+
json = JSON.parse(jsonString.trim());
|
|
367
|
+
} catch (e) {
|
|
368
|
+
partialChunk = jsonString;
|
|
369
|
+
continue;
|
|
331
370
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
return parseStreamedResponse(
|
|
340
|
-
identifier,
|
|
341
|
-
paragraph,
|
|
342
|
-
functionCallName,
|
|
343
|
-
functionCallArgs,
|
|
344
|
-
functionNames
|
|
345
|
-
);
|
|
346
|
-
} catch (error2) {
|
|
347
|
-
logger_default.error(identifier, "Stream error: parsing response");
|
|
348
|
-
throw error2;
|
|
349
|
-
}
|
|
371
|
+
if (!((_a = json.choices) == null ? void 0 : _a.length)) {
|
|
372
|
+
if (json.error) {
|
|
373
|
+
logger_default.error(id, "Stream error from OpenAI:", json.error);
|
|
374
|
+
const error2 = new Error("Stream error: OpenAI error");
|
|
375
|
+
error2.data = json.error;
|
|
376
|
+
error2.requestBody = truncatePayload(openAiPayload);
|
|
377
|
+
throw error2;
|
|
350
378
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
json = JSON.parse(jsonString.trim());
|
|
354
|
-
} catch (error2) {
|
|
355
|
-
partialChunk = jsonString;
|
|
356
|
-
continue;
|
|
357
|
-
}
|
|
358
|
-
if (!json.choices || !json.choices.length) {
|
|
359
|
-
if (json.error) {
|
|
360
|
-
logger_default.error(identifier, "Stream error: OpenAI error:", json.error);
|
|
361
|
-
const error2 = new Error("Stream error: OpenAI error");
|
|
362
|
-
error2.data = json.error;
|
|
363
|
-
error2.requestBody = truncatePayload(openAiPayload);
|
|
364
|
-
throw error2;
|
|
365
|
-
}
|
|
366
|
-
if (chunkIndex !== 0) {
|
|
367
|
-
logger_default.error(identifier, "Stream error: no choices in JSON:", json);
|
|
368
|
-
}
|
|
369
|
-
continue;
|
|
370
|
-
}
|
|
371
|
-
const dToolCall = (_d = (_c = (_b = (_a = json.choices) == null ? void 0 : _a[0]) == null ? void 0 : _b.delta) == null ? void 0 : _c.tool_calls) == null ? void 0 : _d[0];
|
|
372
|
-
if (dToolCall) {
|
|
373
|
-
const toolCallIndex = dToolCall.index || 0;
|
|
374
|
-
if (toolCallIndex === 0) {
|
|
375
|
-
const dFn = dToolCall.function || {};
|
|
376
|
-
if (dFn.name)
|
|
377
|
-
functionCallName += dFn.name;
|
|
378
|
-
if (dFn.arguments)
|
|
379
|
-
functionCallArgs += dFn.arguments;
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
const text = (_g = (_f = (_e = json.choices) == null ? void 0 : _e[0]) == null ? void 0 : _f.delta) == null ? void 0 : _g.content;
|
|
383
|
-
if (text) {
|
|
384
|
-
paragraph += text;
|
|
379
|
+
if (chunkIndex !== 0) {
|
|
380
|
+
logger_default.error(id, "Stream error: no choices in JSON:", json);
|
|
385
381
|
}
|
|
382
|
+
continue;
|
|
386
383
|
}
|
|
384
|
+
const toolCall = (_d = (_c = (_b = json.choices[0]) == null ? void 0 : _b.delta) == null ? void 0 : _c.tool_calls) == null ? void 0 : _d[0];
|
|
385
|
+
if ((toolCall == null ? void 0 : toolCall.index) === 0 || (toolCall == null ? void 0 : toolCall.index) === void 0) {
|
|
386
|
+
if ((_e = toolCall == null ? void 0 : toolCall.function) == null ? void 0 : _e.name)
|
|
387
|
+
functionCallName += toolCall.function.name;
|
|
388
|
+
if ((_f = toolCall == null ? void 0 : toolCall.function) == null ? void 0 : _f.arguments)
|
|
389
|
+
functionCallArgs += toolCall.function.arguments;
|
|
390
|
+
}
|
|
391
|
+
const text = (_h = (_g = json.choices[0]) == null ? void 0 : _g.delta) == null ? void 0 : _h.content;
|
|
392
|
+
if (text)
|
|
393
|
+
paragraph += text;
|
|
387
394
|
}
|
|
388
|
-
} else {
|
|
389
|
-
throw new Error("Stream error: no response body");
|
|
390
395
|
}
|
|
391
396
|
}
|
|
392
|
-
async function callOpenAI(
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
const model = openAiPayload.model;
|
|
405
|
-
if (!openAiConfig.modelConfigMap) {
|
|
406
|
-
throw new Error(
|
|
407
|
-
"OpenAI config modelConfigMap is required when using Azure OpenAI service."
|
|
408
|
-
);
|
|
409
|
-
}
|
|
410
|
-
const azureConfig = openAiConfig.modelConfigMap[model];
|
|
411
|
-
let endpoint;
|
|
412
|
-
if (azureConfig.endpoint) {
|
|
413
|
-
endpoint = `${azureConfig.endpoint}/openai/deployments/${azureConfig.deployment}/chat/completions?api-version=${azureConfig.apiVersion}`;
|
|
414
|
-
} else {
|
|
415
|
-
throw new Error("Azure OpenAI endpoint is required in modelConfigMap.");
|
|
416
|
-
}
|
|
417
|
-
logger_default.log(identifier, "Using endpoint", endpoint);
|
|
418
|
-
try {
|
|
419
|
-
const stringifiedPayload = JSON.stringify({
|
|
420
|
-
...openAiPayload,
|
|
421
|
-
stream: false
|
|
422
|
-
});
|
|
423
|
-
const parsedPayload = JSON.parse(stringifiedPayload);
|
|
424
|
-
} catch (error2) {
|
|
425
|
-
logger_default.error(identifier, "OpenAI JSON parsing error:", error2);
|
|
426
|
-
throw error2;
|
|
427
|
-
}
|
|
428
|
-
response = await fetch(endpoint, {
|
|
429
|
-
method: "POST",
|
|
430
|
-
headers: {
|
|
431
|
-
"Content-Type": "application/json",
|
|
432
|
-
"api-key": azureConfig.apiKey
|
|
433
|
-
},
|
|
434
|
-
body: JSON.stringify({
|
|
435
|
-
...openAiPayload,
|
|
436
|
-
stream: false
|
|
437
|
-
})
|
|
438
|
-
});
|
|
439
|
-
} else {
|
|
440
|
-
logger_default.log(identifier, "Using OpenAI service", openAiPayload.model);
|
|
441
|
-
const endpoint = `https://api.openai.com/v1/chat/completions`;
|
|
442
|
-
if (openAiConfig.orgId) {
|
|
443
|
-
logger_default.log(identifier, "Using orgId", openAiConfig.orgId);
|
|
444
|
-
}
|
|
445
|
-
response = await fetch(endpoint, {
|
|
446
|
-
method: "POST",
|
|
447
|
-
headers: {
|
|
448
|
-
"Content-Type": "application/json",
|
|
449
|
-
Authorization: `Bearer ${openAiConfig.apiKey}`,
|
|
450
|
-
...openAiConfig.orgId ? { "OpenAI-Organization": openAiConfig.orgId } : {}
|
|
451
|
-
},
|
|
452
|
-
body: JSON.stringify({
|
|
453
|
-
...openAiPayload,
|
|
454
|
-
stream: false
|
|
455
|
-
})
|
|
456
|
-
});
|
|
457
|
-
}
|
|
397
|
+
async function callOpenAI(id, openAiPayload, openAiConfig) {
|
|
398
|
+
var _a;
|
|
399
|
+
const { endpoint, headers } = buildOpenAIRequestConfig(
|
|
400
|
+
id,
|
|
401
|
+
openAiPayload.model,
|
|
402
|
+
openAiConfig
|
|
403
|
+
);
|
|
404
|
+
const response = await fetch(endpoint, {
|
|
405
|
+
method: "POST",
|
|
406
|
+
headers,
|
|
407
|
+
body: JSON.stringify({ ...openAiPayload, stream: false })
|
|
408
|
+
});
|
|
458
409
|
if (!response.ok) {
|
|
459
410
|
const errorData = await response.json();
|
|
460
|
-
logger_default.error(
|
|
411
|
+
logger_default.error(id, "OpenAI API error:", errorData);
|
|
461
412
|
throw new Error(`OpenAI API Error: ${errorData.error.message}`);
|
|
462
413
|
}
|
|
463
414
|
const data = await response.json();
|
|
464
|
-
if (!data.choices
|
|
415
|
+
if (!((_a = data.choices) == null ? void 0 : _a.length)) {
|
|
465
416
|
if (data.error) {
|
|
466
|
-
logger_default.error(
|
|
467
|
-
throw new Error(
|
|
417
|
+
logger_default.error(id, "OpenAI error:", data.error);
|
|
418
|
+
throw new Error(`OpenAI error: ${data.error.message}`);
|
|
468
419
|
}
|
|
469
420
|
throw new Error("OpenAI error: No choices returned.");
|
|
470
421
|
}
|
|
@@ -480,94 +431,167 @@ async function callOpenAI(identifier, openAiPayload, openAiConfig) {
|
|
|
480
431
|
files: []
|
|
481
432
|
};
|
|
482
433
|
}
|
|
483
|
-
function
|
|
484
|
-
|
|
434
|
+
async function callOpenAiWithRetries(id, openAiPayload, openAiConfig, retries = 5, chunkTimeoutMs = 15e3) {
|
|
435
|
+
logger_default.log(
|
|
436
|
+
id,
|
|
437
|
+
"Calling OpenAI API with retries:",
|
|
438
|
+
openAiConfig == null ? void 0 : openAiConfig.service,
|
|
439
|
+
openAiPayload.model
|
|
440
|
+
);
|
|
441
|
+
const useStreaming = openAiPayload.model !== "o1-mini" /* O1_MINI */ && openAiPayload.model !== "o1-preview" /* O1_PREVIEW */;
|
|
442
|
+
return withRetries(
|
|
443
|
+
id,
|
|
444
|
+
"OpenAI",
|
|
445
|
+
async () => {
|
|
446
|
+
if (useStreaming) {
|
|
447
|
+
return callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs);
|
|
448
|
+
} else {
|
|
449
|
+
return callOpenAI(id, openAiPayload, openAiConfig);
|
|
450
|
+
}
|
|
451
|
+
},
|
|
485
452
|
{
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
453
|
+
retries,
|
|
454
|
+
baseDelayMs: 250,
|
|
455
|
+
onError: (error2, attempt) => {
|
|
456
|
+
var _a, _b;
|
|
457
|
+
logger_default.error(
|
|
458
|
+
id,
|
|
459
|
+
`Retry #${attempt} error: ${error2.message}`,
|
|
460
|
+
((_a = error2.response) == null ? void 0 : _a.data) || error2.data || error2
|
|
461
|
+
);
|
|
462
|
+
if (((_b = error2.data) == null ? void 0 : _b.code) === "content_policy_violation") {
|
|
463
|
+
logger_default.log(id, "Removing images due to content policy violation");
|
|
464
|
+
openAiPayload.messages.forEach((message) => {
|
|
465
|
+
if (Array.isArray(message.content)) {
|
|
466
|
+
message.content = message.content.filter(
|
|
467
|
+
(content) => content.type === "text"
|
|
468
|
+
);
|
|
494
469
|
}
|
|
495
|
-
return block;
|
|
496
470
|
});
|
|
497
471
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
},
|
|
501
|
-
null,
|
|
502
|
-
2
|
|
472
|
+
}
|
|
473
|
+
}
|
|
503
474
|
);
|
|
504
475
|
}
|
|
505
|
-
|
|
506
|
-
var _a, _b
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
476
|
+
function jigAnthropicMessages(messages) {
|
|
477
|
+
var _a, _b;
|
|
478
|
+
let jiggedMessages = messages.slice();
|
|
479
|
+
if (((_a = jiggedMessages[0]) == null ? void 0 : _a.role) !== "user") {
|
|
480
|
+
jiggedMessages = [{ role: "user", content: "..." }, ...jiggedMessages];
|
|
481
|
+
}
|
|
482
|
+
jiggedMessages = jiggedMessages.reduce((acc, message) => {
|
|
483
|
+
if (acc.length === 0)
|
|
484
|
+
return [message];
|
|
485
|
+
const lastMessage = acc[acc.length - 1];
|
|
486
|
+
if (lastMessage.role === message.role) {
|
|
487
|
+
const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
|
|
488
|
+
const newContent = Array.isArray(message.content) ? message.content : [{ type: "text", text: message.content }];
|
|
489
|
+
lastMessage.content = [
|
|
490
|
+
...lastContent,
|
|
491
|
+
{ type: "text", text: "\n\n---\n\n" },
|
|
492
|
+
...newContent
|
|
493
|
+
];
|
|
494
|
+
return acc;
|
|
495
|
+
}
|
|
496
|
+
if (typeof message.content === "string") {
|
|
497
|
+
message.content = [{ type: "text", text: message.content }];
|
|
498
|
+
}
|
|
499
|
+
return [...acc, message];
|
|
500
|
+
}, []);
|
|
501
|
+
if (((_b = jiggedMessages[jiggedMessages.length - 1]) == null ? void 0 : _b.role) === "assistant") {
|
|
502
|
+
jiggedMessages.push({ role: "user", content: "..." });
|
|
503
|
+
}
|
|
504
|
+
return jiggedMessages;
|
|
505
|
+
}
|
|
506
|
+
async function prepareAnthropicPayload(_identifier, payload) {
|
|
507
|
+
const preparedPayload = {
|
|
508
|
+
model: payload.model,
|
|
509
|
+
messages: [],
|
|
510
|
+
functions: payload.functions,
|
|
511
|
+
temperature: payload.temperature
|
|
512
|
+
};
|
|
513
|
+
for (const message of payload.messages) {
|
|
514
|
+
if (message.role === "system") {
|
|
515
|
+
preparedPayload.system = message.content;
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
const contentBlocks = [];
|
|
519
|
+
if (message.content) {
|
|
520
|
+
contentBlocks.push({ type: "text", text: message.content });
|
|
521
|
+
}
|
|
522
|
+
for (const file of message.files || []) {
|
|
523
|
+
if (ALLOWED_IMAGE_MIME_TYPES.includes(file.mimeType)) {
|
|
524
|
+
if (file.url) {
|
|
525
|
+
contentBlocks.push({
|
|
526
|
+
type: "image",
|
|
527
|
+
source: {
|
|
528
|
+
type: "base64",
|
|
529
|
+
media_type: "image/png",
|
|
530
|
+
data: await getNormalizedBase64PNG(file.url, file.mimeType)
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
contentBlocks.push({ type: "text", text: `Image (${file.url})` });
|
|
534
|
+
} else if (file.data) {
|
|
535
|
+
contentBlocks.push({
|
|
536
|
+
type: "image",
|
|
537
|
+
source: {
|
|
538
|
+
type: "base64",
|
|
539
|
+
media_type: file.mimeType,
|
|
540
|
+
data: file.data
|
|
541
|
+
}
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
} else if (file.url) {
|
|
545
|
+
contentBlocks.push({
|
|
546
|
+
type: "text",
|
|
547
|
+
text: `File (${file.url})`
|
|
548
|
+
});
|
|
520
549
|
}
|
|
521
|
-
await timeout(125 * i);
|
|
522
550
|
}
|
|
551
|
+
preparedPayload.messages.push({
|
|
552
|
+
role: message.role,
|
|
553
|
+
content: contentBlocks
|
|
554
|
+
});
|
|
523
555
|
}
|
|
524
|
-
|
|
525
|
-
`Failed to call Anthropic API after ${attempts} attempts`
|
|
526
|
-
);
|
|
527
|
-
error2.response = lastResponse;
|
|
528
|
-
throw error2;
|
|
556
|
+
return preparedPayload;
|
|
529
557
|
}
|
|
530
|
-
async function callAnthropic(
|
|
531
|
-
var _a
|
|
532
|
-
const anthropicMessages = jigAnthropicMessages(
|
|
558
|
+
async function callAnthropic(id, payload, config) {
|
|
559
|
+
var _a;
|
|
560
|
+
const anthropicMessages = jigAnthropicMessages(payload.messages);
|
|
561
|
+
const tools = (_a = payload.functions) == null ? void 0 : _a.map((f) => ({
|
|
562
|
+
...f,
|
|
563
|
+
input_schema: f.parameters,
|
|
564
|
+
parameters: void 0
|
|
565
|
+
}));
|
|
533
566
|
let data;
|
|
534
|
-
|
|
535
|
-
if ((AiConfig == null ? void 0 : AiConfig.service) === "bedrock") {
|
|
567
|
+
if ((config == null ? void 0 : config.service) === "bedrock") {
|
|
536
568
|
const AWS_REGION = "us-east-1";
|
|
537
569
|
const MODEL_ID = "anthropic.claude-3-haiku-20240307-v1:0";
|
|
538
570
|
const client = new BedrockRuntimeClient({ region: AWS_REGION });
|
|
539
|
-
const
|
|
571
|
+
const bedrockPayload = {
|
|
540
572
|
anthropic_version: "bedrock-2023-05-31",
|
|
541
573
|
max_tokens: 4096,
|
|
542
574
|
messages: anthropicMessages,
|
|
543
|
-
tools
|
|
544
|
-
...f,
|
|
545
|
-
input_schema: f.parameters,
|
|
546
|
-
parameters: void 0
|
|
547
|
-
}))
|
|
575
|
+
tools
|
|
548
576
|
};
|
|
549
|
-
const
|
|
577
|
+
const response = await client.send(
|
|
550
578
|
new InvokeModelCommand({
|
|
551
579
|
contentType: "application/json",
|
|
552
|
-
body: JSON.stringify(
|
|
580
|
+
body: JSON.stringify(bedrockPayload),
|
|
553
581
|
modelId: MODEL_ID
|
|
554
582
|
})
|
|
555
583
|
);
|
|
556
|
-
const decodedResponseBody = new TextDecoder().decode(
|
|
584
|
+
const decodedResponseBody = new TextDecoder().decode(response.body);
|
|
557
585
|
data = JSON.parse(decodedResponseBody);
|
|
558
586
|
} else {
|
|
559
|
-
const
|
|
587
|
+
const response = await axios.post(
|
|
560
588
|
"https://api.anthropic.com/v1/messages",
|
|
561
589
|
{
|
|
562
|
-
model:
|
|
590
|
+
model: payload.model,
|
|
563
591
|
messages: anthropicMessages,
|
|
564
|
-
tools
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
parameters: void 0
|
|
568
|
-
})),
|
|
569
|
-
temperature: AiPayload.temperature,
|
|
570
|
-
system: AiPayload.system,
|
|
592
|
+
tools,
|
|
593
|
+
temperature: payload.temperature,
|
|
594
|
+
system: payload.system,
|
|
571
595
|
max_tokens: 4096
|
|
572
596
|
},
|
|
573
597
|
{
|
|
@@ -580,120 +604,64 @@ async function callAnthropic(identifier, AiPayload, AiConfig) {
|
|
|
580
604
|
timeout: 6e4
|
|
581
605
|
}
|
|
582
606
|
);
|
|
583
|
-
data =
|
|
607
|
+
data = response.data;
|
|
584
608
|
}
|
|
585
609
|
const answers = data.content;
|
|
586
|
-
if (!answers[0]) {
|
|
587
|
-
logger_default.error(
|
|
610
|
+
if (!(answers == null ? void 0 : answers[0])) {
|
|
611
|
+
logger_default.error(id, "Missing answer in Anthropic API response:", data);
|
|
588
612
|
throw new Error("Missing answer in Anthropic API");
|
|
589
613
|
}
|
|
590
614
|
let textResponse = "";
|
|
591
|
-
|
|
615
|
+
const functionCalls = [];
|
|
592
616
|
for (const answer of answers) {
|
|
593
617
|
if (!answer.type) {
|
|
594
|
-
logger_default.error(
|
|
618
|
+
logger_default.error(id, "Missing answer type in Anthropic API response:", data);
|
|
595
619
|
throw new Error("Missing answer type in Anthropic API");
|
|
596
620
|
}
|
|
597
|
-
let text = "";
|
|
598
621
|
if (answer.type === "text") {
|
|
599
|
-
text = answer.text.replace(/<thinking>.*?<\/thinking>/gs, "").replace(/<answer>|<\/answer>/gs, "").trim();
|
|
622
|
+
let text = answer.text.replace(/<thinking>.*?<\/thinking>/gs, "").replace(/<answer>|<\/answer>/gs, "").trim();
|
|
600
623
|
if (!text) {
|
|
601
624
|
text = answer.text.replace(
|
|
602
625
|
/<thinking>|<\/thinking>|<answer>|<\/answer>/gs,
|
|
603
626
|
""
|
|
604
627
|
);
|
|
605
|
-
logger_default.log(
|
|
606
|
-
identifier,
|
|
607
|
-
"No text in answer, returning text within tags:",
|
|
608
|
-
text
|
|
609
|
-
);
|
|
628
|
+
logger_default.log(id, "No text in answer, returning text within tags:", text);
|
|
610
629
|
}
|
|
611
|
-
|
|
612
|
-
textResponse += `
|
|
630
|
+
textResponse = textResponse ? `${textResponse}
|
|
613
631
|
|
|
614
|
-
${text}
|
|
615
|
-
} else {
|
|
616
|
-
textResponse = text;
|
|
617
|
-
}
|
|
632
|
+
${text}` : text;
|
|
618
633
|
} else if (answer.type === "tool_use") {
|
|
619
|
-
|
|
634
|
+
functionCalls.push({
|
|
620
635
|
name: answer.name,
|
|
621
636
|
arguments: answer.input
|
|
622
|
-
};
|
|
623
|
-
functionCalls.push(call);
|
|
637
|
+
});
|
|
624
638
|
}
|
|
625
639
|
}
|
|
626
640
|
if (!textResponse && !functionCalls.length) {
|
|
627
|
-
logger_default.error(
|
|
628
|
-
|
|
629
|
-
"Missing text & fns in Anthropic API response:",
|
|
630
|
-
data
|
|
631
|
-
);
|
|
632
|
-
throw new Error("Missing text & fns in Anthropic API response");
|
|
641
|
+
logger_default.error(id, "Missing text & functions in Anthropic API response:", data);
|
|
642
|
+
throw new Error("Missing text & functions in Anthropic API response");
|
|
633
643
|
}
|
|
634
644
|
return {
|
|
635
645
|
role: "assistant",
|
|
636
646
|
content: textResponse,
|
|
637
|
-
function_call: functionCalls[0],
|
|
647
|
+
function_call: functionCalls[0] || null,
|
|
638
648
|
files: []
|
|
639
649
|
};
|
|
640
650
|
}
|
|
641
|
-
function
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
jiggedMessages = [
|
|
646
|
-
{
|
|
647
|
-
role: "user",
|
|
648
|
-
content: "..."
|
|
649
|
-
},
|
|
650
|
-
...jiggedMessages
|
|
651
|
-
];
|
|
652
|
-
}
|
|
653
|
-
jiggedMessages = jiggedMessages.reduce((acc, message) => {
|
|
654
|
-
if (acc.length === 0) {
|
|
655
|
-
return [message];
|
|
656
|
-
}
|
|
657
|
-
const lastMessage = acc[acc.length - 1];
|
|
658
|
-
if (lastMessage.role === message.role) {
|
|
659
|
-
const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
|
|
660
|
-
const newContent = Array.isArray(message.content) ? message.content : [{ type: "text", text: message.content }];
|
|
661
|
-
lastMessage.content = [
|
|
662
|
-
...lastContent,
|
|
663
|
-
{ type: "text", text: "\n\n---\n\n" },
|
|
664
|
-
...newContent
|
|
665
|
-
];
|
|
666
|
-
return acc;
|
|
667
|
-
}
|
|
668
|
-
if (typeof message.content === "string") {
|
|
669
|
-
message.content = [{ type: "text", text: message.content }];
|
|
670
|
-
}
|
|
671
|
-
return [...acc, message];
|
|
672
|
-
}, []);
|
|
673
|
-
if (((_b = jiggedMessages[jiggedMessages.length - 1]) == null ? void 0 : _b.role) === "assistant") {
|
|
674
|
-
jiggedMessages.push({
|
|
675
|
-
role: "user",
|
|
676
|
-
content: "..."
|
|
677
|
-
});
|
|
678
|
-
}
|
|
679
|
-
return jiggedMessages;
|
|
651
|
+
async function callAnthropicWithRetries(id, payload, config, retries = 5) {
|
|
652
|
+
return withRetries(id, "Anthropic", () => callAnthropic(id, payload, config), {
|
|
653
|
+
retries
|
|
654
|
+
});
|
|
680
655
|
}
|
|
681
656
|
function jigGoogleMessages(messages) {
|
|
682
657
|
var _a, _b;
|
|
683
658
|
let jiggedMessages = messages.slice();
|
|
684
659
|
if (((_a = jiggedMessages[0]) == null ? void 0 : _a.role) === "model") {
|
|
685
|
-
jiggedMessages = [
|
|
686
|
-
{
|
|
687
|
-
role: "user",
|
|
688
|
-
parts: [{ text: "..." }]
|
|
689
|
-
},
|
|
690
|
-
...jiggedMessages
|
|
691
|
-
];
|
|
660
|
+
jiggedMessages = [{ role: "user", parts: [{ text: "..." }] }, ...jiggedMessages];
|
|
692
661
|
}
|
|
693
662
|
jiggedMessages = jiggedMessages.reduce((acc, message) => {
|
|
694
|
-
if (acc.length === 0)
|
|
663
|
+
if (acc.length === 0)
|
|
695
664
|
return [message];
|
|
696
|
-
}
|
|
697
665
|
const lastMessage = acc[acc.length - 1];
|
|
698
666
|
if (lastMessage.role === message.role) {
|
|
699
667
|
lastMessage.parts = [...lastMessage.parts, ...message.parts];
|
|
@@ -702,15 +670,11 @@ function jigGoogleMessages(messages) {
|
|
|
702
670
|
return [...acc, message];
|
|
703
671
|
}, []);
|
|
704
672
|
if (((_b = jiggedMessages[jiggedMessages.length - 1]) == null ? void 0 : _b.role) === "model") {
|
|
705
|
-
jiggedMessages.push({
|
|
706
|
-
role: "user",
|
|
707
|
-
parts: [{ text: "..." }]
|
|
708
|
-
});
|
|
673
|
+
jiggedMessages.push({ role: "user", parts: [{ text: "..." }] });
|
|
709
674
|
}
|
|
710
675
|
return jiggedMessages;
|
|
711
676
|
}
|
|
712
|
-
async function prepareGoogleAIPayload(payload) {
|
|
713
|
-
var _a;
|
|
677
|
+
async function prepareGoogleAIPayload(_identifier, payload) {
|
|
714
678
|
const preparedPayload = {
|
|
715
679
|
model: payload.model,
|
|
716
680
|
messages: [],
|
|
@@ -718,7 +682,6 @@ async function prepareGoogleAIPayload(payload) {
|
|
|
718
682
|
functionDeclarations: payload.functions.map((fn) => ({
|
|
719
683
|
name: fn.name,
|
|
720
684
|
parameters: {
|
|
721
|
-
// Google puts their description in the parameters object rather than in a top-level field
|
|
722
685
|
description: fn.description,
|
|
723
686
|
...fn.parameters
|
|
724
687
|
}
|
|
@@ -730,61 +693,47 @@ async function prepareGoogleAIPayload(payload) {
|
|
|
730
693
|
preparedPayload.systemInstruction = message.content;
|
|
731
694
|
continue;
|
|
732
695
|
}
|
|
733
|
-
const
|
|
696
|
+
const parts = [];
|
|
734
697
|
if (message.content) {
|
|
735
|
-
|
|
736
|
-
text: message.content
|
|
737
|
-
});
|
|
698
|
+
parts.push({ text: message.content });
|
|
738
699
|
}
|
|
739
700
|
for (const file of message.files || []) {
|
|
740
|
-
if (
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
});
|
|
757
|
-
} else if (file.data) {
|
|
758
|
-
if (!["image/png", "image/jpeg", "image/gif", "image/webp"].includes(
|
|
759
|
-
file.mimeType
|
|
760
|
-
)) {
|
|
761
|
-
throw new Error(
|
|
762
|
-
"Invalid image mimeType. Supported types are: image/png, image/jpeg, image/gif, image/webp"
|
|
763
|
-
);
|
|
701
|
+
if (ALLOWED_IMAGE_MIME_TYPES.includes(file.mimeType)) {
|
|
702
|
+
if (file.url) {
|
|
703
|
+
parts.push({
|
|
704
|
+
inlineData: {
|
|
705
|
+
mimeType: "image/png",
|
|
706
|
+
data: await getNormalizedBase64PNG(file.url, file.mimeType)
|
|
707
|
+
}
|
|
708
|
+
});
|
|
709
|
+
parts.push({ text: `Image (${file.url})` });
|
|
710
|
+
} else if (file.data) {
|
|
711
|
+
parts.push({
|
|
712
|
+
inlineData: {
|
|
713
|
+
mimeType: file.mimeType,
|
|
714
|
+
data: file.data
|
|
715
|
+
}
|
|
716
|
+
});
|
|
764
717
|
}
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
data: file.data
|
|
769
|
-
}
|
|
718
|
+
} else if (file.url) {
|
|
719
|
+
parts.push({
|
|
720
|
+
text: `File (${file.url})`
|
|
770
721
|
});
|
|
771
722
|
}
|
|
772
723
|
}
|
|
773
724
|
preparedPayload.messages.push({
|
|
774
725
|
role: message.role === "assistant" ? "model" : message.role,
|
|
775
|
-
parts
|
|
726
|
+
parts
|
|
776
727
|
});
|
|
777
728
|
}
|
|
778
729
|
return preparedPayload;
|
|
779
730
|
}
|
|
780
|
-
async function callGoogleAI(
|
|
781
|
-
var _a, _b, _c, _d;
|
|
731
|
+
async function callGoogleAI(id, payload) {
|
|
732
|
+
var _a, _b, _c, _d, _e, _f;
|
|
782
733
|
const googleMessages = jigGoogleMessages(payload.messages);
|
|
783
734
|
const history = googleMessages.slice(0, -1);
|
|
784
735
|
const lastMessage = googleMessages.slice(-1)[0];
|
|
785
|
-
const genAI = new GoogleGenAI({
|
|
786
|
-
apiKey: process.env.GEMINI_API_KEY
|
|
787
|
-
});
|
|
736
|
+
const genAI = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
|
|
788
737
|
const chat = genAI.chats.create({
|
|
789
738
|
model: payload.model,
|
|
790
739
|
history,
|
|
@@ -794,296 +743,84 @@ async function callGoogleAI(identifier, payload) {
|
|
|
794
743
|
systemInstruction: payload.systemInstruction
|
|
795
744
|
}
|
|
796
745
|
});
|
|
797
|
-
const response = await chat.sendMessage({
|
|
798
|
-
message: lastMessage.parts
|
|
799
|
-
});
|
|
746
|
+
const response = await chat.sendMessage({ message: lastMessage.parts });
|
|
800
747
|
let text = "";
|
|
801
748
|
const files = [];
|
|
802
749
|
for (const part of ((_c = (_b = (_a = response.candidates) == null ? void 0 : _a[0]) == null ? void 0 : _b.content) == null ? void 0 : _c.parts) || []) {
|
|
803
|
-
if (part.text)
|
|
750
|
+
if (part.text)
|
|
804
751
|
text += part.text;
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
const imageData = part.inlineData.data;
|
|
808
|
-
if (imageData) {
|
|
809
|
-
files.push({
|
|
810
|
-
mimeType: "image/png",
|
|
811
|
-
data: imageData
|
|
812
|
-
});
|
|
813
|
-
}
|
|
752
|
+
if ((_d = part.inlineData) == null ? void 0 : _d.data) {
|
|
753
|
+
files.push({ mimeType: "image/png", data: part.inlineData.data });
|
|
814
754
|
}
|
|
815
755
|
}
|
|
816
|
-
const functionCalls = response.functionCalls
|
|
817
|
-
const parsedFunctionCalls = functionCalls == null ? void 0 : functionCalls.map((fc) => {
|
|
756
|
+
const functionCalls = (_e = response.functionCalls) == null ? void 0 : _e.map((fc) => {
|
|
818
757
|
var _a2, _b2;
|
|
819
758
|
return {
|
|
820
759
|
name: (_a2 = fc.name) != null ? _a2 : "",
|
|
821
760
|
arguments: (_b2 = fc.args) != null ? _b2 : {}
|
|
822
761
|
};
|
|
823
762
|
});
|
|
824
|
-
if (!text && !(
|
|
825
|
-
const candidate = (
|
|
763
|
+
if (!text && !(functionCalls == null ? void 0 : functionCalls.length) && !files.length) {
|
|
764
|
+
const candidate = (_f = response.candidates) == null ? void 0 : _f[0];
|
|
826
765
|
const finishReason = candidate == null ? void 0 : candidate.finishReason;
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
usageMetadata,
|
|
837
|
-
modelVersion,
|
|
838
|
-
candidateContent: candidate == null ? void 0 : candidate.content,
|
|
839
|
-
promptFeedback: response.promptFeedback,
|
|
840
|
-
fullResponse: JSON.stringify(response)
|
|
841
|
-
}
|
|
842
|
-
);
|
|
843
|
-
let errorMessage = "Missing text & fns in Google AI API response";
|
|
766
|
+
logger_default.error(id, "Missing text & functions in Google AI API response:", {
|
|
767
|
+
finishReason,
|
|
768
|
+
safetyRatings: candidate == null ? void 0 : candidate.safetyRatings,
|
|
769
|
+
usageMetadata: response.usageMetadata,
|
|
770
|
+
modelVersion: response.modelVersion,
|
|
771
|
+
candidateContent: candidate == null ? void 0 : candidate.content,
|
|
772
|
+
promptFeedback: response.promptFeedback
|
|
773
|
+
});
|
|
774
|
+
let errorMessage = "Missing text & functions in Google AI API response";
|
|
844
775
|
if (finishReason) {
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
} else if (finishReason === "MAX_TOKENS") {
|
|
853
|
-
errorMessage += " (response truncated due to max tokens)";
|
|
854
|
-
}
|
|
776
|
+
const reasonDescriptions = {
|
|
777
|
+
MALFORMED_FUNCTION_CALL: "(Google could not generate valid function call arguments)",
|
|
778
|
+
SAFETY: "(blocked by safety filters)",
|
|
779
|
+
RECITATION: "(blocked due to recitation)",
|
|
780
|
+
MAX_TOKENS: "(response truncated due to max tokens)"
|
|
781
|
+
};
|
|
782
|
+
errorMessage += `: finishReason=${finishReason} ${reasonDescriptions[finishReason] || ""}`;
|
|
855
783
|
}
|
|
856
784
|
const error2 = new Error(errorMessage);
|
|
857
785
|
error2.finishReason = finishReason;
|
|
858
|
-
error2.safetyRatings = safetyRatings;
|
|
859
|
-
error2.usageMetadata = usageMetadata;
|
|
860
|
-
error2.modelVersion = modelVersion;
|
|
861
|
-
error2.candidateContent = candidate == null ? void 0 : candidate.content;
|
|
862
|
-
error2.promptFeedback = response.promptFeedback;
|
|
786
|
+
error2.safetyRatings = candidate == null ? void 0 : candidate.safetyRatings;
|
|
787
|
+
error2.usageMetadata = response.usageMetadata;
|
|
863
788
|
throw error2;
|
|
864
789
|
}
|
|
865
790
|
return {
|
|
866
791
|
role: "assistant",
|
|
867
792
|
content: text || null,
|
|
868
793
|
files,
|
|
869
|
-
function_call: (
|
|
794
|
+
function_call: (functionCalls == null ? void 0 : functionCalls[0]) || null
|
|
870
795
|
};
|
|
871
796
|
}
|
|
872
|
-
async function callGoogleAIWithRetries(
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
try {
|
|
877
|
-
return await callGoogleAI(identifier, payload);
|
|
878
|
-
} catch (e) {
|
|
879
|
-
lastError = e;
|
|
797
|
+
async function callGoogleAIWithRetries(id, payload, retries = 5) {
|
|
798
|
+
return withRetries(id, "Google AI", () => callGoogleAI(id, payload), {
|
|
799
|
+
retries,
|
|
800
|
+
onError: (error2, attempt) => {
|
|
880
801
|
const errorDetails = {
|
|
881
|
-
message:
|
|
882
|
-
finishReason:
|
|
883
|
-
modelVersion:
|
|
802
|
+
message: error2.message,
|
|
803
|
+
finishReason: error2.finishReason,
|
|
804
|
+
modelVersion: error2.modelVersion
|
|
884
805
|
};
|
|
885
|
-
if (
|
|
886
|
-
errorDetails.safetyRatings =
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
if (
|
|
892
|
-
errorDetails.
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
errorDetails.
|
|
897
|
-
}
|
|
898
|
-
if (e.code) {
|
|
899
|
-
errorDetails.errorCode = e.code;
|
|
900
|
-
}
|
|
901
|
-
if (e.details) {
|
|
902
|
-
errorDetails.errorDetails = e.details;
|
|
903
|
-
}
|
|
904
|
-
logger_default.error(identifier, `Retry #${i} error: ${e.message}`, errorDetails);
|
|
905
|
-
if (e.finishReason === "MALFORMED_FUNCTION_CALL" && i >= 3) {
|
|
906
|
-
logger_default.log(
|
|
907
|
-
identifier,
|
|
908
|
-
"Removing tools due to persistent MALFORMED_FUNCTION_CALL errors"
|
|
909
|
-
);
|
|
910
|
-
payload.tools = void 0;
|
|
911
|
-
}
|
|
912
|
-
await timeout(125 * i);
|
|
806
|
+
if (error2.safetyRatings)
|
|
807
|
+
errorDetails.safetyRatings = error2.safetyRatings;
|
|
808
|
+
if (error2.usageMetadata)
|
|
809
|
+
errorDetails.usageMetadata = error2.usageMetadata;
|
|
810
|
+
if (error2.promptFeedback)
|
|
811
|
+
errorDetails.promptFeedback = error2.promptFeedback;
|
|
812
|
+
if (error2.status)
|
|
813
|
+
errorDetails.httpStatus = error2.status;
|
|
814
|
+
if (error2.code)
|
|
815
|
+
errorDetails.errorCode = error2.code;
|
|
816
|
+
if (error2.details)
|
|
817
|
+
errorDetails.errorDetails = error2.details;
|
|
818
|
+
logger_default.error(id, `Retry #${attempt} error: ${error2.message}`, errorDetails);
|
|
913
819
|
}
|
|
914
|
-
}
|
|
915
|
-
const error2 = new Error(
|
|
916
|
-
`Failed to call Google AI API after ${retries} attempts`
|
|
917
|
-
);
|
|
918
|
-
error2.cause = lastError;
|
|
919
|
-
error2.finishReason = lastError == null ? void 0 : lastError.finishReason;
|
|
920
|
-
error2.usageMetadata = lastError == null ? void 0 : lastError.usageMetadata;
|
|
921
|
-
error2.safetyRatings = lastError == null ? void 0 : lastError.safetyRatings;
|
|
922
|
-
throw error2;
|
|
923
|
-
}
|
|
924
|
-
async function callWithRetries(identifier, aiPayload, aiConfig, retries = 5, chunkTimeoutMs = 15e3) {
|
|
925
|
-
const id = identifier;
|
|
926
|
-
if (isAnthropicPayload(aiPayload)) {
|
|
927
|
-
return await callAnthropicWithRetries(
|
|
928
|
-
id,
|
|
929
|
-
await prepareAnthropicPayload(aiPayload),
|
|
930
|
-
aiConfig,
|
|
931
|
-
retries
|
|
932
|
-
);
|
|
933
|
-
} else if (isOpenAiPayload(aiPayload)) {
|
|
934
|
-
return await callOpenAiWithRetries(
|
|
935
|
-
id,
|
|
936
|
-
await prepareOpenAIPayload(aiPayload),
|
|
937
|
-
aiConfig,
|
|
938
|
-
retries,
|
|
939
|
-
chunkTimeoutMs
|
|
940
|
-
);
|
|
941
|
-
} else if (isGroqPayload(aiPayload)) {
|
|
942
|
-
return await callGroqWithRetries(id, await prepareGroqPayload(aiPayload));
|
|
943
|
-
} else if (isGoogleAIPayload(aiPayload)) {
|
|
944
|
-
return await callGoogleAIWithRetries(
|
|
945
|
-
id,
|
|
946
|
-
await prepareGoogleAIPayload(aiPayload),
|
|
947
|
-
retries
|
|
948
|
-
);
|
|
949
|
-
} else {
|
|
950
|
-
throw new Error("Invalid AI payload: Unknown model type.");
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
function isAnthropicPayload(payload) {
|
|
954
|
-
return Object.values(ClaudeModel).includes(payload.model);
|
|
955
|
-
}
|
|
956
|
-
async function prepareAnthropicPayload(payload) {
|
|
957
|
-
var _a;
|
|
958
|
-
const preparedPayload = {
|
|
959
|
-
model: payload.model,
|
|
960
|
-
messages: [],
|
|
961
|
-
functions: payload.functions,
|
|
962
|
-
temperature: payload.temperature
|
|
963
|
-
};
|
|
964
|
-
for (const message of payload.messages) {
|
|
965
|
-
const anthropicContentBlocks = [];
|
|
966
|
-
if (message.role === "system") {
|
|
967
|
-
preparedPayload.system = message.content;
|
|
968
|
-
continue;
|
|
969
|
-
}
|
|
970
|
-
if (message.content) {
|
|
971
|
-
anthropicContentBlocks.push({
|
|
972
|
-
type: "text",
|
|
973
|
-
text: message.content
|
|
974
|
-
});
|
|
975
|
-
}
|
|
976
|
-
for (const file of message.files || []) {
|
|
977
|
-
if (!((_a = file.mimeType) == null ? void 0 : _a.startsWith("image"))) {
|
|
978
|
-
logger_default.warn(
|
|
979
|
-
"payload",
|
|
980
|
-
"Anthropic API does not support non-image file types. Skipping file."
|
|
981
|
-
);
|
|
982
|
-
continue;
|
|
983
|
-
}
|
|
984
|
-
if (file.url) {
|
|
985
|
-
anthropicContentBlocks.push({
|
|
986
|
-
type: "image",
|
|
987
|
-
source: {
|
|
988
|
-
type: "base64",
|
|
989
|
-
media_type: "image/png",
|
|
990
|
-
data: await getNormalizedBase64PNG(file.url, file.mimeType)
|
|
991
|
-
}
|
|
992
|
-
});
|
|
993
|
-
} else if (file.data) {
|
|
994
|
-
if (!["image/png", "image/jpeg", "image/gif", "image/webp"].includes(
|
|
995
|
-
file.mimeType
|
|
996
|
-
)) {
|
|
997
|
-
throw new Error(
|
|
998
|
-
"Invalid image mimeType. Supported types are: image/png, image/jpeg, image/gif, image/webp"
|
|
999
|
-
);
|
|
1000
|
-
}
|
|
1001
|
-
anthropicContentBlocks.push({
|
|
1002
|
-
type: "image",
|
|
1003
|
-
source: {
|
|
1004
|
-
type: "base64",
|
|
1005
|
-
media_type: file.mimeType,
|
|
1006
|
-
data: file.data
|
|
1007
|
-
}
|
|
1008
|
-
});
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
preparedPayload.messages.push({
|
|
1012
|
-
role: message.role,
|
|
1013
|
-
content: anthropicContentBlocks
|
|
1014
|
-
});
|
|
1015
|
-
}
|
|
1016
|
-
return preparedPayload;
|
|
1017
|
-
}
|
|
1018
|
-
function isOpenAiPayload(payload) {
|
|
1019
|
-
return Object.values(GPTModel).includes(payload.model);
|
|
1020
|
-
}
|
|
1021
|
-
async function prepareOpenAIPayload(payload) {
|
|
1022
|
-
var _a;
|
|
1023
|
-
const preparedPayload = {
|
|
1024
|
-
model: payload.model,
|
|
1025
|
-
messages: [],
|
|
1026
|
-
tools: (_a = payload.functions) == null ? void 0 : _a.map((fn) => ({
|
|
1027
|
-
type: "function",
|
|
1028
|
-
function: fn
|
|
1029
|
-
})),
|
|
1030
|
-
tool_choice: payload.function_call ? typeof payload.function_call === "string" ? payload.function_call : {
|
|
1031
|
-
type: "function",
|
|
1032
|
-
function: payload.function_call
|
|
1033
|
-
} : void 0
|
|
1034
|
-
};
|
|
1035
|
-
for (const message of payload.messages) {
|
|
1036
|
-
const openAIContentBlocks = [];
|
|
1037
|
-
if (message.content) {
|
|
1038
|
-
openAIContentBlocks.push({
|
|
1039
|
-
type: "text",
|
|
1040
|
-
text: message.content
|
|
1041
|
-
});
|
|
1042
|
-
}
|
|
1043
|
-
const allowedFileMimeTypes = [
|
|
1044
|
-
"image/png",
|
|
1045
|
-
"image/jpeg",
|
|
1046
|
-
"image/gif",
|
|
1047
|
-
"image/webp"
|
|
1048
|
-
];
|
|
1049
|
-
for (const file of message.files || []) {
|
|
1050
|
-
if (allowedFileMimeTypes.includes(file.mimeType)) {
|
|
1051
|
-
if (file.url) {
|
|
1052
|
-
openAIContentBlocks.push({
|
|
1053
|
-
type: "image_url",
|
|
1054
|
-
image_url: {
|
|
1055
|
-
url: file.url
|
|
1056
|
-
}
|
|
1057
|
-
});
|
|
1058
|
-
openAIContentBlocks.push({
|
|
1059
|
-
type: "text",
|
|
1060
|
-
text: `Image URL: ${file.url}`
|
|
1061
|
-
});
|
|
1062
|
-
} else if (file.data) {
|
|
1063
|
-
openAIContentBlocks.push({
|
|
1064
|
-
type: "image_url",
|
|
1065
|
-
image_url: {
|
|
1066
|
-
url: `data:${file.mimeType};base64,${file.data}`
|
|
1067
|
-
}
|
|
1068
|
-
});
|
|
1069
|
-
}
|
|
1070
|
-
} else {
|
|
1071
|
-
logger_default.warn(
|
|
1072
|
-
"payload",
|
|
1073
|
-
"Skipping file in message. File or image type not supported by OpenAI API:",
|
|
1074
|
-
file.mimeType
|
|
1075
|
-
);
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
preparedPayload.messages.push({
|
|
1079
|
-
role: message.role,
|
|
1080
|
-
content: openAIContentBlocks
|
|
1081
|
-
});
|
|
1082
|
-
}
|
|
1083
|
-
return preparedPayload;
|
|
820
|
+
});
|
|
1084
821
|
}
|
|
1085
|
-
function
|
|
1086
|
-
return
|
|
822
|
+
function normalizeMessageContent(content) {
|
|
823
|
+
return Array.isArray(content) ? content.map((c) => c.type === "text" ? c.text : `[${c.type}]`).join("\n") : content;
|
|
1087
824
|
}
|
|
1088
825
|
function prepareGroqPayload(payload) {
|
|
1089
826
|
var _a;
|
|
@@ -1097,20 +834,12 @@ function prepareGroqPayload(payload) {
|
|
|
1097
834
|
type: "function",
|
|
1098
835
|
function: fn
|
|
1099
836
|
})),
|
|
1100
|
-
tool_choice: payload.function_call ? typeof payload.function_call === "string" ? payload.function_call : {
|
|
1101
|
-
type: "function",
|
|
1102
|
-
function: payload.function_call
|
|
1103
|
-
} : void 0,
|
|
837
|
+
tool_choice: payload.function_call ? typeof payload.function_call === "string" ? payload.function_call : { type: "function", function: payload.function_call } : void 0,
|
|
1104
838
|
temperature: payload.temperature
|
|
1105
839
|
};
|
|
1106
840
|
}
|
|
1107
|
-
function
|
|
1108
|
-
|
|
1109
|
-
}
|
|
1110
|
-
function isGoogleAIPayload(payload) {
|
|
1111
|
-
return Object.values(GeminiModel).includes(payload.model);
|
|
1112
|
-
}
|
|
1113
|
-
async function callGroq(identifier, payload) {
|
|
841
|
+
async function callGroq(id, payload) {
|
|
842
|
+
var _a, _b;
|
|
1114
843
|
const response = await axios.post(
|
|
1115
844
|
"https://api.groq.com/openai/v1/chat/completions",
|
|
1116
845
|
payload,
|
|
@@ -1121,15 +850,13 @@ async function callGroq(identifier, payload) {
|
|
|
1121
850
|
}
|
|
1122
851
|
}
|
|
1123
852
|
);
|
|
1124
|
-
const
|
|
1125
|
-
const answer = data.choices[0].message;
|
|
853
|
+
const answer = (_a = response.data.choices[0]) == null ? void 0 : _a.message;
|
|
1126
854
|
if (!answer) {
|
|
1127
|
-
logger_default.error(
|
|
855
|
+
logger_default.error(id, "Missing answer in Groq API response:", response.data);
|
|
1128
856
|
throw new Error("Missing answer in Groq API");
|
|
1129
857
|
}
|
|
1130
|
-
const textResponse = answer.content || null;
|
|
1131
858
|
let functionCall = null;
|
|
1132
|
-
if (answer.tool_calls
|
|
859
|
+
if ((_b = answer.tool_calls) == null ? void 0 : _b.length) {
|
|
1133
860
|
const toolCall = answer.tool_calls[0];
|
|
1134
861
|
functionCall = {
|
|
1135
862
|
name: toolCall.function.name,
|
|
@@ -1138,51 +865,55 @@ async function callGroq(identifier, payload) {
|
|
|
1138
865
|
}
|
|
1139
866
|
return {
|
|
1140
867
|
role: "assistant",
|
|
1141
|
-
content:
|
|
868
|
+
content: answer.content || null,
|
|
1142
869
|
function_call: functionCall,
|
|
1143
870
|
files: []
|
|
1144
871
|
};
|
|
1145
872
|
}
|
|
1146
|
-
async function callGroqWithRetries(
|
|
1147
|
-
|
|
1148
|
-
logger_default.log(identifier, "Calling Groq API with retries");
|
|
1149
|
-
let lastResponse;
|
|
1150
|
-
for (let i = 0; i < retries; i++) {
|
|
1151
|
-
try {
|
|
1152
|
-
lastResponse = await callGroq(identifier, payload);
|
|
1153
|
-
return lastResponse;
|
|
1154
|
-
} catch (e) {
|
|
1155
|
-
logger_default.error(
|
|
1156
|
-
identifier,
|
|
1157
|
-
`Retry #${i} error: ${e.message}`,
|
|
1158
|
-
((_a = e.response) == null ? void 0 : _a.data) || e
|
|
1159
|
-
);
|
|
1160
|
-
await timeout(125 * i);
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
const error2 = new Error(
|
|
1164
|
-
`Failed to call Groq API after ${retries} attempts`
|
|
1165
|
-
);
|
|
1166
|
-
error2.response = lastResponse;
|
|
1167
|
-
throw error2;
|
|
873
|
+
async function callGroqWithRetries(id, payload, retries = 5) {
|
|
874
|
+
return withRetries(id, "Groq", () => callGroq(id, payload), { retries });
|
|
1168
875
|
}
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
876
|
+
function isAnthropicPayload(payload) {
|
|
877
|
+
return Object.values(ClaudeModel).includes(payload.model);
|
|
878
|
+
}
|
|
879
|
+
function isOpenAiPayload(payload) {
|
|
880
|
+
return Object.values(GPTModel).includes(payload.model);
|
|
881
|
+
}
|
|
882
|
+
function isGroqPayload(payload) {
|
|
883
|
+
return Object.values(GroqModel).includes(payload.model);
|
|
884
|
+
}
|
|
885
|
+
function isGoogleAIPayload(payload) {
|
|
886
|
+
return Object.values(GeminiModel).includes(payload.model);
|
|
887
|
+
}
|
|
888
|
+
async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeoutMs = 15e3) {
|
|
889
|
+
if (isAnthropicPayload(aiPayload)) {
|
|
890
|
+
return callAnthropicWithRetries(
|
|
891
|
+
id,
|
|
892
|
+
await prepareAnthropicPayload(id, aiPayload),
|
|
893
|
+
aiConfig,
|
|
894
|
+
retries
|
|
895
|
+
);
|
|
1183
896
|
}
|
|
1184
|
-
|
|
1185
|
-
|
|
897
|
+
if (isOpenAiPayload(aiPayload)) {
|
|
898
|
+
return callOpenAiWithRetries(
|
|
899
|
+
id,
|
|
900
|
+
await prepareOpenAIPayload(id, aiPayload),
|
|
901
|
+
aiConfig,
|
|
902
|
+
retries,
|
|
903
|
+
chunkTimeoutMs
|
|
904
|
+
);
|
|
905
|
+
}
|
|
906
|
+
if (isGroqPayload(aiPayload)) {
|
|
907
|
+
return callGroqWithRetries(id, prepareGroqPayload(aiPayload), retries);
|
|
908
|
+
}
|
|
909
|
+
if (isGoogleAIPayload(aiPayload)) {
|
|
910
|
+
return callGoogleAIWithRetries(
|
|
911
|
+
id,
|
|
912
|
+
await prepareGoogleAIPayload(id, aiPayload),
|
|
913
|
+
retries
|
|
914
|
+
);
|
|
915
|
+
}
|
|
916
|
+
throw new Error("Invalid AI payload: Unknown model type.");
|
|
1186
917
|
}
|
|
1187
918
|
export {
|
|
1188
919
|
ClaudeModel,
|