pixelkiln 0.65.0 → 0.66.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.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/types.ts
2
2
  import { z } from "zod";
3
3
  var MediaTypeSchema = z.enum(["image/png", "image/gif"]);
4
- var GeneratorSchema = z.enum(["1dir", "map", "pixflux", "tiles", "animation", "frames", "character", "terrain", "imagePro", "isometricTile", "objectPro", "uiAsset", "uiElement"]);
4
+ var GeneratorSchema = z.enum(["1dir", "map", "pixflux", "tiles", "animation", "frames", "character", "terrain", "imagePro", "isometricTile", "objectPro", "uiAsset", "uiElement", "imageProFlash"]);
5
5
  var GridConfidenceSchema = z.enum(["low", "medium", "high"]);
6
6
  var RevisionModeSchema = z.enum([
7
7
  "image-to-image",
@@ -328,8 +328,22 @@ var RevisionSchema = z.object({
328
328
  /** `animate-pixminimax` only: facing direction, used only alongside `enhancePrompt` to hold the sprite's facing. */
329
329
  direction: CharacterDirectionSchema.optional(),
330
330
  /** `animate`/`animate-pixminimax` only: let PixelLab expand the action into a fuller motion description first. */
331
- enhancePrompt: z.boolean().optional()
331
+ enhancePrompt: z.boolean().optional(),
332
+ /**
333
+ * `image-to-image`/`inpaint` only: which provider engine draws the
334
+ * edit. `pro-flash` selects PixelLab's Pro Flash edit and inpaint tier
335
+ * (`/edit-image-pro-flash`, `/inpaint-image-pro-flash`) instead of the
336
+ * default Pro endpoints; omit it for the default.
337
+ */
338
+ engine: z.enum(["pro-flash"]).optional()
332
339
  }).strict().superRefine((revision, context) => {
340
+ if (revision.engine !== void 0 && revision.mode !== "image-to-image" && revision.mode !== "inpaint") {
341
+ context.addIssue({
342
+ code: z.ZodIssueCode.custom,
343
+ message: "engine applies to image-to-image and inpaint revisions only",
344
+ path: ["engine"]
345
+ });
346
+ }
333
347
  if (revision.mode === "inpaint" && !revision.mask) {
334
348
  context.addIssue({
335
349
  code: z.ZodIssueCode.custom,
@@ -618,8 +632,8 @@ var StyleObjectSchema = z.object({
618
632
  /** `character` only. Body template: `mannequin` (default), a quadruped (`bear`, `cat`, `dog`, `horse`, `lion`), or `custom` for `pro-flash`. */
619
633
  template: z.string().min(1).optional(),
620
634
  /**
621
- * `character` only, `pro-flash` bases with a style image: which traits
622
- * the style image lends. Each defaults to true.
635
+ * `character` `pro-flash` bases and `imageProFlash` styles, with a
636
+ * style image: which traits the style image lends. Each defaults to true.
623
637
  */
624
638
  styleTraits: z.object({
625
639
  palette: z.boolean().optional(),
@@ -1052,7 +1066,8 @@ var LockEntrySchema = z.object({
1052
1066
  fps: z.number().int().min(1).max(60).optional(),
1053
1067
  lastFrameSha256: z.string().regex(/^[0-9a-f]{64}$/).optional(),
1054
1068
  direction: CharacterDirectionSchema.optional(),
1055
- enhancePrompt: z.boolean().optional()
1069
+ enhancePrompt: z.boolean().optional(),
1070
+ engine: z.enum(["pro-flash"]).optional()
1056
1071
  }).strict().nullable().default(null),
1057
1072
  /** For a mirror: the asset it flips and a hash over that asset's output hashes when this was made. */
1058
1073
  mirror: z.object({
@@ -1429,6 +1444,14 @@ var CorrectPixelartResponseSchema = z2.object({
1429
1444
  images: z2.array(z2.object({ base64: z2.string().min(1) }).passthrough()).min(1),
1430
1445
  usage: z2.unknown().optional()
1431
1446
  }).passthrough();
1447
+ var ProFlashImageSubmitSchema = z2.object({
1448
+ background_job_id: z2.string().min(1),
1449
+ image_id: z2.string().min(1),
1450
+ source_image_id: z2.string().min(1),
1451
+ status: z2.string().default("processing"),
1452
+ estimated_generations: z2.number().nullable().optional(),
1453
+ usage: z2.unknown().optional()
1454
+ }).passthrough();
1432
1455
  var UnzoomResponseSchema = z2.object({
1433
1456
  image: z2.object({ base64: z2.string().min(1) }).passthrough(),
1434
1457
  original_size: z2.object({ width: z2.number().int(), height: z2.number().int() }).passthrough(),
@@ -1869,7 +1892,7 @@ var PixelLabClient = class {
1869
1892
  const body = {
1870
1893
  description: args.description,
1871
1894
  n_directions: args.directions,
1872
- ...args.reference ? { first_frame: encode(args.reference) } : { image_size: { width: args.size, height: args.size } },
1895
+ ...args.sourceImageId ? { source_image_id: args.sourceImageId } : args.reference ? { first_frame: encode(args.reference) } : { image_size: { width: args.size, height: args.size } },
1873
1896
  ...args.view ? { view: args.view } : {},
1874
1897
  ...args.seed != null ? { seed: args.seed } : {},
1875
1898
  ...args.styleReference && args.styleReferenceSize ? {
@@ -2016,8 +2039,9 @@ var PixelLabClient = class {
2016
2039
  description: args.description,
2017
2040
  template_id: args.template,
2018
2041
  n_directions: 8,
2019
- // The author's sprite sets the canvas; a size only applies to text creation.
2020
- ...south ? { first_frame: encode(south) } : { image_size: imageSize },
2042
+ // The author's sprite sets the canvas; a size only applies to text
2043
+ // creation. An owned copy of the same sprite is referenced by id.
2044
+ ...args.sourceImageId ? { source_image_id: args.sourceImageId } : south ? { first_frame: encode(south) } : { image_size: imageSize },
2021
2045
  ...args.view ? { view: args.view } : {},
2022
2046
  ...args.seed != null ? { seed: args.seed } : {},
2023
2047
  ...args.styleReference && args.styleReferenceSize ? {
@@ -2289,6 +2313,66 @@ var PixelLabClient = class {
2289
2313
  "generate-image-v2"
2290
2314
  );
2291
2315
  }
2316
+ /**
2317
+ * `/create-image-pro-flash`: one native pixel-art image from a
2318
+ * description, optionally styled after a style image with per-trait
2319
+ * toggles, on the same Pro Flash model `character`/`objectPro` use for
2320
+ * their `pro-flash` engine. Sizes run 16 to 256 per side in multiples of 4.
2321
+ * A plain background job; `pollRevision`'s generic reader takes the
2322
+ * finished image. The response's `source_image_id` is what a Pro Flash
2323
+ * character or object can reuse instead of an upload.
2324
+ */
2325
+ async createImageProFlash(args) {
2326
+ const body = {
2327
+ description: args.description,
2328
+ image_size: { width: args.width, height: args.height }
2329
+ };
2330
+ if (args.noBackground != null) body.no_background = args.noBackground;
2331
+ if (args.seed != null) body.seed = args.seed;
2332
+ if (args.styleImage) {
2333
+ body.style_image = { image: args.styleImage.image, size: { width: args.styleImage.width, height: args.styleImage.height } };
2334
+ const traits = args.styleTraits;
2335
+ if (traits) {
2336
+ body.style_options = {
2337
+ ...traits.palette !== void 0 ? { color_palette: traits.palette } : {},
2338
+ ...traits.outline !== void 0 ? { outline: traits.outline } : {},
2339
+ ...traits.detail !== void 0 ? { detail: traits.detail } : {},
2340
+ ...traits.shading !== void 0 ? { shading: traits.shading } : {}
2341
+ };
2342
+ }
2343
+ }
2344
+ return validateResponse(
2345
+ ProFlashImageSubmitSchema,
2346
+ await this.request("/create-image-pro-flash", { method: "POST", body: JSON.stringify(body) }),
2347
+ "create-image-pro-flash"
2348
+ );
2349
+ }
2350
+ /** `/edit-image-pro-flash`, text method: edit one image at its own size. The canvas never grows or resizes. */
2351
+ async editImageProFlash(args) {
2352
+ const body = { image: args.image, method: "text", description: args.description };
2353
+ if (args.noBackground != null) body.no_background = args.noBackground;
2354
+ if (args.seed != null) body.seed = args.seed;
2355
+ return validateResponse(
2356
+ ProFlashImageSubmitSchema,
2357
+ await this.request("/edit-image-pro-flash", { method: "POST", body: JSON.stringify(body) }),
2358
+ "edit-image-pro-flash"
2359
+ );
2360
+ }
2361
+ /**
2362
+ * `/inpaint-image-pro-flash`: replace only the white pixels of a same-size
2363
+ * black/white mask, keeping everything else exactly. `Modify current
2364
+ * layer` (the endpoint's default) returns the full composite.
2365
+ */
2366
+ async inpaintImageProFlash(args) {
2367
+ const body = { image: args.image, mask_image: args.maskImage, description: args.description };
2368
+ if (args.noBackground != null) body.no_background = args.noBackground;
2369
+ if (args.seed != null) body.seed = args.seed;
2370
+ return validateResponse(
2371
+ ProFlashImageSubmitSchema,
2372
+ await this.request("/inpaint-image-pro-flash", { method: "POST", body: JSON.stringify(body) }),
2373
+ "inpaint-image-pro-flash"
2374
+ );
2375
+ }
2292
2376
  /**
2293
2377
  * `/generate-ui-v2` ("Generate UI (Pro)"): one UI element (a button, a
2294
2378
  * health bar, an inventory slot, a dialogue box) from a description,
@@ -3169,6 +3253,7 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
3169
3253
  uiPieces: spec.uiPieces,
3170
3254
  uiElements: spec.uiElements,
3171
3255
  uiColorPalette: spec.uiColorPalette,
3256
+ styleTraits: spec.styleTraits,
3172
3257
  styleImages: styleImageHashes,
3173
3258
  // A character family: the engine and rotations of a base, the parent's
3174
3259
  // generated bytes for a state or animation (so a regenerated parent
@@ -3245,7 +3330,8 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
3245
3330
  fps: spec.revision.fps,
3246
3331
  lastFrameSha256: spec.revision.lastFrameSha256,
3247
3332
  direction: spec.revision.direction,
3248
- enhancePrompt: spec.revision.enhancePrompt
3333
+ enhancePrompt: spec.revision.enhancePrompt,
3334
+ engine: spec.revision.engine
3249
3335
  } : void 0
3250
3336
  })
3251
3337
  );
@@ -3301,8 +3387,11 @@ function proFlashCharacterCost(width, height, fromReference) {
3301
3387
  const side = Math.max(32, Math.ceil(Math.max(width, height) / 4) * 4);
3302
3388
  const rotations = Math.max(1, Math.ceil(side * side * 8 / 65536));
3303
3389
  if (fromReference) return rotations;
3304
- const image = side <= 96 ? 5 : side <= 208 ? 6 : 9;
3305
- return image + rotations;
3390
+ return proFlashImageCost(side, side) + rotations;
3391
+ }
3392
+ function proFlashImageCost(width, height) {
3393
+ const side = Math.max(width, height);
3394
+ return side <= 96 ? 5 : side <= 208 ? 6 : 9;
3306
3395
  }
3307
3396
  function characterAnimationName(spec) {
3308
3397
  return `pixelkiln:${spec.styleId}/${spec.assetId}`;
@@ -3378,7 +3467,7 @@ var PixelLabProvider = class _PixelLabProvider {
3378
3467
  return new _PixelLabProvider(new PixelLabClient("download-only"));
3379
3468
  }
3380
3469
  supports(generator) {
3381
- return generator === "1dir" || generator === "map" || generator === "pixflux" || generator === "tiles" || generator === "terrain" || generator === "imagePro" || generator === "character" || generator === "isometricTile" || generator === "objectPro" || generator === "uiAsset" || generator === "uiElement";
3470
+ return generator === "1dir" || generator === "map" || generator === "pixflux" || generator === "tiles" || generator === "terrain" || generator === "imagePro" || generator === "character" || generator === "isometricTile" || generator === "objectPro" || generator === "uiAsset" || generator === "uiElement" || generator === "imageProFlash";
3382
3471
  }
3383
3472
  /**
3384
3473
  * `inpaint` (`/inpaint-v3`, a mask) and `image-to-image` (`/edit-images-v2`,
@@ -3440,6 +3529,13 @@ var PixelLabProvider = class _PixelLabProvider {
3440
3529
  const base = Math.max(1, Math.ceil(width * height * frames / 65536));
3441
3530
  return { unit: "generations", amount: spec.revision.enhancePrompt ? base + 0.05 : base, candidates: 1 };
3442
3531
  }
3532
+ if (spec.revision?.engine === "pro-flash") {
3533
+ return {
3534
+ unit: "generations",
3535
+ amount: proFlashImageCost(spec.revision.sourceWidth ?? spec.width, spec.revision.sourceHeight ?? spec.height),
3536
+ candidates: 1
3537
+ };
3538
+ }
3443
3539
  if (spec.revision) {
3444
3540
  const width = spec.revision.sourceWidth ?? spec.width;
3445
3541
  const height = spec.revision.sourceHeight ?? spec.height;
@@ -3454,6 +3550,9 @@ var PixelLabProvider = class _PixelLabProvider {
3454
3550
  if (spec.generator === "objectPro") {
3455
3551
  return { unit: "generations", amount: objectProCost(spec), candidates: 1 };
3456
3552
  }
3553
+ if (spec.generator === "imageProFlash") {
3554
+ return { unit: "generations", amount: proFlashImageCost(spec.width, spec.height), candidates: 1 };
3555
+ }
3457
3556
  return {
3458
3557
  unit: "generations",
3459
3558
  amount: generationCost(spec.width, spec.height, spec.generator),
@@ -3467,7 +3566,17 @@ var PixelLabProvider = class _PixelLabProvider {
3467
3566
  `PixelLab ${spec.revision.mode} reads one source image; ${spec.revision.sourceAssetId} is a ${members.length}-member set (${members[0].role}, ...). Revise one member through a declared source, or use reduce-colors, correct-pixelart, or edit-animation, which take the whole set`
3468
3567
  );
3469
3568
  }
3470
- if (spec.revision?.mode === "inpaint") {
3569
+ if (spec.revision?.engine === "pro-flash") {
3570
+ const { sourceWidth: width, sourceHeight: height, mode: mode2 } = spec.revision;
3571
+ if (width != null && height != null && (width < 32 || height < 32 || width > 256 || height > 256 || width % 4 || height % 4)) {
3572
+ throw new Error(
3573
+ `PixelLab pro-flash ${mode2} source is ${width}x${height}; the API takes 32 to 256 pixels per side, in multiples of 4`
3574
+ );
3575
+ }
3576
+ if (spec.revision.strength != null) {
3577
+ throw new Error(`PixelLab pro-flash ${mode2} takes no strength; the edit applies in full`);
3578
+ }
3579
+ } else if (spec.revision?.mode === "inpaint") {
3471
3580
  const { sourceWidth: width, sourceHeight: height } = spec.revision;
3472
3581
  if (width != null && height != null && (width < 32 || height < 32 || width > 512 || height > 512)) {
3473
3582
  throw new Error(`PixelLab inpaint source is ${width}x${height}; the API takes 32 to 512 pixels per side`);
@@ -3548,6 +3657,19 @@ var PixelLabProvider = class _PixelLabProvider {
3548
3657
  `PixelLab uiAsset is ${spec.width}x${spec.height}; the API takes 192 to 688 pixels per side (the exact ceiling also depends on aspect ratio \u2014 square tops out at 512, 16:9 at 688x384, 9:16 at 384x688, 4:3 at 600x448, 3:4 at 448x600)`
3549
3658
  );
3550
3659
  }
3660
+ if (spec.generator === "imageProFlash") {
3661
+ if (spec.width < 16 || spec.height < 16 || spec.width > 256 || spec.height > 256 || spec.width % 4 || spec.height % 4) {
3662
+ throw new Error(
3663
+ `PixelLab imageProFlash is ${spec.width}x${spec.height}; the API takes 16 to 256 pixels per side, in multiples of 4`
3664
+ );
3665
+ }
3666
+ if (styleImages.length > 1) {
3667
+ throw new Error("PixelLab imageProFlash takes one style image; list at most one styleImages entry");
3668
+ }
3669
+ if (spec.styleTraits && !styleImages.length) {
3670
+ throw new Error("PixelLab imageProFlash: styleTraits choose what a style image lends; add a styleImages entry or drop them");
3671
+ }
3672
+ }
3551
3673
  if (spec.generator === "uiElement" && (spec.width < 16 || spec.height < 16 || spec.width > 792 || spec.height > 688)) {
3552
3674
  throw new Error(
3553
3675
  `PixelLab uiElement is ${spec.width}x${spec.height}; the API takes 16 to 792 wide and 16 to 688 tall (the exact ceiling depends on aspect ratio \u2014 square tops out at 512, 16:9 at 688x384)`
@@ -3901,7 +4023,8 @@ var PixelLabProvider = class _PixelLabProvider {
3901
4023
  concept: character.concept ? readPose(spec, "concept image", character.concept) : void 0,
3902
4024
  styleCharacterId: character.styleAnchor ? requireStyleObjectId(spec, context) : void 0,
3903
4025
  styleReferenceSize: styleImage ? { width: styleImage.width, height: styleImage.height } : void 0,
3904
- styleTraits: character.styleTraits
4026
+ styleTraits: character.styleTraits,
4027
+ sourceImageId: character.mode === "pro-flash" ? context?.referenceSourceImageId : void 0
3905
4028
  });
3906
4029
  return { jobId: res2.character_id, metadata: { character: { kind: "base", characterId: res2.character_id, mode: character.mode, directions: character.directions, backgroundJobId: res2.background_job_id } } };
3907
4030
  }
@@ -4036,7 +4159,8 @@ var PixelLabProvider = class _PixelLabProvider {
4036
4159
  reference: object.reference ? readPose(spec, "reference sprite", object.reference) : void 0,
4037
4160
  styleReference: styleImage ? { base64: styleImage.base64, format: styleImage.format } : void 0,
4038
4161
  styleReferenceSize: styleImage ? { width: styleImage.width, height: styleImage.height } : void 0,
4039
- styleTraits: object.styleTraits
4162
+ styleTraits: object.styleTraits,
4163
+ sourceImageId: context?.referenceSourceImageId
4040
4164
  });
4041
4165
  return { jobId: res2.object_id, metadata: { objectPro: { kind: "base", objectId: res2.object_id, directions: object.directions, backgroundJobId: res2.background_job_id } } };
4042
4166
  }
@@ -4335,6 +4459,19 @@ var PixelLabProvider = class _PixelLabProvider {
4335
4459
  });
4336
4460
  return { jobId: res2.ui_asset_id, metadata: { backgroundJobId: res2.background_job_id } };
4337
4461
  }
4462
+ if (spec.generator === "imageProFlash") {
4463
+ const style = styleImages[0];
4464
+ const res2 = await this.client.createImageProFlash({
4465
+ description: spec.prompt,
4466
+ width: spec.width,
4467
+ height: spec.height,
4468
+ noBackground: spec.noBackground,
4469
+ seed: spec.seed,
4470
+ styleImage: style ? { image: { base64: style.base64, format: style.format }, width: style.width, height: style.height } : void 0,
4471
+ styleTraits: spec.styleTraits
4472
+ });
4473
+ return { jobId: res2.background_job_id, metadata: { imageProFlash: proFlashRecord(res2) } };
4474
+ }
4338
4475
  if (spec.generator === "uiElement") {
4339
4476
  const concept = styleImages[0];
4340
4477
  const res2 = await this.client.generateUiV2({
@@ -4488,6 +4625,32 @@ var PixelLabProvider = class _PixelLabProvider {
4488
4625
  const width = revision.sourceWidth;
4489
4626
  const height = revision.sourceHeight;
4490
4627
  const roles = revision.sourceMembers?.map((member) => member.role);
4628
+ if (revision.engine === "pro-flash") {
4629
+ if (revision.mode === "inpaint") {
4630
+ if (!revision.maskFile || !revision.maskSha256 || !revision.maskFormat) {
4631
+ throw new Error(`${spec.styleId}/${spec.assetId}: revision mask is not ready`);
4632
+ }
4633
+ const maskBytes = readFileSync(revision.maskFile);
4634
+ if (sha256(maskBytes) !== revision.maskSha256) {
4635
+ throw new Error(`${spec.styleId}/${spec.assetId}: revision mask changed after the manifest was resolved`);
4636
+ }
4637
+ const res3 = await this.client.inpaintImageProFlash({
4638
+ image,
4639
+ maskImage: { base64: maskBytes.toString("base64"), format: revision.maskFormat },
4640
+ description: spec.prompt,
4641
+ noBackground: spec.noBackground,
4642
+ seed: spec.seed
4643
+ });
4644
+ return { jobId: res3.background_job_id, metadata: { imageProFlash: proFlashRecord(res3) } };
4645
+ }
4646
+ const res2 = await this.client.editImageProFlash({
4647
+ image,
4648
+ description: spec.prompt,
4649
+ noBackground: spec.noBackground,
4650
+ seed: spec.seed
4651
+ });
4652
+ return { jobId: res2.background_job_id, metadata: { imageProFlash: proFlashRecord(res2) } };
4653
+ }
4491
4654
  if (revision.mode === "inpaint") {
4492
4655
  if (!revision.maskFile || !revision.maskSha256 || !revision.maskFormat) {
4493
4656
  throw new Error(`${spec.styleId}/${spec.assetId}: revision mask is not ready`);
@@ -4652,6 +4815,7 @@ var PixelLabProvider = class _PixelLabProvider {
4652
4815
  return this.pollAnimateRevision(jobId, context);
4653
4816
  }
4654
4817
  if (context?.spec?.revision) return this.pollRevision(jobId);
4818
+ if (generator === "imageProFlash") return this.pollRevision(jobId);
4655
4819
  if (generator === "pixflux") {
4656
4820
  const file = path.join(_PixelLabProvider.cacheDir(), `${jobId}.png`);
4657
4821
  if (existsSync(file)) {
@@ -5232,6 +5396,13 @@ function readPose(spec, what, image) {
5232
5396
  }
5233
5397
  return { base64: bytes.toString("base64"), format: image.format };
5234
5398
  }
5399
+ function proFlashRecord(res) {
5400
+ return {
5401
+ imageId: res.image_id,
5402
+ sourceImageId: res.source_image_id,
5403
+ ...res.estimated_generations != null ? { estimatedGenerations: res.estimated_generations } : {}
5404
+ };
5405
+ }
5235
5406
  function editAnimationFrameCeiling(width, height) {
5236
5407
  const side = Math.max(width, height);
5237
5408
  if (side <= 64) return 16;
@@ -6435,6 +6606,11 @@ var ComfyUIProvider = class _ComfyUIProvider {
6435
6606
  throw new Error("ComfyUI providerOptions.frames requires generator: frames");
6436
6607
  }
6437
6608
  if (spec.revision) {
6609
+ if (spec.revision.engine) {
6610
+ throw new Error(
6611
+ `ComfyUI has no "${spec.revision.engine}" revision engine; that selects PixelLab's Pro Flash edit/inpaint endpoints. Drop engine to run the revision through this style's own workflow.`
6612
+ );
6613
+ }
6438
6614
  if (spec.revision.sourceMembers) {
6439
6615
  throw new Error(
6440
6616
  `ComfyUI revisions read one source image; ${spec.revision.sourceAssetId} is a ${spec.revision.sourceMembers.length}-member set (directions or frames)`
@@ -8032,6 +8208,7 @@ async function resolveSpecs(loaded, filter) {
8032
8208
  uiPieces: generator === "uiAsset" ? asset.pieces : void 0,
8033
8209
  uiElements: generator === "uiAsset" ? asset.elements : void 0,
8034
8210
  uiColorPalette: generator === "uiAsset" || generator === "uiElement" ? style.uiColorPalette : void 0,
8211
+ ...generator === "imageProFlash" && style.styleTraits ? { styleTraits: style.styleTraits } : {},
8035
8212
  palette: style.palette,
8036
8213
  enforcePalette: style.enforcePalette,
8037
8214
  noBackground: style.noBackground,
@@ -8315,7 +8492,8 @@ async function resolveSpecs(loaded, filter) {
8315
8492
  lastFrameFormat: lastFrame?.format ?? null
8316
8493
  } : {},
8317
8494
  ...asset.revision.direction ? { direction: asset.revision.direction } : {},
8318
- ...asset.revision.enhancePrompt == null ? {} : { enhancePrompt: asset.revision.enhancePrompt }
8495
+ ...asset.revision.enhancePrompt == null ? {} : { enhancePrompt: asset.revision.enhancePrompt },
8496
+ ...asset.revision.engine ? { engine: asset.revision.engine } : {}
8319
8497
  };
8320
8498
  }
8321
8499
  if (asset.batch) {
@@ -13087,7 +13265,8 @@ async function submit(provider, loaded, items, lock, lockPath, opts = {}) {
13087
13265
  ...spec.revision.fps == null ? {} : { fps: spec.revision.fps },
13088
13266
  ...spec.revision.lastFrameSha256 ? { lastFrameSha256: spec.revision.lastFrameSha256 } : {},
13089
13267
  ...spec.revision.direction ? { direction: spec.revision.direction } : {},
13090
- ...spec.revision.enhancePrompt == null ? {} : { enhancePrompt: spec.revision.enhancePrompt }
13268
+ ...spec.revision.enhancePrompt == null ? {} : { enhancePrompt: spec.revision.enhancePrompt },
13269
+ ...spec.revision.engine ? { engine: spec.revision.engine } : {}
13091
13270
  } : null,
13092
13271
  outfit: spec.character?.kind === "outfit" && outfitParentEntry ? {
13093
13272
  sourceAssetId: spec.character.parentAssetId,
@@ -13131,8 +13310,10 @@ async function submit(provider, loaded, items, lock, lockPath, opts = {}) {
13131
13310
  path: currentEntryOutputPath(parentEntry, spec.character.parentSpec, index),
13132
13311
  role: output.role
13133
13312
  })) : void 0;
13313
+ const referenceSourceImageId = ownedReferenceImageId(spec, lock, provider.id);
13134
13314
  const { jobId, metadata } = await provider.submit(spec, refs, {
13135
13315
  ...previousJobId ? { previousJobId } : {},
13316
+ ...referenceSourceImageId ? { referenceSourceImageId } : {},
13136
13317
  ...parentEntry?.objectId ? { parentObjectId: parentEntry.objectId } : {},
13137
13318
  ...anchorEntry?.objectId ? { styleObjectId: anchorEntry.objectId } : {},
13138
13319
  ...parentOutputs ? { parentOutputs } : {},
@@ -13199,6 +13380,17 @@ async function submit(provider, loaded, items, lock, lockPath, opts = {}) {
13199
13380
  }
13200
13381
  return { submitted, failed, spent, unit };
13201
13382
  }
13383
+ function ownedReferenceImageId(spec, lock, providerId) {
13384
+ const sha2562 = spec.character?.kind === "base" && spec.character.mode === "pro-flash" ? spec.character.reference?.south?.sha256 : spec.objectPro?.kind === "base" ? spec.objectPro.reference?.sha256 : void 0;
13385
+ if (!sha2562) return void 0;
13386
+ for (const entry of Object.values(lock.entries)) {
13387
+ if (entry.provider !== providerId || entry.generator !== "imageProFlash" || entry.status !== "downloaded") continue;
13388
+ if (entry.outputs.length !== 1 || entry.outputs[0].sha256 !== sha2562) continue;
13389
+ const recorded = entry.providerMetadata?.[providerId]?.imageProFlash;
13390
+ if (typeof recorded?.sourceImageId === "string" && recorded.sourceImageId) return recorded.sourceImageId;
13391
+ }
13392
+ return void 0;
13393
+ }
13202
13394
 
13203
13395
  // src/pipeline/poll.ts
13204
13396
  var sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));