batchwork 1.4.1 → 1.5.0
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/body.d.ts +2 -2
- package/dist/body.d.ts.map +1 -1
- package/dist/chunk-6jgvqdpc.js +52 -0
- package/dist/chunk-6jgvqdpc.js.map +11 -0
- package/dist/{chunk-n50t31ca.js → chunk-7y95mhvm.js} +118 -139
- package/dist/chunk-7y95mhvm.js.map +27 -0
- package/dist/{chunk-mathjpg6.js → chunk-k7n7k3et.js} +46 -41
- package/dist/chunk-k7n7k3et.js.map +13 -0
- package/dist/{chunk-14qcscwd.js → chunk-zss8h417.js} +203 -191
- package/dist/chunk-zss8h417.js.map +12 -0
- package/dist/guards.d.ts +5 -0
- package/dist/guards.d.ts.map +1 -0
- package/dist/http.d.ts +3 -2
- package/dist/http.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -28
- package/dist/index.js.map +1 -1
- package/dist/jsonl.d.ts +3 -2
- package/dist/jsonl.d.ts.map +1 -1
- package/dist/model.d.ts +48 -1
- package/dist/model.d.ts.map +1 -1
- package/dist/next/index.d.ts +1 -1
- package/dist/next/index.d.ts.map +1 -1
- package/dist/next/index.js +14 -20
- package/dist/next/index.js.map +3 -3
- package/dist/postgres/batch-store.d.ts.map +1 -1
- package/dist/postgres/index.js +22 -15
- package/dist/postgres/index.js.map +4 -4
- package/dist/postgres/types.d.ts +1 -1
- package/dist/postgres/types.d.ts.map +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/azure.d.ts.map +1 -1
- package/dist/providers/google.d.ts.map +1 -1
- package/dist/providers/mistral.d.ts.map +1 -1
- package/dist/providers/openai-compatible.d.ts +2 -2
- package/dist/providers/openai-compatible.d.ts.map +1 -1
- package/dist/providers/shared.d.ts +8 -8
- package/dist/providers/shared.d.ts.map +1 -1
- package/dist/providers/xai.d.ts.map +1 -1
- package/dist/redis/index.js +40 -6
- package/dist/redis/index.js.map +4 -4
- package/dist/redis/types.d.ts +18 -5
- package/dist/redis/types.d.ts.map +1 -1
- package/dist/server/index.js +13 -14
- package/dist/server/index.js.map +1 -1
- package/dist/server/poller.d.ts +6 -4
- package/dist/server/poller.d.ts.map +1 -1
- package/dist/server/signing.d.ts.map +1 -1
- package/dist/types.d.ts +16 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/util.d.ts +16 -7
- package/dist/util.d.ts.map +1 -1
- package/package.json +19 -19
- package/dist/chunk-14qcscwd.js.map +0 -12
- package/dist/chunk-mathjpg6.js.map +0 -13
- package/dist/chunk-n50t31ca.js.map +0 -28
- package/dist/chunk-v0bahtg2.js +0 -7
- package/dist/chunk-v0bahtg2.js.map +0 -9
|
@@ -1,12 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isBoolean,
|
|
3
|
+
trimTrailingSlashes,
|
|
4
|
+
parseJson,
|
|
5
|
+
asRecord,
|
|
6
|
+
asString,
|
|
7
|
+
asNumber,
|
|
8
|
+
asArray,
|
|
9
|
+
asNumberArray,
|
|
10
|
+
omit,
|
|
11
|
+
toDate
|
|
12
|
+
} from "./chunk-6jgvqdpc.js";
|
|
13
|
+
|
|
1
14
|
// src/errors.ts
|
|
2
|
-
class
|
|
15
|
+
class BatchworkError2 extends Error {
|
|
3
16
|
constructor(message, options) {
|
|
4
17
|
super(message, options);
|
|
5
18
|
this.name = "BatchworkError";
|
|
6
19
|
}
|
|
7
20
|
}
|
|
8
21
|
|
|
9
|
-
class
|
|
22
|
+
class UnsupportedProviderError2 extends BatchworkError2 {
|
|
10
23
|
provider;
|
|
11
24
|
constructor(provider, detail) {
|
|
12
25
|
super(detail ?? `batchwork: provider "${provider}" is not supported yet. Supported providers: openai, azure, anthropic, google, groq, mistral, together, xai.`);
|
|
@@ -15,7 +28,7 @@ class UnsupportedProviderError extends BatchworkError {
|
|
|
15
28
|
}
|
|
16
29
|
}
|
|
17
30
|
|
|
18
|
-
class
|
|
31
|
+
class MissingDependencyError2 extends BatchworkError2 {
|
|
19
32
|
constructor(pkg, provider) {
|
|
20
33
|
super(`batchwork: install \`${pkg}\` to batch ${provider} models (\`npm install ${pkg}\`).`);
|
|
21
34
|
this.name = "MissingDependencyError";
|
|
@@ -31,16 +44,16 @@ var TERMINAL_STATUSES = new Set([
|
|
|
31
44
|
"expired",
|
|
32
45
|
"cancelled"
|
|
33
46
|
]);
|
|
34
|
-
var
|
|
47
|
+
var isTerminalStatus2 = (status) => TERMINAL_STATUSES.has(status);
|
|
35
48
|
var delay = (ms, signal) => new Promise((resolve, reject) => {
|
|
36
49
|
if (signal?.aborted) {
|
|
37
|
-
reject(new
|
|
50
|
+
reject(new BatchworkError2(WAIT_ABORTED_MESSAGE));
|
|
38
51
|
return;
|
|
39
52
|
}
|
|
40
53
|
let timer;
|
|
41
54
|
const onAbort = () => {
|
|
42
55
|
clearTimeout(timer);
|
|
43
|
-
reject(new
|
|
56
|
+
reject(new BatchworkError2(WAIT_ABORTED_MESSAGE));
|
|
44
57
|
};
|
|
45
58
|
timer = setTimeout(() => {
|
|
46
59
|
signal?.removeEventListener("abort", onAbort);
|
|
@@ -49,7 +62,7 @@ var delay = (ms, signal) => new Promise((resolve, reject) => {
|
|
|
49
62
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
50
63
|
});
|
|
51
64
|
|
|
52
|
-
class
|
|
65
|
+
class BatchJob2 {
|
|
53
66
|
provider;
|
|
54
67
|
id;
|
|
55
68
|
#adapter;
|
|
@@ -80,12 +93,12 @@ class BatchJob {
|
|
|
80
93
|
const deadline = options.timeoutMs ? Date.now() + options.timeoutMs : undefined;
|
|
81
94
|
let snapshot = await this.poll();
|
|
82
95
|
options.onPoll?.(snapshot);
|
|
83
|
-
while (!
|
|
96
|
+
while (!isTerminalStatus2(snapshot.status)) {
|
|
84
97
|
if (options.signal?.aborted) {
|
|
85
|
-
throw new
|
|
98
|
+
throw new BatchworkError2(WAIT_ABORTED_MESSAGE);
|
|
86
99
|
}
|
|
87
100
|
if (deadline !== undefined && Date.now() > deadline) {
|
|
88
|
-
throw new
|
|
101
|
+
throw new BatchworkError2(`batchwork: timed out waiting for batch "${this.id}".`);
|
|
89
102
|
}
|
|
90
103
|
await delay(interval, options.signal);
|
|
91
104
|
snapshot = await this.poll();
|
|
@@ -119,7 +132,7 @@ var DEFAULT_LIMITS = {
|
|
|
119
132
|
var encoder = new TextEncoder;
|
|
120
133
|
var positiveInteger = (name, value) => {
|
|
121
134
|
if (!(Number.isInteger(value) && value > 0)) {
|
|
122
|
-
throw new
|
|
135
|
+
throw new BatchworkError2(`batchwork: limits.${name} must be a positive integer.`);
|
|
123
136
|
}
|
|
124
137
|
return value;
|
|
125
138
|
};
|
|
@@ -132,72 +145,29 @@ var resolveBatchLimits = (limits) => ({
|
|
|
132
145
|
var byteLength = (value) => encoder.encode(value).length;
|
|
133
146
|
var assertByteCount = (label, bytes, maxBytes) => {
|
|
134
147
|
if (bytes > maxBytes) {
|
|
135
|
-
throw new
|
|
148
|
+
throw new BatchworkError2(`batchwork: ${label} is ${bytes} bytes, exceeding the ${maxBytes} byte limit.`);
|
|
136
149
|
}
|
|
137
150
|
};
|
|
138
151
|
var assertByteLength = (label, value, maxBytes) => {
|
|
139
152
|
assertByteCount(label, byteLength(value), maxBytes);
|
|
140
153
|
};
|
|
141
154
|
|
|
142
|
-
// src/util.ts
|
|
143
|
-
var trimTrailingSlashes = (value) => {
|
|
144
|
-
let end = value.length;
|
|
145
|
-
while (end > 0 && value[end - 1] === "/") {
|
|
146
|
-
end -= 1;
|
|
147
|
-
}
|
|
148
|
-
return value.slice(0, end);
|
|
149
|
-
};
|
|
150
|
-
var asRecord = (value) => {
|
|
151
|
-
if (typeof value === "object" && value !== null) {
|
|
152
|
-
return value;
|
|
153
|
-
}
|
|
154
|
-
return {};
|
|
155
|
-
};
|
|
156
|
-
var asString = (value) => typeof value === "string" ? value : undefined;
|
|
157
|
-
var asNumber = (value) => typeof value === "number" ? value : undefined;
|
|
158
|
-
var asArray = (value) => Array.isArray(value) ? value : [];
|
|
159
|
-
var asNumberArray = (value) => {
|
|
160
|
-
if (!Array.isArray(value) || value.length === 0) {
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
const numbers = value.filter((item) => typeof item === "number");
|
|
164
|
-
return numbers.length === value.length ? numbers : undefined;
|
|
165
|
-
};
|
|
166
|
-
var omit = (obj, key) => {
|
|
167
|
-
const result = {};
|
|
168
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
169
|
-
if (k !== key) {
|
|
170
|
-
result[k] = v;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
return result;
|
|
174
|
-
};
|
|
175
|
-
var validDate = (date) => Number.isNaN(date.getTime()) ? undefined : date;
|
|
176
|
-
var toDate = (value) => {
|
|
177
|
-
if (typeof value === "string") {
|
|
178
|
-
return validDate(new Date(value));
|
|
179
|
-
}
|
|
180
|
-
if (typeof value === "number") {
|
|
181
|
-
return validDate(new Date(value * 1000));
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
|
|
185
155
|
// src/http.ts
|
|
186
156
|
var assertOk = (url, init, response) => {
|
|
187
157
|
if (!response.ok) {
|
|
188
|
-
throw new
|
|
158
|
+
throw new BatchworkError2(`batchwork: ${init.method ?? "GET"} ${url} failed with ${response.status}.`);
|
|
189
159
|
}
|
|
190
160
|
};
|
|
191
161
|
var requestJson = async (url, init) => {
|
|
192
162
|
const response = await fetch(url, init);
|
|
193
163
|
assertOk(url, init, response);
|
|
194
|
-
return await response.
|
|
164
|
+
return parseJson(await response.text());
|
|
195
165
|
};
|
|
196
166
|
var requestStream = async (url, init) => {
|
|
197
167
|
const response = await fetch(url, init);
|
|
198
168
|
assertOk(url, init, response);
|
|
199
169
|
if (!response.body) {
|
|
200
|
-
throw new
|
|
170
|
+
throw new BatchworkError2(`batchwork: ${url} returned an empty body.`);
|
|
201
171
|
}
|
|
202
172
|
return response.body;
|
|
203
173
|
};
|
|
@@ -210,14 +180,14 @@ var NEWLINE_BYTES = byteLength(NEWLINE);
|
|
|
210
180
|
var resolveMaxLineBytes = (options) => {
|
|
211
181
|
const maxLineBytes = options?.maxLineBytes ?? DEFAULT_MAX_JSONL_LINE_BYTES;
|
|
212
182
|
if (!(Number.isInteger(maxLineBytes) && maxLineBytes > 0)) {
|
|
213
|
-
throw new
|
|
183
|
+
throw new BatchworkError2("batchwork: JSONL maxLineBytes must be a positive integer.");
|
|
214
184
|
}
|
|
215
185
|
return maxLineBytes;
|
|
216
186
|
};
|
|
217
187
|
var assertLineSize = (line, lineNumber, maxLineBytes) => {
|
|
218
188
|
const bytes = byteLength(line);
|
|
219
189
|
if (bytes > maxLineBytes) {
|
|
220
|
-
throw new
|
|
190
|
+
throw new BatchworkError2(`batchwork: JSONL line ${lineNumber} is ${bytes} bytes, exceeding the ${maxLineBytes} byte limit.`);
|
|
221
191
|
}
|
|
222
192
|
};
|
|
223
193
|
var parseLine = (line, lineNumber, maxLineBytes) => {
|
|
@@ -227,15 +197,15 @@ var parseLine = (line, lineNumber, maxLineBytes) => {
|
|
|
227
197
|
return;
|
|
228
198
|
}
|
|
229
199
|
try {
|
|
230
|
-
return
|
|
200
|
+
return parseJson(trimmed);
|
|
231
201
|
} catch (error) {
|
|
232
|
-
throw new
|
|
202
|
+
throw new BatchworkError2(`batchwork: invalid JSONL at line ${lineNumber}.`, { cause: error });
|
|
233
203
|
}
|
|
234
204
|
};
|
|
235
205
|
var resolveMaxBytes = (options) => {
|
|
236
206
|
const maxBytes = options?.maxBytes;
|
|
237
207
|
if (maxBytes !== undefined && !(Number.isInteger(maxBytes) && maxBytes > 0)) {
|
|
238
|
-
throw new
|
|
208
|
+
throw new BatchworkError2("batchwork: JSONL maxBytes must be a positive integer.");
|
|
239
209
|
}
|
|
240
210
|
return maxBytes;
|
|
241
211
|
};
|
|
@@ -250,7 +220,7 @@ var encodeJsonl = (items, options) => {
|
|
|
250
220
|
for (const item of items) {
|
|
251
221
|
const line = JSON.stringify(item);
|
|
252
222
|
if (line === undefined) {
|
|
253
|
-
throw new
|
|
223
|
+
throw new BatchworkError2(`batchwork: ${label} contains a value that cannot be JSON encoded.`);
|
|
254
224
|
}
|
|
255
225
|
bytes += byteLength(line) + NEWLINE_BYTES;
|
|
256
226
|
if (maxBytes !== undefined) {
|
|
@@ -290,9 +260,9 @@ async function* streamJsonl(source, options) {
|
|
|
290
260
|
while (newlineIndex !== -1) {
|
|
291
261
|
const line = buffer.slice(0, newlineIndex);
|
|
292
262
|
buffer = buffer.slice(newlineIndex + 1);
|
|
293
|
-
const
|
|
294
|
-
if (
|
|
295
|
-
yield
|
|
263
|
+
const parsed = parseLine(line, lineNumber, maxLineBytes);
|
|
264
|
+
if (parsed !== undefined) {
|
|
265
|
+
yield parsed;
|
|
296
266
|
}
|
|
297
267
|
lineNumber += 1;
|
|
298
268
|
newlineIndex = buffer.indexOf(NEWLINE);
|
|
@@ -320,7 +290,7 @@ var encodeJsonArrayPayload = ({
|
|
|
320
290
|
for (const [index, item] of items.entries()) {
|
|
321
291
|
const encoded = JSON.stringify(item);
|
|
322
292
|
if (encoded === undefined) {
|
|
323
|
-
throw new
|
|
293
|
+
throw new BatchworkError2(`batchwork: ${label} contains a value that cannot be JSON encoded.`);
|
|
324
294
|
}
|
|
325
295
|
bytes += byteLength(encoded);
|
|
326
296
|
if (index > 0) {
|
|
@@ -336,14 +306,14 @@ var encodeJsonArrayPayload = ({
|
|
|
336
306
|
var SIMPLE_PROVIDER_ID = /^[A-Za-z0-9_-]+$/u;
|
|
337
307
|
var assertSimpleProviderId = (label, id) => {
|
|
338
308
|
if (!SIMPLE_PROVIDER_ID.test(id)) {
|
|
339
|
-
throw new
|
|
309
|
+
throw new BatchworkError2(`batchwork: invalid ${label}.`);
|
|
340
310
|
}
|
|
341
311
|
return id;
|
|
342
312
|
};
|
|
343
313
|
var assertPrefixedProviderId = (label, id, prefix) => {
|
|
344
314
|
const [actualPrefix, value, ...rest] = id.split("/");
|
|
345
315
|
if (rest.length > 0 || actualPrefix !== prefix || !value || !SIMPLE_PROVIDER_ID.test(value)) {
|
|
346
|
-
throw new
|
|
316
|
+
throw new BatchworkError2(`batchwork: invalid ${label}.`);
|
|
347
317
|
}
|
|
348
318
|
return id;
|
|
349
319
|
};
|
|
@@ -354,7 +324,7 @@ var ANTHROPIC_VERSION = "2023-06-01";
|
|
|
354
324
|
var apiKey = (credentials) => {
|
|
355
325
|
const key = credentials.apiKey ?? process.env.ANTHROPIC_API_KEY;
|
|
356
326
|
if (!key) {
|
|
357
|
-
throw new
|
|
327
|
+
throw new BatchworkError2("batchwork: missing Anthropic API key. Set ANTHROPIC_API_KEY or pass `apiKey`.");
|
|
358
328
|
}
|
|
359
329
|
return key;
|
|
360
330
|
};
|
|
@@ -366,15 +336,15 @@ var validateResultsUrl = (rawUrl, credentials) => {
|
|
|
366
336
|
resultsUrl = new URL(rawUrl);
|
|
367
337
|
expectedBase = new URL(baseUrl(credentials));
|
|
368
338
|
} catch (error) {
|
|
369
|
-
throw new
|
|
339
|
+
throw new BatchworkError2("batchwork: invalid Anthropic results_url.", {
|
|
370
340
|
cause: error
|
|
371
341
|
});
|
|
372
342
|
}
|
|
373
343
|
if (resultsUrl.origin !== expectedBase.origin) {
|
|
374
|
-
throw new
|
|
344
|
+
throw new BatchworkError2("batchwork: Anthropic results_url must match the configured API origin.");
|
|
375
345
|
}
|
|
376
346
|
if (resultsUrl.username || resultsUrl.password) {
|
|
377
|
-
throw new
|
|
347
|
+
throw new BatchworkError2("batchwork: Anthropic results_url must not include credentials.");
|
|
378
348
|
}
|
|
379
349
|
return resultsUrl.toString();
|
|
380
350
|
};
|
|
@@ -504,7 +474,7 @@ async function* results(id, credentials) {
|
|
|
504
474
|
const snapshot = await retrieve(id, credentials);
|
|
505
475
|
const resultsUrl = asString(asRecord(snapshot.raw).results_url);
|
|
506
476
|
if (!resultsUrl) {
|
|
507
|
-
throw new
|
|
477
|
+
throw new BatchworkError2(`batchwork: results are not ready for batch "${id}" (status: ${snapshot.status}).`);
|
|
508
478
|
}
|
|
509
479
|
const stream = await requestStream(validateResultsUrl(resultsUrl, credentials), {
|
|
510
480
|
headers: headers(credentials),
|
|
@@ -535,7 +505,7 @@ var HTTP_OK_MAX = 300;
|
|
|
535
505
|
var resolveApiKey = (credentials, envVar, label) => {
|
|
536
506
|
const key = credentials.apiKey ?? process.env[envVar];
|
|
537
507
|
if (!key) {
|
|
538
|
-
throw new
|
|
508
|
+
throw new BatchworkError2(`batchwork: missing ${label} API key. Set ${envVar} or pass \`apiKey\`.`);
|
|
539
509
|
}
|
|
540
510
|
return key;
|
|
541
511
|
};
|
|
@@ -612,14 +582,14 @@ var imagesFromBody = (body) => {
|
|
|
612
582
|
return images.length > 0 ? images : undefined;
|
|
613
583
|
};
|
|
614
584
|
var moderationFromBody = (body) => {
|
|
615
|
-
const
|
|
616
|
-
if (
|
|
585
|
+
const results = asArray(asRecord(body).results);
|
|
586
|
+
if (results.length === 0) {
|
|
617
587
|
return;
|
|
618
588
|
}
|
|
619
|
-
const first = asRecord(
|
|
589
|
+
const first = asRecord(results[0]);
|
|
620
590
|
const categories = {};
|
|
621
591
|
for (const [key, value] of Object.entries(asRecord(first.categories))) {
|
|
622
|
-
if (
|
|
592
|
+
if (isBoolean(value)) {
|
|
623
593
|
categories[key] = value;
|
|
624
594
|
}
|
|
625
595
|
}
|
|
@@ -633,7 +603,7 @@ var moderationFromBody = (body) => {
|
|
|
633
603
|
categoryScores[key] = score;
|
|
634
604
|
}
|
|
635
605
|
}
|
|
636
|
-
const flagged =
|
|
606
|
+
const flagged = isBoolean(first.flagged) ? first.flagged : Object.values(categories).some(Boolean);
|
|
637
607
|
return { categories, categoryScores, flagged };
|
|
638
608
|
};
|
|
639
609
|
var usageFromBody = (body) => {
|
|
@@ -693,24 +663,28 @@ var normalizeOpenAIResult = (line) => {
|
|
|
693
663
|
status: "errored"
|
|
694
664
|
};
|
|
695
665
|
};
|
|
696
|
-
var uploadInputFile = async (jsonl,
|
|
666
|
+
var uploadInputFile = async (jsonl, baseUrl, headers, options = {}) => {
|
|
697
667
|
const form = new FormData;
|
|
698
668
|
const purpose = options.purpose === undefined ? "batch" : options.purpose;
|
|
699
669
|
if (purpose !== null) {
|
|
700
670
|
form.append("purpose", purpose);
|
|
701
671
|
}
|
|
702
672
|
form.append("file", new Blob([jsonl], { type: "application/jsonl" }), "batchwork.jsonl");
|
|
703
|
-
const raw = await requestJson(`${
|
|
673
|
+
const raw = await requestJson(`${baseUrl}/files`, {
|
|
704
674
|
body: form,
|
|
705
|
-
headers
|
|
675
|
+
headers,
|
|
706
676
|
method: "POST",
|
|
707
677
|
redirect: "manual"
|
|
708
678
|
});
|
|
709
|
-
|
|
679
|
+
const id = asString(asRecord(raw).id);
|
|
680
|
+
if (!id) {
|
|
681
|
+
throw new BatchworkError2("batchwork: the file upload response carried no file id.");
|
|
682
|
+
}
|
|
683
|
+
return id;
|
|
710
684
|
};
|
|
711
|
-
async function* streamResultFile(fileId,
|
|
712
|
-
const stream = await requestStream(`${
|
|
713
|
-
headers
|
|
685
|
+
async function* streamResultFile(fileId, baseUrl, headers) {
|
|
686
|
+
const stream = await requestStream(`${baseUrl}/files/${fileId}/content`, {
|
|
687
|
+
headers,
|
|
714
688
|
redirect: "manual"
|
|
715
689
|
});
|
|
716
690
|
for await (const line of streamJsonl(stream)) {
|
|
@@ -761,8 +735,8 @@ var normalizeSnapshot2 = (raw, provider) => {
|
|
|
761
735
|
var createOpenAICompatibleAdapter = (config) => {
|
|
762
736
|
const completionWindow = config.completionWindow ?? DEFAULT_COMPLETION_WINDOW;
|
|
763
737
|
const lineFormat = config.lineFormat ?? "method-url";
|
|
764
|
-
const
|
|
765
|
-
throw new
|
|
738
|
+
const baseUrl = (credentials) => config.resolveBaseUrl?.(credentials) ?? credentials.baseURL ?? config.baseUrl ?? (() => {
|
|
739
|
+
throw new BatchworkError2(`batchwork: missing ${config.apiKeyLabel} base URL. Pass \`baseURL\`.`);
|
|
766
740
|
})();
|
|
767
741
|
const authHeaders = (credentials) => ({
|
|
768
742
|
...config.authHeaders ? config.authHeaders(credentials) : {
|
|
@@ -770,7 +744,7 @@ var createOpenAICompatibleAdapter = (config) => {
|
|
|
770
744
|
},
|
|
771
745
|
...credentials.headers
|
|
772
746
|
});
|
|
773
|
-
const
|
|
747
|
+
const submit = async (input) => {
|
|
774
748
|
const limits = resolveBatchLimits(input.limits);
|
|
775
749
|
const endpoint = config.normalizeEndpoint ? config.normalizeEndpoint(input.endpoint) : input.endpoint;
|
|
776
750
|
const batchEndpoint = config.batchEndpoint?.(endpoint) ?? endpoint;
|
|
@@ -790,10 +764,10 @@ var createOpenAICompatibleAdapter = (config) => {
|
|
|
790
764
|
url: endpoint
|
|
791
765
|
};
|
|
792
766
|
}), { label: "batch upload JSONL", maxBytes: limits.maxUploadBytes });
|
|
793
|
-
const
|
|
794
|
-
const url =
|
|
767
|
+
const headers = authHeaders(input.credentials);
|
|
768
|
+
const url = baseUrl(input.credentials);
|
|
795
769
|
const purpose = config.filePurpose ?? "batch";
|
|
796
|
-
const inputFileId = await (config.uploadFile ? config.uploadFile({ baseUrl: url, headers
|
|
770
|
+
const inputFileId = await (config.uploadFile ? config.uploadFile({ baseUrl: url, headers, jsonl, purpose }) : uploadInputFile(jsonl, url, headers, { purpose }));
|
|
797
771
|
const raw = await requestJson(`${url}/batches`, {
|
|
798
772
|
body: JSON.stringify({
|
|
799
773
|
completion_window: completionWindow,
|
|
@@ -801,42 +775,42 @@ var createOpenAICompatibleAdapter = (config) => {
|
|
|
801
775
|
input_file_id: inputFileId,
|
|
802
776
|
metadata: input.metadata
|
|
803
777
|
}),
|
|
804
|
-
headers: { ...
|
|
778
|
+
headers: { ...headers, "content-type": "application/json" },
|
|
805
779
|
method: "POST"
|
|
806
780
|
});
|
|
807
781
|
return normalizeSnapshot2(raw, config.id);
|
|
808
782
|
};
|
|
809
|
-
const
|
|
783
|
+
const retrieve = async (id, credentials) => {
|
|
810
784
|
const batchId = assertSimpleProviderId(`${config.id} batch id`, id);
|
|
811
|
-
const raw = await requestJson(`${
|
|
785
|
+
const raw = await requestJson(`${baseUrl(credentials)}/batches/${batchId}`, {
|
|
812
786
|
headers: authHeaders(credentials)
|
|
813
787
|
});
|
|
814
788
|
return normalizeSnapshot2(raw, config.id);
|
|
815
789
|
};
|
|
816
|
-
async function*
|
|
817
|
-
const snapshot = await
|
|
790
|
+
async function* results(id, credentials) {
|
|
791
|
+
const snapshot = await retrieve(id, credentials);
|
|
818
792
|
const raw = asRecord(snapshot.raw);
|
|
819
793
|
const outputFileId = asString(raw.output_file_id);
|
|
820
794
|
const errorFileId = asString(raw.error_file_id);
|
|
821
795
|
if (!(outputFileId || errorFileId)) {
|
|
822
|
-
throw new
|
|
796
|
+
throw new BatchworkError2(`batchwork: results are not ready for batch "${id}" (status: ${snapshot.status}).`);
|
|
823
797
|
}
|
|
824
|
-
const
|
|
798
|
+
const headers = authHeaders(credentials);
|
|
825
799
|
if (outputFileId) {
|
|
826
|
-
yield* streamResultFile(assertSimpleProviderId(`${config.id} output file id`, outputFileId),
|
|
800
|
+
yield* streamResultFile(assertSimpleProviderId(`${config.id} output file id`, outputFileId), baseUrl(credentials), headers);
|
|
827
801
|
}
|
|
828
802
|
if (errorFileId) {
|
|
829
|
-
yield* streamResultFile(assertSimpleProviderId(`${config.id} error file id`, errorFileId),
|
|
803
|
+
yield* streamResultFile(assertSimpleProviderId(`${config.id} error file id`, errorFileId), baseUrl(credentials), headers);
|
|
830
804
|
}
|
|
831
805
|
}
|
|
832
|
-
const
|
|
806
|
+
const cancel = async (id, credentials) => {
|
|
833
807
|
const batchId = assertSimpleProviderId(`${config.id} batch id`, id);
|
|
834
|
-
await requestJson(`${
|
|
808
|
+
await requestJson(`${baseUrl(credentials)}/batches/${batchId}/cancel`, {
|
|
835
809
|
headers: authHeaders(credentials),
|
|
836
810
|
method: "POST"
|
|
837
811
|
});
|
|
838
812
|
};
|
|
839
|
-
return { cancel
|
|
813
|
+
return { cancel, id: config.id, results, retrieve, submit };
|
|
840
814
|
};
|
|
841
815
|
|
|
842
816
|
// src/providers/azure.ts
|
|
@@ -850,7 +824,7 @@ var isAzureOpenAIUrl = (value) => {
|
|
|
850
824
|
var baseUrl2 = (credentials) => {
|
|
851
825
|
const configured = credentials.baseURL ?? (process.env.AZURE_RESOURCE_NAME ? `https://${process.env.AZURE_RESOURCE_NAME}.openai.azure.com/openai` : undefined);
|
|
852
826
|
if (!configured) {
|
|
853
|
-
throw new
|
|
827
|
+
throw new BatchworkError2("batchwork: missing Azure OpenAI resource. Set AZURE_RESOURCE_NAME or pass `baseURL`.");
|
|
854
828
|
}
|
|
855
829
|
const normalized = trimTrailingSlashes(configured);
|
|
856
830
|
if (!isAzureOpenAIUrl(normalized)) {
|
|
@@ -861,7 +835,7 @@ var baseUrl2 = (credentials) => {
|
|
|
861
835
|
}
|
|
862
836
|
return normalized.endsWith("/openai") ? `${normalized}/v1` : `${normalized}/openai/v1`;
|
|
863
837
|
};
|
|
864
|
-
var hasCallerAuth = (
|
|
838
|
+
var hasCallerAuth = (headers) => Object.keys(headers ?? {}).some((name) => {
|
|
865
839
|
const normalized = name.toLowerCase();
|
|
866
840
|
return normalized === "api-key" || normalized === "authorization";
|
|
867
841
|
});
|
|
@@ -872,11 +846,11 @@ var authHeaders = (credentials) => {
|
|
|
872
846
|
if (hasCallerAuth(credentials.headers)) {
|
|
873
847
|
return {};
|
|
874
848
|
}
|
|
875
|
-
const
|
|
876
|
-
if (
|
|
877
|
-
return { "api-key":
|
|
849
|
+
const apiKey = process.env.AZURE_API_KEY ?? process.env.AZURE_OPENAI_API_KEY;
|
|
850
|
+
if (apiKey) {
|
|
851
|
+
return { "api-key": apiKey };
|
|
878
852
|
}
|
|
879
|
-
throw new
|
|
853
|
+
throw new BatchworkError2("batchwork: missing Azure OpenAI API key. Set AZURE_API_KEY or pass `apiKey`.");
|
|
880
854
|
};
|
|
881
855
|
var azureAdapter = createOpenAICompatibleAdapter({
|
|
882
856
|
apiKeyEnv: "AZURE_API_KEY",
|
|
@@ -895,7 +869,7 @@ var GOOGLE_BATCH_PREFIX = "batches";
|
|
|
895
869
|
var apiKey2 = (credentials) => {
|
|
896
870
|
const key = credentials.apiKey ?? process.env.GOOGLE_GENERATIVE_AI_API_KEY ?? process.env.GEMINI_API_KEY;
|
|
897
871
|
if (!key) {
|
|
898
|
-
throw new
|
|
872
|
+
throw new BatchworkError2("batchwork: missing Google Gemini API key. Set GOOGLE_GENERATIVE_AI_API_KEY (or GEMINI_API_KEY) or pass `apiKey`.");
|
|
899
873
|
}
|
|
900
874
|
return key;
|
|
901
875
|
};
|
|
@@ -1082,11 +1056,11 @@ async function* results2(id, credentials) {
|
|
|
1082
1056
|
const dest = asRecord(raw.dest);
|
|
1083
1057
|
const responsesFile = fileNameFrom(response.responsesFile) ?? fileNameFrom(response.responses_file) ?? asString(dest.fileName) ?? asString(dest.file_name);
|
|
1084
1058
|
if (responsesFile) {
|
|
1085
|
-
throw new
|
|
1059
|
+
throw new BatchworkError2(`batchwork: batch "${id}" returned file-mode results, which are not supported yet.`);
|
|
1086
1060
|
}
|
|
1087
1061
|
const items = inlinedResponses(raw);
|
|
1088
1062
|
if (items.length === 0) {
|
|
1089
|
-
throw new
|
|
1063
|
+
throw new BatchworkError2(`batchwork: results are not ready for batch "${id}" (status: ${snapshot.status}).`);
|
|
1090
1064
|
}
|
|
1091
1065
|
for (const item of items) {
|
|
1092
1066
|
yield normalizeResult2(item);
|
|
@@ -1204,15 +1178,15 @@ async function* results3(id, credentials) {
|
|
|
1204
1178
|
const raw = asRecord(snapshot.raw);
|
|
1205
1179
|
const outputFileId = asString(raw.output_file);
|
|
1206
1180
|
const errorFileId = asString(raw.error_file);
|
|
1207
|
-
const
|
|
1181
|
+
const headers = authHeaders2(credentials);
|
|
1208
1182
|
if (outputFileId) {
|
|
1209
|
-
yield* streamResultFile(assertSimpleProviderId("Mistral output file id", outputFileId), baseUrl4(credentials),
|
|
1183
|
+
yield* streamResultFile(assertSimpleProviderId("Mistral output file id", outputFileId), baseUrl4(credentials), headers);
|
|
1210
1184
|
}
|
|
1211
1185
|
if (errorFileId) {
|
|
1212
|
-
yield* streamResultFile(assertSimpleProviderId("Mistral error file id", errorFileId), baseUrl4(credentials),
|
|
1186
|
+
yield* streamResultFile(assertSimpleProviderId("Mistral error file id", errorFileId), baseUrl4(credentials), headers);
|
|
1213
1187
|
}
|
|
1214
1188
|
if (!(outputFileId || errorFileId)) {
|
|
1215
|
-
throw new
|
|
1189
|
+
throw new BatchworkError2(`batchwork: results are not ready for batch "${id}" (status: ${snapshot.status}).`);
|
|
1216
1190
|
}
|
|
1217
1191
|
}
|
|
1218
1192
|
var cancel3 = async (id, credentials) => {
|
|
@@ -1298,16 +1272,16 @@ var validateUploadLocation = (location) => {
|
|
|
1298
1272
|
try {
|
|
1299
1273
|
url = new URL(location);
|
|
1300
1274
|
} catch (error) {
|
|
1301
|
-
throw new
|
|
1275
|
+
throw new BatchworkError2("batchwork: Together upload Location must be a valid URL.", { cause: error });
|
|
1302
1276
|
}
|
|
1303
1277
|
if (url.protocol !== "https:") {
|
|
1304
|
-
throw new
|
|
1278
|
+
throw new BatchworkError2("batchwork: Together upload Location must use https.");
|
|
1305
1279
|
}
|
|
1306
1280
|
if (url.username || url.password) {
|
|
1307
|
-
throw new
|
|
1281
|
+
throw new BatchworkError2("batchwork: Together upload Location must not include credentials.");
|
|
1308
1282
|
}
|
|
1309
1283
|
if (isPrivateHost(url.hostname.toLowerCase())) {
|
|
1310
|
-
throw new
|
|
1284
|
+
throw new BatchworkError2("batchwork: Together upload Location must not target localhost or private networks.");
|
|
1311
1285
|
}
|
|
1312
1286
|
return url.toString();
|
|
1313
1287
|
};
|
|
@@ -1325,7 +1299,7 @@ var uploadTogetherFile = async (args) => {
|
|
|
1325
1299
|
const location = init.headers.get("location");
|
|
1326
1300
|
const fileId = init.headers.get("x-together-file-id");
|
|
1327
1301
|
if (init.status !== HTTP_FOUND || !(location && fileId)) {
|
|
1328
|
-
throw new
|
|
1302
|
+
throw new BatchworkError2(`batchwork: Together upload could not be initiated (${init.status}).`);
|
|
1329
1303
|
}
|
|
1330
1304
|
const uploadLocation = validateUploadLocation(location);
|
|
1331
1305
|
const upload = await fetch(uploadLocation, {
|
|
@@ -1334,7 +1308,7 @@ var uploadTogetherFile = async (args) => {
|
|
|
1334
1308
|
redirect: "manual"
|
|
1335
1309
|
});
|
|
1336
1310
|
if (!upload.ok) {
|
|
1337
|
-
throw new
|
|
1311
|
+
throw new BatchworkError2(`batchwork: Together file upload failed (${upload.status}).`);
|
|
1338
1312
|
}
|
|
1339
1313
|
const safeFileId = assertSimpleProviderId("Together file id", fileId);
|
|
1340
1314
|
await requestJson(`${args.baseUrl}/files/${safeFileId}/preprocess`, {
|
|
@@ -1413,10 +1387,14 @@ var imagesFromXaiCompletion = (completion) => {
|
|
|
1413
1387
|
const data = asString(record.base64) ?? asString(record.b64_json);
|
|
1414
1388
|
const url = asString(record.url);
|
|
1415
1389
|
if (data || url) {
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
}
|
|
1390
|
+
const image = {};
|
|
1391
|
+
if (data) {
|
|
1392
|
+
image.data = data;
|
|
1393
|
+
}
|
|
1394
|
+
if (url) {
|
|
1395
|
+
image.url = url;
|
|
1396
|
+
}
|
|
1397
|
+
images.push(image);
|
|
1420
1398
|
}
|
|
1421
1399
|
}
|
|
1422
1400
|
return images.length > 0 ? images : undefined;
|
|
@@ -1431,11 +1409,12 @@ var videosFromXaiCompletion = (completion) => {
|
|
|
1431
1409
|
const video = asRecord(record.video);
|
|
1432
1410
|
const url = asString(video.url) ?? asString(record.url);
|
|
1433
1411
|
if (url) {
|
|
1412
|
+
const entry = { url };
|
|
1434
1413
|
const duration = asNumber(video.duration) ?? asNumber(record.duration);
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1414
|
+
if (duration !== undefined) {
|
|
1415
|
+
entry.durationSeconds = duration;
|
|
1416
|
+
}
|
|
1417
|
+
videos.push(entry);
|
|
1439
1418
|
}
|
|
1440
1419
|
}
|
|
1441
1420
|
return videos.length > 0 ? videos : undefined;
|
|
@@ -1498,16 +1477,16 @@ var retrieve4 = async (id, credentials) => {
|
|
|
1498
1477
|
};
|
|
1499
1478
|
async function* results4(id, credentials) {
|
|
1500
1479
|
const batchId = assertSimpleProviderId(BATCH_ID_LABEL, id);
|
|
1501
|
-
const
|
|
1480
|
+
const headers = authHeaders3(credentials);
|
|
1502
1481
|
let token;
|
|
1503
1482
|
do {
|
|
1504
1483
|
const query = new URLSearchParams({ limit: String(RESULTS_PAGE_SIZE) });
|
|
1505
1484
|
if (token) {
|
|
1506
1485
|
query.set("pagination_token", token);
|
|
1507
1486
|
}
|
|
1508
|
-
const raw = await requestJson(`${baseUrl5(credentials)}/batches/${batchId}/results?${query.toString()}`, { headers
|
|
1487
|
+
const raw = await requestJson(`${baseUrl5(credentials)}/batches/${batchId}/results?${query.toString()}`, { headers });
|
|
1509
1488
|
const page = asRecord(raw);
|
|
1510
|
-
for (const item of
|
|
1489
|
+
for (const item of asArray(page.results)) {
|
|
1511
1490
|
yield normalizeResult3(item);
|
|
1512
1491
|
}
|
|
1513
1492
|
token = asString(page.pagination_token);
|
|
@@ -1541,7 +1520,7 @@ var adapters = {
|
|
|
1541
1520
|
};
|
|
1542
1521
|
var getAdapter = (provider) => adapters[provider];
|
|
1543
1522
|
|
|
1544
|
-
export {
|
|
1523
|
+
export { BatchworkError2, UnsupportedProviderError2, MissingDependencyError2, resolveBatchLimits, assertByteLength, isTerminalStatus2, BatchJob2, getAdapter };
|
|
1545
1524
|
|
|
1546
|
-
//# debugId=
|
|
1547
|
-
//# sourceMappingURL=chunk-
|
|
1525
|
+
//# debugId=7B0EC738FEADB97E64756E2164756E21
|
|
1526
|
+
//# sourceMappingURL=chunk-7y95mhvm.js.map
|