@apicity/fireworks 0.6.6 → 0.7.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.
@@ -2,268 +2,164 @@ import { FireworksError, } from "./types.js";
2
2
  import { sseToIterable } from "./sse.js";
3
3
  import { FireworksChatRequestSchema, FireworksCompletionRequestSchema, FireworksEmbeddingRequestSchema, FireworksRerankRequestSchema, AnthropicMessagesRequestSchema, FireworksTextToImageRequestSchema, FireworksKontextRequestSchema, FireworksGetResultRequestSchema, FireworksTranscriptionRequestSchema, FireworksTranslationRequestSchema, FireworksStreamingTranscriptionOptionsSchema, FireworksAudioBatchTranscriptionRequestSchema, FireworksAudioBatchTranslationRequestSchema, FireworksCreateModelRequestSchema, FireworksPrepareModelRequestSchema, FireworksGetUploadEndpointRequestSchema, FireworksUpdateModelRequestSchema, FireworksValidateUploadRequestSchema, FireworksBatchJobCreateRequestSchema, FireworksSFTCreateRequestSchema, FireworksCreateDeploymentRequestSchema, FireworksUpdateDeploymentRequestSchema, FireworksScaleDeploymentRequestSchema, FireworksDpoJobCreateRequestSchema, FireworksCreateDeployedModelRequestSchema, FireworksUpdateDeployedModelRequestSchema, FireworksCreateUserRequestSchema, FireworksUpdateUserRequestSchema, FireworksCreateApiKeyRequestSchema, FireworksDeleteApiKeyRequestSchema, FireworksCreateSecretRequestSchema, FireworksUpdateSecretRequestSchema, FireworksCreateDatasetRequestSchema, FireworksUpdateDatasetRequestSchema, FireworksDatasetGetUploadEndpointRequestSchema, FireworksDatasetValidateUploadRequestSchema, FireworksCreateEvaluatorRequestSchema, FireworksUpdateEvaluatorRequestSchema, FireworksGetUploadEndpointEvaluatorRequestSchema, FireworksCreateEvaluationJobRequestSchema, FireworksRFTCreateRequestSchema, FireworksRlorTrainerJobCreateRequestSchema, FireworksRlorTrainerJobExecuteStepRequestSchema, FireworksEmptySchema, } from "./zod.js";
4
4
  import { attachExamples } from "./example.js";
