@shop-os/modelkit 0.2.14 → 0.2.16

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
@@ -1373,7 +1373,8 @@ var VIDEO_MODELS = [
1373
1373
  // reference clip keeps its own framing.
1374
1374
  aspectRatios: [...OMNI_RATIOS],
1375
1375
  durations: [3, 4, 5, 6, 7, 8, 9, 10],
1376
- references: { images: 6, videos: 1 },
1376
+ references: { images: 6, videos: 1, videoSeconds: { max: 10 } },
1377
+ sourceVideoSeconds: { max: 10 },
1377
1378
  supports: []
1378
1379
  },
1379
1380
  defaults: {},
@@ -1399,8 +1400,16 @@ var VIDEO_MODELS = [
1399
1400
  aspectRatios: [...OMNI_RATIOS],
1400
1401
  resolutions: ["360p", "720p", "1080p", "4k"],
1401
1402
  durations: [3, 4, 5, 6, 7, 8, 9, 10],
1402
- references: { images: 6, videos: 1 },
1403
- supports: []
1403
+ references: { images: 6, videos: 1, videoSeconds: { max: 10 } },
1404
+ sourceVideoSeconds: { max: 10 },
1405
+ // Extension (probe 2026-09-24, 360p): each `taskType: "extend"` call
1406
+ // renders `durationSeconds` more and returns the FULL cumulative clip
1407
+ // (3 s -> 6 s -> 9 s); the provider caps the clip at 40 s. A first
1408
+ // extension can upload a <= 10 s source with task "extend"; later ones
1409
+ // chain by `previousInteractionId` (the API rejects the id together
1410
+ // with a video task, so those calls carry the prompt alone).
1411
+ supports: ["videoExtension"],
1412
+ extension: { segmentSeconds: 10, maxTotalSeconds: 40 }
1404
1413
  },
1405
1414
  defaults: {},
1406
1415
  usage: { ...VIDEO_USAGE },
@@ -1408,7 +1417,7 @@ var VIDEO_MODELS = [
1408
1417
  display: {
1409
1418
  provider: "google",
1410
1419
  logo: GOOGLE_LOGO2,
1411
- description: "Google Gemini Omni Flash 1.1 conversational video generation and editing; text, image, and up to 10-second video input, 3-10 second output at up to 4K and 24 FPS."
1420
+ description: "Google Gemini Omni Flash 1.1 conversational video generation, editing and extension; text, image, and up to 10-second video input, 3-10 second output at up to 4K and 24 FPS, extendable to 40 seconds."
1412
1421
  },
1413
1422
  capabilities: { acceptsSourceVideo: true }
1414
1423
  },
@@ -1427,7 +1436,14 @@ var VIDEO_MODELS = [
1427
1436
  resolutions: ["480p", "720p", "1080p", "4k"],
1428
1437
  durations: { min: 4, max: 15 },
1429
1438
  durationPresets: [4, 6, 8, 10, 12, 15],
1430
- references: { images: 9, videos: 3, audios: 3, audioOnly: false },
1439
+ references: {
1440
+ images: 9,
1441
+ videos: 3,
1442
+ audios: 3,
1443
+ audioOnly: false,
1444
+ videoSeconds: { min: 2, max: 15, total: 15 }
1445
+ },
1446
+ sourceVideoSeconds: { min: 2, max: 15, inReferenceTotal: true },
1431
1447
  ratioIgnoredWith: ["firstFrame", "sourceVideo"],
1432
1448
  supports: ["generateAudio", "seed", "lastFrame", "watermark"]
1433
1449
  },
@@ -1459,7 +1475,14 @@ var VIDEO_MODELS = [
1459
1475
  aspectRatios: [...SEEDANCE_RATIOS],
1460
1476
  resolutions: ["480p", "720p"],
1461
1477
  durations: { min: 4, max: 15 },
1462
- references: { images: 9, videos: 3, audios: 3, audioOnly: false },
1478
+ references: {
1479
+ images: 9,
1480
+ videos: 3,
1481
+ audios: 3,
1482
+ audioOnly: false,
1483
+ videoSeconds: { min: 2, max: 15, total: 15 }
1484
+ },
1485
+ sourceVideoSeconds: { min: 2, max: 15, inReferenceTotal: true },
1463
1486
  ratioIgnoredWith: ["firstFrame", "sourceVideo"],
1464
1487
  supports: ["generateAudio", "seed", "lastFrame", "watermark"]
1465
1488
  },
