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/cli.js CHANGED
@@ -679,6 +679,7 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
679
679
  uiPieces: spec.uiPieces,
680
680
  uiElements: spec.uiElements,
681
681
  uiColorPalette: spec.uiColorPalette,
682
+ styleTraits: spec.styleTraits,
682
683
  styleImages: styleImageHashes,
683
684
  // A character family: the engine and rotations of a base, the parent's
684
685
  // generated bytes for a state or animation (so a regenerated parent
@@ -755,7 +756,8 @@ function specHash(spec, styleImageHashes, providerOptionIdentity = spec.provider
755
756
  fps: spec.revision.fps,
756
757
  lastFrameSha256: spec.revision.lastFrameSha256,
757
758
  direction: spec.revision.direction,
758
- enhancePrompt: spec.revision.enhancePrompt
759
+ enhancePrompt: spec.revision.enhancePrompt,
760
+ engine: spec.revision.engine
759
761
  } : void 0
760
762
  })
761
763
  );
@@ -773,7 +775,7 @@ import path2 from "path";
773
775
  // src/types.ts
774
776
  import { z } from "zod";
775
777
  var MediaTypeSchema = z.enum(["image/png", "image/gif"]);
776
- var GeneratorSchema = z.enum(["1dir", "map", "pixflux", "tiles", "animation", "frames", "character", "terrain", "imagePro", "isometricTile", "objectPro", "uiAsset", "uiElement"]);
778
+ var GeneratorSchema = z.enum(["1dir", "map", "pixflux", "tiles", "animation", "frames", "character", "terrain", "imagePro", "isometricTile", "objectPro", "uiAsset", "uiElement", "imageProFlash"]);
777
779
  var GridConfidenceSchema = z.enum(["low", "medium", "high"]);
