@mux/ai 0.34.0 → 0.36.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.
@@ -2,7 +2,7 @@ import { z } from 'zod';
2
2
  import { createAnthropic } from '@ai-sdk/anthropic';
3
3
  import { createGoogleGenerativeAI } from '@ai-sdk/google';
4
4
  import { createOpenAI } from '@ai-sdk/openai';
5
- import { f as ScopedMuxAIOptions, I as ImageSubmissionMode, i as TokenUsage, M as MuxAIOptions, b as ChunkingStrategy, k as VideoEmbeddingsResult, H as Hotspot, v as Shot, j as ToneType, g as StorageAdapter } from './shots-BMbViFbZ.js';
5
+ import { f as ScopedMuxAIOptions, I as ImageSubmissionMode, i as TokenUsage, M as MuxAIOptions, b as ChunkingStrategy, k as VideoEmbeddingsResult, H as Hotspot, v as Shot, j as ToneType, g as StorageAdapter } from './shots-CUI09Ohe.js';
6
6
 
7
7
  /**
8
8
  * Language Code Conversion Utilities
@@ -1416,7 +1416,10 @@ interface TranslationOptions<P extends SupportedProvider = SupportedProvider> ex
1416
1416
  interface TranslationChunkingOptions {
1417
1417
  /** Set to false to translate all cues in a single structured request. Defaults to true. */
1418
1418
  enabled?: boolean;
1419
- /** Prefer a single request until the asset is at least this long. Defaults to 30 minutes. */
1419
+ /**
1420
+ * Skip duration-based chunking until the asset is at least this long. Defaults to 30 minutes.
1421
+ * Shorter assets are still split by `maxCuesPerChunk` and `maxCueTextTokensPerChunk`.
1422
+ */
1420
1423
  minimumAssetDurationSeconds?: number;
1421
1424
  /** Soft target for chunk duration once chunking starts. Defaults to 30 minutes. */
1422
1425
  targetChunkDurationSeconds?: number;
@@ -1,4 +1,4 @@
1
- import { l as WorkflowCredentialsInput, n as WorkflowScope, A as AssetTextTrack, d as MuxAsset, T as TextChunk, b as ChunkingStrategy, q as CompletedShotsResult, r as ErroredShotsResult, H as Hotspot, s as HotspotOptions, t as HotspotResponse, u as PendingShotsResult, v as Shot, w as ShotRequestOptions, x as ShotsResult, y as WaitForShotsOptions, z as getHotspotsForAsset, B as getHotspotsForPlaybackId, D as getHotspotsForVideo, F as getShotsForAsset, G as requestShotsForAsset, J as waitForShotsForAsset } from './shots-BMbViFbZ.js';
1
+ import { l as WorkflowCredentialsInput, n as WorkflowScope, A as AssetTextTrack, d as MuxAsset, T as TextChunk, b as ChunkingStrategy, q as CompletedShotsResult, r as ErroredShotsResult, H as Hotspot, s as HotspotOptions, t as HotspotResponse, u as PendingShotsResult, v as Shot, w as ShotRequestOptions, x as ShotsResult, y as WaitForShotsOptions, z as getHotspotsForAsset, B as getHotspotsForPlaybackId, D as getHotspotsForVideo, F as getShotsForAsset, G as requestShotsForAsset, J as waitForShotsForAsset } from './shots-CUI09Ohe.js';
2
2
 