@@ -1493,7 +1516,13 @@ var VIDEO_MODELS = [
1493
1516
  aspectRatios: [...SEEDANCE_RATIOS],
1494
1517
  resolutions: ["480p", "720p", "1080p"],
1495
1518
  durations: { min: 4, max: 30 },
1496
- references: { images: 30, videos: 10, audios: 10 },
1519
+ references: {
1520
+ images: 30,
1521
+ videos: 10,
1522
+ audios: 10,
1523
+ videoSeconds: { min: 2, max: 30, total: 30, editMin: 4 }
1524
+ },
1525
+ sourceVideoSeconds: { min: 2, max: 30, editMin: 4, inReferenceTotal: true },
1497
1526
  ratioIgnoredWith: ["firstFrame", "sourceVideo"],
1498
1527
  supports: ["generateAudio", "seed", "lastFrame", "watermark", "taskType"]
1499
1528
  },
@@ -1705,7 +1734,14 @@ var VIDEO_MODELS = [
1705
1734
  aspectRatios: [...H3_REFERENCE_RATIOS],
1706
1735
  resolutions: ["480p", "768p", "2k", "4k"],
1707
1736
  durations: { min: 5, max: 15 },
1708
- references: { images: 9, videos: 3, audios: 3, total: 12, audioOnly: false },
1737
+ references: {
1738
+ images: 9,
1739
+ videos: 3,
1740
+ audios: 3,
1741
+ total: 12,
1742
+ audioOnly: false,
1743
+ videoSeconds: { min: 2, max: 15, total: 15 }
1744
+ },
1709
1745
  supports: ["seed", "promptExpansion", "safetyChecker"]
1710
1746
  },
