@broberg/ai-sdk 0.13.1 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -165,6 +165,21 @@ interface ImageRequest {
165
165
  height?: number;
166
166
  /** LoRAs to merge at inference (F021) — e.g. a trained brand/style LoRA. */
167
167
  loras?: LoraWeight[];
168
+ /** F023 — a BFL finetune id (a subject trained in the BFL dashboard). Routes to the
169
+ * EU-resident BFL finetuned-portrait endpoint. */
170
+ finetune?: string;
171
+ /** F023 — how strongly the finetune is applied (BFL finetune_strength, ~0–2). */
172
+ finetuneStrength?: number;
173
+ /** F023.5 — 1–8 reference photos of a subject (URL or raw bytes). Routes to the
174
+ * EU-resident BFL FLUX 2 multi-reference endpoint — generate a likeness with NO
175
+ * training step. Bytes are base64-inlined into the EU call (no cross-region fetch). */
176
+ referenceImages?: (string | Uint8Array)[];
177
+ /** F023.5 — fixed seed for reproducible output (BFL). */
178
+ seed?: number;
179
+ /** F023.5 — output container (BFL FLUX 2): "jpeg" | "png" | "webp". Default jpeg. */
180
+ outputFormat?: "jpeg" | "png" | "webp";
181
+ /** F023.5 — BFL content-moderation strictness, 0 (strict) … 6 (lax). Default 2. */
182
+ safetyTolerance?: number;
168
183
  /** F021.4 — re-roll once with a fresh seed if fal's safety-checker false-positives
169
184
  * and returns a black image (has_nsfw_concepts). fal only. */
170
185
  retryOnBlack?: boolean;
@@ -942,6 +957,20 @@ declare const imageInputSchema: z.ZodObject<{
942
957
  }>, "many">>;
943
958
  /** Shorthand for a single LoRA — normalized to loras:[{path, scale:1}]. */
944
959
  lora: z.ZodOptional<z.ZodString>;
960
+ /** F023 — a BFL finetune id (subject trained in the BFL dashboard). Routes to the
961
+ * EU-resident BFL finetuned-portrait endpoint. */
962
+ finetune: z.ZodOptional<z.ZodString>;
963
+ /** F023 — BFL finetune_strength (~0–2; higher = stronger likeness). */
964
+ finetuneStrength: z.ZodOptional<z.ZodNumber>;
965
+ /** F023.5 — 1–8 reference photos (URL or raw bytes) → EU-resident BFL FLUX 2
966
+ * multi-reference generation (likeness, no training step). */
967
+ referenceImages: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodType<Uint8Array<ArrayBuffer>, z.ZodTypeDef, Uint8Array<ArrayBuffer>>]>, "many">>;
968
+ /** F023.5 — fixed seed for reproducible output (BFL). */
969
+ seed: z.ZodOptional<z.ZodNumber>;
970
+ /** F023.5 — output container (BFL FLUX 2). Default jpeg. */
971
+ outputFormat: z.ZodOptional<z.ZodEnum<["jpeg", "png", "webp"]>>;
972
+ /** F023.5 — BFL content-moderation strictness, 0 (strict) … 6 (lax). Default 2. */
973
+ safetyTolerance: z.ZodOptional<z.ZodNumber>;
945
974
  /** F021.4 — re-roll once if fal returns a black image (NSFW false-positive). */
946
975
  retryOnBlack: z.ZodOptional<z.ZodBoolean>;
