batchwork 1.0.0 → 1.0.1
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/batch.d.ts.map +1 -1
- package/dist/body.d.ts +3 -2
- package/dist/body.d.ts.map +1 -1
- package/dist/{chunk-zp2cxkyb.js → chunk-e6qn48qa.js} +88 -13
- package/dist/chunk-e6qn48qa.js.map +13 -0
- package/dist/{chunk-kv3847wy.js → chunk-g481f961.js} +220 -56
- package/dist/chunk-g481f961.js.map +26 -0
- package/dist/{chunk-ab2d71gk.js → chunk-m4n610nm.js} +20 -7
- package/dist/chunk-m4n610nm.js.map +12 -0
- 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 +2 -2
- package/dist/jsonl.d.ts +5 -15
- package/dist/jsonl.d.ts.map +1 -1
- package/dist/limits.d.ts +12 -0
- package/dist/limits.d.ts.map +1 -0
- package/dist/next/index.d.ts +3 -1
- package/dist/next/index.d.ts.map +1 -1
- package/dist/next/index.js +7 -4
- package/dist/next/index.js.map +3 -3
- package/dist/providers/adapter.d.ts +2 -1
- package/dist/providers/adapter.d.ts.map +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/google.d.ts.map +1 -1
- package/dist/providers/ids.d.ts +3 -0
- package/dist/providers/ids.d.ts.map +1 -0
- package/dist/providers/mistral.d.ts.map +1 -1
- package/dist/providers/openai-compatible.d.ts.map +1 -1
- package/dist/providers/together.d.ts.map +1 -1
- package/dist/providers/xai.d.ts.map +1 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -2
- package/dist/server/poller.d.ts +3 -0
- package/dist/server/poller.d.ts.map +1 -1
- package/dist/server/signing.d.ts +9 -2
- package/dist/server/signing.d.ts.map +1 -1
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-ab2d71gk.js.map +0 -12
- package/dist/chunk-kv3847wy.js.map +0 -24
- package/dist/chunk-zp2cxkyb.js.map +0 -13
|
@@ -103,28 +103,65 @@ class BatchJob {
|
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
// src/
|
|
107
|
-
var
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
106
|
+
// src/limits.ts
|
|
107
|
+
var DEFAULT_LIMITS = {
|
|
108
|
+
captureConcurrency: 16,
|
|
109
|
+
maxRequestBytes: 20 * 1024 * 1024,
|
|
110
|
+
maxRequests: 50000,
|
|
111
|
+
maxUploadBytes: 200 * 1024 * 1024
|
|
112
|
+
};
|
|
113
|
+
var encoder = new TextEncoder;
|
|
114
|
+
var positiveInteger = (name, value) => {
|
|
115
|
+
if (!(Number.isInteger(value) && value > 0)) {
|
|
116
|
+
throw new BatchworkError(`batchwork: limits.${name} must be a positive integer.`);
|
|
117
|
+
}
|
|
118
|
+
return value;
|
|
119
|
+
};
|
|
120
|
+
var resolveBatchLimits = (limits) => ({
|
|
121
|
+
captureConcurrency: positiveInteger("captureConcurrency", limits?.captureConcurrency ?? DEFAULT_LIMITS.captureConcurrency),
|
|
122
|
+
maxRequestBytes: positiveInteger("maxRequestBytes", limits?.maxRequestBytes ?? DEFAULT_LIMITS.maxRequestBytes),
|
|
123
|
+
maxRequests: positiveInteger("maxRequests", limits?.maxRequests ?? DEFAULT_LIMITS.maxRequests),
|
|
124
|
+
maxUploadBytes: positiveInteger("maxUploadBytes", limits?.maxUploadBytes ?? DEFAULT_LIMITS.maxUploadBytes)
|
|
125
|
+
});
|
|
126
|
+
var byteLength = (value) => encoder.encode(value).length;
|
|
127
|
+
var assertByteLength = (label, value, maxBytes) => {
|
|
128
|
+
const bytes = byteLength(value);
|
|
129
|
+
if (bytes > maxBytes) {
|
|
130
|
+
throw new BatchworkError(`batchwork: ${label} is ${bytes} bytes, exceeding the ${maxBytes} byte limit.`);
|
|
112
131
|
}
|
|
113
132
|
};
|
|
114
|
-
var
|
|
133
|
+
var mapWithConcurrency = async (items, concurrency, mapper) => {
|
|
134
|
+
const results = [];
|
|
135
|
+
results.length = items.length;
|
|
136
|
+
let nextIndex = 0;
|
|
137
|
+
const workerCount = Math.min(concurrency, items.length);
|
|
138
|
+
const runNext = async () => {
|
|
139
|
+
const index = nextIndex;
|
|
140
|
+
nextIndex += 1;
|
|
141
|
+
if (index >= items.length) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
results[index] = await mapper(items[index]);
|
|
145
|
+
await runNext();
|
|
146
|
+
};
|
|
147
|
+
await Promise.all(Array.from({ length: workerCount }, () => runNext()));
|
|
148
|
+
return results;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// src/http.ts
|
|
152
|
+
var assertOk = (url, init, response) => {
|
|
115
153
|
if (!response.ok) {
|
|
116
|
-
|
|
117
|
-
throw new BatchworkError(`batchwork: ${init.method ?? "GET"} ${url} failed with ${response.status}: ${detail}`);
|
|
154
|
+
throw new BatchworkError(`batchwork: ${init.method ?? "GET"} ${url} failed with ${response.status}.`);
|
|
118
155
|
}
|
|
119
156
|
};
|
|
120
157
|
var requestJson = async (url, init) => {
|
|
121
158
|
const response = await fetch(url, init);
|
|
122
|
-
|
|
159
|
+
assertOk(url, init, response);
|
|
123
160
|
return await response.json();
|
|
124
161
|
};
|
|
125
162
|
var requestStream = async (url, init) => {
|
|
126
163
|
const response = await fetch(url, init);
|
|
127
|
-
|
|
164
|
+
assertOk(url, init, response);
|
|
128
165
|
if (!response.body) {
|
|
129
166
|
throw new BatchworkError(`batchwork: ${url} returned an empty body.`);
|
|
130
167
|
}
|
|
@@ -134,6 +171,32 @@ var requestStream = async (url, init) => {
|
|
|
134
171
|
// src/jsonl.ts
|
|
135
172
|
var NEWLINE = `
|
|
136
173
|
`;
|
|
174
|
+
var DEFAULT_MAX_JSONL_LINE_BYTES = 20 * 1024 * 1024;
|
|
175
|
+
var resolveMaxLineBytes = (options) => {
|
|
176
|
+
const maxLineBytes = options?.maxLineBytes ?? DEFAULT_MAX_JSONL_LINE_BYTES;
|
|
177
|
+
if (!(Number.isInteger(maxLineBytes) && maxLineBytes > 0)) {
|
|
178
|
+
throw new BatchworkError("batchwork: JSONL maxLineBytes must be a positive integer.");
|
|
179
|
+
}
|
|
180
|
+
return maxLineBytes;
|
|
181
|
+
};
|
|
182
|
+
var assertLineSize = (line, lineNumber, maxLineBytes) => {
|
|
183
|
+
const bytes = byteLength(line);
|
|
184
|
+
if (bytes > maxLineBytes) {
|
|
185
|
+
throw new BatchworkError(`batchwork: JSONL line ${lineNumber} is ${bytes} bytes, exceeding the ${maxLineBytes} byte limit.`);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
var parseLine = (line, lineNumber, maxLineBytes) => {
|
|
189
|
+
assertLineSize(line, lineNumber, maxLineBytes);
|
|
190
|
+
const trimmed = line.trim();
|
|
191
|
+
if (trimmed.length === 0) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
return JSON.parse(trimmed);
|
|
196
|
+
} catch (error) {
|
|
197
|
+
throw new BatchworkError(`batchwork: invalid JSONL at line ${lineNumber}.`, { cause: error });
|
|
198
|
+
}
|
|
199
|
+
};
|
|
137
200
|
var encodeJsonl = (items) => {
|
|
138
201
|
if (items.length === 0) {
|
|
139
202
|
return "";
|
|
@@ -160,25 +223,30 @@ async function* toByteIterable(source) {
|
|
|
160
223
|
}
|
|
161
224
|
yield* source;
|
|
162
225
|
}
|
|
163
|
-
async function* streamJsonl(source) {
|
|
226
|
+
async function* streamJsonl(source, options) {
|
|
164
227
|
const decoder = new TextDecoder;
|
|
228
|
+
const maxLineBytes = resolveMaxLineBytes(options);
|
|
165
229
|
let buffer = "";
|
|
230
|
+
let lineNumber = 1;
|
|
166
231
|
for await (const chunk of toByteIterable(source)) {
|
|
167
232
|
buffer += decoder.decode(chunk, { stream: true });
|
|
168
233
|
let newlineIndex = buffer.indexOf(NEWLINE);
|
|
169
234
|
while (newlineIndex !== -1) {
|
|
170
|
-
const line = buffer.slice(0, newlineIndex)
|
|
235
|
+
const line = buffer.slice(0, newlineIndex);
|
|
171
236
|
buffer = buffer.slice(newlineIndex + 1);
|
|
172
|
-
|
|
173
|
-
|
|
237
|
+
const parsed2 = parseLine(line, lineNumber, maxLineBytes);
|
|
238
|
+
if (parsed2 !== undefined) {
|
|
239
|
+
yield parsed2;
|
|
174
240
|
}
|
|
241
|
+
lineNumber += 1;
|
|
175
242
|
newlineIndex = buffer.indexOf(NEWLINE);
|
|
176
243
|
}
|
|
244
|
+
assertLineSize(buffer, lineNumber, maxLineBytes);
|
|
177
245
|
}
|
|
178
246
|
buffer += decoder.decode();
|
|
179
|
-
const
|
|
180
|
-
if (
|
|
181
|
-
yield
|
|
247
|
+
const parsed = parseLine(buffer, lineNumber, maxLineBytes);
|
|
248
|
+
if (parsed !== undefined) {
|
|
249
|
+
yield parsed;
|
|
182
250
|
}
|
|
183
251
|
}
|
|
184
252
|
|
|
@@ -210,6 +278,22 @@ var toDate = (value) => {
|
|
|
210
278
|
}
|
|
211
279
|
};
|
|
212
280
|
|
|
281
|
+
// src/providers/ids.ts
|
|
282
|
+
var SIMPLE_PROVIDER_ID = /^[A-Za-z0-9_-]+$/u;
|
|
283
|
+
var assertSimpleProviderId = (label, id) => {
|
|
284
|
+
if (!SIMPLE_PROVIDER_ID.test(id)) {
|
|
285
|
+
throw new BatchworkError(`batchwork: invalid ${label}.`);
|
|
286
|
+
}
|
|
287
|
+
return id;
|
|
288
|
+
};
|
|
289
|
+
var assertPrefixedProviderId = (label, id, prefix) => {
|
|
290
|
+
const [actualPrefix, value, ...rest] = id.split("/");
|
|
291
|
+
if (rest.length > 0 || actualPrefix !== prefix || !value || !SIMPLE_PROVIDER_ID.test(value)) {
|
|
292
|
+
throw new BatchworkError(`batchwork: invalid ${label}.`);
|
|
293
|
+
}
|
|
294
|
+
return id;
|
|
295
|
+
};
|
|
296
|
+
|
|
213
297
|
// src/providers/anthropic.ts
|
|
214
298
|
var ANTHROPIC_BASE = "https://api.anthropic.com";
|
|
215
299
|
var ANTHROPIC_VERSION = "2023-06-01";
|
|
@@ -221,6 +305,25 @@ var apiKey = (credentials) => {
|
|
|
221
305
|
return key;
|
|
222
306
|
};
|
|
223
307
|
var baseUrl = (credentials) => credentials.baseURL ?? ANTHROPIC_BASE;
|
|
308
|
+
var validateResultsUrl = (rawUrl, credentials) => {
|
|
309
|
+
let resultsUrl;
|
|
310
|
+
let expectedBase;
|
|
311
|
+
try {
|
|
312
|
+
resultsUrl = new URL(rawUrl);
|
|
313
|
+
expectedBase = new URL(baseUrl(credentials));
|
|
314
|
+
} catch (error) {
|
|
315
|
+
throw new BatchworkError("batchwork: invalid Anthropic results_url.", {
|
|
316
|
+
cause: error
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
if (resultsUrl.origin !== expectedBase.origin) {
|
|
320
|
+
throw new BatchworkError("batchwork: Anthropic results_url must match the configured API origin.");
|
|
321
|
+
}
|
|
322
|
+
if (resultsUrl.username || resultsUrl.password) {
|
|
323
|
+
throw new BatchworkError("batchwork: Anthropic results_url must not include credentials.");
|
|
324
|
+
}
|
|
325
|
+
return resultsUrl.toString();
|
|
326
|
+
};
|
|
224
327
|
var headers = (credentials) => ({
|
|
225
328
|
"anthropic-version": ANTHROPIC_VERSION,
|
|
226
329
|
"content-type": "application/json",
|
|
@@ -313,19 +416,23 @@ var normalizeResult = (line) => {
|
|
|
313
416
|
return { customId, status: "canceled" };
|
|
314
417
|
};
|
|
315
418
|
var submit = async (input) => {
|
|
419
|
+
const limits = resolveBatchLimits(input.limits);
|
|
316
420
|
const requests = input.built.map((item) => ({
|
|
317
421
|
custom_id: item.customId,
|
|
318
422
|
params: omit(item.body, "stream")
|
|
319
423
|
}));
|
|
424
|
+
const body = JSON.stringify({ requests });
|
|
425
|
+
assertByteLength("batch upload payload", body, limits.maxUploadBytes);
|
|
320
426
|
const raw = await requestJson(`${baseUrl(input.credentials)}/v1/messages/batches`, {
|
|
321
|
-
body
|
|
427
|
+
body,
|
|
322
428
|
headers: headers(input.credentials),
|
|
323
429
|
method: "POST"
|
|
324
430
|
});
|
|
325
431
|
return normalizeSnapshot(raw);
|
|
326
432
|
};
|
|
327
433
|
var retrieve = async (id, credentials) => {
|
|
328
|
-
const
|
|
434
|
+
const batchId = assertSimpleProviderId("Anthropic batch id", id);
|
|
435
|
+
const raw = await requestJson(`${baseUrl(credentials)}/v1/messages/batches/${batchId}`, { headers: headers(credentials) });
|
|
329
436
|
return normalizeSnapshot(raw);
|
|
330
437
|
};
|
|
331
438
|
async function* results(id, credentials) {
|
|
@@ -334,7 +441,7 @@ async function* results(id, credentials) {
|
|
|
334
441
|
if (!resultsUrl) {
|
|
335
442
|
throw new BatchworkError(`batchwork: results are not ready for batch "${id}" (status: ${snapshot.status}).`);
|
|
336
443
|
}
|
|
337
|
-
const stream = await requestStream(resultsUrl, {
|
|
444
|
+
const stream = await requestStream(validateResultsUrl(resultsUrl, credentials), {
|
|
338
445
|
headers: headers(credentials)
|
|
339
446
|
});
|
|
340
447
|
for await (const line of streamJsonl(stream)) {
|
|
@@ -342,7 +449,8 @@ async function* results(id, credentials) {
|
|
|
342
449
|
}
|
|
343
450
|
}
|
|
344
451
|
var cancel = async (id, credentials) => {
|
|
345
|
-
|
|
452
|
+
const batchId = assertSimpleProviderId("Anthropic batch id", id);
|
|
453
|
+
await requestJson(`${baseUrl(credentials)}/v1/messages/batches/${batchId}/cancel`, {
|
|
346
454
|
headers: headers(credentials),
|
|
347
455
|
method: "POST"
|
|
348
456
|
});
|
|
@@ -357,6 +465,7 @@ var anthropicAdapter = {
|
|
|
357
465
|
|
|
358
466
|
// src/providers/google.ts
|
|
359
467
|
var GOOGLE_BASE = "https://generativelanguage.googleapis.com/v1beta";
|
|
468
|
+
var GOOGLE_BATCH_PREFIX = "batches";
|
|
360
469
|
var apiKey2 = (credentials) => {
|
|
361
470
|
const key = credentials.apiKey ?? process.env.GOOGLE_GENERATIVE_AI_API_KEY ?? process.env.GEMINI_API_KEY;
|
|
362
471
|
if (!key) {
|
|
@@ -414,8 +523,9 @@ var normalizeSnapshot2 = (raw) => {
|
|
|
414
523
|
const obj = asRecord(raw);
|
|
415
524
|
const items = inlinedResponses(raw);
|
|
416
525
|
const failed = items.filter((item) => asRecord(item).error).length;
|
|
526
|
+
const id = asString(obj.name) ?? "";
|
|
417
527
|
return {
|
|
418
|
-
id:
|
|
528
|
+
id: id ? assertPrefixedProviderId("Google operation id", id, GOOGLE_BATCH_PREFIX) : "",
|
|
419
529
|
provider: "google",
|
|
420
530
|
raw,
|
|
421
531
|
requestCounts: {
|
|
@@ -470,24 +580,28 @@ var normalizeResult2 = (item) => {
|
|
|
470
580
|
};
|
|
471
581
|
};
|
|
472
582
|
var submit2 = async (input) => {
|
|
583
|
+
const limits = resolveBatchLimits(input.limits);
|
|
473
584
|
const requests = input.built.map((item) => ({
|
|
474
585
|
metadata: { key: item.customId },
|
|
475
586
|
request: omit(item.body, "stream")
|
|
476
587
|
}));
|
|
588
|
+
const body = JSON.stringify({
|
|
589
|
+
batch: {
|
|
590
|
+
display_name: "batchwork",
|
|
591
|
+
input_config: { requests: { requests } }
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
assertByteLength("batch upload payload", body, limits.maxUploadBytes);
|
|
477
595
|
const raw = await requestJson(`${baseUrl2(input.credentials)}/models/${input.modelId}:batchGenerateContent`, {
|
|
478
|
-
body
|
|
479
|
-
batch: {
|
|
480
|
-
display_name: "batchwork",
|
|
481
|
-
input_config: { requests: { requests } }
|
|
482
|
-
}
|
|
483
|
-
}),
|
|
596
|
+
body,
|
|
484
597
|
headers: headers2(input.credentials),
|
|
485
598
|
method: "POST"
|
|
486
599
|
});
|
|
487
600
|
return normalizeSnapshot2(raw);
|
|
488
601
|
};
|
|
489
602
|
var retrieve2 = async (id, credentials) => {
|
|
490
|
-
const
|
|
603
|
+
const operationId = assertPrefixedProviderId("Google operation id", id, GOOGLE_BATCH_PREFIX);
|
|
604
|
+
const raw = await requestJson(`${baseUrl2(credentials)}/${operationId}`, {
|
|
491
605
|
headers: headers2(credentials)
|
|
492
606
|
});
|
|
493
607
|
return normalizeSnapshot2(raw);
|
|
@@ -510,7 +624,8 @@ async function* results2(id, credentials) {
|
|
|
510
624
|
}
|
|
511
625
|
}
|
|
512
626
|
var cancel2 = async (id, credentials) => {
|
|
513
|
-
|
|
627
|
+
const operationId = assertPrefixedProviderId("Google operation id", id, GOOGLE_BATCH_PREFIX);
|
|
628
|
+
await requestJson(`${baseUrl2(credentials)}/${operationId}:cancel`, {
|
|
514
629
|
headers: headers2(credentials),
|
|
515
630
|
method: "POST"
|
|
516
631
|
});
|
|
@@ -669,6 +784,7 @@ var createOpenAICompatibleAdapter = (config) => {
|
|
|
669
784
|
...credentials.headers
|
|
670
785
|
});
|
|
671
786
|
const submit3 = async (input) => {
|
|
787
|
+
const limits = resolveBatchLimits(input.limits);
|
|
672
788
|
const endpoint = config.normalizeEndpoint ? config.normalizeEndpoint(input.endpoint) : input.endpoint;
|
|
673
789
|
const jsonl = encodeJsonl(input.built.map((item) => {
|
|
674
790
|
const body = omit(item.body, "stream");
|
|
@@ -682,6 +798,7 @@ var createOpenAICompatibleAdapter = (config) => {
|
|
|
682
798
|
url: endpoint
|
|
683
799
|
};
|
|
684
800
|
}));
|
|
801
|
+
assertByteLength("batch upload JSONL", jsonl, limits.maxUploadBytes);
|
|
685
802
|
const headers3 = authHeaders(input.credentials);
|
|
686
803
|
const url = baseUrl3(input.credentials);
|
|
687
804
|
const purpose = config.filePurpose ?? "batch";
|
|
@@ -699,7 +816,8 @@ var createOpenAICompatibleAdapter = (config) => {
|
|
|
699
816
|
return normalizeSnapshot3(raw, config.id);
|
|
700
817
|
};
|
|
701
818
|
const retrieve3 = async (id, credentials) => {
|
|
702
|
-
const
|
|
819
|
+
const batchId = assertSimpleProviderId(`${config.id} batch id`, id);
|
|
820
|
+
const raw = await requestJson(`${baseUrl3(credentials)}/batches/${batchId}`, {
|
|
703
821
|
headers: authHeaders(credentials)
|
|
704
822
|
});
|
|
705
823
|
return normalizeSnapshot3(raw, config.id);
|
|
@@ -714,14 +832,15 @@ var createOpenAICompatibleAdapter = (config) => {
|
|
|
714
832
|
}
|
|
715
833
|
const headers3 = authHeaders(credentials);
|
|
716
834
|
if (outputFileId) {
|
|
717
|
-
yield* streamResultFile(outputFileId, baseUrl3(credentials), headers3);
|
|
835
|
+
yield* streamResultFile(assertSimpleProviderId(`${config.id} output file id`, outputFileId), baseUrl3(credentials), headers3);
|
|
718
836
|
}
|
|
719
837
|
if (errorFileId) {
|
|
720
|
-
yield* streamResultFile(errorFileId, baseUrl3(credentials), headers3);
|
|
838
|
+
yield* streamResultFile(assertSimpleProviderId(`${config.id} error file id`, errorFileId), baseUrl3(credentials), headers3);
|
|
721
839
|
}
|
|
722
840
|
}
|
|
723
841
|
const cancel3 = async (id, credentials) => {
|
|
724
|
-
|
|
842
|
+
const batchId = assertSimpleProviderId(`${config.id} batch id`, id);
|
|
843
|
+
await requestJson(`${baseUrl3(credentials)}/batches/${batchId}/cancel`, {
|
|
725
844
|
headers: authHeaders(credentials),
|
|
726
845
|
method: "POST"
|
|
727
846
|
});
|
|
@@ -776,10 +895,11 @@ var normalizeSnapshot4 = (raw) => {
|
|
|
776
895
|
const obj = asRecord(raw);
|
|
777
896
|
const succeeded = asNumber(obj.succeeded_requests) ?? 0;
|
|
778
897
|
const failed = asNumber(obj.failed_requests) ?? 0;
|
|
898
|
+
const id = asString(obj.id) ?? "";
|
|
779
899
|
return {
|
|
780
900
|
completedAt: toDate(obj.completed_at),
|
|
781
901
|
createdAt: toDate(obj.created_at),
|
|
782
|
-
id:
|
|
902
|
+
id: id ? assertSimpleProviderId("Mistral job id", id) : "",
|
|
783
903
|
provider: "mistral",
|
|
784
904
|
raw,
|
|
785
905
|
requestCounts: {
|
|
@@ -791,10 +911,12 @@ var normalizeSnapshot4 = (raw) => {
|
|
|
791
911
|
};
|
|
792
912
|
};
|
|
793
913
|
var submit3 = async (input) => {
|
|
914
|
+
const limits = resolveBatchLimits(input.limits);
|
|
794
915
|
const jsonl = encodeJsonl(input.built.map((item) => ({
|
|
795
916
|
body: omit(omit(item.body, "stream"), "model"),
|
|
796
917
|
custom_id: item.customId
|
|
797
918
|
})));
|
|
919
|
+
assertByteLength("batch upload JSONL", jsonl, limits.maxUploadBytes);
|
|
798
920
|
const inputFileId = await uploadInputFile(jsonl, baseUrl3(input.credentials), authHeaders(input.credentials));
|
|
799
921
|
const raw = await requestJson(`${baseUrl3(input.credentials)}/batch/jobs`, {
|
|
800
922
|
body: JSON.stringify({
|
|
@@ -812,7 +934,8 @@ var submit3 = async (input) => {
|
|
|
812
934
|
return normalizeSnapshot4(raw);
|
|
813
935
|
};
|
|
814
936
|
var retrieve3 = async (id, credentials) => {
|
|
815
|
-
const
|
|
937
|
+
const jobId = assertSimpleProviderId("Mistral job id", id);
|
|
938
|
+
const raw = await requestJson(`${baseUrl3(credentials)}/batch/jobs/${jobId}`, {
|
|
816
939
|
headers: authHeaders(credentials)
|
|
817
940
|
});
|
|
818
941
|
return normalizeSnapshot4(raw);
|
|
@@ -824,17 +947,18 @@ async function* results3(id, credentials) {
|
|
|
824
947
|
const errorFileId = asString(raw.error_file);
|
|
825
948
|
const headers3 = authHeaders(credentials);
|
|
826
949
|
if (outputFileId) {
|
|
827
|
-
yield* streamResultFile(outputFileId, baseUrl3(credentials), headers3);
|
|
950
|
+
yield* streamResultFile(assertSimpleProviderId("Mistral output file id", outputFileId), baseUrl3(credentials), headers3);
|
|
828
951
|
}
|
|
829
952
|
if (errorFileId) {
|
|
830
|
-
yield* streamResultFile(errorFileId, baseUrl3(credentials), headers3);
|
|
953
|
+
yield* streamResultFile(assertSimpleProviderId("Mistral error file id", errorFileId), baseUrl3(credentials), headers3);
|
|
831
954
|
}
|
|
832
955
|
if (!(outputFileId || errorFileId)) {
|
|
833
956
|
throw new BatchworkError(`batchwork: results are not ready for batch "${id}" (status: ${snapshot.status}).`);
|
|
834
957
|
}
|
|
835
958
|
}
|
|
836
959
|
var cancel3 = async (id, credentials) => {
|
|
837
|
-
|
|
960
|
+
const jobId = assertSimpleProviderId("Mistral job id", id);
|
|
961
|
+
await requestJson(`${baseUrl3(credentials)}/batch/jobs/${jobId}/cancel`, {
|
|
838
962
|
headers: authHeaders(credentials),
|
|
839
963
|
method: "POST"
|
|
840
964
|
});
|
|
@@ -859,12 +983,41 @@ var openaiAdapter = createOpenAICompatibleAdapter({
|
|
|
859
983
|
// src/providers/together.ts
|
|
860
984
|
var INPUT_FILE_NAME = "batchwork.jsonl";
|
|
861
985
|
var HTTP_FOUND = 302;
|
|
862
|
-
var
|
|
986
|
+
var parseIpv4 = (host) => {
|
|
987
|
+
if (!/^\d{1,3}(?:\.\d{1,3}){3}$/u.test(host)) {
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
const parts = host.split(".").map(Number);
|
|
991
|
+
const valid = parts.every((part) => Number.isInteger(part) && part >= 0 && part <= 255);
|
|
992
|
+
return valid ? parts : undefined;
|
|
993
|
+
};
|
|
994
|
+
var isPrivateIpv4 = (parts) => {
|
|
995
|
+
const [a = 0, b = 0] = parts;
|
|
996
|
+
return a === 0 || a === 10 || a === 127 || a === 100 && b >= 64 && b <= 127 || a === 169 && b === 254 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168 || a === 198 && (b === 18 || b === 19) || a >= 224;
|
|
997
|
+
};
|
|
998
|
+
var isPrivateIpv6 = (host) => {
|
|
999
|
+
const normalized = host.replace(/^\[/u, "").replace(/\]$/u, "").toLowerCase();
|
|
1000
|
+
return normalized === "::" || normalized === "::1" || normalized.startsWith("fc") || normalized.startsWith("fd") || normalized.startsWith("fe80:");
|
|
1001
|
+
};
|
|
1002
|
+
var validateUploadLocation = (location) => {
|
|
1003
|
+
let url;
|
|
863
1004
|
try {
|
|
864
|
-
|
|
865
|
-
} catch {
|
|
866
|
-
|
|
1005
|
+
url = new URL(location);
|
|
1006
|
+
} catch (error) {
|
|
1007
|
+
throw new BatchworkError("batchwork: Together upload Location must be a valid URL.", { cause: error });
|
|
1008
|
+
}
|
|
1009
|
+
if (url.protocol !== "https:") {
|
|
1010
|
+
throw new BatchworkError("batchwork: Together upload Location must use https.");
|
|
1011
|
+
}
|
|
1012
|
+
if (url.username || url.password) {
|
|
1013
|
+
throw new BatchworkError("batchwork: Together upload Location must not include credentials.");
|
|
867
1014
|
}
|
|
1015
|
+
const host = url.hostname.toLowerCase();
|
|
1016
|
+
const ipv4 = parseIpv4(host);
|
|
1017
|
+
if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local") || ipv4 && isPrivateIpv4(ipv4) || isPrivateIpv6(host)) {
|
|
1018
|
+
throw new BatchworkError("batchwork: Together upload Location must not target localhost or private networks.");
|
|
1019
|
+
}
|
|
1020
|
+
return url.toString();
|
|
868
1021
|
};
|
|
869
1022
|
var uploadTogetherFile = async (args) => {
|
|
870
1023
|
const metadata = new FormData;
|
|
@@ -880,17 +1033,22 @@ var uploadTogetherFile = async (args) => {
|
|
|
880
1033
|
const location = init.headers.get("location");
|
|
881
1034
|
const fileId = init.headers.get("x-together-file-id");
|
|
882
1035
|
if (init.status !== HTTP_FOUND || !(location && fileId)) {
|
|
883
|
-
throw new BatchworkError(`batchwork: Together upload could not be initiated (${init.status})
|
|
1036
|
+
throw new BatchworkError(`batchwork: Together upload could not be initiated (${init.status}).`);
|
|
884
1037
|
}
|
|
885
|
-
const
|
|
1038
|
+
const uploadLocation = validateUploadLocation(location);
|
|
1039
|
+
const upload = await fetch(uploadLocation, {
|
|
1040
|
+
body: args.jsonl,
|
|
1041
|
+
method: "PUT"
|
|
1042
|
+
});
|
|
886
1043
|
if (!upload.ok) {
|
|
887
|
-
throw new BatchworkError(`batchwork: Together file upload failed (${upload.status})
|
|
1044
|
+
throw new BatchworkError(`batchwork: Together file upload failed (${upload.status}).`);
|
|
888
1045
|
}
|
|
889
|
-
|
|
1046
|
+
const safeFileId = assertSimpleProviderId("Together file id", fileId);
|
|
1047
|
+
await requestJson(`${args.baseUrl}/files/${safeFileId}/preprocess`, {
|
|
890
1048
|
headers: args.headers,
|
|
891
1049
|
method: "POST"
|
|
892
1050
|
});
|
|
893
|
-
return
|
|
1051
|
+
return safeFileId;
|
|
894
1052
|
};
|
|
895
1053
|
var togetherAdapter = createOpenAICompatibleAdapter({
|
|
896
1054
|
apiKeyEnv: "TOGETHER_API_KEY",
|
|
@@ -932,11 +1090,12 @@ var deriveStatus = (state) => {
|
|
|
932
1090
|
var normalizeSnapshot5 = (raw) => {
|
|
933
1091
|
const obj = asRecord(raw);
|
|
934
1092
|
const state = asRecord(obj.state);
|
|
1093
|
+
const id = asString(obj.batch_id) ?? asString(obj.id) ?? "";
|
|
935
1094
|
return {
|
|
936
1095
|
completedAt: toDate(obj.cancel_time),
|
|
937
1096
|
createdAt: toDate(obj.create_time),
|
|
938
1097
|
expiresAt: toDate(obj.expire_time ?? obj.expires_at),
|
|
939
|
-
id:
|
|
1098
|
+
id: id ? assertSimpleProviderId("xAI batch id", id) : "",
|
|
940
1099
|
provider: "xai",
|
|
941
1100
|
raw,
|
|
942
1101
|
requestCounts: {
|
|
@@ -977,12 +1136,14 @@ var normalizeResult3 = (item) => {
|
|
|
977
1136
|
};
|
|
978
1137
|
};
|
|
979
1138
|
var submit4 = async (input) => {
|
|
1139
|
+
const limits = resolveBatchLimits(input.limits);
|
|
980
1140
|
const jsonl = encodeJsonl(input.built.map((item) => ({
|
|
981
1141
|
body: omit(item.body, "stream"),
|
|
982
1142
|
custom_id: item.customId,
|
|
983
1143
|
method: "POST",
|
|
984
1144
|
url: input.endpoint
|
|
985
1145
|
})));
|
|
1146
|
+
assertByteLength("batch upload JSONL", jsonl, limits.maxUploadBytes);
|
|
986
1147
|
const inputFileId = await uploadInputFile(jsonl, baseUrl4(input.credentials), authHeaders2(input.credentials), { purpose: null });
|
|
987
1148
|
const raw = await requestJson(`${baseUrl4(input.credentials)}/batches`, {
|
|
988
1149
|
body: JSON.stringify({ input_file_id: inputFileId, name: "batchwork" }),
|
|
@@ -995,12 +1156,14 @@ var submit4 = async (input) => {
|
|
|
995
1156
|
return normalizeSnapshot5(raw);
|
|
996
1157
|
};
|
|
997
1158
|
var retrieve4 = async (id, credentials) => {
|
|
998
|
-
const
|
|
1159
|
+
const batchId = assertSimpleProviderId("xAI batch id", id);
|
|
1160
|
+
const raw = await requestJson(`${baseUrl4(credentials)}/batches/${batchId}`, {
|
|
999
1161
|
headers: authHeaders2(credentials)
|
|
1000
1162
|
});
|
|
1001
1163
|
return normalizeSnapshot5(raw);
|
|
1002
1164
|
};
|
|
1003
1165
|
async function* results4(id, credentials) {
|
|
1166
|
+
const batchId = assertSimpleProviderId("xAI batch id", id);
|
|
1004
1167
|
const headers3 = authHeaders2(credentials);
|
|
1005
1168
|
let token;
|
|
1006
1169
|
do {
|
|
@@ -1008,7 +1171,7 @@ async function* results4(id, credentials) {
|
|
|
1008
1171
|
if (token) {
|
|
1009
1172
|
query.set("pagination_token", token);
|
|
1010
1173
|
}
|
|
1011
|
-
const raw = await requestJson(`${baseUrl4(credentials)}/batches/${
|
|
1174
|
+
const raw = await requestJson(`${baseUrl4(credentials)}/batches/${batchId}/results?${query.toString()}`, { headers: headers3 });
|
|
1012
1175
|
const page = asRecord(raw);
|
|
1013
1176
|
for (const item of Array.isArray(page.results) ? page.results : []) {
|
|
1014
1177
|
yield normalizeResult3(item);
|
|
@@ -1017,7 +1180,8 @@ async function* results4(id, credentials) {
|
|
|
1017
1180
|
} while (token);
|
|
1018
1181
|
}
|
|
1019
1182
|
var cancel4 = async (id, credentials) => {
|
|
1020
|
-
|
|
1183
|
+
const batchId = assertSimpleProviderId("xAI batch id", id);
|
|
1184
|
+
await requestJson(`${baseUrl4(credentials)}/batches/${batchId}:cancel`, {
|
|
1021
1185
|
headers: authHeaders2(credentials),
|
|
1022
1186
|
method: "POST"
|
|
1023
1187
|
});
|
|
@@ -1042,7 +1206,7 @@ var adapters = {
|
|
|
1042
1206
|
};
|
|
1043
1207
|
var getAdapter = (provider) => adapters[provider];
|
|
1044
1208
|
|
|
1045
|
-
export { BatchworkError, UnsupportedProviderError, MissingDependencyError, isTerminalStatus, BatchJob, getAdapter };
|
|
1209
|
+
export { BatchworkError, UnsupportedProviderError, MissingDependencyError, resolveBatchLimits, assertByteLength, mapWithConcurrency, isTerminalStatus, BatchJob, getAdapter };
|
|
1046
1210
|
|
|
1047
|
-
//# debugId=
|
|
1048
|
-
//# sourceMappingURL=chunk-
|
|
1211
|
+
//# debugId=A38719FEA6433ECA64756E2164756E21
|
|
1212
|
+
//# sourceMappingURL=chunk-g481f961.js.map
|