3
3
  interface HeatmapOptions {
4
4
  /** Time window for results, e.g., '7:days' (default: '7:days') */
package/dist/index.d.ts CHANGED
@@ -1,15 +1,15 @@
1
- export { I as ISO639_1, a as ISO639_3, L as LanguageCodePair, S as SupportedISO639_1, b as SupportedISO639_3, g as getLanguageCodePair, c as getLanguageName, i as isUndeterminedLanguageCode, d as isValidISO639_1, e as isValidISO639_3, t as toISO639_1, f as toISO639_3, h as workflows } from './index-B5l0yXZD.js';
2
- import { W as WorkflowCredentials, S as StoragePutObjectInput, a as StoragePresignGetObjectInput } from './shots-BMbViFbZ.js';
3
- export { A as AssetTextTrack, C as ChunkEmbedding, b as ChunkingStrategy, E as Encrypted, c as EncryptedPayload, I as ImageSubmissionMode, M as MuxAIOptions, d as MuxAsset, P as PlaybackAsset, e as PlaybackPolicy, f as ScopedMuxAIOptions, g as StorageAdapter, T as TextChunk, h as TokenChunkingConfig, i as TokenUsage, j as ToneType, U as UsageMetadata, V as VTTChunkingConfig, k as VideoEmbeddingsResult, l as WorkflowCredentialsInput, m as WorkflowMuxClient, n as WorkflowScope, o as decryptFromWorkflow, p as encryptForWorkflow } from './shots-BMbViFbZ.js';
1
+ export { I as ISO639_1, a as ISO639_3, L as LanguageCodePair, S as SupportedISO639_1, b as SupportedISO639_3, g as getLanguageCodePair, c as getLanguageName, i as isUndeterminedLanguageCode, d as isValidISO639_1, e as isValidISO639_3, t as toISO639_1, f as toISO639_3, h as workflows } from './index-C2FORyvQ.js';
2
+ import { W as WorkflowCredentials, S as StoragePutObjectInput, a as StoragePresignGetObjectInput } from './shots-CUI09Ohe.js';
3
+ export { A as AssetTextTrack, C as ChunkEmbedding, b as ChunkingStrategy, E as Encrypted, c as EncryptedPayload, I as ImageSubmissionMode, M as MuxAIOptions, d as MuxAsset, P as PlaybackAsset, e as PlaybackPolicy, f as ScopedMuxAIOptions, g as StorageAdapter, T as TextChunk, h as TokenChunkingConfig, i as TokenUsage, j as ToneType, U as UsageMetadata, V as VTTChunkingConfig, k as VideoEmbeddingsResult, l as WorkflowCredentialsInput, m as WorkflowMuxClient, n as WorkflowScope, o as decryptFromWorkflow, p as encryptForWorkflow } from './shots-CUI09Ohe.js';
4
4
  import { WORKFLOW_SERIALIZE, WORKFLOW_DESERIALIZE } from '@workflow/serde';
5
- export { i as primitives } from './index-SjpXUdXl.js';
5
+ export { i as primitives } from './index-C2Pk7bbF.js';
6
6
  import 'zod';
7
7
  import '@ai-sdk/anthropic';
8
8
  import '@ai-sdk/google';
9
9
  import '@ai-sdk/openai';
10
10
  import '@mux/mux-node';
11
11
 
12
- var version = "0.34.0";
12
+ var version = "0.36.0";
13
13
 
14
14
  type MuxAiErrorType = "validation_error" | "processing_error" | "timeout_error" | "content_policy_error";
15
15
  /**
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ var __export = (target, all) => {
5
5
  };
6
6
 
7
7
  // package.json
8
- var version = "0.34.0";
8
+ var version = "0.36.0";
9
9
 
10
10
  // src/lib/language-codes.ts
11
11
  var ISO639_1_TO_3 = {
@@ -2534,9 +2534,12 @@ function toPlaybackAsset(asset) {
2534
2534
  const { id: playbackId, policy } = getPlaybackId(asset);
2535
2535
  return { asset, playbackId, policy };
2536
2536
  }
2537
- async function getPlaybackIdForAsset(assetId, credentials) {
2537
+ async function getPlaybackIdForAsset(assetId, credentials, assetSnapshot) {
2538
2538
  "use step";
2539
- const asset = await getMuxAsset(assetId, credentials);
2539
+ const asset = assetSnapshot ?? await getMuxAsset(assetId, credentials);
2540
+ if (asset.id !== assetId) {
2541
+ throw new MuxAiError("Asset snapshot does not match the requested asset ID.", { type: "validation_error" });
2542
+ }
2540
2543
  return toPlaybackAsset(asset);
2541
2544
  }
2542
2545
  async function getMuxAsset(assetId, credentials) {
@@ -3157,6 +3160,22 @@ var CONTENT_POLICY_REASONS = /* @__PURE__ */ new Set([
3157
3160
  "SAFETY",
3158
3161
  "SPII"
3159
3162
  ]);
3163
+ var IncompleteGenerationError = class extends MuxAiError {
3164
+ constructor(finishReason, rawFinishReason, usage) {
3165
+ const reason = rawFinishReason ?? finishReason;
3166
+ const message = finishReason === "length" ? `The model reached its output limit before producing a complete response (finish reason: ${reason}).` : `The model stopped before producing a complete response (finish reason: ${reason}).`;
3167
+ super(message, {
3168
+ type: "processing_error",
3169
+ retryable: finishReason !== "length"
3170
+ });
3171
+ this.finishReason = finishReason;
3172
+ this.rawFinishReason = rawFinishReason;
3173
+ this.usage = usage;
3174
+ }
3175
+ };
3176
+ function isIncompleteGenerationError(error) {
3177
+ return MuxAiError.is(error) && typeof error.finishReason === "string";
3178
+ }
3160
3179
  async function withContentPolicyErrorHandling(operation) {
3161
3180
  try {
3162
3181
  return await operation();
@@ -3183,6 +3202,14 @@ function getGeneratedOutputWithContentPolicyHandling(response) {
3183
3202
  const reason = rawReason.success && isContentPolicyReason(rawReason.data) ? rawReason.data : "CONTENT_FILTER";
3184
3203
  throwContentPolicyError({ reason }, getErrorTokenUsage(response));
3185
3204
  }
3205
+ if (response.finishReason !== "stop") {
3206
+ const rawReason = PolicyTokenSchema.safeParse(response.rawFinishReason);
3207
+ throw new IncompleteGenerationError(
3208
+ response.finishReason,
3209
+ rawReason.success ? rawReason.data : void 0,
3210
+ getErrorTokenUsage(response)
3211
+ );
3212
+ }
3186
3213
  return response.output;
3187
3214
  }
3188
3215
  function throwContentPolicyError(block, usage) {
@@ -3966,7 +3993,7 @@ async function askQuestionsInternal(assetId, questions, options, collectedUsage)
3966
3993
  model,
3967
3994
  provider
3968
3995
  });
3969
- const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials);
3996
+ const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials, options?.assetSnapshot);
3970
3997
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(assetData);
3971
3998
  const isAudioOnly = isAudioOnlyAsset(assetData);