5
- // Helper function to safely handle AbortSignal across different environments
6
- function attachAbortHandler(signal, controller) {
7
- if (!signal)
8
- return;
9
- // Handle both standard AbortSignal and node-fetch's AbortSignal
10
- if (typeof signal.addEventListener === "function") {
11
- signal.addEventListener("abort", () => controller.abort(), { once: true });
5
+ import { createTransport } from "./transport.js";
6
+ function parseFireworksErrorBody(status, body) {
7
+ if (typeof body === "object" && body !== null && "error" in body) {
8
+ const err = body.error;
9
+ if (err?.message) {
10
+ return { message: `Fireworks API error ${status}: ${err.message}` };
11
+ }
12
12
  }
13
- else if (signal.aborted) {
14
- // Already aborted, abort our controller too
15
- controller.abort();
13
+ return { message: `Fireworks API error: ${status}` };
14
+ }
15
+ function parseFireworksWorkflowErrorBody(status, body) {
16
+ if (typeof body === "object" && body !== null && "error_message" in body) {
17
+ return {
18
+ message: `Fireworks API error ${status}: ${body.error_message}`,
19
+ };
16
20
  }
21
+ return parseFireworksErrorBody(status, body);
22
+ }
23
+ async function wrapFireworksTransportFailure(fn) {
24
+ try {
25
+ return await fn();
26
+ }
27
+ catch (error) {
28
+ if (error instanceof FireworksError)
29
+ throw error;
30
+ throw new FireworksError(`Fireworks request failed: ${error}`, 500);
31
+ }
32
+ }
33
+ async function readJsonResponse(res) {
34
+ return await wrapFireworksTransportFailure(async () => (await res.json()));
35
+ }
36
+ function withQuery(path, query) {
37
+ if (!query) {
38
+ return path;
39
+ }
40
+ const params = new URLSearchParams();
41
+ for (const [key, value] of Object.entries(query)) {
42
+ if (value !== undefined) {
43
+ params.append(key, String(value));
44
+ }
45
+ }
46
+ const qs = params.toString();
47
+ return qs ? `${path}?${qs}` : path;
48
+ }
49
+ async function jsonRequest(transport, method, path, body, query, signal) {
50
+ const hasBody = body !== undefined && method !== "GET" && method !== "DELETE";
51
+ const res = await transport.raw(withQuery(path, query), {
52
+ method,
53
+ headers: hasBody ? { "Content-Type": "application/json" } : undefined,
54
+ body: hasBody ? JSON.stringify(body) : undefined,
55
+ signal,
56
+ });
57
+ return await readJsonResponse(res);
17
58
  }
18
59
  export function createFireworks(opts) {
19
60
  const baseURL = opts.baseURL ?? "https://api.fireworks.ai/inference/v1";
20
61
  const modelsBaseURL = "https://api.fireworks.ai";
21
62
  const audioBaseURL = opts.audioBaseURL ?? "https://audio-prod.api.fireworks.ai/v1";
22
63
  const audioStreamingBaseURL = opts.audioStreamingBaseURL ?? "wss://audio-streaming.api.fireworks.ai";
23
- const doFetch = opts.fetch ?? fetch;
24
64
  const WS = opts.WebSocket ?? globalThis.WebSocket;
25
65
  const timeout = opts.timeout ?? 30000;
66
+ const transport = createTransport({
67
+ baseUrl: baseURL,
68
+ timeoutMs: timeout,
69
+ fetchImpl: opts.fetch,
70
+ defaultHeaders: () => ({ Authorization: `Bearer ${opts.apiKey}` }),
71
+ parseErrorBody: parseFireworksErrorBody,
72
+ errorClass: FireworksError,
73
+ requestFailedPrefix: "Fireworks request failed",
74
+ });
75
+ const workflowTransport = createTransport({
76
+ baseUrl: baseURL,
77
+ timeoutMs: timeout,
78
+ fetchImpl: opts.fetch,
79
+ defaultHeaders: () => ({ Authorization: `Bearer ${opts.apiKey}` }),
80
+ parseErrorBody: parseFireworksWorkflowErrorBody,
81
+ errorClass: FireworksError,
82
+ requestFailedPrefix: "Fireworks request failed",
83
+ });
84
+ const audioTransport = createTransport({
85
+ baseUrl: audioBaseURL,
86
+ timeoutMs: timeout,
87
+ fetchImpl: opts.fetch,
88
+ defaultHeaders: () => ({ Authorization: opts.apiKey }),
89
+ parseErrorBody: parseFireworksErrorBody,
90
+ errorClass: FireworksError,
91
+ requestFailedPrefix: "Fireworks request failed",
92
+ });
93
+ const audioBatchBaseURL = "https://audio-batch.api.fireworks.ai/v1";
94
+ const audioBatchTransport = createTransport({
95
+ baseUrl: audioBatchBaseURL,
96
+ timeoutMs: timeout,
97
+ fetchImpl: opts.fetch,
98
+ defaultHeaders: () => ({ Authorization: opts.apiKey }),
99
+ parseErrorBody: parseFireworksErrorBody,
100
+ errorClass: FireworksError,
101
+ requestFailedPrefix: "Fireworks request failed",
102
+ });
103
+ const modelsTransport = createTransport({
104
+ baseUrl: modelsBaseURL,
105
+ timeoutMs: timeout,
106
+ fetchImpl: opts.fetch,
107
+ defaultHeaders: () => ({ Authorization: `Bearer ${opts.apiKey}` }),
108
+ parseErrorBody: parseFireworksErrorBody,
109
+ errorClass: FireworksError,
110
+ requestFailedPrefix: "Fireworks request failed",
111
+ });
26
112
  async function makeRequest(path, body, signal) {
27
- const controller = new AbortController();
28
- const timeoutId = setTimeout(() => controller.abort(), timeout);
29
- if (signal) {
30
- attachAbortHandler(signal, controller);
31
- }
32
- try {
33
- const res = await doFetch(`${baseURL}${path}`, {
34
- method: "POST",
35
- headers: {
36
- Authorization: `Bearer ${opts.apiKey}`,
37
- "Content-Type": "application/json",
38
- },
39
- body: JSON.stringify(body),
40
- signal: controller.signal,
41
- });
42
- clearTimeout(timeoutId);
43
- if (!res.ok) {
44
- let message = `Fireworks API error: ${res.status}`;
45
- let resBody = null;
46
- try {
47
- resBody = await res.json();
48
- if (typeof resBody === "object" &&
49
- resBody !== null &&
50
- "error" in resBody) {
51
- const err = resBody.error;
52
- if (err?.message) {
53
- message = `Fireworks API error ${res.status}: ${err.message}`;
54
- }
55
- }
56
- }
57
- catch {
58
- // ignore parse errors
59
- }
60
- throw new FireworksError(message, res.status, resBody);
61
- }
62
- return (await res.json());
63
- }
64
- catch (error) {
65
- clearTimeout(timeoutId);
66
- if (error instanceof FireworksError)
67
- throw error;
68
- throw new FireworksError(`Fireworks request failed: ${error}`, 500);
69
- }
113
+ return await transport.postJson(path, body, { signal });
70
114
  }
71
115
  async function* makeStreamRequest(path, body, signal) {
72
- const controller = new AbortController();
73
- const timeoutId = setTimeout(() => controller.abort(), timeout);
74
- if (signal) {
75
- attachAbortHandler(signal, controller);
76
- }
77
- try {
78
- const res = await doFetch(`${baseURL}${path}`, {
79
- method: "POST",
80
- headers: {
81
- Authorization: `Bearer ${opts.apiKey}`,
82
- "Content-Type": "application/json",
83
- },
84
- body: JSON.stringify(body),
85
- signal: controller.signal,
86
- });
87
- clearTimeout(timeoutId);
88
- if (!res.ok) {
89
- let message = `Fireworks API error: ${res.status}`;
90
- let resBody = null;
91
- try {
92
- resBody = await res.json();
93
- if (typeof resBody === "object" &&
94
- resBody !== null &&
95
- "error" in resBody) {
96
- const err = resBody.error;
97
- if (err?.message) {
98
- message = `Fireworks API error ${res.status}: ${err.message}`;
99
- }
100
- }
101
- }
102
- catch {
103
- // ignore parse errors
104
- }
105
- throw new FireworksError(message, res.status, resBody);
116
+ const res = await transport.raw(path, {
117
+ method: "POST",
118
+ headers: { "Content-Type": "application/json" },
119
+ body: JSON.stringify(body),
120
+ signal,
121
+ });
122
+ for await (const { data } of sseToIterable(res)) {
123
+ if (data === "[DONE]") {
124
+ break;
106
125
  }
107
- for await (const { data } of sseToIterable(res)) {
108
- if (data === "[DONE]") {
109
- break;
110
- }
111
- try {
112
- yield JSON.parse(data);
113
- }
114
- catch {
115
- // ignore non-JSON lines
116
- }
126
+ try {
127
+ yield JSON.parse(data);
128
+ }
129
+ catch {
130
+ // ignore non-JSON lines
117
131
  }
118
- }
119
- finally {
120
- clearTimeout(timeoutId);
121
132
  }
122
133
  }
123
134
  // POST https://api.fireworks.ai/inference/v1/messages
124
135
  // Docs: https://docs.fireworks.ai/api-reference
125
136
  async function* messagesStreamImpl(req, signal) {
126
- const controller = new AbortController();
127
- const timeoutId = setTimeout(() => controller.abort(), timeout);
128
- try {
129
- const res = await doFetch(`${baseURL}/messages`, {
130
- method: "POST",
131
- headers: {
132
- Authorization: `Bearer ${opts.apiKey}`,
133
- "Content-Type": "application/json",
134
- },
135
- body: JSON.stringify(req),
136
- signal: signal || controller.signal,
137
- });
138
- clearTimeout(timeoutId);
139
- if (!res.ok) {
140
- let message = `Fireworks API error: ${res.status}`;
141
- let resBody = null;
142
- try {
143
- resBody = await res.json();
144
- if (typeof resBody === "object" &&
145
- resBody !== null &&
146
- "error" in resBody) {
147
- const err = resBody.error;
148
- if (err?.message) {
149
- message = `Fireworks API error ${res.status}: ${err.message}`;
150
- }
151
- }
152
- }
153
- catch {
154
- // ignore parse errors
155
- }
156
- throw new FireworksError(message, res.status, resBody);
137
+ const res = await transport.raw("/messages", {
138
+ method: "POST",
139
+ headers: { "Content-Type": "application/json" },
140
+ body: JSON.stringify(req),
141
+ signal,
142
+ });
143
+ for await (const { event, data } of sseToIterable(res)) {
144
+ if (event === "message_stop") {
145
+ break;
157
146
  }
158
- for await (const { event, data } of sseToIterable(res)) {
159
- if (event === "message_stop") {
160
- break;
161
- }
162
- try {
163
- const parsed = JSON.parse(data);
164
- yield parsed;
165
- }
166
- catch {
167
- // ignore non-JSON lines
168
- }
147
+ try {
148
+ const parsed = JSON.parse(data);
149
+ yield parsed;
150
+ }
151
+ catch {
152
+ // ignore non-JSON lines
169
153
  }
170
- }
171
- finally {
172
- clearTimeout(timeoutId);
173
154
  }
174
155
  }
175
156
  // POST https://api.fireworks.ai/inference/v1/messages
176
157
  // Docs: https://docs.fireworks.ai/api-reference
177
158
  async function messagesImpl(req, signal) {
178
- const controller = new AbortController();
179
- const timeoutId = setTimeout(() => controller.abort(), timeout);
180
- try {
181
- const res = await doFetch(`${baseURL}/messages`, {
182
- method: "POST",
183
- headers: {
184
- Authorization: `Bearer ${opts.apiKey}`,
185
- "Content-Type": "application/json",
186
- },
187
- body: JSON.stringify(req),
188
- signal: signal || controller.signal,
189
- });
190
- clearTimeout(timeoutId);
191
- if (!res.ok) {
192
- let message = `Fireworks API error: ${res.status}`;
193
- let resBody = null;
194
- try {
195
- resBody = await res.json();
196
- if (typeof resBody === "object" &&
197
- resBody !== null &&
198
- "error" in resBody) {
199
- const err = resBody.error;
200
- if (err?.message) {
201
- message = `Fireworks API error ${res.status}: ${err.message}`;
202
- }
203
- }
204
- }
205
- catch {
206
- // ignore parse errors
207
- }
208
- throw new FireworksError(message, res.status, resBody);
209
- }
210
- return (await res.json());
211
- }
212
- finally {
213
- clearTimeout(timeoutId);
214
- }
159
+ return await transport.postJson("/messages", req, { signal });
215
160
  }
216
161
  async function makeWorkflowRequest(model, suffix, body, signal) {
217
- const controller = new AbortController();
218
- const timeoutId = setTimeout(() => controller.abort(), timeout);
219
- if (signal) {
220
- attachAbortHandler(signal, controller);
221
- }
222
- try {
223
- const url = `${baseURL}/workflows/accounts/fireworks/models/${model}${suffix}`;
224
- const res = await doFetch(url, {
225
- method: "POST",
226
- headers: {
227
- Authorization: `Bearer ${opts.apiKey}`,
228
- "Content-Type": "application/json",
229
- Accept: "application/json",
230
- },
231
- body: JSON.stringify(body),
232
- signal: controller.signal,
233
- });
234
- clearTimeout(timeoutId);
235
- if (!res.ok) {
236
- let message = `Fireworks API error: ${res.status}`;
237
- let resBody = null;
238
- try {
239
- resBody = await res.json();
240
- if (typeof resBody === "object" &&
241
- resBody !== null &&
242
- "error" in resBody) {
243
- const err = resBody.error;
244
- if (err?.message) {
245
- message = `Fireworks API error ${res.status}: ${err.message}`;
246
- }
247
- }
248
- if (typeof resBody === "object" &&
249
- resBody !== null &&
250
- "error_message" in resBody) {
251
- message = `Fireworks API error ${res.status}: ${resBody.error_message}`;
252
- }
253
- }
254
- catch {
255
- // ignore parse errors
256
- }
257
- throw new FireworksError(message, res.status, resBody);
258
- }
259
- return (await res.json());
260
- }
261
- catch (error) {
262
- clearTimeout(timeoutId);
263
- if (error instanceof FireworksError)
264
- throw error;
265
- throw new FireworksError(`Fireworks request failed: ${error}`, 500);
266
- }
162
+ return await workflowTransport.postJson(`/workflows/accounts/fireworks/models/${model}${suffix}`, body, { headers: { Accept: "application/json" }, signal });
267
163
  }
268
164
  function getAudioBaseURL(model) {
269
165
  if (model === "whisper-v3-turbo") {
@@ -272,157 +168,16 @@ export function createFireworks(opts) {
272
168
  return audioBaseURL;
273
169
  }
274
170
  async function makeAudioRequest(path, form, model, signal) {
275
- const controller = new AbortController();
276
- const timeoutId = setTimeout(() => controller.abort(), timeout);
277
- if (signal) {
278
- attachAbortHandler(signal, controller);
279
- }
280
- try {
281
- const url = `${getAudioBaseURL(model)}${path}`;
282
- const res = await doFetch(url, {
283
- method: "POST",
284
- headers: {
285
- Authorization: opts.apiKey,
286
- },
287
- body: form,
288
- signal: controller.signal,
289
- });
290
- clearTimeout(timeoutId);
291
- if (!res.ok) {
292
- let message = `Fireworks API error: ${res.status}`;
293
- let resBody = null;
294
- try {
295
- resBody = await res.json();
296
- if (typeof resBody === "object" &&
297
- resBody !== null &&
298
- "error" in resBody) {
299
- const err = resBody.error;
300
- if (err?.message) {
301
- message = `Fireworks API error ${res.status}: ${err.message}`;
302
- }
303
- }
304
- }
305
- catch {
306
- // ignore parse errors
307
- }
308
- throw new FireworksError(message, res.status, resBody);
309
- }
310
- return (await res.json());
311
- }
312
- catch (error) {
313
- clearTimeout(timeoutId);
314
- if (error instanceof FireworksError)
315
- throw error;
316
- throw new FireworksError(`Fireworks request failed: ${error}`, 500);
317
- }
171
+ return await audioTransport.postForm(path, form, {
172
+ baseUrl: getAudioBaseURL(model),
173
+ signal,
174
+ });
318
175
  }
319
- const audioBatchBaseURL = "https://audio-batch.api.fireworks.ai/v1";
320
176
  async function makeAudioBatchRequest(path, form, endpointId, signal) {
321
- const controller = new AbortController();
322
- const timeoutId = setTimeout(() => controller.abort(), timeout);
323
- if (signal) {
324
- attachAbortHandler(signal, controller);
325
- }
326
- try {
327
- const url = `${audioBatchBaseURL}${path}?endpoint_id=${encodeURIComponent(endpointId)}`;
328
- const res = await doFetch(url, {
329
- method: "POST",
330
- headers: {
331
- Authorization: opts.apiKey,
332
- },
333
- body: form,
334
- signal: controller.signal,
335
- });
336
- clearTimeout(timeoutId);
337
- if (!res.ok) {
338
- let message = `Fireworks API error: ${res.status}`;
339
- let resBody = null;
340
- try {
341
- resBody = await res.json();
342
- if (typeof resBody === "object" &&
343
- resBody !== null &&
344
- "error" in resBody) {
345
- const err = resBody.error;
346
- if (err?.message) {
347
- message = `Fireworks API error ${res.status}: ${err.message}`;
348
- }
349
- }
350
- }
351
- catch {
352
- // ignore parse errors
353
- }
354
- throw new FireworksError(message, res.status, resBody);
355
- }
356
- return (await res.json());
357
- }
358
- catch (error) {
359
- clearTimeout(timeoutId);
360
- if (error instanceof FireworksError)
361
- throw error;
362
- throw new FireworksError(`Fireworks request failed: ${error}`, 500);
363
- }
177
+ return await audioBatchTransport.postForm(`${path}?endpoint_id=${encodeURIComponent(endpointId)}`, form, { signal });
364
178
  }
365
179
  async function makeModelsRequest(method, path, body, query, signal) {
366
- const controller = new AbortController();
367
- const timeoutId = setTimeout(() => controller.abort(), timeout);
368
- if (signal) {
369
- attachAbortHandler(signal, controller);
370
- }
371
- try {
372
- let url = `${modelsBaseURL}${path}`;
373
- if (query) {
374
- const params = new URLSearchParams();
375
- for (const [k, v] of Object.entries(query)) {
376
- if (v !== undefined)
377
- params.append(k, String(v));
378
- }
379
- const qs = params.toString();
380
- if (qs)
381
- url += `?${qs}`;
382
- }
383
- const headers = {
384
- Authorization: `Bearer ${opts.apiKey}`,
385
- };
386
- if (method !== "GET" && method !== "DELETE") {
387
- headers["Content-Type"] = "application/json";
388
- }
389
- const init = {
390
- method,
391
- headers,
392
- signal: controller.signal,
393
- };
394
- if (body !== undefined && method !== "GET" && method !== "DELETE") {
395
- init.body = JSON.stringify(body);
396
- }
397
- const res = await doFetch(url, init);
398
- clearTimeout(timeoutId);
399
- if (!res.ok) {
400
- let message = `Fireworks API error: ${res.status}`;
401
- let resBody = null;
402
- try {
403
- resBody = await res.json();
404
- if (typeof resBody === "object" &&
405
- resBody !== null &&
406
- "error" in resBody) {
407
- const err = resBody.error;
408
- if (err?.message) {
409
- message = `Fireworks API error ${res.status}: ${err.message}`;
410
- }
411
- }
412
- }
413
- catch {
414
- // ignore parse errors
415
- }
416
- throw new FireworksError(message, res.status, resBody);
417
- }
418
- return (await res.json());
419
- }
420
- catch (error) {
421
- clearTimeout(timeoutId);
422
- if (error instanceof FireworksError)
423
- throw error;
424
- throw new FireworksError(`Fireworks request failed: ${error}`, 500);
425
- }
180
+ return await jsonRequest(modelsTransport, method, path, body, query, signal);
426
181
  }
427
182
  // ============================================================
428
183
  // Verb-Prefixed API Surface Implementation