@shop-os/modelkit 0.2.9 → 0.2.11

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.cjs CHANGED
@@ -63,6 +63,7 @@ __export(index_exports, {
63
63
  generateVideo: () => generateVideo,
64
64
  googleGenaiAdapter: () => googleGenaiAdapter,
65
65
  googleImageAdapter: () => googleImageAdapter,
66
+ hasAwsCredentials: () => hasAwsCredentials,
66
67
  higgsfieldAdapter: () => higgsfieldAdapter,
67
68
  isListed: () => isListed,
68
69
  isListedOn: () => isListedOn,
@@ -100,6 +101,14 @@ __export(index_exports, {
100
101
  module.exports = __toCommonJS(index_exports);
101
102
  __reExport(index_exports, require("ai"), module.exports);
102
103
 
104
+ // src/types.ts
105
+ function hasAwsCredentials(aws) {
106
+ if (!aws || !aws.region) return false;
107
+ if (aws.apiKey) return true;
108
+ if (aws.credentialProvider) return true;
109
+ return Boolean(aws.accessKeyId && aws.secretAccessKey);
110
+ }
111
+
103
112
  // src/errors.ts
104
113
  var ModelKitError = class extends Error {
105
114
  code;
@@ -1569,6 +1578,7 @@ var VIDEO_MODELS = [
1569
1578
  },
1570
1579
  {
1571
1580
  // generateAudio defaults to false here (trigger-workflows); Space Builder defaults it to true.
1581
+ // omni_reference_task_type edit/extend: adaptive ratio, edit sends duration -1.
1572
1582
  id: "seedance-2.5",
1573
1583
  aliases: ["seedance-2-5", "dreamina-seedance-2-5-260628"],
1574
1584
  label: "Seedance 2.5",
@@ -1583,7 +1593,7 @@ var VIDEO_MODELS = [
1583
1593
  durations: { min: 4, max: 30 },
1584
1594
  references: { images: 30, videos: 10, audios: 10 },
1585
1595
  ratioIgnoredWith: ["firstFrame", "sourceVideo"],
1586
- supports: ["generateAudio", "seed", "lastFrame", "watermark"]
1596
+ supports: ["generateAudio", "seed", "lastFrame", "watermark", "taskType"]
1587
1597
  },
1588
1598
  defaults: {
1589
1599
  durationSeconds: 5,
@@ -1692,6 +1702,9 @@ var VIDEO_MODELS = [
1692
1702
  },
1693
1703
  {
1694
1704
  // mode standard/pro selects 720p/1080p; the endpoint takes no separate resolution.
1705
+ // Replicate: "Max 7 [images] without video, 4 with video"; 4K does not support
1706
+ // reference_video. No `videos` limit yet: the adapter sends no reference video,
1707
+ // so `imagesWithVideo` stays dormant until one is wired through.
1695
1708
  id: "kling-v3-omni-video",
1696
1709
  aliases: ["kwaivgi/kling-v3-omni-video", "kling-v3-omni"],
1697
1710
  label: "Kling V3 Omni",
@@ -1704,7 +1717,7 @@ var VIDEO_MODELS = [
1704
1717
  aspectRatios: [...KLING_RATIOS],
1705
1718
  resolutions: ["720p", "1080p"],
1706
1719
  durations: { min: 3, max: 15 },
1707
- references: { images: 7 },
1720
+ references: { images: 7, imagesWithVideo: 4 },
1708
1721
  supports: ["generateAudio", "lastFrame"]
1709
1722
  },
1710
1723
  defaults: { durationSeconds: 5, aspectRatio: "16:9", generateAudio: false, mode: "pro" },
@@ -1980,6 +1993,7 @@ var SupportedOptionSchema = import_zod.z.enum([
1980
1993
  "upscale",
1981
1994
  "watermark",
1982
1995
  "safetyChecker",
1996
+ "taskType",
1983
1997
  "instrumental"
1984
1998
  ]);
1985
1999
  var UsageUnitSchema = import_zod.z.enum([
@@ -2002,6 +2016,7 @@ var ProviderOptionValueSchema = import_zod.z.lazy(
2002
2016
  var ProviderOptionsSchema = import_zod.z.record(import_zod.z.string(), import_zod.z.record(import_zod.z.string(), ProviderOptionValueSchema));
2003
2017
  var ReferenceLimitsSchema = import_zod.z.looseObject({
2004
2018
  images: import_zod.z.number().optional(),
2019
+ imagesWithVideo: import_zod.z.number().optional(),
2005
2020
  videos: import_zod.z.number().optional(),
2006
2021
  audios: import_zod.z.number().optional(),
2007
2022
  total: import_zod.z.number().optional(),
@@ -2063,6 +2078,7 @@ var DefaultsSchema = import_zod.z.looseObject({
2063
2078
  promptExpansion: import_zod.z.enum(["fast", "balanced", "quality"]).optional(),
2064
2079
  watermark: import_zod.z.boolean().optional(),
2065
2080
  safetyChecker: import_zod.z.boolean().optional(),
2081
+ taskType: import_zod.z.enum(["reference", "edit", "extend"]).optional(),
2066
2082
  mode: import_zod.z.enum(["standard", "pro"]).optional(),
2067
2083
  instrumental: import_zod.z.boolean().optional()
2068
2084
  });
@@ -2129,7 +2145,18 @@ var CatalogModelSchemaBase = import_zod.z.looseObject({
2129
2145
  });
2130
2146
  }
2131
2147
  });
2132
- var CatalogModelSchema = CatalogModelSchemaBase;
2148
+ var CatalogModelSchema = CatalogModelSchemaBase.superRefine(
2149
+ (row, ctx) => {
2150
+ const transport = row.providerOptions?.["modelkit"]?.["transport"];
2151
+ if (transport !== void 0 && transport !== "direct" && transport !== "bedrock") {
2152
+ ctx.addIssue({
2153
+ code: "custom",
2154
+ path: ["providerOptions", "modelkit", "transport"],
2155
+ message: 'transport must be "direct" or "bedrock"'
2156
+ });
2157
+ }
2158
+ }
2159
+ );
2133
2160
  var CatalogSchema = import_zod.z.array(CatalogModelSchemaBase).superRefine((rows, ctx) => {
2134
2161
  const seenIds = /* @__PURE__ */ new Map();
2135
2162
  rows.forEach((row, index) => {
@@ -2622,6 +2649,9 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
2622
2649
  model,
2623
2650
  warnings
2624
2651
  );
2652
+ if (limits.imagesWithVideo !== void 0 && (limits.videos ?? 0) > 0 && videos.length > 0 && images.length > limits.imagesWithVideo) {
2653
+ images = trim("referenceImages", images, limits.imagesWithVideo, model, warnings);
2654
+ }
2625
2655
  if (limits.total !== void 0) {
2626
2656
  let over = images.length + videos.length + audios.length - limits.total;
2627
2657
  if (over > 0) {
@@ -2655,7 +2685,8 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
2655
2685
  "promptExpansion",
2656
2686
  "lastFrame",
2657
2687
  "watermark",
2658
- "safetyChecker"
2688
+ "safetyChecker",
2689
+ "taskType"
2659
2690
  ]);
2660
2691
  return { request: merged, warnings };
2661
2692
  }
@@ -2730,9 +2761,12 @@ var ADAPTER_KEYS = {
2730
2761
  function hasAll(keys, names) {
2731
2762
  if (!keys) return false;
2732
2763
  return names.every(
2733
- (n) => Boolean(keys[n]) && (n !== "higgsfield" || Boolean(keys.higgsfieldSecret))
2764
+ (n) => n === "aws" ? hasAwsCredentials(keys.aws) : Boolean(keys[n]) && (n !== "higgsfield" || Boolean(keys.higgsfieldSecret))
2734
2765
  );
2735
2766
  }
2767
+ function hasKey(keys, name) {
2768
+ return hasAll(keys, [name]);
2769
+ }
2736
2770
  function missingEnterpriseKeys(config, names) {
2737
2771
  return names.filter((name) => !hasAll(config.keys.enterprise, [name]));
2738
2772
  }
@@ -2769,6 +2803,22 @@ function keysFromEnv(env, prefix = "") {
2769
2803
  set("higgsfield", pick("HIGGSFIELD_API_KEY"));
2770
2804
  set("higgsfieldSecret", pick("HIGGSFIELD_API_SECRET"));
2771
2805
  set("cloudflare", pick("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
2806
+ const bearer = pick("AWS_BEARER_TOKEN_BEDROCK");
2807
+ const accessKeyId = pick("AWS_ACCESS_KEY_ID");
2808
+ const secretAccessKey = pick("AWS_SECRET_ACCESS_KEY");
2809
+ if (bearer || accessKeyId && secretAccessKey) {
2810
+ const aws = {
2811
+ region: env[`${prefix}BEDROCK_REGION`] || "us-east-1"
2812
+ };
2813
+ if (accessKeyId && secretAccessKey) {
2814
+ aws.accessKeyId = accessKeyId;
2815
+ aws.secretAccessKey = secretAccessKey;
2816
+ }
2817
+ const sessionToken = pick("AWS_SESSION_TOKEN");
2818
+ if (sessionToken) aws.sessionToken = sessionToken;
2819
+ if (bearer) aws.apiKey = bearer;
2820
+ keys.aws = aws;
2821
+ }
2772
2822
  return keys;
2773
2823
  }
2774
2824
 
@@ -3097,7 +3147,8 @@ function toGeneratedImage(image) {
3097
3147
  }
3098
3148
 
3099
3149
  // src/adapters/ai-sdk-text.ts
3100
- var import_anthropic = require("@ai-sdk/anthropic");
3150
+ var import_anthropic = require("@ai-sdk/amazon-bedrock/anthropic");
3151
+ var import_anthropic2 = require("@ai-sdk/anthropic");
3101
3152
  var import_google = require("@ai-sdk/google");
3102
3153
  var import_openai = require("@ai-sdk/openai");
3103
3154
  var import_openai_compatible = require("@ai-sdk/openai-compatible");
@@ -3148,16 +3199,47 @@ function detectTextProvider(modelId) {
3148
3199
  message: `ai-sdk-text cannot detect a provider for "${modelId}". Set providerOptions.provider to one of ${TEXT_PROVIDERS.join(", ")}.`
3149
3200
  });
3150
3201
  }
3151
- function textKeyName(model, _routing) {
3152
- return textProviderOf(model);
3202
+ function textKeyName(model, transport) {
3203
+ const provider = textProviderOf(model);
3204
+ return provider === "anthropic" && transport === "bedrock" ? "aws" : provider;
3153
3205
  }
3154
3206
  function textProviderOf(model) {
3155
3207
  const explicit = model.providerOptions?.["modelkit"]?.["provider"];
3156
3208
  return isTextProvider(explicit) ? explicit : detectTextProvider(model.providerModelId);
3157
3209
  }
3158
- function textUsesCloudflareGateway(model, routing) {
3210
+ function textUsesCloudflareGateway(model, routing, transport) {
3159
3211
  if (routing.text !== "cloudflare") return false;
3160
- return GATEWAY_SLUGS[textProviderOf(model)] !== void 0;
3212
+ const provider = textProviderOf(model);
3213
+ if (provider === "anthropic" && transport === "bedrock") return false;
3214
+ return GATEWAY_SLUGS[provider] !== void 0;
3215
+ }
3216
+ var BEDROCK_DATED_MODEL_IDS = {
3217
+ "claude-haiku-4-5": "anthropic.claude-haiku-4-5-20251001-v1:0",
3218
+ "claude-haiku-4-5-20251001": "anthropic.claude-haiku-4-5-20251001-v1:0",
3219
+ "claude-sonnet-4-5": "anthropic.claude-sonnet-4-5-20250929-v1:0",
3220
+ "claude-sonnet-4-5-20250929": "anthropic.claude-sonnet-4-5-20250929-v1:0"
3221
+ };
3222
+ var BEDROCK_PROFILE_PREFIXES = ["us.", "global.", "eu.", "jp.", "au.", "apac."];
3223
+ function toBedrockModelId(model, routing) {
3224
+ const profile = routing.bedrockProfile ?? "us";
3225
+ const override = model.providerOptions?.["modelkit"]?.["bedrockModelId"];
3226
+ if (typeof override === "string" && override.length > 0) {
3227
+ if (BEDROCK_PROFILE_PREFIXES.some((prefix) => override.startsWith(prefix))) return override;
3228
+ if (override.startsWith("anthropic.")) return `${profile}.${override}`;
3229
+ return override;
3230
+ }
3231
+ const id = model.providerModelId;
3232
+ if (BEDROCK_PROFILE_PREFIXES.some((prefix) => id.startsWith(prefix))) return id;
3233
+ const dated = BEDROCK_DATED_MODEL_IDS[id];
3234
+ if (dated) return `${profile}.${dated}`;
3235
+ if (id.startsWith("claude-")) return `${profile}.anthropic.${id}`;
3236
+ throw new ModelKitError({
3237
+ code: "unsupported_option",
3238
+ message: `No Bedrock model id for "${id}". Set providerOptions.modelkit.bedrockModelId on the catalog row.`,
3239
+ provider: "ai-sdk-text",
3240
+ model: model.id,
3241
+ retryable: false
3242
+ });
3161
3243
  }
3162
3244
  function nativeClientFor(provider) {
3163
3245
  switch (provider) {
@@ -3182,14 +3264,14 @@ function nativeClientFor(provider) {
3182
3264
  function resolveTextRoute(ctx) {
3183
3265
  const provider = textProviderOf(ctx.model);
3184
3266
  const mode = ctx.routing.text ?? "direct";
3185
- if (provider === "anthropic" && ctx.routing.anthropic === "bedrock") {
3186
- throw new ModelKitError({
3187
- code: "unsupported_option",
3188
- message: "ai-sdk-text has no Bedrock transport (@ai-sdk/amazon-bedrock is not installed). Pass the Bedrock model through catalogOverride with providerOptions.bedrockModel and resolve it outside the SDK.",
3189
- provider: "ai-sdk-text",
3190
- model: ctx.model.id,
3191
- retryable: false
3192
- });
3267
+ if (provider === "anthropic" && ctx.anthropicTransport === "bedrock") {
3268
+ return {
3269
+ provider,
3270
+ client: "bedrock-anthropic",
3271
+ modelId: toBedrockModelId(ctx.model, ctx.routing),
3272
+ keyName: "aws",
3273
+ canonicalModelId: ctx.model.id
3274
+ };
3193
3275
  }
3194
3276
  const compatBase = OPENAI_COMPATIBLE_BASE_URLS[provider];
3195
3277
  const route2 = {
@@ -3233,6 +3315,70 @@ function missingKey(ctx, name) {
3233
3315
  retryable: false
3234
3316
  });
3235
3317
  }
3318
+ function bedrockMiddleware(ctx, canonicalModelId) {
3319
+ let warned = false;
3320
+ return {
3321
+ specificationVersion: "v3",
3322
+ transformParams: async ({ params }) => {
3323
+ const anthropic = params.providerOptions?.["anthropic"];
3324
+ if (typeof anthropic !== "object" || anthropic === null || !("cacheControl" in anthropic))
3325
+ return params;
3326
+ if (!warned) {
3327
+ warned = true;
3328
+ ctx.logger.warn(
3329
+ `[modelkit] ${canonicalModelId} drops call-level providerOptions.anthropic.cacheControl: not supported on Bedrock, use message-level cacheControl`
3330
+ );
3331
+ }
3332
+ const { cacheControl: _dropped, ...rest } = anthropic;
3333
+ return {
3334
+ ...params,
3335
+ providerOptions: { ...params.providerOptions, anthropic: rest }
3336
+ };
3337
+ },
3338
+ // Bedrock echoes its own id for dated models (anthropic.claude-haiku-4-5-20251001-v1:0),
3339
+ // and consumers bill on response.modelId.
3340
+ wrapGenerate: async ({ doGenerate }) => {
3341
+ const result = await doGenerate();
3342
+ if (!result.response) return result;
3343
+ return { ...result, response: { ...result.response, modelId: canonicalModelId } };
3344
+ },
3345
+ wrapStream: async ({ doStream }) => {
3346
+ const result = await doStream();
3347
+ return {
3348
+ ...result,
3349
+ stream: result.stream.pipeThrough(
3350
+ new TransformStream({
3351
+ transform(part, controller) {
3352
+ controller.enqueue(
3353
+ part.type === "response-metadata" && part.modelId !== void 0 ? { ...part, modelId: canonicalModelId } : part
3354
+ );
3355
+ }
3356
+ })
3357
+ )
3358
+ };
3359
+ }
3360
+ };
3361
+ }
3362
+ function bedrockLanguageModel(ctx, route2) {
3363
+ const aws = ctx.keys.aws;
3364
+ if (!hasAwsCredentials(aws)) throw missingKey(ctx, "aws");
3365
+ const canonical = route2.canonicalModelId ?? ctx.model.id;
3366
+ const inner = (0, import_anthropic.createBedrockAnthropic)({
3367
+ region: aws.region,
3368
+ fetch: ctx.fetch,
3369
+ ...aws.apiKey ? { apiKey: aws.apiKey } : aws.credentialProvider ? { credentialProvider: aws.credentialProvider } : aws.accessKeyId !== void 0 && aws.secretAccessKey !== void 0 ? {
3370
+ accessKeyId: aws.accessKeyId,
3371
+ secretAccessKey: aws.secretAccessKey,
3372
+ ...aws.sessionToken !== void 0 ? { sessionToken: aws.sessionToken } : {}
3373
+ } : {}
3374
+ })(route2.modelId);
3375
+ return (0, import_ai2.wrapLanguageModel)({
3376
+ model: inner,
3377
+ middleware: bedrockMiddleware(ctx, canonical),
3378
+ modelId: canonical,
3379
+ providerId: "anthropic.messages"
3380
+ });
3381
+ }
3236
3382
  function minimaxDefaults(params) {
3237
3383
  return params.responseFormat?.type === "json" ? { reasoning_split: true, thinking: { type: "disabled" } } : { reasoning_split: true };
3238
3384
  }
@@ -3271,14 +3417,17 @@ var aiSdkTextAdapter = {
3271
3417
  id: "ai-sdk-text",
3272
3418
  languageModel(ctx) {
3273
3419
  const route2 = resolveTextRoute(ctx);
3274
- const apiKey = ctx.keys[route2.keyName];
3275
- if (!apiKey) throw missingKey(ctx, route2.keyName);
3420
+ if (route2.client === "bedrock-anthropic") return bedrockLanguageModel(ctx, route2);
3421
+ const { keyName } = route2;
3422
+ if (keyName === "aws") throw missingKey(ctx, keyName);
3423
+ const apiKey = ctx.keys[keyName];
3424
+ if (!apiKey) throw missingKey(ctx, keyName);
3276
3425
  const settings = { apiKey, fetch: ctx.fetch };
3277
3426
  if (route2.baseURL !== void 0) settings.baseURL = route2.baseURL;
3278
3427
  if (route2.headers !== void 0) settings.headers = route2.headers;
3279
3428
  switch (route2.client) {
3280
3429
  case "anthropic":
3281
- return (0, import_anthropic.createAnthropic)(settings)(route2.modelId);
3430
+ return (0, import_anthropic2.createAnthropic)(settings)(route2.modelId);
3282
3431
  case "google":
3283
3432
  return (0, import_google.createGoogleGenerativeAI)(settings)(route2.modelId);
3284
3433
  case "xai":
@@ -3311,14 +3460,43 @@ var aiSdkTextAdapter = {
3311
3460
  }
3312
3461
  };
3313
3462
 
3463
+ // src/anthropic-transport.ts
3464
+ var ANTHROPIC_TRANSPORTS = ["direct", "bedrock"];
3465
+ function isAnthropicTransport(value) {
3466
+ return ANTHROPIC_TRANSPORTS.some((transport) => transport === value);
3467
+ }
3468
+ function preferredAnthropicTransport(model, routing) {
3469
+ const row = model.providerOptions?.["modelkit"]?.["transport"];
3470
+ if (isAnthropicTransport(row)) return row;
3471
+ return routing.anthropic ?? "direct";
3472
+ }
3473
+ function resolveAnthropicTransport(model, config, tier, warn) {
3474
+ if (model.adapter !== "ai-sdk-text" || textProviderOf(model) !== "anthropic") return void 0;
3475
+ const rowValue = model.providerOptions?.["modelkit"]?.["transport"];
3476
+ if (rowValue !== void 0 && !isAnthropicTransport(rowValue))
3477
+ warn(
3478
+ `[modelkit] ${model.id} has an unknown providerOptions.modelkit.transport "${String(rowValue)}"; ignoring it`
3479
+ );
3480
+ const preferred = preferredAnthropicTransport(model, config.routing ?? {});
3481
+ const usable = (transport) => {
3482
+ const name = transport === "bedrock" ? "aws" : "anthropic";
3483
+ return hasKey(config.keys.pro, name) || tier === "enterprise" && hasKey(config.keys.enterprise, name);
3484
+ };
3485
+ if (usable(preferred)) return preferred;
3486
+ const other = preferred === "bedrock" ? "direct" : "bedrock";
3487
+ if (!usable(other)) return preferred;
3488
+ warn(`[modelkit] ${model.id}: no credentials for the ${preferred} transport; using ${other}`);
3489
+ return other;
3490
+ }
3491
+
3314
3492
  // src/client.ts
3315
- function requiredKeys(model, config) {
3493
+ function requiredKeys(model, config, transport) {
3316
3494
  if (model.adapter === "fal" && config.routing?.fal === "cloudflare-passthrough")
3317
3495
  return ["cloudflare"];
3318
3496
  if (model.adapter === "ai-sdk-text") {
3319
3497
  const routing = config.routing ?? {};
3320
- const names = [textKeyName(model, routing)];
3321
- if (textUsesCloudflareGateway(model, routing)) names.push("cloudflare");
3498
+ const names = [textKeyName(model, transport)];
3499
+ if (textUsesCloudflareGateway(model, routing, transport)) names.push("cloudflare");
3322
3500
  return names;
3323
3501
  }
3324
3502
  return ADAPTER_KEYS[model.adapter];
@@ -3405,6 +3583,12 @@ function createModelKit(config, adapters) {
3405
3583
  const catalog = config.catalogOverride ? liveCatalog.withOverrides(config.catalogOverride) : liveCatalog;
3406
3584
  const logger = config.logger ?? console;
3407
3585
  const fetchImpl = config.fetch ?? globalThis.fetch;
3586
+ const transportWarnings = /* @__PURE__ */ new Set();
3587
+ function warnOnce(message) {
3588
+ if (transportWarnings.has(message)) return;
3589
+ transportWarnings.add(message);
3590
+ logger.warn(message);
3591
+ }
3408
3592
  function context(model, call, warnings) {
3409
3593
  const adapter = adapters[model.adapter];
3410
3594
  if (!adapter)
@@ -3413,7 +3597,8 @@ function createModelKit(config, adapters) {
3413
3597
  message: `No adapter registered for ${model.adapter}`,
3414
3598
  model: model.id
3415
3599
  });
3416
- const names = requiredKeys(model, config);
3600
+ const transport = resolveAnthropicTransport(model, config, call.tier, warnOnce);
3601
+ const names = requiredKeys(model, config, transport);
3417
3602
  if (call.tier === "enterprise") {
3418
3603
  const missing = missingEnterpriseKeys(config, names);
3419
3604
  if (missing.length > 0)
@@ -3432,6 +3617,7 @@ function createModelKit(config, adapters) {
3432
3617
  call,
3433
3618
  warnings
3434
3619
  };
3620
+ if (transport) ctx.anthropicTransport = transport;
3435
3621
  if (config.endpoints) ctx.endpoints = config.endpoints;
3436
3622
  if (call.signal) ctx.signal = call.signal;
3437
3623
  return { adapter, ctx };
@@ -3766,7 +3952,7 @@ function createModelKit(config, adapters) {
3766
3952
  async prepareMediaPart(modelId, ref, mediaType, call = {}) {
3767
3953
  const model = catalog.require(modelId);
3768
3954
  const { adapter, ctx } = context(model, call, []);
3769
- const fileStore = model.adapter === "ai-sdk-text" && textKeyName(model, config.routing ?? {}) === "google" ? adapters["google-genai"] : adapter;
3955
+ const fileStore = model.adapter === "ai-sdk-text" && textKeyName(model) === "google" ? adapters["google-genai"] : adapter;
3770
3956
  if (fileStore?.prepareMediaPart) return fileStore.prepareMediaPart(ref, mediaType, ctx);
3771
3957
  return "url" in ref ? { type: "file", data: ref.url, mediaType } : { type: "file", data: ref.bytes, mediaType };
3772
3958
  },
@@ -4096,9 +4282,22 @@ function seedanceErrorMessage(error, status) {
4096
4282
  return `Seedance task ${status}`;
4097
4283
  }
4098
4284
  async function generateSeedanceVideo(req, ctx) {
4099
- const key = arkKey(ctx);
4100
4285
  const modelId = ctx.model.id;
4101
- const duration = req.durationSeconds ?? 5;
4286
+ const taskType = req.taskType;
4287
+ const hasVideo = Boolean(req.sourceVideo) || (req.referenceVideos?.length ?? 0) > 0;
4288
+ if ((taskType === "edit" || taskType === "extend") && !hasVideo) {
4289
+ throw new ModelKitError({
4290
+ code: "missing_input",
4291
+ message: `${ctx.model.id} ${taskType} task needs a source or reference video`,
4292
+ provider: "ark",
4293
+ model: ctx.model.id,
4294
+ retryable: false
4295
+ });
4296
+ }
4297
+ const key = arkKey(ctx);
4298
+ const requestedDuration = req.durationSeconds ?? 5;
4299
+ let duration = requestedDuration;
4300
+ if (taskType === "edit") duration = -1;
4102
4301
  const resolution = req.resolution ?? "720p";
4103
4302
  const content = [{ type: "text", text: req.prompt }];
4104
4303
  if (req.firstFrame) {
@@ -4150,7 +4349,10 @@ async function generateSeedanceVideo(req, ctx) {
4150
4349
  duration,
4151
4350
  resolution
4152
4351
  };
4153
- if (!hasFrameAnchor && req.aspectRatio !== void 0) body.ratio = req.aspectRatio;
4352
+ if (taskType === "edit" || taskType === "extend") body.ratio = "adaptive";
4353
+ else if (!hasFrameAnchor && req.aspectRatio !== void 0) body.ratio = req.aspectRatio;
4354
+ if (taskType !== void 0 && ctx.model.id === "seedance-2.5")
4355
+ body.omni_reference_task_type = taskType;
4154
4356
  if (req.generateAudio !== void 0) body.generate_audio = req.generateAudio;
4155
4357
  if (req.seed !== void 0) body.seed = req.seed;
4156
4358
  if (req.watermark !== void 0) body.watermark = req.watermark;
@@ -4170,7 +4372,7 @@ async function generateSeedanceVideo(req, ctx) {
4170
4372
  }, retryOptsFor(ctx));
4171
4373
  if (!submit.id) throwArkError(void 0, "Seedance task create returned no id", modelId);
4172
4374
  const jobId = submit.id;
4173
- const usage2 = seedanceUsage(ctx, req, duration);
4375
+ const usage2 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
4174
4376
  const fetchStatus = async () => {
4175
4377
  const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`, {
4176
4378
  headers: { Authorization: `Bearer ${key}` }
@@ -4217,6 +4419,10 @@ async function generateSeedanceVideo(req, ctx) {
4217
4419
  "Seedance task succeeded but returned no video_url",
4218
4420
  modelId
4219
4421
  );
4422
+ if (polled.duration !== void 0 && polled.duration > 0) {
4423
+ usage2.quantity = polled.duration;
4424
+ usage2.durationSeconds = polled.duration;
4425
+ }
4220
4426
  const tokens = polled.usage;
4221
4427
  if (tokens?.total_tokens !== void 0 && tokens.completion_tokens !== void 0) {
4222
4428
  usage2.inputTokens = tokens.total_tokens - tokens.completion_tokens;
@@ -5270,7 +5476,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
5270
5476
  const apiKey = googleKey(ctx);
5271
5477
  const modelId = ctx.model.id;
5272
5478
  const providerModelId = ctx.model.providerModelId;
5273
- const duration = req.durationSeconds ?? 8;
5479
+ const duration = req.durationSeconds ?? 10;
5274
5480
  const images = req.referenceImages ?? [];
5275
5481
  const videos = req.referenceVideos ?? [];
5276
5482
  const task = req.sourceVideo ? "edit" : req.firstFrame ? "image_to_video" : images.length > 0 || videos.length > 0 ? "reference_to_video" : "text_to_video";
@@ -7538,6 +7744,7 @@ var describe = (modelId) => createDefaultModelKit().describe(modelId);
7538
7744
  generateVideo,
7539
7745
  googleGenaiAdapter,
7540
7746
  googleImageAdapter,
7747
+ hasAwsCredentials,
7541
7748
  higgsfieldAdapter,
7542
7749
  isListed,
7543
7750
  isListedOn,