947
976
  }, "strip", z.ZodTypeAny, {
@@ -951,7 +980,10 @@ declare const imageInputSchema: z.ZodObject<{
951
980
  path: string;
952
981
  scale?: number | undefined;
953
982
  }[] | undefined;
983
+ seed?: number | undefined;
954
984
  lora?: string | undefined;
985
+ width?: number | undefined;
986
+ height?: number | undefined;
955
987
  tier?: "fast" | "smart" | "powerful" | "cheap" | "vision" | "video" | "embedding" | undefined;
956
988
  override?: {
957
989
  provider?: string | undefined;
@@ -964,8 +996,11 @@ declare const imageInputSchema: z.ZodObject<{
964
996
  transport: "http" | "subprocess";
965
997
  })[] | undefined;
966
998
  labels?: Record<string, string> | undefined;
967
- width?: number | undefined;
968
- height?: number | undefined;
999
+ finetune?: string | undefined;
1000
+ finetuneStrength?: number | undefined;
1001
+ referenceImages?: (string | Uint8Array<ArrayBuffer>)[] | undefined;
1002
+ outputFormat?: "jpeg" | "png" | "webp" | undefined;
1003
+ safetyTolerance?: number | undefined;
969
1004
  retryOnBlack?: boolean | undefined;
970
1005
  }, {
971
1006
  prompt: string;
@@ -974,7 +1009,10 @@ declare const imageInputSchema: z.ZodObject<{
974
1009
  path: string;
975
1010
  scale?: number | undefined;
976
1011
  }[] | undefined;
1012
+ seed?: number | undefined;
977
1013
  lora?: string | undefined;
1014
+ width?: number | undefined;
1015
+ height?: number | undefined;
978
1016
  tier?: "fast" | "smart" | "powerful" | "cheap" | "vision" | "video" | "embedding" | undefined;
979
1017
  override?: {
980
1018
  provider?: string | undefined;
@@ -987,8 +1025,11 @@ declare const imageInputSchema: z.ZodObject<{
987
1025
  transport: "http" | "subprocess";
988
1026
  })[] | undefined;
989
1027
  labels?: Record<string, string> | undefined;
990
- width?: number | undefined;
991
- height?: number | undefined;
1028
+ finetune?: string | undefined;
1029
+ finetuneStrength?: number | undefined;
1030
+ referenceImages?: (string | Uint8Array<ArrayBuffer>)[] | undefined;
1031
+ outputFormat?: "jpeg" | "png" | "webp" | undefined;
1032
+ safetyTolerance?: number | undefined;
992
1033
  retryOnBlack?: boolean | undefined;
993
1034
  }>;