3972
3999
  const effectiveScope = hasWorkflowScopeBoundaries(scope) ? scope : void 0;
@@ -4320,7 +4347,7 @@ async function hasBurnedInCaptionsInternal(assetId, options, collectedUsage) {
4320
4347
  model,
4321
4348
  provider
4322
4349
  });
4323
- const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials);
4350
+ const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials, options.assetSnapshot);
4324
4351
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(assetData);
4325
4352
  const storyboardScope = resolveRenderableVideoScope(
4326
4353
  scope,
@@ -4585,7 +4612,7 @@ async function generateChaptersInternal(assetId, options, collectedUsage) {
4585
4612
  model,
4586
4613
  provider
4587
4614
  });
4588
- const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials);
4615
+ const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials, options.assetSnapshot);
4589
4616
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(assetData);
4590
4617
  const effectiveScope = hasWorkflowScopeBoundaries(scope) ? scope : void 0;
4591
4618
  const resolvedScope = effectiveScope ? resolveWorkflowScope(effectiveScope, assetDurationSeconds) : void 0;
@@ -5069,7 +5096,7 @@ async function editCaptionsInternal(assetId, trackId, options, collectedUsage) {
5069
5096
  { type: "validation_error" }
5070
5097
  );
5071
5098
  }
5072
- const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials);
5099
+ const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials, options.assetSnapshot);
5073
5100
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(assetData);
5074
5101
  const signingContext = await resolveMuxSigningContext(credentials);
5075
5102
  if (policy === "signed" && !signingContext) {
@@ -5265,7 +5292,7 @@ async function generateEmbeddingsInternal(assetId, options, collectedUsage) {
5265
5292
  scope
5266
5293
  } = options;
5267
5294
  const embeddingModel = resolveEmbeddingModelConfig({ ...options, provider, model });
5268
- const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials);
5295
+ const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials, options.assetSnapshot);
5269
5296
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(assetData);
5270
5297
  const effectiveScope = hasWorkflowScopeBoundaries(scope) ? scope : void 0;
5271
5298
  if (effectiveScope) {
@@ -5739,7 +5766,7 @@ async function generateEngagementInsightsInternal(assetId, options, collectedUsa
5739
5766
  model,
5740
5767
  provider
5741
5768
  });
5742
- const { asset, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials);
5769
+ const { asset, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials, options.assetSnapshot);
5743
5770
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(asset);
5744
5771
  if (!assetDurationSeconds) {
5745
5772
  throw new MuxAiError(`Asset ${assetId} has no valid duration.`, { type: "validation_error" });
@@ -6456,7 +6483,7 @@ async function getModerationScores(assetId, options = {}) {
6456
6483
  scope
6457
6484
  } = options;
6458
6485
  const credentials = providedCredentials;
6459
- const { asset, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials);
6486
+ const { asset, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials, options.assetSnapshot);
6460
6487
  const videoTrackDurationSeconds = getVideoTrackDurationSecondsFromAsset(asset);
6461
6488
  const videoTrackFps = getVideoTrackMaxFrameRateFromAsset(asset);
6462
6489
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(asset);
@@ -7070,7 +7097,7 @@ async function getSummaryAndTagsInternal(assetId, options, collectedUsage) {
7070
7097
  provider
7071
7098
  });
7072
7099
  const workflowCredentials = credentials;
7073
- const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, workflowCredentials);
7100
+ const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, workflowCredentials, options?.assetSnapshot);
7074
7101
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(assetData);
7075
7102
  const isAudioOnly = isAudioOnlyAsset(assetData);
7076
7103
  const effectiveScope = hasWorkflowScopeBoundaries(scope) ? scope : void 0;
