@broberg/ai-sdk 0.10.0 → 0.10.2

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
@@ -936,6 +936,7 @@ declare const imageInputSchema: z.ZodObject<{
936
936
  path: string;
937
937
  scale?: number | undefined;
938
938
  }[] | undefined;
939
+ lora?: string | undefined;
939
940
  tier?: "fast" | "smart" | "powerful" | "cheap" | "vision" | "video" | "embedding" | undefined;
940
941
  override?: {
941
942
  provider?: string | undefined;
@@ -950,7 +951,6 @@ declare const imageInputSchema: z.ZodObject<{
950
951
  labels?: Record<string, string> | undefined;
951
952
  width?: number | undefined;
952
953
  height?: number | undefined;
953
- lora?: string | undefined;
954
954
  }, {
955
955
  prompt: string;
956
956
  purpose?: string | undefined;
@@ -958,6 +958,7 @@ declare const imageInputSchema: z.ZodObject<{
958
958
  path: string;
959
959
  scale?: number | undefined;
960
960
  }[] | undefined;
961
+ lora?: string | undefined;
961
962
  tier?: "fast" | "smart" | "powerful" | "cheap" | "vision" | "video" | "embedding" | undefined;
962
963
  override?: {
963
964
  provider?: string | undefined;
@@ -972,7 +973,6 @@ declare const imageInputSchema: z.ZodObject<{
972
973
  labels?: Record<string, string> | undefined;
973
974
  width?: number | undefined;
974
975
  height?: number | undefined;
975
- lora?: string | undefined;
976
976
  }>;
977
977
  declare const trainStyleInputSchema: z.ZodObject<{
978
978
  tier: z.ZodOptional<z.ZodEnum<["fast", "smart", "powerful", "cheap", "vision", "video", "embedding"]>>;
@@ -1680,8 +1680,8 @@ declare const falStubAdapter: ProviderAdapter;
1680
1680
  * wires the live adapters. */
1681
1681
  declare const stubProviders: Record<string, ProviderAdapter>;
1682
1682
 
1683
- declare const VERSION: "0.10.0";
1684
- declare const SDK_TAG: "@broberg/ai-sdk@0.10.0";
1683
+ declare const VERSION: "0.10.2";
1684
+ declare const SDK_TAG: "@broberg/ai-sdk@0.10.2";
1685
1685
 
1686
1686
  /** Built-in defaults. Every entry is overridable via AiConfig.defaults or a
1687
1687
  * per-call override. Model IDs are current at scaffold time; callers pin their
package/dist/index.js CHANGED
@@ -1334,7 +1334,7 @@ function falAdapter(config = {}) {
1334
1334
  if (!apiKey) throw new Error("fal adapter: FAL_KEY not set");
1335
1335
  const headers = authHeaders(apiKey);
1336
1336
  const body = {
1337
- images_data_url: await resolveImagesDataUrl(req.images),
1337
+ images_data_url: await resolveImagesUrl(req.images, apiKey),
1338
1338
  is_style: req.isStyle ?? true
1339
1339
  };
1340
1340
  if (req.triggerWord !== void 0) body.trigger_word = req.triggerWord;
@@ -1346,8 +1346,14 @@ function falAdapter(config = {}) {
1346
1346
  body,
1347
1347
  config.trainTimeoutMs ?? 6e5
1348
1348
  );
1349
- const loraUrl = result.diffusers_lora_file?.url;
1350
- if (!loraUrl) throw new Error("fal trainStyle: no diffusers_lora_file.url in result");
1349
+ const { loraUrl, configUrl } = extractTrainedFiles(result);
1350
+ if (!loraUrl) {
1351
+ throw new Error(
1352
+ `fal trainStyle: no LoRA file url in result \u2014 fal returned keys [${Object.keys(
1353
+ result ?? {}
1354
+ ).join(", ")}]: ${JSON.stringify(result).slice(0, 800)}`
1355
+ );
1356
+ }
1351
1357
  const usage = freshUsage({
1352
1358
  provider: "fal",
1353
1359
  model: req.spec.model,
@@ -1357,9 +1363,9 @@ function falAdapter(config = {}) {
1357
1363
  outputTokens: 0
1358
1364
  });
1359
1365
  usage.costUsd = config.pricePerTraining ?? FAL_TRAIN_PRICE_ESTIMATE;
1360
- return { loraUrl, configUrl: result.config_file?.url ?? "", usage };
1366
+ return { loraUrl, configUrl: configUrl ?? "", usage };
1361
1367
  }
1362
- async function resolveImagesDataUrl(images) {
1368
+ async function resolveImagesUrl(images, apiKey) {
1363
1369
  if (typeof images === "string") return images;
1364
1370
  const files = await Promise.all(
1365
1371
  images.map(async (url, i) => {
@@ -1368,8 +1374,27 @@ function falAdapter(config = {}) {
1368
1374
  return { name: fileNameFromUrl(url, i), data: new Uint8Array(await res.arrayBuffer()) };
1369
1375
  })
1370
1376
  );
1371
- const zip = buildZip(files);
1372
- return `data:application/zip;base64,${Buffer.from(zip).toString("base64")}`;
1377
+ return uploadToFalStorage(buildZip(files), "application/zip", "styleset.zip", apiKey);
1378
+ }
1379
+ async function uploadToFalStorage(bytes, contentType, fileName, apiKey) {
1380
+ const initiate = await doFetch("https://rest.alpha.fal.ai/storage/upload/initiate", {
1381
+ method: "POST",
1382
+ headers: { Authorization: `Key ${apiKey}`, "content-type": "application/json" },
1383
+ body: JSON.stringify({ content_type: contentType, file_name: fileName })
1384
+ });
1385
+ if (!initiate.ok) {
1386
+ throw new Error(
1387
+ `fal storage initiate ${initiate.status}: ${(await initiate.text().catch(() => "")).slice(0, 200)}`
1388
+ );
1389
+ }
1390
+ const { upload_url, file_url } = await initiate.json();
1391
+ const put = await doFetch(upload_url, {
1392
+ method: "PUT",
1393
+ headers: { "content-type": contentType },
1394
+ body: bytes
1395
+ });
1396
+ if (!put.ok) throw new Error(`fal storage upload PUT ${put.status}`);
1397
+ return file_url;
1373
1398
  }
1374
1399
  async function runSync(model, headers, body) {
1375
1400
  const res = await doFetch(`${syncBase}/${model}`, {
@@ -1416,10 +1441,45 @@ function falAdapter(config = {}) {
1416
1441
  await sleep(pollIntervalMs);
1417
1442
  }
1418
1443
  const resultRes = await doFetch(responseUrl, { headers });
1444
+ if (!resultRes.ok) {
1445
+ throw new Error(
1446
+ `fal queue result ${resultRes.status}: ${(await resultRes.text().catch(() => "")).slice(0, 300)}`
1447
+ );
1448
+ }
1419
1449
  return resultRes.json();
1420
1450
  }
1421
1451
  return { name: "fal", image, trainStyle };
1422
1452
  }
1453
+ function urlOf(v) {
1454
+ if (typeof v === "string") return v;
1455
+ if (v && typeof v === "object" && typeof v.url === "string") {
1456
+ return v.url;
1457
+ }
1458
+ return void 0;
1459
+ }
1460
+ function deepFindUrl(obj, match) {
1461
+ const stack = [obj];
1462
+ while (stack.length) {
1463
+ const cur = stack.pop();
1464
+ if (typeof cur === "string") {
1465
+ if (match(cur)) return cur;
1466
+ continue;
1467
+ }
1468
+ if (cur && typeof cur === "object") {
1469
+ const u = cur.url;
1470
+ if (typeof u === "string" && match(u)) return u;
1471
+ for (const v of Object.values(cur)) stack.push(v);
1472
+ }
1473
+ }
1474
+ return void 0;
1475
+ }
1476
+ function extractTrainedFiles(result) {
1477
+ const r = result;
1478
+ const root = r?.data ?? r?.response ?? r?.output ?? r;
1479
+ const loraUrl = urlOf(root?.diffusers_lora_file) ?? urlOf(root?.lora_file) ?? urlOf(root?.safetensors) ?? urlOf(root?.lora) ?? deepFindUrl(root, (u) => /\.safetensors(\?|$)/i.test(u));
1480
+ const configUrl = urlOf(root?.config_file) ?? urlOf(root?.config) ?? deepFindUrl(root, (u) => /config[^/]*\.json(\?|$)/i.test(u));
1481
+ return { loraUrl, configUrl };
1482
+ }
1423
1483
  function fileNameFromUrl(url, i) {
1424
1484
  const base = url.split("?")[0].split("/").pop() || "";
1425
1485
  return /\.[a-z0-9]+$/i.test(base) ? base : `image_${i}.png`;
@@ -2378,8 +2438,8 @@ var stubProviders = {
2378
2438
  };
2379
2439
 
2380
2440
  // src/version.ts
2381
- var VERSION = "0.10.0";
2382
- var SDK_TAG = "@broberg/ai-sdk@0.10.0";
2441
+ var VERSION = "0.10.2";
2442
+ var SDK_TAG = "@broberg/ai-sdk@0.10.2";
2383
2443
 
2384
2444
  // src/cost/budget-store.ts
2385
2445
  function sqliteBudgetStore(config) {