batchwork 1.4.0 → 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.
Files changed (61) hide show
  1. package/dist/body.d.ts +2 -2
  2. package/dist/body.d.ts.map +1 -1
  3. package/dist/chunk-6jgvqdpc.js +52 -0
  4. package/dist/chunk-6jgvqdpc.js.map +11 -0
  5. package/dist/{chunk-vy4w8mpb.js → chunk-7y95mhvm.js} +119 -151
  6. package/dist/chunk-7y95mhvm.js.map +27 -0
  7. package/dist/{chunk-ka9d4t6v.js → chunk-k7n7k3et.js} +66 -152
  8. package/dist/chunk-k7n7k3et.js.map +13 -0
  9. package/dist/{chunk-2ea62n95.js → chunk-zss8h417.js} +213 -200
  10. package/dist/chunk-zss8h417.js.map +12 -0
  11. package/dist/guards.d.ts +5 -0
  12. package/dist/guards.d.ts.map +1 -0
  13. package/dist/http.d.ts +3 -2
  14. package/dist/http.d.ts.map +1 -1
  15. package/dist/index.d.ts +1 -1
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +27 -28
  18. package/dist/index.js.map +1 -1
  19. package/dist/jsonl.d.ts +3 -2
  20. package/dist/jsonl.d.ts.map +1 -1
  21. package/dist/limits.d.ts +0 -1
  22. package/dist/limits.d.ts.map +1 -1
  23. package/dist/model.d.ts +48 -1
  24. package/dist/model.d.ts.map +1 -1
  25. package/dist/next/index.d.ts +1 -1
  26. package/dist/next/index.d.ts.map +1 -1
  27. package/dist/next/index.js +14 -20
  28. package/dist/next/index.js.map +3 -3
  29. package/dist/postgres/batch-store.d.ts.map +1 -1
  30. package/dist/postgres/index.js +22 -15
  31. package/dist/postgres/index.js.map +4 -4
  32. package/dist/postgres/types.d.ts +1 -1
  33. package/dist/postgres/types.d.ts.map +1 -1
  34. package/dist/providers/anthropic.d.ts.map +1 -1
  35. package/dist/providers/azure.d.ts.map +1 -1
  36. package/dist/providers/google.d.ts.map +1 -1
  37. package/dist/providers/mistral.d.ts.map +1 -1
  38. package/dist/providers/openai-compatible.d.ts +2 -2
  39. package/dist/providers/openai-compatible.d.ts.map +1 -1
  40. package/dist/providers/shared.d.ts +8 -8
  41. package/dist/providers/shared.d.ts.map +1 -1
  42. package/dist/providers/xai.d.ts.map +1 -1
  43. package/dist/redis/index.js +40 -6
  44. package/dist/redis/index.js.map +4 -4
  45. package/dist/redis/types.d.ts +18 -5
  46. package/dist/redis/types.d.ts.map +1 -1
  47. package/dist/server/index.js +13 -14
  48. package/dist/server/index.js.map +1 -1
  49. package/dist/server/poller.d.ts +6 -4
  50. package/dist/server/poller.d.ts.map +1 -1
  51. package/dist/server/signing.d.ts.map +1 -1
  52. package/dist/types.d.ts +16 -2
  53. package/dist/types.d.ts.map +1 -1
  54. package/dist/util.d.ts +18 -7
  55. package/dist/util.d.ts.map +1 -1
  56. package/package.json +20 -17
  57. package/dist/chunk-2ea62n95.js.map +0 -12
  58. package/dist/chunk-ka9d4t6v.js.map +0 -13
  59. package/dist/chunk-v0bahtg2.js +0 -7
  60. package/dist/chunk-v0bahtg2.js.map +0 -9
  61. package/dist/chunk-vy4w8mpb.js.map +0 -28