@@ -7517,7 +7544,7 @@ async function translateAudio(assetId, toLanguageCode, options = {}) {
7517
7544
  if (uploadToS3 && (!s3Endpoint || !s3Bucket || !effectiveStorageAdapter && (!s3AccessKeyId || !s3SecretAccessKey))) {
7518
7545
  throw new MuxAiError("Storage configuration is required for uploading. Provide s3Endpoint and s3Bucket. If no storageAdapter is supplied, also provide s3AccessKeyId and s3SecretAccessKey in options or set S3_ENDPOINT, S3_BUCKET, S3_ACCESS_KEY_ID, and S3_SECRET_ACCESS_KEY environment variables.", { type: "validation_error" });
7519
7546
  }
7520
- const { asset: initialAsset, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials);
7547
+ const { asset: initialAsset, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials, options.assetSnapshot);
7521
7548
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(initialAsset);
7522
7549
  let currentAsset = initialAsset;
7523
7550
  let createdStaticRenditionId;
@@ -7709,6 +7736,7 @@ import {
7709
7736
  APICallError as APICallError3,
7710
7737
  generateText as generateText7,
7711
7738
  NoObjectGeneratedError as NoObjectGeneratedError2,
7739
+ NoOutputGeneratedError as NoOutputGeneratedError2,
7712
7740
  Output as Output7,
7713
7741
  RetryError as RetryError2,
7714
7742
  TypeValidationError
@@ -7872,7 +7900,7 @@ function shouldSplitChunkTranslationError(error) {
7872
7900
  if (isProviderServiceError(error)) {
7873
7901
  return false;
7874
7902
  }
7875
- return NoObjectGeneratedError2.isInstance(error) || TypeValidationError.isInstance(error) || isTranslationChunkValidationError(error);
7903
+ return NoObjectGeneratedError2.isInstance(error) || NoOutputGeneratedError2.isInstance(error) || TypeValidationError.isInstance(error) || isIncompleteGenerationError(error) || isTranslationChunkValidationError(error);
7876
7904
  }
7877
7905
  function resolveTranslationChunkingOptions(options) {
7878
7906
  const targetChunkDurationSeconds = Math.max(
@@ -7969,9 +7997,13 @@ function buildTranslationChunkRequests(vttContent, assetDurationSeconds, chunkin
7969
7997
  if (typeof assetDurationSeconds !== "number" || assetDurationSeconds < resolvedChunking.minimumAssetDurationSeconds) {
7970
7998
  return {
7971
7999
  preamble,
7972
- chunks: [
7973
- createTranslationChunkRequest("chunk-0", cues, cueBlocks)
7974
- ]
8000
+ chunks: splitTranslationChunkRequestByBudget(
8001
+ "chunk-0",
8002
+ cues,
8003
+ cueBlocks,
8004
+ resolvedChunking.maxCuesPerChunk,
8005
+ resolvedChunking.maxCueTextTokensPerChunk
8006
+ )
7975
8007
  };
7976
8008
  }
7977
8009
  const targetChunkDurationSeconds = resolvedChunking.targetChunkDurationSeconds;
@@ -8232,7 +8264,11 @@ async function translateChunkWithFallback({
8232
8264
  );
8233
8265
  return {
8234
8266
  translatedVtt: concatenateVttSegments([leftResult.translatedVtt, rightResult.translatedVtt]),
8235
- usage: aggregateTokenUsage([leftResult.usage, rightResult.usage]),
8267
+ usage: aggregateTokenUsage([
8268
+ ...failedAttemptUsage ? [failedAttemptUsage] : [],
8269
+ leftResult.usage,
8270
+ rightResult.usage
8271
+ ]),
8236
8272
  scrubbedCueCounts: mergeScrubbedCueCounts(
8237
8273
  leftResult.scrubbedCueCounts,
8238
8274
  rightResult.scrubbedCueCounts
@@ -8378,7 +8414,7 @@ async function translateCaptionsInternal(assetId, trackId, toLanguageCode, optio
8378
8414
  if (uploadToS3 && (!s3Endpoint || !s3Bucket || !effectiveStorageAdapter && (!s3AccessKeyId || !s3SecretAccessKey))) {
8379
8415
  throw new MuxAiError("Storage configuration is required for uploading. Provide s3Endpoint and s3Bucket. If no storageAdapter is supplied, also provide s3AccessKeyId and s3SecretAccessKey in options or set S3_ENDPOINT, S3_BUCKET, S3_ACCESS_KEY_ID, and S3_SECRET_ACCESS_KEY environment variables.", { type: "validation_error" });
8380
8416
  }
8381
- const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials);
8417
+ const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials, options.assetSnapshot);
8382
8418
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(assetData);
8383
8419
  const signingContext = await resolveMuxSigningContext(credentials);
8384
8420
  if (policy === "signed" && !signingContext) {