994
1035
  declare const trainStyleInputSchema: z.ZodObject<{
@@ -1682,6 +1723,18 @@ interface FalAdapterConfig {
1682
1723
  }
1683
1724
  declare function falAdapter(config?: FalAdapterConfig): ProviderAdapter;
1684
1725
 
1726
+ interface BflAdapterConfig {
1727
+ apiKey?: string;
1728
+ /** EU-resident base. Do NOT point this at api.bfl.ai (global, US-failover) — see header. */
1729
+ baseUrl?: string;
1730
+ pollIntervalMs?: number;
1731
+ timeoutMs?: number;
1732
+ fetch?: typeof fetch;
1733
+ /** Override the per-image USD price (else the built-in finetuned-inference estimate). */
1734
+ pricePerImage?: number;
1735
+ }
1736
+ declare function bflAdapter(config?: BflAdapterConfig): ProviderAdapter;
1737
+
1685
1738
  interface OpenAICompatibleConfig {
1686
1739
  /** Provider name recorded on Usage (e.g. "openai", "deepinfra", "openrouter"). */
1687
1740
  name: string;
@@ -1715,8 +1768,8 @@ declare const falStubAdapter: ProviderAdapter;
1715
1768
  * wires the live adapters. */
1716
1769
  declare const stubProviders: Record<string, ProviderAdapter>;
1717
1770
 
1718
- declare const VERSION: "0.13.1";
1719
- declare const SDK_TAG: "@broberg/ai-sdk@0.13.1";
1771
+ declare const VERSION: "0.15.0";
1772
+ declare const SDK_TAG: "@broberg/ai-sdk@0.15.0";
1720
1773
 
1721
1774
  /** Built-in defaults. Every entry is overridable via AiConfig.defaults or a
1722
1775
  * per-call override. Model IDs are current at scaffold time; callers pin their
@@ -1942,4 +1995,4 @@ interface StreamTransportRequest extends TransportRequest {
1942
1995
  */
1943
1996
  declare function streamTransport(req: StreamTransportRequest): AsyncIterable<string>;
1944
1997
 
1945
- export { type AiClient, type AiConfig, type BatchJob, type BatchRequestItem, type BatchResultItem, type BudgetConfig, BudgetExceededError, BudgetGuard, type BudgetStore, type CallOptions, type Capability, type ChatInput, type ChatRequest, type ChatResult, type ChatStreamEvent, type ClassifyInput, type ClassifyResult, type ContentPart, type Contracts, type CostSink, type CostSummary, DEFAULT_TIER_MAP, type DesignInput, type DesignResult, type DialogueRequest, type DialogueTurn, type DiscordSinkConfig, ELEVENLABS_DANISH_VOICES, type EmbeddingInput, type EmbeddingRequest, type EmbeddingResult, type ExtractInput, type ExtractResult, type FalAdapterConfig, type HttpResponse, type ImageInput, type ImageRequest, type ImageResult, type LoraWeight, type Message, type MockupInput, type MockupResult, type ModerationInput, type ModerationItem, type ModerationRequest, type ModerationResult, type OcrInput, type OcrPage, type OcrRequest, type OcrResult, type OpenAICompatibleConfig, type PodcastInput, type PodcastResult, type PricingEntry, type ProviderAdapter, type RefreshOptions, type RefreshResult, type RerankInput, type RerankResult, type Role, SDK_TAG, type SqliteBudgetStoreConfig, type SqliteSinkConfig, StreamHttpError, type SubprocessResponse, type Tier, type TierSpec, type Tool, type ToolCall, type TrainStyleInput, type TrainStyleRequest, type TrainStyleResult, type TranscribeInput, type TranscribeRequest, type TranscribeResult, type TranslateInput, type TranslateResult, type Transport, type TransportRequest, type TransportResponse, type TtsInput, type TtsRequest, type UpmetricsSinkConfig, type Usage, VERSION, type VideoInput, type VisionInput, aiConfigSchema, anthropicAdapter, anthropicApiAdapter, anthropicSubprocessAdapter, chatInputSchema, computeCost, createAI, deepinfraAdapter, defaultProviders, discordSink, elevenlabsAdapter, embeddingInputSchema, falAdapter, falStubAdapter, freshUsage, fromProviderToolCall, geminiAdapter, getCostSummary, getPrice, httpTransport, imageInputSchema, makeContracts, makeOpenAICompatibleAdapter, messageSchema, mistralAdapter, multiSink, noopSink, openaiAdapter, openaiStubAdapter, openrouterAdapter, parseClaudeCliJson, parseJsonLoose, refreshAvailability, resetRefreshState, resetRegistry, resolveTier, resolveVoice, sqliteBudgetStore, sqliteSink, streamTransport, stubProviders, subprocessTransport, tierSpecSchema, toProviderTools, toolSchema, translateInputSchema, upmetricsSink, visionInputSchema };
1998
+ export { type AiClient, type AiConfig, type BatchJob, type BatchRequestItem, type BatchResultItem, type BflAdapterConfig, type BudgetConfig, BudgetExceededError, BudgetGuard, type BudgetStore, type CallOptions, type Capability, type ChatInput, type ChatRequest, type ChatResult, type ChatStreamEvent, type ClassifyInput, type ClassifyResult, type ContentPart, type Contracts, type CostSink, type CostSummary, DEFAULT_TIER_MAP, type DesignInput, type DesignResult, type DialogueRequest, type DialogueTurn, type DiscordSinkConfig, ELEVENLABS_DANISH_VOICES, type EmbeddingInput, type EmbeddingRequest, type EmbeddingResult, type ExtractInput, type ExtractResult, type FalAdapterConfig, type HttpResponse, type ImageInput, type ImageRequest, type ImageResult, type LoraWeight, type Message, type MockupInput, type MockupResult, type ModerationInput, type ModerationItem, type ModerationRequest, type ModerationResult, type OcrInput, type OcrPage, type OcrRequest, type OcrResult, type OpenAICompatibleConfig, type PodcastInput, type PodcastResult, type PricingEntry, type ProviderAdapter, type RefreshOptions, type RefreshResult, type RerankInput, type RerankResult, type Role, SDK_TAG, type SqliteBudgetStoreConfig, type SqliteSinkConfig, StreamHttpError, type SubprocessResponse, type Tier, type TierSpec, type Tool, type ToolCall, type TrainStyleInput, type TrainStyleRequest, type TrainStyleResult, type TranscribeInput, type TranscribeRequest, type TranscribeResult, type TranslateInput, type TranslateResult, type Transport, type TransportRequest, type TransportResponse, type TtsInput, type TtsRequest, type UpmetricsSinkConfig, type Usage, VERSION, type VideoInput, type VisionInput, aiConfigSchema, anthropicAdapter, anthropicApiAdapter, anthropicSubprocessAdapter, bflAdapter, chatInputSchema, computeCost, createAI, deepinfraAdapter, defaultProviders, discordSink, elevenlabsAdapter, embeddingInputSchema, falAdapter, falStubAdapter, freshUsage, fromProviderToolCall, geminiAdapter, getCostSummary, getPrice, httpTransport, imageInputSchema, makeContracts, makeOpenAICompatibleAdapter, messageSchema, mistralAdapter, multiSink, noopSink, openaiAdapter, openaiStubAdapter, openrouterAdapter, parseClaudeCliJson, parseJsonLoose, refreshAvailability, resetRefreshState, resetRegistry, resolveTier, resolveVoice, sqliteBudgetStore, sqliteSink, streamTransport, stubProviders, subprocessTransport, tierSpecSchema, toProviderTools, toolSchema, translateInputSchema, upmetricsSink, visionInputSchema };
package/dist/index.js CHANGED
@@ -1573,6 +1573,100 @@ function buildZip(files) {
1573
1573
  return Buffer.concat([...parts, cd, eocd]);
1574
1574
  }
1575
1575
 
1576
+ // src/providers/bfl.ts
1577
+ var EU_BASE = "https://api.eu.bfl.ai";
1578
+ var BFL_CREDIT_USD = 0.01;
1579
+ var BFL_IMAGE_PRICE = 0.06;
1580
+ var sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
1581
+ function gcd(a, b) {
1582
+ return b === 0 ? a : gcd(b, a % b);
1583
+ }
1584
+ function bflAdapter(config = {}) {
1585
+ const doFetch = config.fetch ?? fetch;
1586
+ const base = config.baseUrl ?? EU_BASE;
1587
+ const pollIntervalMs = config.pollIntervalMs ?? 1500;
1588
+ const timeoutMs = config.timeoutMs ?? 12e4;
1589
+ const resolveKey = () => config.apiKey ?? process.env.BFL_API_KEY;
1590
+ async function image(req) {
1591
+ const apiKey = resolveKey();
1592
+ if (!apiKey) throw new Error("bfl adapter: BFL_API_KEY not set");
1593
+ const headers = { "content-type": "application/json", "x-key": apiKey };
1594
+ const body = { prompt: req.prompt };
1595
+ if (req.referenceImages?.length) {
1596
+ req.referenceImages.forEach((img, i) => {
1597
+ body[i === 0 ? "input_image" : `input_image_${i + 1}`] = toBflImage(img);
1598
+ });
1599
+ if (req.width) body.width = req.width;
1600
+ if (req.height) body.height = req.height;
1601
+ if (req.seed !== void 0) body.seed = req.seed;
1602
+ body.output_format = req.outputFormat ?? "jpeg";
1603
+ body.safety_tolerance = req.safetyTolerance ?? 2;
1604
+ } else if (req.finetune) {
1605
+ body.finetune_id = req.finetune;
1606
+ if (req.finetuneStrength !== void 0) body.finetune_strength = req.finetuneStrength;
1607
+ if (req.width && req.height) {
1608
+ const g = gcd(req.width, req.height) || 1;
1609
+ body.aspect_ratio = `${req.width / g}:${req.height / g}`;
1610
+ }
1611
+ } else {
1612
+ throw new Error(
1613
+ "bfl adapter: requires referenceImages (FLUX 2 multi-reference) or a finetune id. ai.image({ referenceImages: [...] }) needs no training; ai.image({ finetune }) uses a subject trained once in the BFL dashboard (dashboard.bfl.ai \u2014 finetune-create is not in the public API)."
1614
+ );
1615
+ }
1616
+ const submitRes = await doFetch(`${base}/v1/${req.spec.model}`, {
1617
+ method: "POST",
1618
+ headers,
1619
+ body: JSON.stringify(body)
1620
+ });
1621
+ if (!submitRes.ok) {
1622
+ throw new Error(`bfl ${submitRes.status}: ${(await submitRes.text().catch(() => "")).slice(0, 200)}`);
1623
+ }
1624
+ const submit = await submitRes.json();
1625
+ if (!submit.id) throw new Error("bfl: no task id in submit response");
1626
+ const sample = await poll(submit.id, apiKey);
1627
+ const usage = freshUsage({
1628
+ provider: "bfl",
1629
+ model: req.spec.model,
1630
+ transport: "http",
1631
+ capability: "image",
1632
+ inputTokens: 0,
1633
+ outputTokens: 0
1634
+ });
1635
+ usage.costUsd = typeof submit.cost === "number" ? submit.cost * BFL_CREDIT_USD : config.pricePerImage ?? BFL_IMAGE_PRICE;
1636
+ return { url: sample, usage };
1637
+ }
1638
+ function toBflImage(img) {
1639
+ if (typeof img !== "string") return Buffer.from(img).toString("base64");
1640
+ if (/^https?:\/\//i.test(img)) return img;
1641
+ const comma = img.startsWith("data:") ? img.indexOf(",") : -1;
1642
+ return comma >= 0 ? img.slice(comma + 1) : img;
1643
+ }
1644
+ async function poll(id, apiKey) {
1645
+ const headers = { "x-key": apiKey };
1646
+ const deadline = Date.now() + timeoutMs;
1647
+ for (; ; ) {
1648
+ const res = await doFetch(`${base}/v1/get_result?id=${encodeURIComponent(id)}`, { headers });
1649
+ if (!res.ok) throw new Error(`bfl get_result ${res.status}`);
1650
+ const data = await res.json();
1651
+ const status = data.status ?? "";
1652
+ if (status === "Ready") {
1653
+ const sample = data.result?.sample;
1654
+ if (!sample) throw new Error("bfl: status Ready but no result.sample url");
1655
+ return sample;
1656
+ }
1657
+ if (status === "Error" || status === "Failed" || status === "Task not found") {
1658
+ throw new Error(`bfl: generation ${status}`);
1659
+ }
1660
+ if (status.includes("Moderated")) {
1661
+ throw new Error(`bfl: ${status} \u2014 prompt or output flagged by BFL safety`);
1662
+ }
1663
+ if (Date.now() >= deadline) throw new Error(`bfl: timed out after ${timeoutMs}ms`);
1664
+ await sleep2(pollIntervalMs);
1665
+ }
1666
+ }
1667
+ return { name: "bfl", image };
1668
+ }
1669
+
1576
1670
  // src/providers/registry.ts
1577
1671
  var defaultProviders = {
1578
1672
  anthropic: anthropicAdapter(),
@@ -1582,7 +1676,8 @@ var defaultProviders = {
1582
1676
  openrouter: openrouterAdapter(),
1583
1677
  mistral: mistralAdapter(),
1584
1678
  elevenlabs: elevenlabsAdapter(),
1585
- fal: falAdapter()
1679
+ fal: falAdapter(),
1680
+ bfl: bflAdapter()
1586
1681
  };
1587
1682
 
1588
1683
  // src/cost/budget.ts
@@ -1894,6 +1989,20 @@ var imageInputSchema = z.object({
1894
1989
  loras: z.array(loraWeightSchema).optional(),
1895
1990
  /** Shorthand for a single LoRA — normalized to loras:[{path, scale:1}]. */
1896
1991
  lora: z.string().optional(),
1992
+ /** F023 — a BFL finetune id (subject trained in the BFL dashboard). Routes to the
1993
+ * EU-resident BFL finetuned-portrait endpoint. */
1994
+ finetune: z.string().optional(),
1995
+ /** F023 — BFL finetune_strength (~0–2; higher = stronger likeness). */
1996
+ finetuneStrength: z.number().min(0).max(2).optional(),
1997
+ /** F023.5 — 1–8 reference photos (URL or raw bytes) → EU-resident BFL FLUX 2
1998
+ * multi-reference generation (likeness, no training step). */
1999
+ referenceImages: z.array(z.union([z.string(), z.instanceof(Uint8Array)])).min(1).max(8).optional(),
2000
+ /** F023.5 — fixed seed for reproducible output (BFL). */
2001
+ seed: z.number().int().optional(),
2002
+ /** F023.5 — output container (BFL FLUX 2). Default jpeg. */
2003
+ outputFormat: z.enum(["jpeg", "png", "webp"]).optional(),
2004
+ /** F023.5 — BFL content-moderation strictness, 0 (strict) … 6 (lax). Default 2. */
2005
+ safetyTolerance: z.number().int().min(0).max(6).optional(),
1897
2006
  /** F021.4 — re-roll once if fal returns a black image (NSFW false-positive). */
1898
2007
  retryOnBlack: z.boolean().optional(),
1899
2008
  ...callOptions
@@ -1976,6 +2085,16 @@ var DEFAULT_TRAINSTYLE_SPEC = {
1976
2085
  model: "fal-ai/flux-lora-fast-training",
1977
2086
  transport: "http"
1978
2087
  };
2088
+ var DEFAULT_BFL_FINETUNE_SPEC = {
2089
+ provider: "bfl",
2090
+ model: "flux-pro-1.1-ultra-finetuned",
2091
+ transport: "http"
2092
+ };
2093
+ var DEFAULT_BFL_REFERENCE_SPEC = {
2094
+ provider: "bfl",
2095
+ model: "flux-2-max",
2096
+ transport: "http"
2097
+ };
1979
2098
  var DEFAULT_OCR_SPEC = { provider: "mistral", model: "mistral-ocr-latest", transport: "http" };
1980
2099
  var DEFAULT_MODERATION_SPEC = { provider: "mistral", model: "mistral-moderation-latest", transport: "http" };
1981
2100
  var DEFAULT_PODCAST_SPEC = { provider: "elevenlabs", model: "eleven_v3", transport: "http" };
@@ -2222,7 +2341,7 @@ function createAI(config = {}) {
2222
2341
  ...input.loras ?? [],
2223
2342
  ...input.lora ? [{ path: input.lora }] : []
2224
2343
  ];
2225
- const base = loras.length > 0 ? DEFAULT_LORA_IMAGE_SPEC : DEFAULT_IMAGE_SPEC;
2344
+ const base = input.referenceImages?.length ? DEFAULT_BFL_REFERENCE_SPEC : input.finetune ? DEFAULT_BFL_FINETUNE_SPEC : loras.length > 0 ? DEFAULT_LORA_IMAGE_SPEC : DEFAULT_IMAGE_SPEC;
2226
2345
  return runCapability({
2227
2346
  primary: { ...base, ...input.override },
2228
2347
  fallback: input.fallback,
@@ -2241,6 +2360,12 @@ function createAI(config = {}) {
2241
2360
  width: input.width,
2242
2361
  height: input.height,
2243
2362
  loras: loras.length ? loras : void 0,
2363
+ finetune: input.finetune,
2364
+ finetuneStrength: input.finetuneStrength,
2365
+ referenceImages: input.referenceImages,
2366
+ seed: input.seed,
2367
+ outputFormat: input.outputFormat,
2368
+ safetyTolerance: input.safetyTolerance,
2244
2369
  retryOnBlack: input.retryOnBlack
2245
2370
  });
2246
2371
  }
@@ -2496,8 +2621,8 @@ var stubProviders = {
2496
2621
  };
2497
2622
 
2498
2623
  // src/version.ts
2499
- var VERSION = "0.13.1";
2500
- var SDK_TAG = "@broberg/ai-sdk@0.13.1";
2624
+ var VERSION = "0.15.0";
2625
+ var SDK_TAG = "@broberg/ai-sdk@0.15.0";
2501
2626
 
2502
2627
  // src/availability/refresh.ts
2503
2628
  var NOT_REFRESHED = { refreshed: false, checked: 0, markedUnavailable: [] };
@@ -2783,6 +2908,7 @@ export {
2783
2908
  anthropicAdapter,
2784
2909
  anthropicApiAdapter,
2785
2910
  anthropicSubprocessAdapter,
2911
+ bflAdapter,
2786
2912
  chatInputSchema,
2787
2913
  computeCost,
2788
2914
  createAI,