@shop-os/modelkit 0.2.15 → 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.d.cts CHANGED
@@ -110,8 +110,14 @@ interface VideoRequest {
110
110
  watermark?: boolean;
111
111
  /** Provider-side safety checker toggle (fal MiniMax). Provider default when unset. */
112
112
  safetyChecker?: boolean;
113
- /** Seedance omni-reference subtask hint. `edit` forces duration -1 and adaptive ratio. */
113
+ /** Seedance omni-reference subtask hint. `edit` forces duration -1 and adaptive ratio.
114
+ * `extend` on a `videoExtension` row continues the clip by `durationSeconds` more. */
114
115
  taskType?: "reference" | "edit" | "extend";
116
+ /** Continue a provider-side session instead of re-sending the clip (Gemini Omni
117
+ * Interactions `previous_interaction_id`). The prior call's `VideoResult.providerRef`
118
+ * carries it. The provider rejects it together with an explicit video task, so the
119
+ * adapter sends the prompt alone; `taskType: "extend"` still selects the extend path. */
120
+ previousInteractionId?: string;
115
121
  mode?: "standard" | "pro";
116
122
  }
117
123
  /**
@@ -163,7 +169,9 @@ interface MediaPart {
163
169
  cleanup?: () => Promise<void>;
164
170
  }
165
171
  type RequiredInput = "firstFrame" | "sourceVideo" | "references";
166
- type SupportedOption = "seed" | "quality" | "negativePrompt" | "cfgScale" | "generateAudio" | "promptExpansion" | "lastFrame" | "count" | "outputFormat" | "scaleFactor" | "safetySettings" | "temperature" | "upscale" | "watermark" | "safetyChecker" | "taskType" | "instrumental";
172
+ type SupportedOption = "seed" | "quality" | "negativePrompt" | "cfgScale" | "generateAudio" | "promptExpansion" | "lastFrame" | "count" | "outputFormat" | "scaleFactor" | "safetySettings" | "temperature" | "upscale" | "watermark" | "safetyChecker" | "taskType" | "instrumental"
173
+ /** Video rows that extend a clip in fixed segments up to a cumulative cap (see `ModelConstraints.extension`). */
174
+ | "videoExtension";
167
175
  interface VideoSecondsLimits {
168
176
  /** Minimum length of each reference video, in seconds. */
169
177
  min?: number;
@@ -213,6 +221,12 @@ interface ModelConstraints {
213
221
  /** The provider sends the source as a reference video, so it counts toward `references.videoSeconds.total` (Seedance). */
214
222
  inReferenceTotal?: boolean;
215
223
  };
224
+ /** Video extension (rows with `supports: ["videoExtension"]`): each `taskType: "extend"`
225
+ * call adds up to `segmentSeconds` and the clip can grow to `maxTotalSeconds`. */
226
+ extension?: {
227
+ segmentSeconds: number;
228
+ maxTotalSeconds: number;
229
+ };
216
230
  }
217
231
  /** JSON-compatible value. Provider options and raw payloads carry these, never `unknown`. */
218
232
  type JsonPrimitive = string | number | boolean | null;
@@ -354,6 +368,10 @@ interface VideoResult {
354
368
  };
355
369
  usage: UsageEvent;
356
370
  raw?: unknown;
371
+ /** Provider handle for chaining a follow-up call (`VideoRequest.previousInteractionId`). */
372
+ providerRef?: {
373
+ interactionId: string;
374
+ };
357
375
  }