1711
1747
  defaults: {
@@ -1736,7 +1772,14 @@ var VIDEO_MODELS = [
1736
1772
  aspectRatios: [...H3_REFERENCE_RATIOS],
1737
1773
  resolutions: ["480p", "768p"],
1738
1774
  durations: { min: 5, max: 15 },
1739
- references: { images: 9, videos: 3, audios: 3, total: 12, audioOnly: false },
1775
+ references: {
1776
+ images: 9,
1777
+ videos: 3,
1778
+ audios: 3,
1779
+ total: 12,
1780
+ audioOnly: false,
1781
+ videoSeconds: { min: 2, max: 15, total: 15 }
1782
+ },
1740
1783
  supports: ["seed", "promptExpansion", "safetyChecker"]
1741
1784
  },
1742
1785
  defaults: {
@@ -1768,6 +1811,7 @@ var VIDEO_MODELS = [
1768
1811
  aspectRatios: [...KLING_RATIOS],
1769
1812
  durations: { min: 3, max: 10 },
1770
1813
  requires: ["sourceVideo"],
1814
+ sourceVideoSeconds: { min: 3, max: 10.05 },
1771
1815
  supports: []
1772
1816
  },
1773
1817
  defaults: { durationSeconds: 5, aspectRatio: "16:9" },
@@ -2107,6 +2151,7 @@ var SupportedOptionSchema = z2.enum([
2107
2151
  "watermark",
2108
2152
  "safetyChecker",
2109
2153
  "taskType",
2154
+ "videoExtension",
2110
2155
  "instrumental"
2111
2156
  ]);
2112
2157
  var UsageUnitSchema = z2.enum([
@@ -2127,13 +2172,20 @@ var ProviderOptionValueSchema = z2.lazy(
2127
2172
  ])
2128
2173
  );
2129
2174
  var ProviderOptionsSchema = z2.record(z2.string(), z2.record(z2.string(), ProviderOptionValueSchema));
2175
+ var VideoSecondsLimitsSchema = z2.looseObject({
2176
+ min: z2.number().optional(),
2177
+ max: z2.number().optional(),
2178
+ total: z2.number().optional(),
2179
+ editMin: z2.number().optional()
2180
+ });
2130
2181
  var ReferenceLimitsSchema = z2.looseObject({
2131
2182
  images: z2.number().optional(),
2132
2183
  imagesWithVideo: z2.number().optional(),
2133
2184
  videos: z2.number().optional(),
2134
2185
  audios: z2.number().optional(),
2135
2186
  total: z2.number().optional(),
2136
- audioOnly: z2.boolean().optional()
2187
+ audioOnly: z2.boolean().optional(),
2188
+ videoSeconds: VideoSecondsLimitsSchema.optional()
2137
2189
  });
2138
2190
  var ModelConstraintsSchema = z2.looseObject({
2139
2191
  aspectRatios: z2.array(AspectRatioSchema).optional(),
@@ -2146,14 +2198,21 @@ var ModelConstraintsSchema = z2.looseObject({
2146
2198
  references: ReferenceLimitsSchema.optional(),
2147
2199
  requires: z2.array(RequiredInputSchema).optional(),
2148
2200
  supports: z2.array(SupportedOptionSchema).optional(),
2149
- ratioIgnoredWith: z2.array(z2.enum(["firstFrame", "sourceVideo"])).optional()
2201
+ ratioIgnoredWith: z2.array(z2.enum(["firstFrame", "sourceVideo"])).optional(),
2202
+ sourceVideoSeconds: VideoSecondsLimitsSchema.omit({ total: true }).extend({ inReferenceTotal: z2.boolean().optional() }).optional(),
2203
+ extension: z2.looseObject({ segmentSeconds: z2.number(), maxTotalSeconds: z2.number() }).optional()
2150
2204
  });
2151
2205
  var MediaRefSchema = z2.union([
2152
- z2.looseObject({ url: z2.string(), label: z2.string().optional() }),
2206
+ z2.looseObject({
2207
+ url: z2.string(),
2208
+ label: z2.string().optional(),
2209
+ durationSeconds: z2.number().optional()
2210
+ }),
2153
2211
  z2.looseObject({
2154
2212
  bytes: z2.instanceof(Uint8Array),
2155
2213
  mime: z2.string(),
2156
- label: z2.string().optional()
2214
+ label: z2.string().optional(),
2215
+ durationSeconds: z2.number().optional()
2157
2216
  })
2158
2217
  ]);
2159
2218
  var ImageSafetySettingSchema = z2.looseObject({ category: z2.string(), threshold: z2.string() });
@@ -4410,12 +4469,34 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
4410
4469
  const modelId = ctx.model.id;
4411
4470
  const providerModelId = ctx.model.providerModelId;
4412
4471
  const duration = req.durationSeconds ?? 10;
4413
- const images = req.referenceImages ?? [];
4414
- const videos = req.referenceVideos ?? [];
4415
- const task = req.sourceVideo ? "edit" : req.firstFrame ? "image_to_video" : images.length > 0 || videos.length > 0 ? "reference_to_video" : "text_to_video";
4472
+ const extend = req.taskType === "extend";
4473
+ const previousId = extend ? req.previousInteractionId : void 0;
4474
+ const chained = previousId !== void 0;
4475
+ for (const field of ["referenceImages", "referenceVideos", "firstFrame"]) {
4476
+ const value = req[field];
4477
+ if (!chained || value === void 0 || Array.isArray(value) && value.length === 0)
4478
+ continue;
4479
+ ctx.warnings.push({
4480
+ code: "option_ignored",
4481
+ field,
4482
+ from: Array.isArray(value) ? value.length : "set",
4483
+ message: `${modelId} chained extension sends the prompt alone; ${field} ignored`
4484
+ });
4485
+ }
4486
+ const images = chained ? [] : req.referenceImages ?? [];
4487
+ const videos = chained ? [] : req.referenceVideos ?? [];
4488
+ const firstFrame = chained ? void 0 : req.firstFrame;
4489
+ if (extend && !chained && req.sourceVideo === void 0) {
4490
+ throw new ModelKitError({
4491
+ code: "missing_input",
4492
+ message: `${modelId} extend needs a source video or a previousInteractionId`,
4493
+ model: modelId
4494
+ });
4495
+ }
4496
+ const task = extend ? "extend" : req.sourceVideo ? "edit" : firstFrame ? "image_to_video" : images.length > 0 || videos.length > 0 ? "reference_to_video" : "text_to_video";
4416
4497
  const isOmniV1 = providerModelId === "gemini-omni-flash-preview";
4417
4498
  const responseFormat = { type: "video", delivery: "uri" };
4418
- if (req.sourceVideo === void 0 && req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive") {
4499
+ if (req.sourceVideo === void 0 && !extend && req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive") {
4419
4500
  responseFormat.aspect_ratio = toOmniAspect(req.aspectRatio);
4420
4501
  }
4421
4502
  if (!isOmniV1) {
@@ -4447,18 +4528,26 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
4447
4528
  const cleanupUploads = async () => {
4448
4529
  for (const fileName of uploadedNames) await deleteGoogleFile(fileName, apiKey, ctx.fetch);
4449
4530
  };
4450
- const callCreate = (input) => client2.interactions.create({
4451
- model: providerModelId,
4452
- input,
4453
- response_format: responseFormat,
4454
- generation_config: { video_config: { task } },
4455
- store: true
4456
- });
4531
+ const callCreate = (input) => client2.interactions.create(
4532
+ previousId !== void 0 ? {
4533
+ model: providerModelId,
4534
+ input,
4535
+ response_format: responseFormat,
4536
+ store: true,
4537
+ previous_interaction_id: previousId
4538
+ } : {
4539
+ model: providerModelId,
4540
+ input,
4541
+ response_format: responseFormat,
4542
+ generation_config: { video_config: { task } },
4543
+ store: true
4544
+ }
4545
+ );
4457
4546
  const createRetryOptions = mediaRetryOptions(ctx.call, ctx.signal);
4458
4547
  let interaction;
4459
4548
  try {
4460
4549
  const parts = [];
4461
- if (req.sourceVideo) {
4550
+ if (req.sourceVideo && !chained) {
4462
4551
  const media = await resolveMedia(
4463
4552
  req.sourceVideo,
4464
4553
  ctx.fetch,
@@ -4481,11 +4570,11 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
4481
4570
  mime_type: media.mime
4482
4571
  });
4483
4572
  }
4484
- if (req.firstFrame) {
4485
- if (req.firstFrame.label !== void 0)
4486
- parts.push({ type: "text", text: req.firstFrame.label });
4573
+ if (firstFrame) {
4574
+ if (firstFrame.label !== void 0)
4575
+ parts.push({ type: "text", text: firstFrame.label });
4487
4576
  const media = await resolveMedia(
4488
- req.firstFrame,
4577
+ firstFrame,
4489
4578
  ctx.fetch,
4490
4579
  ctx.signal,
4491
4580
  "image/png",
@@ -4588,6 +4677,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
4588
4677
  return void 0;
4589
4678
  }, pollOptions);
4590
4679
  const video = extractOmniVideo(done, modelId);
4680
+ const providerRef = { interactionId: done.id ?? jobId };
4591
4681
  if (video.data) {
4592
4682
  return {
4593
4683
  video: {
@@ -4595,14 +4685,16 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
4595
4685
  mime: video.mime_type ?? "video/mp4"
4596
4686
  },
4597
4687
  usage: usage2,
4598
- raw: done
4688
+ raw: done,
4689
+ providerRef
4599
4690
  };
4600
4691
  }
4601
4692
  if (video.uri)
4602
4693
  return {
4603
4694
  video: await downloadVideo(ctx, video.uri, apiKey, signal),
4604
4695
  usage: usage2,
4605
- raw: done
4696
+ raw: done,
4697
+ providerRef
4606
4698
  };
4607
4699
  throw classifyHttpError(
4608
4700
  void 0,
@@ -6540,8 +6632,8 @@ function lyriaAudioInput(req, ctx) {
6540
6632
  if (negative) input.negative_prompt = negative;
6541
6633
  return input;
6542
6634
  }
6543
- function elevenLabsMusicDuration(seconds) {
6544
- return Math.min(300, Math.max(5, seconds ?? 15));
6635
+ function elevenLabsMusicDuration(seconds2) {
6636
+ return Math.min(300, Math.max(5, seconds2 ?? 15));
6545
6637
  }
6546
6638
  function elevenLabsMusicInput(req, ctx) {
6547
6639
  const prompt = req.prompt.trim();
@@ -6606,9 +6698,9 @@ async function generateReplicateAudio(req, ctx, deps) {
6606
6698
  const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
6607
6699
  const usage2 = audioUsage(ctx, req);
6608
6700
  if (ctx.model.usage.unit === "seconds") {
6609
- const seconds = elevenLabsMusicDuration(req.durationSeconds);
6610
- usage2.quantity = seconds;
6611
- usage2.durationSeconds = seconds;
6701
+ const seconds2 = elevenLabsMusicDuration(req.durationSeconds);
6702
+ usage2.quantity = seconds2;
6703
+ usage2.durationSeconds = seconds2;
6612
6704
  } else {
6613
6705
  usage2.quantity = predictTime;
6614
6706
  }
@@ -7248,6 +7340,49 @@ function trim(field, refs, limit, model, warnings) {
7248
7340
  });
7249
7341
  return refs.slice(0, limit);
7250
7342
  }
7343
+ function knownLength(value) {
7344
+ return value !== void 0 && Number.isFinite(value) ? value : void 0;
7345
+ }
7346
+ function seconds(len, limit) {
7347
+ let digits = 1;
7348
+ while (digits < 3 && Number(len.toFixed(digits)) === limit) digits++;
7349
+ return len.toFixed(digits);
7350
+ }
7351
+ function effectiveMin(limits, taskType) {
7352
+ if (taskType !== "edit" || limits?.editMin === void 0) return limits?.min;
7353
+ return Math.max(limits.min ?? 0, limits.editMin);
7354
+ }
7355
+ function videoLengthViolation(model, input) {
7356
+ const limits = model.constraints.references?.videoSeconds;
7357
+ const refMin = effectiveMin(limits, input.taskType);
7358
+ const lengths = (input.referenceVideos ?? []).map(knownLength);
7359
+ if (limits?.max !== void 0) {
7360
+ const max = limits.max;
7361
+ const i = lengths.findIndex((len) => len !== void 0 && len > max);
7362
+ if (i >= 0)
7363
+ return `${model.label} takes reference videos up to ${String(max)} s each; video ${i + 1} is ${seconds(lengths[i], max)} s.`;
7364
+ }
7365
+ if (refMin !== void 0) {
7366
+ const i = lengths.findIndex((len) => len !== void 0 && len < refMin);
7367
+ if (i >= 0)
7368
+ return `${model.label} takes reference videos of at least ${String(refMin)} s each; video ${i + 1} is ${seconds(lengths[i], refMin)} s.`;
7369
+ }
7370
+ const source = knownLength(input.sourceVideo);
7371
+ const sourceLimits = model.constraints.sourceVideoSeconds;
7372
+ if (limits?.total !== void 0) {
7373
+ const refSum = lengths.reduce((acc, len) => acc + (len ?? 0), 0);
7374
+ const sum = refSum + (sourceLimits?.inReferenceTotal ? source ?? 0 : 0);
7375
+ if (sum > limits.total)
7376
+ return `${model.label} takes reference videos up to ${String(limits.total)} s combined; these add up to ${seconds(sum, limits.total)} s.`;
7377
+ }
7378
+ if (source === void 0) return void 0;
7379
+ const sourceMin = effectiveMin(sourceLimits, input.taskType);
7380
+ if (sourceLimits?.max !== void 0 && source > sourceLimits.max)
7381
+ return `${model.label} takes a source video up to ${String(sourceLimits.max)} s; this one is ${seconds(source, sourceLimits.max)} s.`;
7382
+ if (sourceMin !== void 0 && source < sourceMin)
7383
+ return `${model.label} takes a source video of at least ${String(sourceMin)} s; this one is ${seconds(source, sourceMin)} s.`;
7384
+ return void 0;
7385
+ }
7251
7386
  function resolveImageOptions(model, request, onUnsupported = "error") {
7252
7387
  const warnings = [];
7253
7388
  const c = model.constraints;
@@ -7433,9 +7568,25 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
7433
7568
  model: model.id
7434
7569
  });
7435
7570
  }
7571
+ const lengthViolation = videoLengthViolation(model, {
7572
+ referenceVideos: videos.map((v) => v.durationSeconds),
7573
+ taskType: merged.taskType,
7574
+ ...merged.sourceVideo?.durationSeconds !== void 0 && {
7575
+ sourceVideo: merged.sourceVideo.durationSeconds
7576
+ }
7577
+ });
7578
+ if (lengthViolation !== void 0) {
7579
+ throw new ModelKitError({
7580
+ code: "unsupported_option",
7581
+ message: lengthViolation,
7582
+ model: model.id,
7583
+ retryable: false
7584
+ });
7585
+ }
7436
7586
  setOrDelete(merged, "referenceImages", images);
7437
7587
  setOrDelete(merged, "referenceVideos", videos);
7438
7588
  setOrDelete(merged, "referenceAudios", audios);
7589
+ const keepExtend = merged.taskType === "extend" && (model.constraints.supports ?? []).includes("videoExtension");
7439
7590
  dropUnsupported(merged, model, warnings, [
7440
7591
  "seed",
7441
7592
  "negativePrompt",
@@ -7445,8 +7596,17 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
7445
7596
  "lastFrame",
7446
7597
  "watermark",
7447
7598
  "safetyChecker",
7448
- "taskType"
7599
+ ...keepExtend ? [] : ["taskType"]
7449
7600
  ]);
7601
+ if (merged.previousInteractionId !== void 0 && !keepExtend) {
7602
+ warnings.push({
7603
+ code: "option_ignored",
7604
+ field: "previousInteractionId",
7605
+ from: merged.previousInteractionId,
7606
+ message: `${model.id} does not support previousInteractionId; ignored`
7607
+ });
7608
+ delete merged.previousInteractionId;
7609
+ }
7450
7610
  return { request: merged, warnings };
7451
7611
  }
7452
7612
  function resolveAudioOptions(model, request, onUnsupported = "error") {
@@ -7990,7 +8150,7 @@ function createModelKit(config, adapters) {
7990
8150
  promptExpansion: _promptExpansion,
7991
8151
  mode: _mode
7992
8152
  } = req;
7993
- const seconds = duration ?? durationSeconds;
8153
+ const seconds2 = duration ?? durationSeconds;
7994
8154
  const abortSignal = combineSignals(req.abortSignal, call.signal);
7995
8155
  const options = { model, prompt };
7996
8156
  if (call.maxRetries !== void 0) options.maxRetries = call.maxRetries;
@@ -7999,7 +8159,7 @@ function createModelKit(config, adapters) {
7999
8159
  if (ratio) options.aspectRatio = ratio;
8000
8160
  else if (aspectRatio !== void 0)
8001
8161
  pushIgnored(warnings, "aspectRatio", aspectRatio, model.modelId);
8002
- if (seconds !== void 0) options.duration = seconds;
8162
+ if (seconds2 !== void 0) options.duration = seconds2;
8003
8163
  if (seed !== void 0) options.seed = seed;
8004
8164
  if (generateAudio2 !== void 0) options.generateAudio = generateAudio2;
8005
8165
  const frames = [
@@ -8046,8 +8206,8 @@ function createModelKit(config, adapters) {
8046
8206
  provider: model.provider,
8047
8207
  modality: "VIDEO",
8048
8208
  unit: "seconds",
8049
- quantity: seconds ?? 0,
8050
- ...seconds !== void 0 && { durationSeconds: seconds }
8209
+ quantity: seconds2 ?? 0,
8210
+ ...seconds2 !== void 0 && { durationSeconds: seconds2 }
8051
8211
  };
8052
8212
  settled = {
8053
8213
  video: { bytes: result.video.uint8Array, mime: result.video.mediaType },
@@ -8397,6 +8557,7 @@ export {
8397
8557
  textUsageEvent,
8398
8558
  toGeneratedImage,
8399
8559
  validateInputSpec,
8560
+ videoLengthViolation,
8400
8561
  withRetry,
8401
8562
  xaiVideoAdapter
8402
8563
  };