778
780
  var RevisionModeSchema = z.enum([
779
781
  "image-to-image",
@@ -1100,8 +1102,22 @@ var RevisionSchema = z.object({
1100
1102
  /** `animate-pixminimax` only: facing direction, used only alongside `enhancePrompt` to hold the sprite's facing. */
1101
1103
  direction: CharacterDirectionSchema.optional(),
1102
1104
  /** `animate`/`animate-pixminimax` only: let PixelLab expand the action into a fuller motion description first. */
1103
- enhancePrompt: z.boolean().optional()
1105
+ enhancePrompt: z.boolean().optional(),
1106
+ /**
1107
+ * `image-to-image`/`inpaint` only: which provider engine draws the
1108
+ * edit. `pro-flash` selects PixelLab's Pro Flash edit and inpaint tier
1109
+ * (`/edit-image-pro-flash`, `/inpaint-image-pro-flash`) instead of the
1110
+ * default Pro endpoints; omit it for the default.
1111
+ */
1112
+ engine: z.enum(["pro-flash"]).optional()
1104
1113
  }).strict().superRefine((revision, context) => {
1114
+ if (revision.engine !== void 0 && revision.mode !== "image-to-image" && revision.mode !== "inpaint") {
1115
+ context.addIssue({
1116
+ code: z.ZodIssueCode.custom,
1117
+ message: "engine applies to image-to-image and inpaint revisions only",
1118
+ path: ["engine"]
1119
+ });
1120
+ }
1105
1121
  if (revision.mode === "inpaint" && !revision.mask) {
1106
1122
  context.addIssue({
1107
1123
  code: z.ZodIssueCode.custom,
@@ -1390,8 +1406,8 @@ var StyleObjectSchema = z.object({
1390
1406
  /** `character` only. Body template: `mannequin` (default), a quadruped (`bear`, `cat`, `dog`, `horse`, `lion`), or `custom` for `pro-flash`. */
1391
1407
  template: z.string().min(1).optional(),
1392
1408
  /**
1393
- * `character` only, `pro-flash` bases with a style image: which traits
1394
- * the style image lends. Each defaults to true.
1409
+ * `character` `pro-flash` bases and `imageProFlash` styles, with a
1410
+ * style image: which traits the style image lends. Each defaults to true.
1395
1411
  */
1396
1412
  styleTraits: z.object({
1397
1413
  palette: z.boolean().optional(),
@@ -1824,7 +1840,8 @@ var LockEntrySchema = z.object({
1824
1840
  fps: z.number().int().min(1).max(60).optional(),
1825
1841
  lastFrameSha256: z.string().regex(/^[0-9a-f]{64}$/).optional(),
1826
1842
  direction: CharacterDirectionSchema.optional(),
1827
- enhancePrompt: z.boolean().optional()
1843
+ enhancePrompt: z.boolean().optional(),
1844
+ engine: z.enum(["pro-flash"]).optional()
1828
1845
  }).strict().nullable().default(null),
1829
1846
  /** For a mirror: the asset it flips and a hash over that asset's output hashes when this was made. */
1830
1847
  mirror: z.object({
@@ -5036,6 +5053,11 @@ var ComfyUIProvider = class _ComfyUIProvider {
5036
5053
  throw new Error("ComfyUI providerOptions.frames requires generator: frames");
5037
5054
  }
5038
5055
  if (spec.revision) {
5056
+ if (spec.revision.engine) {
5057
+ throw new Error(
5058
+ `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.`
5059
+ );
5060
+ }
5039
5061
  if (spec.revision.sourceMembers) {
5040
5062
  throw new Error(
5041
5063
  `ComfyUI revisions read one source image; ${spec.revision.sourceAssetId} is a ${spec.revision.sourceMembers.length}-member set (directions or frames)`
@@ -5776,6 +5798,14 @@ var CorrectPixelartResponseSchema = z2.object({
5776
5798
  images: z2.array(z2.object({ base64: z2.string().min(1) }).passthrough()).min(1),
5777
5799
  usage: z2.unknown().optional()
5778
5800
  }).passthrough();
5801
+ var ProFlashImageSubmitSchema = z2.object({
5802
+ background_job_id: z2.string().min(1),
5803
+ image_id: z2.string().min(1),
5804
+ source_image_id: z2.string().min(1),
5805
+ status: z2.string().default("processing"),
5806
+ estimated_generations: z2.number().nullable().optional(),
5807
+ usage: z2.unknown().optional()
5808
+ }).passthrough();
5779
5809
  var UnzoomResponseSchema = z2.object({
5780
5810
  image: z2.object({ base64: z2.string().min(1) }).passthrough(),
5781
5811
  original_size: z2.object({ width: z2.number().int(), height: z2.number().int() }).passthrough(),
@@ -6216,7 +6246,7 @@ var PixelLabClient = class {
6216
6246
  const body = {
6217
6247
  description: args.description,
6218
6248
  n_directions: args.directions,
6219
- ...args.reference ? { first_frame: encode(args.reference) } : { image_size: { width: args.size, height: args.size } },
6249
+ ...args.sourceImageId ? { source_image_id: args.sourceImageId } : args.reference ? { first_frame: encode(args.reference) } : { image_size: { width: args.size, height: args.size } },
6220
6250
  ...args.view ? { view: args.view } : {},
6221
6251
  ...args.seed != null ? { seed: args.seed } : {},
6222
6252
  ...args.styleReference && args.styleReferenceSize ? {
@@ -6363,8 +6393,9 @@ var PixelLabClient = class {
6363
6393
  description: args.description,
6364
6394
  template_id: args.template,
6365
6395
  n_directions: 8,
6366
- // The author's sprite sets the canvas; a size only applies to text creation.
6367
- ...south ? { first_frame: encode(south) } : { image_size: imageSize },
6396
+ // The author's sprite sets the canvas; a size only applies to text
6397
+ // creation. An owned copy of the same sprite is referenced by id.
6398
+ ...args.sourceImageId ? { source_image_id: args.sourceImageId } : south ? { first_frame: encode(south) } : { image_size: imageSize },
6368
6399
  ...args.view ? { view: args.view } : {},
6369
6400
  ...args.seed != null ? { seed: args.seed } : {},
6370
6401
  ...args.styleReference && args.styleReferenceSize ? {
@@ -6636,6 +6667,66 @@ var PixelLabClient = class {
6636
6667
  "generate-image-v2"
6637
6668
  );
6638
6669
  }
6670
+ /**
6671
+ * `/create-image-pro-flash`: one native pixel-art image from a
6672
+ * description, optionally styled after a style image with per-trait
6673
+ * toggles, on the same Pro Flash model `character`/`objectPro` use for
6674
+ * their `pro-flash` engine. Sizes run 16 to 256 per side in multiples of 4.
6675
+ * A plain background job; `pollRevision`'s generic reader takes the
6676
+ * finished image. The response's `source_image_id` is what a Pro Flash
6677
+ * character or object can reuse instead of an upload.
6678
+ */
6679
+ async createImageProFlash(args) {
6680
+ const body = {
6681
+ description: args.description,
6682
+ image_size: { width: args.width, height: args.height }
6683
+ };
6684
+ if (args.noBackground != null) body.no_background = args.noBackground;
6685
+ if (args.seed != null) body.seed = args.seed;
6686
+ if (args.styleImage) {
6687
+ body.style_image = { image: args.styleImage.image, size: { width: args.styleImage.width, height: args.styleImage.height } };
6688
+ const traits = args.styleTraits;
6689
+ if (traits) {
6690
+ body.style_options = {
6691
+ ...traits.palette !== void 0 ? { color_palette: traits.palette } : {},
6692
+ ...traits.outline !== void 0 ? { outline: traits.outline } : {},
6693
+ ...traits.detail !== void 0 ? { detail: traits.detail } : {},
6694
+ ...traits.shading !== void 0 ? { shading: traits.shading } : {}
6695
+ };
6696
+ }
6697
+ }
6698
+ return validateResponse(
6699
+ ProFlashImageSubmitSchema,
6700
+ await this.request("/create-image-pro-flash", { method: "POST", body: JSON.stringify(body) }),
6701
+ "create-image-pro-flash"
6702
+ );
6703
+ }
6704
+ /** `/edit-image-pro-flash`, text method: edit one image at its own size. The canvas never grows or resizes. */
6705
+ async editImageProFlash(args) {
6706
+ const body = { image: args.image, method: "text", description: args.description };
6707
+ if (args.noBackground != null) body.no_background = args.noBackground;
6708
+ if (args.seed != null) body.seed = args.seed;
6709
+ return validateResponse(
6710
+ ProFlashImageSubmitSchema,
6711
+ await this.request("/edit-image-pro-flash", { method: "POST", body: JSON.stringify(body) }),
6712
+ "edit-image-pro-flash"
6713
+ );
6714
+ }
6715
+ /**
6716
+ * `/inpaint-image-pro-flash`: replace only the white pixels of a same-size
6717
+ * black/white mask, keeping everything else exactly. `Modify current
6718
+ * layer` (the endpoint's default) returns the full composite.
6719
+ */
6720
+ async inpaintImageProFlash(args) {
6721
+ const body = { image: args.image, mask_image: args.maskImage, description: args.description };
6722
+ if (args.noBackground != null) body.no_background = args.noBackground;
6723
+ if (args.seed != null) body.seed = args.seed;
6724
+ return validateResponse(
6725
+ ProFlashImageSubmitSchema,
6726
+ await this.request("/inpaint-image-pro-flash", { method: "POST", body: JSON.stringify(body) }),
6727
+ "inpaint-image-pro-flash"
6728
+ );
6729
+ }
6639
6730
  /**
6640
6731
  * `/generate-ui-v2` ("Generate UI (Pro)"): one UI element (a button, a
6641
6732
  * health bar, an inventory slot, a dialogue box) from a description,
@@ -6961,8 +7052,11 @@ function proFlashCharacterCost(width, height, fromReference) {
6961
7052
  const side = Math.max(32, Math.ceil(Math.max(width, height) / 4) * 4);
6962
7053
  const rotations = Math.max(1, Math.ceil(side * side * 8 / 65536));
6963
7054
  if (fromReference) return rotations;
6964
- const image = side <= 96 ? 5 : side <= 208 ? 6 : 9;
6965
- return image + rotations;
7055
+ return proFlashImageCost(side, side) + rotations;
7056
+ }
7057
+ function proFlashImageCost(width, height) {
7058
+ const side = Math.max(width, height);
7059
+ return side <= 96 ? 5 : side <= 208 ? 6 : 9;
6966
7060
  }
6967
7061
  function characterAnimationName(spec) {
6968
7062
  return `pixelkiln:${spec.styleId}/${spec.assetId}`;
@@ -7038,7 +7132,7 @@ var PixelLabProvider = class _PixelLabProvider {
7038
7132
  return new _PixelLabProvider(new PixelLabClient("download-only"));
7039
7133
  }
7040
7134
  supports(generator) {
7041
- return generator === "1dir" || generator === "map" || generator === "pixflux" || generator === "tiles" || generator === "terrain" || generator === "imagePro" || generator === "character" || generator === "isometricTile" || generator === "objectPro" || generator === "uiAsset" || generator === "uiElement";
7135
+ 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";
7042
7136
  }
7043
7137
  /**
7044
7138
  * `inpaint` (`/inpaint-v3`, a mask) and `image-to-image` (`/edit-images-v2`,
@@ -7100,6 +7194,13 @@ var PixelLabProvider = class _PixelLabProvider {
7100
7194
  const base = Math.max(1, Math.ceil(width * height * frames / 65536));
7101
7195
  return { unit: "generations", amount: spec.revision.enhancePrompt ? base + 0.05 : base, candidates: 1 };
7102
7196
  }
7197
+ if (spec.revision?.engine === "pro-flash") {
7198
+ return {
7199
+ unit: "generations",
7200
+ amount: proFlashImageCost(spec.revision.sourceWidth ?? spec.width, spec.revision.sourceHeight ?? spec.height),
7201
+ candidates: 1
7202
+ };
7203
+ }
7103
7204
  if (spec.revision) {
7104
7205
  const width = spec.revision.sourceWidth ?? spec.width;
7105
7206
  const height = spec.revision.sourceHeight ?? spec.height;
@@ -7114,6 +7215,9 @@ var PixelLabProvider = class _PixelLabProvider {
7114
7215
  if (spec.generator === "objectPro") {
7115
7216
  return { unit: "generations", amount: objectProCost(spec), candidates: 1 };
7116
7217
  }
7218
+ if (spec.generator === "imageProFlash") {
7219
+ return { unit: "generations", amount: proFlashImageCost(spec.width, spec.height), candidates: 1 };
7220
+ }
7117
7221
  return {
7118
7222
  unit: "generations",
7119
7223
  amount: generationCost(spec.width, spec.height, spec.generator),
@@ -7127,7 +7231,17 @@ var PixelLabProvider = class _PixelLabProvider {
7127
7231
  `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`
7128
7232
  );
7129
7233
  }
7130
- if (spec.revision?.mode === "inpaint") {
7234
+ if (spec.revision?.engine === "pro-flash") {
7235
+ const { sourceWidth: width, sourceHeight: height, mode: mode2 } = spec.revision;
7236
+ if (width != null && height != null && (width < 32 || height < 32 || width > 256 || height > 256 || width % 4 || height % 4)) {
7237
+ throw new Error(
7238
+ `PixelLab pro-flash ${mode2} source is ${width}x${height}; the API takes 32 to 256 pixels per side, in multiples of 4`
7239
+ );
7240
+ }
7241
+ if (spec.revision.strength != null) {
7242
+ throw new Error(`PixelLab pro-flash ${mode2} takes no strength; the edit applies in full`);
7243
+ }
7244
+ } else if (spec.revision?.mode === "inpaint") {
7131
7245
  const { sourceWidth: width, sourceHeight: height } = spec.revision;
7132
7246
  if (width != null && height != null && (width < 32 || height < 32 || width > 512 || height > 512)) {
7133
7247
  throw new Error(`PixelLab inpaint source is ${width}x${height}; the API takes 32 to 512 pixels per side`);
@@ -7208,6 +7322,19 @@ var PixelLabProvider = class _PixelLabProvider {
7208
7322
  `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)`
7209
7323
  );
7210
7324
  }
7325
+ if (spec.generator === "imageProFlash") {
7326
+ if (spec.width < 16 || spec.height < 16 || spec.width > 256 || spec.height > 256 || spec.width % 4 || spec.height % 4) {
7327
+ throw new Error(
7328
+ `PixelLab imageProFlash is ${spec.width}x${spec.height}; the API takes 16 to 256 pixels per side, in multiples of 4`
7329
+ );
7330
+ }
7331
+ if (styleImages.length > 1) {
7332
+ throw new Error("PixelLab imageProFlash takes one style image; list at most one styleImages entry");
7333
+ }
7334
+ if (spec.styleTraits && !styleImages.length) {
7335
+ throw new Error("PixelLab imageProFlash: styleTraits choose what a style image lends; add a styleImages entry or drop them");
7336
+ }
7337
+ }
7211
7338
  if (spec.generator === "uiElement" && (spec.width < 16 || spec.height < 16 || spec.width > 792 || spec.height > 688)) {
7212
7339
  throw new Error(
7213
7340
  `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)`
@@ -7561,7 +7688,8 @@ var PixelLabProvider = class _PixelLabProvider {
7561
7688
  concept: character.concept ? readPose(spec, "concept image", character.concept) : void 0,
7562
7689
  styleCharacterId: character.styleAnchor ? requireStyleObjectId(spec, context) : void 0,
7563
7690
  styleReferenceSize: styleImage ? { width: styleImage.width, height: styleImage.height } : void 0,
7564
- styleTraits: character.styleTraits
7691
+ styleTraits: character.styleTraits,
7692
+ sourceImageId: character.mode === "pro-flash" ? context?.referenceSourceImageId : void 0
7565
7693
  });
7566
7694
  return { jobId: res2.character_id, metadata: { character: { kind: "base", characterId: res2.character_id, mode: character.mode, directions: character.directions, backgroundJobId: res2.background_job_id } } };
7567
7695
  }
@@ -7696,7 +7824,8 @@ var PixelLabProvider = class _PixelLabProvider {
7696
7824
  reference: object.reference ? readPose(spec, "reference sprite", object.reference) : void 0,
7697
7825
  styleReference: styleImage ? { base64: styleImage.base64, format: styleImage.format } : void 0,
7698
7826
  styleReferenceSize: styleImage ? { width: styleImage.width, height: styleImage.height } : void 0,
7699
- styleTraits: object.styleTraits
7827
+ styleTraits: object.styleTraits,
7828
+ sourceImageId: context?.referenceSourceImageId
7700
7829
  });
7701
7830
  return { jobId: res2.object_id, metadata: { objectPro: { kind: "base", objectId: res2.object_id, directions: object.directions, backgroundJobId: res2.background_job_id } } };
7702
7831
  }
@@ -7995,6 +8124,19 @@ var PixelLabProvider = class _PixelLabProvider {
7995
8124
  });
7996
8125
  return { jobId: res2.ui_asset_id, metadata: { backgroundJobId: res2.background_job_id } };
7997
8126
  }
8127
+ if (spec.generator === "imageProFlash") {
8128
+ const style = styleImages[0];
8129
+ const res2 = await this.client.createImageProFlash({
8130
+ description: spec.prompt,
8131
+ width: spec.width,
8132
+ height: spec.height,
8133
+ noBackground: spec.noBackground,
8134
+ seed: spec.seed,
8135
+ styleImage: style ? { image: { base64: style.base64, format: style.format }, width: style.width, height: style.height } : void 0,
8136
+ styleTraits: spec.styleTraits
8137
+ });
8138
+ return { jobId: res2.background_job_id, metadata: { imageProFlash: proFlashRecord(res2) } };
8139
+ }
7998
8140
  if (spec.generator === "uiElement") {
7999
8141
  const concept = styleImages[0];
8000
8142
  const res2 = await this.client.generateUiV2({
@@ -8148,6 +8290,32 @@ var PixelLabProvider = class _PixelLabProvider {
8148
8290
  const width = revision.sourceWidth;
8149
8291
  const height = revision.sourceHeight;
8150
8292
  const roles = revision.sourceMembers?.map((member) => member.role);
8293
+ if (revision.engine === "pro-flash") {
8294
+ if (revision.mode === "inpaint") {
8295
+ if (!revision.maskFile || !revision.maskSha256 || !revision.maskFormat) {
8296
+ throw new Error(`${spec.styleId}/${spec.assetId}: revision mask is not ready`);
8297
+ }
8298
+ const maskBytes = readFileSync2(revision.maskFile);
8299
+ if (sha256(maskBytes) !== revision.maskSha256) {
8300
+ throw new Error(`${spec.styleId}/${spec.assetId}: revision mask changed after the manifest was resolved`);
8301
+ }
8302
+ const res3 = await this.client.inpaintImageProFlash({
8303
+ image,
8304
+ maskImage: { base64: maskBytes.toString("base64"), format: revision.maskFormat },
8305
+ description: spec.prompt,
8306
+ noBackground: spec.noBackground,
8307
+ seed: spec.seed
8308
+ });
8309
+ return { jobId: res3.background_job_id, metadata: { imageProFlash: proFlashRecord(res3) } };
8310
+ }
8311
+ const res2 = await this.client.editImageProFlash({
8312
+ image,
8313
+ description: spec.prompt,
8314
+ noBackground: spec.noBackground,
8315
+ seed: spec.seed
8316
+ });
8317
+ return { jobId: res2.background_job_id, metadata: { imageProFlash: proFlashRecord(res2) } };
8318
+ }
8151
8319
  if (revision.mode === "inpaint") {
8152
8320
  if (!revision.maskFile || !revision.maskSha256 || !revision.maskFormat) {
8153
8321
  throw new Error(`${spec.styleId}/${spec.assetId}: revision mask is not ready`);
@@ -8312,6 +8480,7 @@ var PixelLabProvider = class _PixelLabProvider {
8312
8480
  return this.pollAnimateRevision(jobId, context);
8313
8481
  }
8314
8482
  if (context?.spec?.revision) return this.pollRevision(jobId);
8483
+ if (generator === "imageProFlash") return this.pollRevision(jobId);
8315
8484
  if (generator === "pixflux") {
8316
8485
  const file = path12.join(_PixelLabProvider.cacheDir(), `${jobId}.png`);
8317
8486
  if (existsSync7(file)) {
@@ -8892,6 +9061,13 @@ function readPose(spec, what, image) {
8892
9061
  }
8893
9062
  return { base64: bytes.toString("base64"), format: image.format };
8894
9063
  }
9064
+ function proFlashRecord(res) {
9065
+ return {
9066
+ imageId: res.image_id,
9067
+ sourceImageId: res.source_image_id,
9068
+ ...res.estimated_generations != null ? { estimatedGenerations: res.estimated_generations } : {}
9069
+ };
9070
+ }
8895
9071
  function editAnimationFrameCeiling(width, height) {
8896
9072
  const side = Math.max(width, height);
8897
9073
  if (side <= 64) return 16;
@@ -10291,6 +10467,7 @@ async function resolveSpecs(loaded, filter) {
10291
10467
  uiPieces: generator === "uiAsset" ? asset.pieces : void 0,
10292
10468
  uiElements: generator === "uiAsset" ? asset.elements : void 0,
10293
10469
  uiColorPalette: generator === "uiAsset" || generator === "uiElement" ? style.uiColorPalette : void 0,
10470
+ ...generator === "imageProFlash" && style.styleTraits ? { styleTraits: style.styleTraits } : {},
10294
10471
  palette: style.palette,
10295
10472
  enforcePalette: style.enforcePalette,
10296
10473
  noBackground: style.noBackground,
@@ -10574,7 +10751,8 @@ async function resolveSpecs(loaded, filter) {
10574
10751
  lastFrameFormat: lastFrame?.format ?? null
10575
10752
  } : {},
10576
10753
  ...asset.revision.direction ? { direction: asset.revision.direction } : {},
10577
- ...asset.revision.enhancePrompt == null ? {} : { enhancePrompt: asset.revision.enhancePrompt }
10754
+ ...asset.revision.enhancePrompt == null ? {} : { enhancePrompt: asset.revision.enhancePrompt },
10755
+ ...asset.revision.engine ? { engine: asset.revision.engine } : {}
10578
10756
  };
10579
10757
  }
10580
10758
  if (asset.batch) {
@@ -15315,7 +15493,8 @@ async function submit(provider, loaded, items, lock, lockPath, opts = {}) {
15315
15493
  ...spec.revision.fps == null ? {} : { fps: spec.revision.fps },
15316
15494
  ...spec.revision.lastFrameSha256 ? { lastFrameSha256: spec.revision.lastFrameSha256 } : {},
15317
15495
  ...spec.revision.direction ? { direction: spec.revision.direction } : {},
15318
- ...spec.revision.enhancePrompt == null ? {} : { enhancePrompt: spec.revision.enhancePrompt }
15496
+ ...spec.revision.enhancePrompt == null ? {} : { enhancePrompt: spec.revision.enhancePrompt },
15497
+ ...spec.revision.engine ? { engine: spec.revision.engine } : {}
15319
15498
  } : null,
15320
15499
  outfit: spec.character?.kind === "outfit" && outfitParentEntry ? {
15321
15500
  sourceAssetId: spec.character.parentAssetId,
@@ -15359,8 +15538,10 @@ async function submit(provider, loaded, items, lock, lockPath, opts = {}) {
15359
15538
  path: currentEntryOutputPath(parentEntry, spec.character.parentSpec, index),
15360
15539
  role: output.role
15361
15540
  })) : void 0;
15541
+ const referenceSourceImageId = ownedReferenceImageId(spec, lock, provider.id);
15362
15542
  const { jobId, metadata } = await provider.submit(spec, refs, {
15363
15543
  ...previousJobId ? { previousJobId } : {},
15544
+ ...referenceSourceImageId ? { referenceSourceImageId } : {},
15364
15545
  ...parentEntry?.objectId ? { parentObjectId: parentEntry.objectId } : {},
15365
15546
  ...anchorEntry?.objectId ? { styleObjectId: anchorEntry.objectId } : {},
15366
15547
  ...parentOutputs ? { parentOutputs } : {},
@@ -15427,6 +15608,17 @@ async function submit(provider, loaded, items, lock, lockPath, opts = {}) {
15427
15608
  }
15428
15609
  return { submitted, failed, spent, unit };
15429
15610
  }
15611
+ function ownedReferenceImageId(spec, lock, providerId) {
15612
+ 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;
15613
+ if (!sha2562) return void 0;
15614
+ for (const entry of Object.values(lock.entries)) {
15615
+ if (entry.provider !== providerId || entry.generator !== "imageProFlash" || entry.status !== "downloaded") continue;
15616
+ if (entry.outputs.length !== 1 || entry.outputs[0].sha256 !== sha2562) continue;
15617
+ const recorded = entry.providerMetadata?.[providerId]?.imageProFlash;
15618
+ if (typeof recorded?.sourceImageId === "string" && recorded.sourceImageId) return recorded.sourceImageId;
15619
+ }
15620
+ return void 0;
15621
+ }
15430
15622
 
15431
15623
  // src/pick/server.ts
15432
15624
  import { existsSync as existsSync21 } from "fs";