358
376
  interface VideoCallJob extends VideoJob {
359
377
  warnings: Warning[];
@@ -640,6 +658,7 @@ declare const CatalogModelSchemaBase: z.ZodObject<{
640
658
  safetyChecker: "safetyChecker";
641
659
  taskType: "taskType";
642
660
  instrumental: "instrumental";
661
+ videoExtension: "videoExtension";
643
662
  }>>>;
644
663
  ratioIgnoredWith: z.ZodOptional<z.ZodArray<z.ZodEnum<{
645
664
  firstFrame: "firstFrame";
@@ -651,6 +670,10 @@ declare const CatalogModelSchemaBase: z.ZodObject<{
651
670
  editMin: z.ZodOptional<z.ZodNumber>;
652
671
  inReferenceTotal: z.ZodOptional<z.ZodBoolean>;
653
672
  }, z.core.$loose>>;
673
+ extension: z.ZodOptional<z.ZodObject<{
674
+ segmentSeconds: z.ZodNumber;
675
+ maxTotalSeconds: z.ZodNumber;
676
+ }, z.core.$loose>>;
654
677
  }, z.core.$loose>;
655
678
  defaults: z.ZodObject<{
656
679
  references: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
package/dist/index.d.ts CHANGED
@@ -110,8 +110,14 @@ interface VideoRequest {
110
110
  watermark?: boolean;
111
111
  /** Provider-side safety checker toggle (fal MiniMax). Provider default when unset. */
112
112
  safetyChecker?: boolean;
113
- /** Seedance omni-reference subtask hint. `edit` forces duration -1 and adaptive ratio. */
113
+ /** Seedance omni-reference subtask hint. `edit` forces duration -1 and adaptive ratio.
114
+ * `extend` on a `videoExtension` row continues the clip by `durationSeconds` more. */
114
115
  taskType?: "reference" | "edit" | "extend";
116
+ /** Continue a provider-side session instead of re-sending the clip (Gemini Omni
117
+ * Interactions `previous_interaction_id`). The prior call's `VideoResult.providerRef`
118
+ * carries it. The provider rejects it together with an explicit video task, so the
119
+ * adapter sends the prompt alone; `taskType: "extend"` still selects the extend path. */
120
+ previousInteractionId?: string;
115
121
  mode?: "standard" | "pro";
116
122
  }
117
123
  /**
@@ -163,7 +169,9 @@ interface MediaPart {
163
169
  cleanup?: () => Promise<void>;
164
170
  }
165
171
  type RequiredInput = "firstFrame" | "sourceVideo" | "references";
166
- type SupportedOption = "seed" | "quality" | "negativePrompt" | "cfgScale" | "generateAudio" | "promptExpansion" | "lastFrame" | "count" | "outputFormat" | "scaleFactor" | "safetySettings" | "temperature" | "upscale" | "watermark" | "safetyChecker" | "taskType" | "instrumental";
172
+ type SupportedOption = "seed" | "quality" | "negativePrompt" | "cfgScale" | "generateAudio" | "promptExpansion" | "lastFrame" | "count" | "outputFormat" | "scaleFactor" | "safetySettings" | "temperature" | "upscale" | "watermark" | "safetyChecker" | "taskType" | "instrumental"
173
+ /** Video rows that extend a clip in fixed segments up to a cumulative cap (see `ModelConstraints.extension`). */
174
+ | "videoExtension";
167
175
  interface VideoSecondsLimits {
168
176
  /** Minimum length of each reference video, in seconds. */
169
177
  min?: number;
@@ -213,6 +221,12 @@ interface ModelConstraints {
213
221
  /** The provider sends the source as a reference video, so it counts toward `references.videoSeconds.total` (Seedance). */
214
222
  inReferenceTotal?: boolean;
215
223
  };
224
+ /** Video extension (rows with `supports: ["videoExtension"]`): each `taskType: "extend"`
225
+ * call adds up to `segmentSeconds` and the clip can grow to `maxTotalSeconds`. */
226
+ extension?: {
227
+ segmentSeconds: number;
228
+ maxTotalSeconds: number;
229
+ };
216
230
  }
217
231
  /** JSON-compatible value. Provider options and raw payloads carry these, never `unknown`. */
218
232
  type JsonPrimitive = string | number | boolean | null;
@@ -354,6 +368,10 @@ interface VideoResult {
354
368
  };
355
369
  usage: UsageEvent;
356
370
  raw?: unknown;
371
+ /** Provider handle for chaining a follow-up call (`VideoRequest.previousInteractionId`). */
372
+ providerRef?: {
373
+ interactionId: string;
374
+ };
357
375
  }
358
376
  interface VideoCallJob extends VideoJob {
359
377
  warnings: Warning[];
@@ -640,6 +658,7 @@ declare const CatalogModelSchemaBase: z.ZodObject<{
640
658
  safetyChecker: "safetyChecker";
641
659
  taskType: "taskType";
642
660
  instrumental: "instrumental";
661
+ videoExtension: "videoExtension";
643
662
  }>>>;
644
663
  ratioIgnoredWith: z.ZodOptional<z.ZodArray<z.ZodEnum<{
645
664
  firstFrame: "firstFrame";
@@ -651,6 +670,10 @@ declare const CatalogModelSchemaBase: z.ZodObject<{
651
670
  editMin: z.ZodOptional<z.ZodNumber>;
652
671
  inReferenceTotal: z.ZodOptional<z.ZodBoolean>;
653
672
  }, z.core.$loose>>;
673
+ extension: z.ZodOptional<z.ZodObject<{
674
+ segmentSeconds: z.ZodNumber;
675
+ maxTotalSeconds: z.ZodNumber;
676
+ }, z.core.$loose>>;
654
677
  }, z.core.$loose>;
655
678
  defaults: z.ZodObject<{
656
679
  references: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
package/dist/index.js CHANGED
@@ -1402,7 +1402,14 @@ var VIDEO_MODELS = [
1402
1402
  durations: [3, 4, 5, 6, 7, 8, 9, 10],
1403
1403
  references: { images: 6, videos: 1, videoSeconds: { max: 10 } },
1404
1404
  sourceVideoSeconds: { max: 10 },
1405
- supports: []
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 }
1406
1413
  },
1407
1414
  defaults: {},
1408
1415
  usage: { ...VIDEO_USAGE },
@@ -1410,7 +1417,7 @@ var VIDEO_MODELS = [
1410
1417
  display: {
1411
1418
  provider: "google",
1412
1419
  logo: GOOGLE_LOGO2,
1413
- 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."
1414
1421
  },
1415
1422
  capabilities: { acceptsSourceVideo: true }
1416
1423
  },
@@ -2144,6 +2151,7 @@ var SupportedOptionSchema = z2.enum([
2144
2151
  "watermark",
2145
2152
  "safetyChecker",
2146
2153
  "taskType",
2154
+ "videoExtension",
2147
2155
  "instrumental"
2148
2156
  ]);
2149
2157
  var UsageUnitSchema = z2.enum([
@@ -2191,7 +2199,8 @@ var ModelConstraintsSchema = z2.looseObject({
2191
2199
  requires: z2.array(RequiredInputSchema).optional(),
2192
2200
  supports: z2.array(SupportedOptionSchema).optional(),
2193
2201
  ratioIgnoredWith: z2.array(z2.enum(["firstFrame", "sourceVideo"])).optional(),
2194
- sourceVideoSeconds: VideoSecondsLimitsSchema.omit({ total: true }).extend({ inReferenceTotal: z2.boolean().optional() }).optional()
2202
+ sourceVideoSeconds: VideoSecondsLimitsSchema.omit({ total: true }).extend({ inReferenceTotal: z2.boolean().optional() }).optional(),
2203
+ extension: z2.looseObject({ segmentSeconds: z2.number(), maxTotalSeconds: z2.number() }).optional()
2195
2204
  });
2196
2205
  var MediaRefSchema = z2.union([
2197
2206
  z2.looseObject({
@@ -4460,12 +4469,34 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
4460
4469
  const modelId = ctx.model.id;
4461
4470
  const providerModelId = ctx.model.providerModelId;
4462
4471
  const duration = req.durationSeconds ?? 10;
4463
- const images = req.referenceImages ?? [];
4464
- const videos = req.referenceVideos ?? [];
4465
- 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";
4466
4497
  const isOmniV1 = providerModelId === "gemini-omni-flash-preview";
4467
4498
  const responseFormat = { type: "video", delivery: "uri" };
4468
- 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") {
4469
4500
  responseFormat.aspect_ratio = toOmniAspect(req.aspectRatio);
4470
4501
  }
4471
4502
  if (!isOmniV1) {
@@ -4497,18 +4528,26 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
4497
4528
  const cleanupUploads = async () => {
4498
4529
  for (const fileName of uploadedNames) await deleteGoogleFile(fileName, apiKey, ctx.fetch);
4499
4530
  };
4500
- const callCreate = (input) => client2.interactions.create({
4501
- model: providerModelId,
4502
- input,
4503
- response_format: responseFormat,
4504
- generation_config: { video_config: { task } },
4505
- store: true
4506
- });
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
+ );
4507
4546
  const createRetryOptions = mediaRetryOptions(ctx.call, ctx.signal);
4508
4547
  let interaction;
4509
4548
  try {
4510
4549
  const parts = [];
4511
- if (req.sourceVideo) {
4550
+ if (req.sourceVideo && !chained) {
4512
4551
  const media = await resolveMedia(
4513
4552
  req.sourceVideo,
4514
4553
  ctx.fetch,
@@ -4531,11 +4570,11 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
4531
4570
  mime_type: media.mime
4532
4571
  });
4533
4572
  }
4534
- if (req.firstFrame) {
4535
- if (req.firstFrame.label !== void 0)
4536
- 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 });
4537
4576
  const media = await resolveMedia(
4538
- req.firstFrame,
4577
+ firstFrame,
4539
4578
  ctx.fetch,
4540
4579
  ctx.signal,
4541
4580
  "image/png",
@@ -4638,6 +4677,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
4638
4677
  return void 0;
4639
4678
  }, pollOptions);
4640
4679
  const video = extractOmniVideo(done, modelId);
4680
+ const providerRef = { interactionId: done.id ?? jobId };
4641
4681
  if (video.data) {
4642
4682
  return {
4643
4683
  video: {
@@ -4645,14 +4685,16 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
4645
4685
  mime: video.mime_type ?? "video/mp4"
4646
4686
  },
4647
4687
  usage: usage2,
4648
- raw: done
4688
+ raw: done,
4689
+ providerRef
4649
4690
  };
4650
4691
  }
4651
4692
  if (video.uri)
4652
4693
  return {
4653
4694
  video: await downloadVideo(ctx, video.uri, apiKey, signal),
4654
4695
  usage: usage2,
4655
- raw: done
4696
+ raw: done,
4697
+ providerRef
4656
4698
  };
4657
4699
  throw classifyHttpError(
4658
4700
  void 0,
@@ -7544,6 +7586,7 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
7544
7586
  setOrDelete(merged, "referenceImages", images);
7545
7587
  setOrDelete(merged, "referenceVideos", videos);
7546
7588
  setOrDelete(merged, "referenceAudios", audios);
7589
+ const keepExtend = merged.taskType === "extend" && (model.constraints.supports ?? []).includes("videoExtension");
7547
7590
  dropUnsupported(merged, model, warnings, [
7548
7591
  "seed",
7549
7592
  "negativePrompt",
@@ -7553,8 +7596,17 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
7553
7596
  "lastFrame",
7554
7597
  "watermark",
7555
7598
  "safetyChecker",
7556
- "taskType"
7599
+ ...keepExtend ? [] : ["taskType"]
7557
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
+ }
7558
7610
  return { request: merged, warnings };
7559
7611
  }
7560
7612
  function resolveAudioOptions(model, request, onUnsupported = "error") {