@ai-sdk/fireworks
Version:
The **[Fireworks provider](https://ai-sdk.dev/providers/ai-sdk-providers/fireworks)** for the [AI SDK](https://ai-sdk.dev/docs) contains language model and image model support for the [Fireworks](https://fireworks.ai) platform.
471 lines (465 loc) • 14.6 kB
JavaScript
// src/fireworks-image-model.ts
import {
combineHeaders,
convertImageModelFileToDataUri,
createBinaryResponseHandler,
createJsonResponseHandler,
createStatusCodeErrorResponseHandler,
delay,
getFromApi,
isSameOrigin,
parseProviderOptions,
postJsonToApi,
serializeModelOptions,
WORKFLOW_SERIALIZE,
WORKFLOW_DESERIALIZE
} from "@ai-sdk/provider-utils";
// src/fireworks-image-api.ts
import { lazySchema, zodSchema } from "@ai-sdk/provider-utils";
import { z } from "zod/v4";
var asyncSubmitResponseSchema = lazySchema(
() => zodSchema(
z.object({
request_id: z.string()
})
)
);
var asyncPollResponseSchema = lazySchema(
() => zodSchema(
z.object({
id: z.string(),
status: z.string(),
result: z.object({
sample: z.string().optional()
}).nullable()
})
)
);
// src/fireworks-image-model-options.ts
import {
lazySchema as lazySchema2,
zodSchema as zodSchema2
} from "@ai-sdk/provider-utils";
import { z as z2 } from "zod/v4";
var fireworksImageModelOptionsSchema = lazySchema2(
() => zodSchema2(
z2.looseObject({
/**
* Classifier-free guidance scale for the image diffusion process.
*/
guidance_scale: z2.number().optional(),
/**
* Number of denoising steps for the image generation process.
*/
num_inference_steps: z2.number().int().optional(),
/**
* Desired output image format.
*/
output_format: z2.enum(["jpeg", "png"]).optional(),
/**
* URL to receive webhook notifications for async Kontext requests.
*/
webhook_url: z2.string().optional(),
/**
* Secret for webhook signature verification.
*/
webhook_secret: z2.string().optional(),
/**
* Whether Fireworks should automatically modify the prompt for more creative generation.
*/
prompt_upsampling: z2.boolean().optional(),
/**
* Moderation tolerance level for inputs and outputs.
*/
safety_tolerance: z2.number().int().min(0).max(6).optional(),
/**
* Guidance scale for legacy image_generation models.
*/
cfg_scale: z2.number().optional(),
/**
* Number of generation steps for legacy image_generation models.
*/
steps: z2.number().int().optional()
})
)
);
// src/fireworks-image-model.ts
var DEFAULT_POLL_INTERVAL_MILLIS = 500;
var DEFAULT_POLL_TIMEOUT_MILLIS = 12e4;
var modelToBackendConfig = {
"accounts/fireworks/models/flux-1-dev-fp8": {
urlFormat: "workflows"
},
"accounts/fireworks/models/flux-1-schnell-fp8": {
urlFormat: "workflows"
},
"accounts/fireworks/models/flux-kontext-pro": {
urlFormat: "workflows_async",
supportsEditing: true
},
"accounts/fireworks/models/flux-kontext-max": {
urlFormat: "workflows_async",
supportsEditing: true
},
"accounts/fireworks/models/playground-v2-5-1024px-aesthetic": {
urlFormat: "image_generation",
supportsSize: true
},
"accounts/fireworks/models/japanese-stable-diffusion-xl": {
urlFormat: "image_generation",
supportsSize: true
},
"accounts/fireworks/models/playground-v2-1024px-aesthetic": {
urlFormat: "image_generation",
supportsSize: true
},
"accounts/fireworks/models/stable-diffusion-xl-1024-v1-0": {
urlFormat: "image_generation",
supportsSize: true
},
"accounts/fireworks/models/SSD-1B": {
urlFormat: "image_generation",
supportsSize: true
}
};
function getUrlForModel(baseUrl, modelId) {
const config = modelToBackendConfig[modelId];
switch (config == null ? void 0 : config.urlFormat) {
case "image_generation":
return `${baseUrl}/image_generation/${modelId}`;
case "workflows_async":
return `${baseUrl}/workflows/${modelId}`;
case "workflows":
default:
return `${baseUrl}/workflows/${modelId}/text_to_image`;
}
}
function getPollUrlForModel(baseUrl, modelId) {
return `${baseUrl}/workflows/${modelId}/get_result`;
}
var FireworksImageModel = class _FireworksImageModel {
constructor(modelId, config) {
this.modelId = modelId;
this.config = config;
this.specificationVersion = "v4";
this.maxImagesPerCall = 1;
}
get provider() {
return this.config.provider;
}
static [WORKFLOW_SERIALIZE](model) {
return serializeModelOptions({
modelId: model.modelId,
config: model.config
});
}
static [WORKFLOW_DESERIALIZE](options) {
return new _FireworksImageModel(options.modelId, options.config);
}
async doGenerate({
prompt,
n,
size,
aspectRatio,
seed,
providerOptions,
headers,
abortSignal,
files,
mask
}) {
var _a, _b, _c, _d, _e, _f;
const warnings = [];
const backendConfig = modelToBackendConfig[this.modelId];
if (!(backendConfig == null ? void 0 : backendConfig.supportsSize) && size != null) {
warnings.push({
type: "unsupported",
feature: "size",
details: "This model does not support the `size` option. Use `aspectRatio` instead."
});
}
if ((backendConfig == null ? void 0 : backendConfig.supportsSize) && aspectRatio != null) {
warnings.push({
type: "unsupported",
feature: "aspectRatio",
details: "This model does not support the `aspectRatio` option."
});
}
const hasInputImage = files != null && files.length > 0;
let inputImage;
if (hasInputImage) {
inputImage = convertImageModelFileToDataUri(files[0]);
if (files.length > 1) {
warnings.push({
type: "other",
message: "Fireworks only supports a single input image. Additional images are ignored."
});
}
}
if (mask != null) {
warnings.push({
type: "unsupported",
feature: "mask",
details: "Fireworks Kontext models do not support explicit masks. Use the prompt to describe the areas to edit."
});
}
const splitSize = size == null ? void 0 : size.split("x");
const currentDate = (_c = (_b = (_a = this.config._internal) == null ? void 0 : _a.currentDate) == null ? void 0 : _b.call(_a)) != null ? _c : /* @__PURE__ */ new Date();
const combinedHeaders = combineHeaders((_e = (_d = this.config).headers) == null ? void 0 : _e.call(_d), headers);
const fireworksOptions = (_f = await parseProviderOptions({
provider: "fireworks",
providerOptions,
schema: fireworksImageModelOptionsSchema
})) != null ? _f : {};
const body = {
prompt,
aspect_ratio: aspectRatio,
seed,
samples: n,
...inputImage && { input_image: inputImage },
...splitSize && { width: splitSize[0], height: splitSize[1] },
...fireworksOptions
};
if ((backendConfig == null ? void 0 : backendConfig.urlFormat) === "workflows_async") {
return this.doGenerateAsync({
body,
headers: combinedHeaders,
abortSignal,
warnings,
currentDate
});
}
const { value: response, responseHeaders } = await postJsonToApi({
url: getUrlForModel(this.config.baseURL, this.modelId),
headers: combinedHeaders,
body,
failedResponseHandler: createStatusCodeErrorResponseHandler(),
successfulResponseHandler: createBinaryResponseHandler(),
abortSignal,
fetch: this.config.fetch
});
return {
images: [response],
warnings,
response: {
timestamp: currentDate,
modelId: this.modelId,
headers: responseHeaders
}
};
}
/**
* Handles async image generation for models like flux-kontext-* that return
* a request_id and require polling for results.
*/
async doGenerateAsync({
body,
headers,
abortSignal,
warnings,
currentDate
}) {
const { value: submitResponse } = await postJsonToApi({
url: getUrlForModel(this.config.baseURL, this.modelId),
headers,
body,
failedResponseHandler: createStatusCodeErrorResponseHandler(),
successfulResponseHandler: createJsonResponseHandler(
asyncSubmitResponseSchema
),
abortSignal,
fetch: this.config.fetch
});
const requestId = submitResponse.request_id;
const imageUrl = await this.pollForImageUrl({
requestId,
headers,
abortSignal
});
const { value: imageBytes, responseHeaders } = await getFromApi({
url: imageUrl,
headers: isSameOrigin(imageUrl, this.config.baseURL) ? headers : void 0,
abortSignal,
failedResponseHandler: createStatusCodeErrorResponseHandler(),
successfulResponseHandler: createBinaryResponseHandler(),
fetch: this.config.fetch
});
return {
images: [imageBytes],
warnings,
response: {
timestamp: currentDate,
modelId: this.modelId,
headers: responseHeaders
}
};
}
/**
* Polls the get_result endpoint until the image is ready.
*/
async pollForImageUrl({
requestId,
headers,
abortSignal
}) {
var _a, _b, _c;
const pollIntervalMillis = (_a = this.config.pollIntervalMillis) != null ? _a : DEFAULT_POLL_INTERVAL_MILLIS;
const pollTimeoutMillis = (_b = this.config.pollTimeoutMillis) != null ? _b : DEFAULT_POLL_TIMEOUT_MILLIS;
const maxPollAttempts = Math.ceil(
pollTimeoutMillis / Math.max(1, pollIntervalMillis)
);
const pollUrl = getPollUrlForModel(this.config.baseURL, this.modelId);
for (let i = 0; i < maxPollAttempts; i++) {
const { value: pollResponse } = await postJsonToApi({
url: pollUrl,
headers,
body: { id: requestId },
failedResponseHandler: createStatusCodeErrorResponseHandler(),
successfulResponseHandler: createJsonResponseHandler(
asyncPollResponseSchema
),
abortSignal,
fetch: this.config.fetch
});
const status = pollResponse.status;
if (status === "Ready") {
const imageUrl = (_c = pollResponse.result) == null ? void 0 : _c.sample;
if (typeof imageUrl === "string") {
return imageUrl;
}
throw new Error(
"Fireworks poll response is Ready but missing result.sample"
);
}
if (status === "Error" || status === "Failed") {
throw new Error(
`Fireworks image generation failed with status: ${status}`
);
}
await delay(pollIntervalMillis);
}
throw new Error(
`Fireworks image generation timed out after ${pollTimeoutMillis}ms`
);
}
};
// src/fireworks-provider.ts
import {
OpenAICompatibleChatLanguageModel,
OpenAICompatibleCompletionLanguageModel,
OpenAICompatibleEmbeddingModel
} from "@ai-sdk/openai-compatible";
import {
loadApiKey,
withoutTrailingSlash,
withUserAgentSuffix
} from "@ai-sdk/provider-utils";
import { z as z3 } from "zod/v4";
// src/version.ts
var VERSION = true ? "3.0.8" : "0.0.0-test";
// src/fireworks-provider.ts
var fireworksErrorSchema = z3.object({
error: z3.string()
});
var fireworksErrorStructure = {
errorSchema: fireworksErrorSchema,
errorToMessage: (data) => data.error
};
var defaultBaseURL = "https://api.fireworks.ai/inference/v1";
function createFireworks(options = {}) {
var _a;
const baseURL = withoutTrailingSlash((_a = options.baseURL) != null ? _a : defaultBaseURL);
const getHeaders = () => withUserAgentSuffix(
{
Authorization: `Bearer ${loadApiKey({
apiKey: options.apiKey,
environmentVariableName: "FIREWORKS_API_KEY",
description: "Fireworks API key"
})}`,
...options.headers
},
`ai-sdk/fireworks/${VERSION}`
);
const getCommonModelConfig = (modelType) => ({
provider: `fireworks.${modelType}`,
url: ({ path }) => `${baseURL}${path}`,
headers: getHeaders,
fetch: options.fetch
});
const createChatModel = (modelId) => {
return new OpenAICompatibleChatLanguageModel(modelId, {
...getCommonModelConfig("chat"),
includeUsage: true,
errorStructure: fireworksErrorStructure,
transformRequestBody: (args) => {
const thinking = args.thinking;
const reasoningHistory = args.reasoningHistory;
const promptCacheKey = args.promptCacheKey;
const serviceTier = args.serviceTier;
const {
thinking: _,
reasoningHistory: __,
promptCacheKey: ___,
serviceTier: ____,
reasoning_effort,
...rest
} = args;
return {
...rest,
...reasoning_effort != null && {
// Workaround since OpenAI spec allows for 5 reasoning levels, but Fireworks only supports 3 of them.
reasoning_effort: reasoning_effort === "minimal" ? "low" : reasoning_effort === "xhigh" ? "high" : reasoning_effort
},
...promptCacheKey !== void 0 && {
prompt_cache_key: promptCacheKey
},
...serviceTier !== void 0 && {
service_tier: serviceTier
},
...thinking && {
thinking: {
type: thinking.type,
...thinking.budgetTokens !== void 0 && {
budget_tokens: thinking.budgetTokens
}
}
},
...reasoningHistory && {
reasoning_history: reasoningHistory
}
};
}
});
};
const createCompletionModel = (modelId) => new OpenAICompatibleCompletionLanguageModel(modelId, {
...getCommonModelConfig("completion"),
includeUsage: true,
errorStructure: fireworksErrorStructure
});
const createEmbeddingModel = (modelId) => new OpenAICompatibleEmbeddingModel(modelId, {
...getCommonModelConfig("embedding"),
errorStructure: fireworksErrorStructure
});
const createImageModel = (modelId) => new FireworksImageModel(modelId, {
...getCommonModelConfig("image"),
baseURL: baseURL != null ? baseURL : defaultBaseURL
});
const provider = (modelId) => createChatModel(modelId);
provider.specificationVersion = "v4";
provider.completionModel = createCompletionModel;
provider.chatModel = createChatModel;
provider.languageModel = createChatModel;
provider.embeddingModel = createEmbeddingModel;
provider.textEmbeddingModel = createEmbeddingModel;
provider.image = createImageModel;
provider.imageModel = createImageModel;
return provider;
}
var fireworks = createFireworks();
export {
FireworksImageModel,
VERSION,
createFireworks,
fireworks
};
//# sourceMappingURL=index.js.map