@@ -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 BatchworkError extends Error {
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 UnsupportedProviderError extends BatchworkError {
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 MissingDependencyError extends BatchworkError {
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 isTerminalStatus = (status) => TERMINAL_STATUSES.has(status);
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 BatchworkError(WAIT_ABORTED_MESSAGE));
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 BatchworkError(WAIT_ABORTED_MESSAGE));
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 BatchJob {
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 (!isTerminalStatus(snapshot.status)) {
96
+ while (!isTerminalStatus2(snapshot.status)) {
84
97
  if (options.signal?.aborted) {
85
- throw new BatchworkError(WAIT_ABORTED_MESSAGE);
98
+ throw new BatchworkError2(WAIT_ABORTED_MESSAGE);
86
99
  }
87
100
  if (deadline !== undefined && Date.now() > deadline) {
88
- throw new BatchworkError(`batchwork: timed out waiting for batch "${this.id}".`);
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 BatchworkError(`batchwork: limits.${name} must be a positive integer.`);
135
+ throw new BatchworkError2(`batchwork: limits.${name} must be a positive integer.`);
123
136
  }
124
137
  return value;
125
138
  };
@@ -132,46 +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 BatchworkError(`batchwork: ${label} is ${bytes} bytes, exceeding the ${maxBytes} byte limit.`);
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
- var mapWithConcurrency = async (items, concurrency, mapper) => {
142
- const results = [];
143
- results.length = items.length;
144
- let nextIndex = 0;
145
- const workerCount = Math.min(concurrency, items.length);
146
- const runNext = async () => {
147
- const index = nextIndex;
148
- nextIndex += 1;
149
- if (index >= items.length) {
150
- return;
151
- }
152
- results[index] = await mapper(items[index]);
153
- await runNext();
154
- };
155
- await Promise.all(Array.from({ length: workerCount }, () => runNext()));
156
- return results;
157
- };
158
154
 
159
155
  // src/http.ts
160
156
  var assertOk = (url, init, response) => {
161
157
  if (!response.ok) {
162
- throw new BatchworkError(`batchwork: ${init.method ?? "GET"} ${url} failed with ${response.status}.`);
158
+ throw new BatchworkError2(`batchwork: ${init.method ?? "GET"} ${url} failed with ${response.status}.`);
163
159
  }
164
160
  };
165
161
  var requestJson = async (url, init) => {
166
162
  const response = await fetch(url, init);
167
163
  assertOk(url, init, response);
168
- return await response.json();
164
+ return parseJson(await response.text());
169
165
  };
170
166
  var requestStream = async (url, init) => {
171
167
  const response = await fetch(url, init);
172
168
  assertOk(url, init, response);
173
169
  if (!response.body) {
174
- throw new BatchworkError(`batchwork: ${url} returned an empty body.`);
170
+ throw new BatchworkError2(`batchwork: ${url} returned an empty body.`);
175
171
  }
176
172
  return response.body;
177
173
  };
@@ -184,14 +180,14 @@ var NEWLINE_BYTES = byteLength(NEWLINE);
184
180
  var resolveMaxLineBytes = (options) => {
185
181
  const maxLineBytes = options?.maxLineBytes ?? DEFAULT_MAX_JSONL_LINE_BYTES;
186
182
  if (!(Number.isInteger(maxLineBytes) && maxLineBytes > 0)) {
187
- throw new BatchworkError("batchwork: JSONL maxLineBytes must be a positive integer.");
183
+ throw new BatchworkError2("batchwork: JSONL maxLineBytes must be a positive integer.");
188
184
  }
189
185
  return maxLineBytes;
190
186
  };
191
187
  var assertLineSize = (line, lineNumber, maxLineBytes) => {
192
188
  const bytes = byteLength(line);
193
189
  if (bytes > maxLineBytes) {
194
- throw new BatchworkError(`batchwork: JSONL line ${lineNumber} is ${bytes} bytes, exceeding the ${maxLineBytes} byte limit.`);
190
+ throw new BatchworkError2(`batchwork: JSONL line ${lineNumber} is ${bytes} bytes, exceeding the ${maxLineBytes} byte limit.`);
195
191
  }
196
192
  };
197
193
  var parseLine = (line, lineNumber, maxLineBytes) => {
@@ -201,15 +197,15 @@ var parseLine = (line, lineNumber, maxLineBytes) => {
201
197
  return;
202
198
  }
203
199
  try {
204
- return JSON.parse(trimmed);
200
+ return parseJson(trimmed);
205
201
  } catch (error) {
206
- throw new BatchworkError(`batchwork: invalid JSONL at line ${lineNumber}.`, { cause: error });
202
+ throw new BatchworkError2(`batchwork: invalid JSONL at line ${lineNumber}.`, { cause: error });
207
203
  }
208
204
  };
209
205
  var resolveMaxBytes = (options) => {
210
206
  const maxBytes = options?.maxBytes;
211
207
  if (maxBytes !== undefined && !(Number.isInteger(maxBytes) && maxBytes > 0)) {
212
- throw new BatchworkError("batchwork: JSONL maxBytes must be a positive integer.");
208
+ throw new BatchworkError2("batchwork: JSONL maxBytes must be a positive integer.");
213
209
  }
214
210
  return maxBytes;
215
211
  };
@@ -224,7 +220,7 @@ var encodeJsonl = (items, options) => {
224
220
  for (const item of items) {
225
221
  const line = JSON.stringify(item);
226
222
  if (line === undefined) {
227
- throw new BatchworkError(`batchwork: ${label} contains a value that cannot be JSON encoded.`);
223
+ throw new BatchworkError2(`batchwork: ${label} contains a value that cannot be JSON encoded.`);
228
224
  }
229
225
  bytes += byteLength(line) + NEWLINE_BYTES;
230
226
  if (maxBytes !== undefined) {
@@ -264,9 +260,9 @@ async function* streamJsonl(source, options) {
264
260
  while (newlineIndex !== -1) {
265
261
  const line = buffer.slice(0, newlineIndex);
266
262
  buffer = buffer.slice(newlineIndex + 1);
267
- const parsed2 = parseLine(line, lineNumber, maxLineBytes);
268
- if (parsed2 !== undefined) {
269
- yield parsed2;
263
+ const parsed = parseLine(line, lineNumber, maxLineBytes);
264
+ if (parsed !== undefined) {
265
+ yield parsed;
270
266
  }
271
267
  lineNumber += 1;
272
268
  newlineIndex = buffer.indexOf(NEWLINE);
@@ -294,7 +290,7 @@ var encodeJsonArrayPayload = ({
294
290
  for (const [index, item] of items.entries()) {
295
291
  const encoded = JSON.stringify(item);
296
292
  if (encoded === undefined) {
297
- throw new BatchworkError(`batchwork: ${label} contains a value that cannot be JSON encoded.`);
293
+ throw new BatchworkError2(`batchwork: ${label} contains a value that cannot be JSON encoded.`);
298
294
  }
299
295
  bytes += byteLength(encoded);
300
296
  if (index > 0) {
@@ -306,54 +302,18 @@ var encodeJsonArrayPayload = ({
306
302
  return `${prefix}${encodedItems.join(",")}${suffix}`;
307
303
  };
308
304
 
309
- // src/util.ts
310
- var asRecord = (value) => {
311
- if (typeof value === "object" && value !== null) {
312
- return value;
313
- }
314
- return {};
315
- };
316
- var asString = (value) => typeof value === "string" ? value : undefined;
317
- var asNumber = (value) => typeof value === "number" ? value : undefined;
318
- var asArray = (value) => Array.isArray(value) ? value : [];
319
- var asNumberArray = (value) => {
320
- if (!Array.isArray(value) || value.length === 0) {
321
- return;
322
- }
323
- const numbers = value.filter((item) => typeof item === "number");
324
- return numbers.length === value.length ? numbers : undefined;
325
- };
326
- var omit = (obj, key) => {
327
- const result = {};
328
- for (const [k, v] of Object.entries(obj)) {
329
- if (k !== key) {
330
- result[k] = v;
331
- }
332
- }
333
- return result;
334
- };
335
- var validDate = (date) => Number.isNaN(date.getTime()) ? undefined : date;
336
- var toDate = (value) => {
337
- if (typeof value === "string") {
338
- return validDate(new Date(value));
339
- }
340
- if (typeof value === "number") {
341
- return validDate(new Date(value * 1000));
342
- }
343
- };
344
-
345
305
  // src/providers/ids.ts
346
306
  var SIMPLE_PROVIDER_ID = /^[A-Za-z0-9_-]+$/u;
347
307
  var assertSimpleProviderId = (label, id) => {
348
308
  if (!SIMPLE_PROVIDER_ID.test(id)) {
349
- throw new BatchworkError(`batchwork: invalid ${label}.`);
309
+ throw new BatchworkError2(`batchwork: invalid ${label}.`);
350
310
  }
351
311
  return id;
352
312
  };
353
313
  var assertPrefixedProviderId = (label, id, prefix) => {
354
314
  const [actualPrefix, value, ...rest] = id.split("/");
355
315
  if (rest.length > 0 || actualPrefix !== prefix || !value || !SIMPLE_PROVIDER_ID.test(value)) {
356
- throw new BatchworkError(`batchwork: invalid ${label}.`);
316
+ throw new BatchworkError2(`batchwork: invalid ${label}.`);
357
317
  }
358
318
  return id;
359
319
  };
@@ -364,7 +324,7 @@ var ANTHROPIC_VERSION = "2023-06-01";
364
324
  var apiKey = (credentials) => {
365
325
  const key = credentials.apiKey ?? process.env.ANTHROPIC_API_KEY;
366
326
  if (!key) {
367
- throw new BatchworkError("batchwork: missing Anthropic API key. Set ANTHROPIC_API_KEY or pass `apiKey`.");
327
+ throw new BatchworkError2("batchwork: missing Anthropic API key. Set ANTHROPIC_API_KEY or pass `apiKey`.");
368
328
  }
369
329
  return key;
370
330
  };
@@ -376,15 +336,15 @@ var validateResultsUrl = (rawUrl, credentials) => {
376
336
  resultsUrl = new URL(rawUrl);
377
337
  expectedBase = new URL(baseUrl(credentials));
378
338
  } catch (error) {
379
- throw new BatchworkError("batchwork: invalid Anthropic results_url.", {
339
+ throw new BatchworkError2("batchwork: invalid Anthropic results_url.", {
380
340
  cause: error
381
341
  });
382
342
  }
383
343
  if (resultsUrl.origin !== expectedBase.origin) {
384
- throw new BatchworkError("batchwork: Anthropic results_url must match the configured API origin.");
344
+ throw new BatchworkError2("batchwork: Anthropic results_url must match the configured API origin.");
385
345
  }
386
346
  if (resultsUrl.username || resultsUrl.password) {
387
- throw new BatchworkError("batchwork: Anthropic results_url must not include credentials.");
347
+ throw new BatchworkError2("batchwork: Anthropic results_url must not include credentials.");
388
348
  }
389
349
  return resultsUrl.toString();
390
350
  };
@@ -514,7 +474,7 @@ async function* results(id, credentials) {
514
474
  const snapshot = await retrieve(id, credentials);
515
475
  const resultsUrl = asString(asRecord(snapshot.raw).results_url);
516
476
  if (!resultsUrl) {
517
- throw new BatchworkError(`batchwork: results are not ready for batch "${id}" (status: ${snapshot.status}).`);
477
+ throw new BatchworkError2(`batchwork: results are not ready for batch "${id}" (status: ${snapshot.status}).`);
518
478
  }
519
479
  const stream = await requestStream(validateResultsUrl(resultsUrl, credentials), {
520
480
  headers: headers(credentials),
@@ -545,7 +505,7 @@ var HTTP_OK_MAX = 300;
545
505
  var resolveApiKey = (credentials, envVar, label) => {
546
506
  const key = credentials.apiKey ?? process.env[envVar];
547
507
  if (!key) {
548
- throw new BatchworkError(`batchwork: missing ${label} API key. Set ${envVar} or pass \`apiKey\`.`);
508
+ throw new BatchworkError2(`batchwork: missing ${label} API key. Set ${envVar} or pass \`apiKey\`.`);
549
509
  }
550
510
  return key;
551
511
  };
@@ -622,14 +582,14 @@ var imagesFromBody = (body) => {
622
582
  return images.length > 0 ? images : undefined;
623
583
  };
624
584
  var moderationFromBody = (body) => {
625
- const results2 = asArray(asRecord(body).results);
626
- if (results2.length === 0) {
585
+ const results = asArray(asRecord(body).results);
586
+ if (results.length === 0) {
627
587
  return;
628
588
  }
629
- const first = asRecord(results2[0]);
589
+ const first = asRecord(results[0]);
630
590
  const categories = {};
631
591
  for (const [key, value] of Object.entries(asRecord(first.categories))) {
632
- if (typeof value === "boolean") {
592
+ if (isBoolean(value)) {
633
593
  categories[key] = value;
634
594
  }
635
595
  }
@@ -643,7 +603,7 @@ var moderationFromBody = (body) => {
643
603
  categoryScores[key] = score;
644
604
  }
645
605
  }
646
- const flagged = typeof first.flagged === "boolean" ? first.flagged : Object.values(categories).some(Boolean);
606
+ const flagged = isBoolean(first.flagged) ? first.flagged : Object.values(categories).some(Boolean);
647
607
  return { categories, categoryScores, flagged };
648
608
  };
649
609
  var usageFromBody = (body) => {
@@ -703,24 +663,28 @@ var normalizeOpenAIResult = (line) => {
703
663
  status: "errored"
704
664
  };
705
665
  };
706
- var uploadInputFile = async (jsonl, baseUrl2, headers2, options = {}) => {
666
+ var uploadInputFile = async (jsonl, baseUrl, headers, options = {}) => {
707
667
  const form = new FormData;
708
668
  const purpose = options.purpose === undefined ? "batch" : options.purpose;
709
669
  if (purpose !== null) {
710
670
  form.append("purpose", purpose);
711
671
  }
712
672
  form.append("file", new Blob([jsonl], { type: "application/jsonl" }), "batchwork.jsonl");
713
- const raw = await requestJson(`${baseUrl2}/files`, {
673
+ const raw = await requestJson(`${baseUrl}/files`, {
714
674
  body: form,
715
- headers: headers2,
675
+ headers,
716
676
  method: "POST",
717
677
  redirect: "manual"
718
678
  });
719
- return raw.id;
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;
720
684
  };
721
- async function* streamResultFile(fileId, baseUrl2, headers2) {
722
- const stream = await requestStream(`${baseUrl2}/files/${fileId}/content`, {
723
- headers: headers2,
685
+ async function* streamResultFile(fileId, baseUrl, headers) {
686
+ const stream = await requestStream(`${baseUrl}/files/${fileId}/content`, {
687
+ headers,
724
688
  redirect: "manual"
725
689
  });
726
690
  for await (const line of streamJsonl(stream)) {
@@ -771,8 +735,8 @@ var normalizeSnapshot2 = (raw, provider) => {
771
735
  var createOpenAICompatibleAdapter = (config) => {
772
736
  const completionWindow = config.completionWindow ?? DEFAULT_COMPLETION_WINDOW;
773
737
  const lineFormat = config.lineFormat ?? "method-url";
774
- const baseUrl2 = (credentials) => config.resolveBaseUrl?.(credentials) ?? credentials.baseURL ?? config.baseUrl ?? (() => {
775
- throw new BatchworkError(`batchwork: missing ${config.apiKeyLabel} base URL. Pass \`baseURL\`.`);
738
+ const baseUrl = (credentials) => config.resolveBaseUrl?.(credentials) ?? credentials.baseURL ?? config.baseUrl ?? (() => {
739
+ throw new BatchworkError2(`batchwork: missing ${config.apiKeyLabel} base URL. Pass \`baseURL\`.`);
776
740
  })();
777
741
  const authHeaders = (credentials) => ({
778
742
  ...config.authHeaders ? config.authHeaders(credentials) : {
@@ -780,7 +744,7 @@ var createOpenAICompatibleAdapter = (config) => {
780
744
  },
781
745
  ...credentials.headers
782
746
  });
783
- const submit2 = async (input) => {
747
+ const submit = async (input) => {
784
748
  const limits = resolveBatchLimits(input.limits);
785
749
  const endpoint = config.normalizeEndpoint ? config.normalizeEndpoint(input.endpoint) : input.endpoint;
786
750
  const batchEndpoint = config.batchEndpoint?.(endpoint) ?? endpoint;
@@ -800,10 +764,10 @@ var createOpenAICompatibleAdapter = (config) => {
800
764
  url: endpoint
801
765
  };
802
766
  }), { label: "batch upload JSONL", maxBytes: limits.maxUploadBytes });
803
- const headers2 = authHeaders(input.credentials);
804
- const url = baseUrl2(input.credentials);
767
+ const headers = authHeaders(input.credentials);
768
+ const url = baseUrl(input.credentials);
805
769
  const purpose = config.filePurpose ?? "batch";
806
- const inputFileId = await (config.uploadFile ? config.uploadFile({ baseUrl: url, headers: headers2, jsonl, purpose }) : uploadInputFile(jsonl, url, headers2, { purpose }));
770
+ const inputFileId = await (config.uploadFile ? config.uploadFile({ baseUrl: url, headers, jsonl, purpose }) : uploadInputFile(jsonl, url, headers, { purpose }));
807
771
  const raw = await requestJson(`${url}/batches`, {
808
772
  body: JSON.stringify({
809
773
  completion_window: completionWindow,
@@ -811,46 +775,45 @@ var createOpenAICompatibleAdapter = (config) => {
811
775
  input_file_id: inputFileId,
812
776
  metadata: input.metadata
813
777
  }),
814
- headers: { ...headers2, "content-type": "application/json" },
778
+ headers: { ...headers, "content-type": "application/json" },
815
779
  method: "POST"
816
780
  });
817
781
  return normalizeSnapshot2(raw, config.id);
818
782
  };
819
- const retrieve2 = async (id, credentials) => {
783
+ const retrieve = async (id, credentials) => {
820
784
  const batchId = assertSimpleProviderId(`${config.id} batch id`, id);
821
- const raw = await requestJson(`${baseUrl2(credentials)}/batches/${batchId}`, {
785
+ const raw = await requestJson(`${baseUrl(credentials)}/batches/${batchId}`, {
822
786
  headers: authHeaders(credentials)
823
787
  });
824
788
  return normalizeSnapshot2(raw, config.id);
825
789
  };
826
- async function* results2(id, credentials) {
827
- const snapshot = await retrieve2(id, credentials);
790
+ async function* results(id, credentials) {
791
+ const snapshot = await retrieve(id, credentials);
828
792
  const raw = asRecord(snapshot.raw);
829
793
  const outputFileId = asString(raw.output_file_id);
830
794
  const errorFileId = asString(raw.error_file_id);
831
795
  if (!(outputFileId || errorFileId)) {
832
- throw new BatchworkError(`batchwork: results are not ready for batch "${id}" (status: ${snapshot.status}).`);
796
+ throw new BatchworkError2(`batchwork: results are not ready for batch "${id}" (status: ${snapshot.status}).`);
833
797
  }
834
- const headers2 = authHeaders(credentials);
798
+ const headers = authHeaders(credentials);
835
799
  if (outputFileId) {
836
- yield* streamResultFile(assertSimpleProviderId(`${config.id} output file id`, outputFileId), baseUrl2(credentials), headers2);
800
+ yield* streamResultFile(assertSimpleProviderId(`${config.id} output file id`, outputFileId), baseUrl(credentials), headers);
837
801
  }
838
802
  if (errorFileId) {
839
- yield* streamResultFile(assertSimpleProviderId(`${config.id} error file id`, errorFileId), baseUrl2(credentials), headers2);
803
+ yield* streamResultFile(assertSimpleProviderId(`${config.id} error file id`, errorFileId), baseUrl(credentials), headers);
840
804
  }
841
805
  }
842
- const cancel2 = async (id, credentials) => {
806
+ const cancel = async (id, credentials) => {
843
807
  const batchId = assertSimpleProviderId(`${config.id} batch id`, id);
844
- await requestJson(`${baseUrl2(credentials)}/batches/${batchId}/cancel`, {
808
+ await requestJson(`${baseUrl(credentials)}/batches/${batchId}/cancel`, {
845
809
  headers: authHeaders(credentials),
846
810
  method: "POST"
847
811
  });
848
812
  };
849
- return { cancel: cancel2, id: config.id, results: results2, retrieve: retrieve2, submit: submit2 };
813
+ return { cancel, id: config.id, results, retrieve, submit };
850
814
  };
851
815
 
852
816
  // src/providers/azure.ts
853
- var withoutTrailingSlash = (value) => value.replace(/\/+$/u, "");
854
817
  var isAzureOpenAIUrl = (value) => {
855
818
  try {
856
819
  return new URL(value).hostname.endsWith(".openai.azure.com");
@@ -861,9 +824,9 @@ var isAzureOpenAIUrl = (value) => {
861
824
  var baseUrl2 = (credentials) => {
862
825
  const configured = credentials.baseURL ?? (process.env.AZURE_RESOURCE_NAME ? `https://${process.env.AZURE_RESOURCE_NAME}.openai.azure.com/openai` : undefined);
863
826
  if (!configured) {
864
- throw new BatchworkError("batchwork: missing Azure OpenAI resource. Set AZURE_RESOURCE_NAME or pass `baseURL`.");
827
+ throw new BatchworkError2("batchwork: missing Azure OpenAI resource. Set AZURE_RESOURCE_NAME or pass `baseURL`.");
865
828
  }
866
- const normalized = withoutTrailingSlash(configured);
829
+ const normalized = trimTrailingSlashes(configured);
867
830
  if (!isAzureOpenAIUrl(normalized)) {
868
831
  return normalized;
869
832
  }
@@ -872,7 +835,7 @@ var baseUrl2 = (credentials) => {
872
835
  }
873
836
  return normalized.endsWith("/openai") ? `${normalized}/v1` : `${normalized}/openai/v1`;
874
837
  };
875
- var hasCallerAuth = (headers2) => Object.keys(headers2 ?? {}).some((name) => {
838
+ var hasCallerAuth = (headers) => Object.keys(headers ?? {}).some((name) => {
876
839
  const normalized = name.toLowerCase();
877
840
  return normalized === "api-key" || normalized === "authorization";
878
841
  });
@@ -883,11 +846,11 @@ var authHeaders = (credentials) => {
883
846
  if (hasCallerAuth(credentials.headers)) {
884
847
  return {};
885
848
  }
886
- const apiKey2 = process.env.AZURE_API_KEY ?? process.env.AZURE_OPENAI_API_KEY;
887
- if (apiKey2) {
888
- return { "api-key": apiKey2 };
849
+ const apiKey = process.env.AZURE_API_KEY ?? process.env.AZURE_OPENAI_API_KEY;
850
+ if (apiKey) {
851
+ return { "api-key": apiKey };
889
852
  }
890
- throw new BatchworkError("batchwork: missing Azure OpenAI API key. Set AZURE_API_KEY or pass `apiKey`.");
853
+ throw new BatchworkError2("batchwork: missing Azure OpenAI API key. Set AZURE_API_KEY or pass `apiKey`.");
891
854
  };
892
855
  var azureAdapter = createOpenAICompatibleAdapter({
893
856
  apiKeyEnv: "AZURE_API_KEY",
@@ -906,7 +869,7 @@ var GOOGLE_BATCH_PREFIX = "batches";
906
869
  var apiKey2 = (credentials) => {
907
870
  const key = credentials.apiKey ?? process.env.GOOGLE_GENERATIVE_AI_API_KEY ?? process.env.GEMINI_API_KEY;
908
871
  if (!key) {
909
- throw new BatchworkError("batchwork: missing Google Gemini API key. Set GOOGLE_GENERATIVE_AI_API_KEY (or GEMINI_API_KEY) or pass `apiKey`.");
872
+ throw new BatchworkError2("batchwork: missing Google Gemini API key. Set GOOGLE_GENERATIVE_AI_API_KEY (or GEMINI_API_KEY) or pass `apiKey`.");
910
873
  }
911
874
  return key;
912
875
  };
@@ -1093,11 +1056,11 @@ async function* results2(id, credentials) {
1093
1056
  const dest = asRecord(raw.dest);
1094
1057
  const responsesFile = fileNameFrom(response.responsesFile) ?? fileNameFrom(response.responses_file) ?? asString(dest.fileName) ?? asString(dest.file_name);
1095
1058
  if (responsesFile) {
1096
- throw new BatchworkError(`batchwork: batch "${id}" returned file-mode results, which are not supported yet.`);
1059
+ throw new BatchworkError2(`batchwork: batch "${id}" returned file-mode results, which are not supported yet.`);
1097
1060
  }
1098
1061
  const items = inlinedResponses(raw);
1099
1062
  if (items.length === 0) {
1100
- throw new BatchworkError(`batchwork: results are not ready for batch "${id}" (status: ${snapshot.status}).`);
1063
+ throw new BatchworkError2(`batchwork: results are not ready for batch "${id}" (status: ${snapshot.status}).`);
1101
1064
  }
1102
1065
  for (const item of items) {
1103
1066
  yield normalizeResult2(item);
@@ -1215,15 +1178,15 @@ async function* results3(id, credentials) {
1215
1178
  const raw = asRecord(snapshot.raw);
1216
1179
  const outputFileId = asString(raw.output_file);
1217
1180
  const errorFileId = asString(raw.error_file);
1218
- const headers3 = authHeaders2(credentials);
1181
+ const headers = authHeaders2(credentials);
1219
1182
  if (outputFileId) {
1220
- yield* streamResultFile(assertSimpleProviderId("Mistral output file id", outputFileId), baseUrl4(credentials), headers3);
1183
+ yield* streamResultFile(assertSimpleProviderId("Mistral output file id", outputFileId), baseUrl4(credentials), headers);
1221
1184
  }
1222
1185
  if (errorFileId) {
1223
- yield* streamResultFile(assertSimpleProviderId("Mistral error file id", errorFileId), baseUrl4(credentials), headers3);
1186
+ yield* streamResultFile(assertSimpleProviderId("Mistral error file id", errorFileId), baseUrl4(credentials), headers);
1224
1187
  }
1225
1188
  if (!(outputFileId || errorFileId)) {
1226
- throw new BatchworkError(`batchwork: results are not ready for batch "${id}" (status: ${snapshot.status}).`);
1189
+ throw new BatchworkError2(`batchwork: results are not ready for batch "${id}" (status: ${snapshot.status}).`);
1227
1190
  }
1228
1191
  }
1229
1192
  var cancel3 = async (id, credentials) => {
@@ -1309,16 +1272,16 @@ var validateUploadLocation = (location) => {
1309
1272
  try {
1310
1273
  url = new URL(location);
1311
1274
  } catch (error) {
1312
- throw new BatchworkError("batchwork: Together upload Location must be a valid URL.", { cause: error });
1275
+ throw new BatchworkError2("batchwork: Together upload Location must be a valid URL.", { cause: error });
1313
1276
  }
1314
1277
  if (url.protocol !== "https:") {
1315
- throw new BatchworkError("batchwork: Together upload Location must use https.");
1278
+ throw new BatchworkError2("batchwork: Together upload Location must use https.");
1316
1279
  }
1317
1280
  if (url.username || url.password) {
1318
- throw new BatchworkError("batchwork: Together upload Location must not include credentials.");
1281
+ throw new BatchworkError2("batchwork: Together upload Location must not include credentials.");
1319
1282
  }
1320
1283
  if (isPrivateHost(url.hostname.toLowerCase())) {
1321
- throw new BatchworkError("batchwork: Together upload Location must not target localhost or private networks.");
1284
+ throw new BatchworkError2("batchwork: Together upload Location must not target localhost or private networks.");
1322
1285
  }
1323
1286
  return url.toString();
1324
1287
  };
@@ -1336,7 +1299,7 @@ var uploadTogetherFile = async (args) => {
1336
1299
  const location = init.headers.get("location");
1337
1300
  const fileId = init.headers.get("x-together-file-id");
1338
1301
  if (init.status !== HTTP_FOUND || !(location && fileId)) {
1339
- throw new BatchworkError(`batchwork: Together upload could not be initiated (${init.status}).`);
1302
+ throw new BatchworkError2(`batchwork: Together upload could not be initiated (${init.status}).`);
1340
1303
  }
1341
1304
  const uploadLocation = validateUploadLocation(location);
1342
1305
  const upload = await fetch(uploadLocation, {
@@ -1345,7 +1308,7 @@ var uploadTogetherFile = async (args) => {
1345
1308
  redirect: "manual"
1346
1309
  });
1347
1310
  if (!upload.ok) {
1348
- throw new BatchworkError(`batchwork: Together file upload failed (${upload.status}).`);
1311
+ throw new BatchworkError2(`batchwork: Together file upload failed (${upload.status}).`);
1349
1312
  }
1350
1313
  const safeFileId = assertSimpleProviderId("Together file id", fileId);
1351
1314
  await requestJson(`${args.baseUrl}/files/${safeFileId}/preprocess`, {
@@ -1424,10 +1387,14 @@ var imagesFromXaiCompletion = (completion) => {
1424
1387
  const data = asString(record.base64) ?? asString(record.b64_json);
1425
1388
  const url = asString(record.url);
1426
1389
  if (data || url) {
1427
- images.push({
1428
- ...data ? { data } : {},
1429
- ...url ? { url } : {}
1430
- });
1390
+ const image = {};
1391
+ if (data) {
1392
+ image.data = data;
1393
+ }
1394
+ if (url) {
1395
+ image.url = url;
1396
+ }
1397
+ images.push(image);
1431
1398
  }
1432
1399
  }
1433
1400
  return images.length > 0 ? images : undefined;
@@ -1442,11 +1409,12 @@ var videosFromXaiCompletion = (completion) => {
1442
1409
  const video = asRecord(record.video);
1443
1410
  const url = asString(video.url) ?? asString(record.url);
1444
1411
  if (url) {
1412
+ const entry = { url };
1445
1413
  const duration = asNumber(video.duration) ?? asNumber(record.duration);
1446
- videos.push({
1447
- ...duration === undefined ? {} : { durationSeconds: duration },
1448
- url
1449
- });
1414
+ if (duration !== undefined) {
1415
+ entry.durationSeconds = duration;
1416
+ }
1417
+ videos.push(entry);
1450
1418
  }
1451
1419
  }
1452
1420
  return videos.length > 0 ? videos : undefined;
@@ -1509,16 +1477,16 @@ var retrieve4 = async (id, credentials) => {
1509
1477
  };
1510
1478
  async function* results4(id, credentials) {
1511
1479
  const batchId = assertSimpleProviderId(BATCH_ID_LABEL, id);
1512
- const headers3 = authHeaders3(credentials);
1480
+ const headers = authHeaders3(credentials);
1513
1481
  let token;
1514
1482
  do {
1515
1483
  const query = new URLSearchParams({ limit: String(RESULTS_PAGE_SIZE) });
1516
1484
  if (token) {
1517
1485
  query.set("pagination_token", token);
1518
1486
  }
1519
- const raw = await requestJson(`${baseUrl5(credentials)}/batches/${batchId}/results?${query.toString()}`, { headers: headers3 });
1487
+ const raw = await requestJson(`${baseUrl5(credentials)}/batches/${batchId}/results?${query.toString()}`, { headers });
1520
1488
  const page = asRecord(raw);
1521
- for (const item of Array.isArray(page.results) ? page.results : []) {
1489
+ for (const item of asArray(page.results)) {
1522
1490
  yield normalizeResult3(item);
1523
1491
  }
1524
1492
  token = asString(page.pagination_token);
@@ -1552,7 +1520,7 @@ var adapters = {
1552
1520
  };
1553
1521
  var getAdapter = (provider) => adapters[provider];
1554
1522
 
1555
- export { BatchworkError, UnsupportedProviderError, MissingDependencyError, resolveBatchLimits, assertByteLength, mapWithConcurrency, isTerminalStatus, BatchJob, getAdapter };
1523
+ export { BatchworkError2, UnsupportedProviderError2, MissingDependencyError2, resolveBatchLimits, assertByteLength, isTerminalStatus2, BatchJob2, getAdapter };
1556
1524
 
1557
- //# debugId=C9B199FFE835E11B64756E2164756E21
1558
- //# sourceMappingURL=chunk-vy4w8mpb.js.map
1525
+ //# debugId=7B0EC738FEADB97E64756E2164756E21
1526
+ //# sourceMappingURL=chunk-7y95mhvm.js.map