@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.
@@ -89,6 +89,12 @@ interface WorkflowMuxClient {
89
89
  interface MuxAIOptions {
90
90
  /** Optional timeout (ms) for helper utilities that support request limits. */
91
91
  timeout?: number;
92
+ /**
93
+ * Optional asset snapshot to reuse instead of retrieving the asset from Mux.
94
+ * The snapshot must belong to `assetId`; callers should capture it immediately
95
+ * before starting the workflow.
96
+ */
97
+ assetSnapshot?: MuxAsset;
92
98
  /**
93
99
  * Optional credentials for workflow execution.
94
100
  * Use encryptForWorkflow when running in Workflow Dev Kit environments.
@@ -1,7 +1,7 @@
1
- export { A as ASK_QUESTIONS_DEFAULT_MAX_ANSWER_OPTION_LENGTH, j as ASK_QUESTIONS_DEFAULT_MAX_FREE_FORM_ANSWER_LENGTH, k as ASK_QUESTIONS_MAX_QUESTION_LENGTH, l as AskQuestionsOptions, m as AskQuestionsResult, n as AskQuestionsType, o as AudioTranslationOptions, p as AudioTranslationResult, q as AutoCensorProfanityOptions, B as BurnedInCaptionsAnalysis, r as BurnedInCaptionsOptions, s as BurnedInCaptionsPromptOverrides, u as BurnedInCaptionsPromptSections, v as BurnedInCaptionsResult, C as CaptionReplacement, w as CensorMode, x as Chapter, y as ChapterSystemPromptSections, z as ChaptersOptions, D as ChaptersPromptOverrides, E as ChaptersPromptSections, F as ChaptersResult, G as ChaptersType, H as DEFAULT_DESCRIPTION_LENGTH, J as DEFAULT_SUMMARY_KEYWORD_LIMIT, K as DEFAULT_TITLE_LENGTH, M as EditCaptionsOptions, N as EditCaptionsResult, O as EmbeddingsOptions, P as EmbeddingsResult, Q as EngagementInsightsOptions, R as EngagementInsightsResult, T as GOOGLE_VISION_LIKELIHOOD_TO_SCORE, U as HIVE_SEXUAL_CATEGORIES, V as HIVE_VIOLENCE_CATEGORIES, W as HiveModerationOutput, X as HiveModerationSource, Y as ModerationOptions, Z as ModerationProvider, _ as ModerationResult, $ as MomentInsight, a0 as OverallInsight, a1 as ProfanityDetectionPayload, a2 as Question, a3 as QuestionAnswer, a4 as QuestionAnswerType, a5 as ReplacementRecord, a6 as StaticRenditionCleanupOutcome, a7 as SummarizationOptions, a8 as SummarizationPromptOverrides, a9 as SummarizationPromptSections, aa as SummaryAndTagsResult, ab as SummaryType, ac as ThumbnailModerationScore, ad as TranslationChunkingOptions, ae as TranslationOptions, af as TranslationPayload, ag as TranslationResult, ah as aggregateTokenUsage, ai as applyOverrideLists, aj as applyReplacements, ak as askQuestions, al as buildReplacementRegex, am as burnedInCaptionsSchema, an as censorVttContent, ao as chapterSchema, ap as chaptersSchema, aq as createReplacer, ar as editCaptions, as as extractTranscriptSegmentsForHotspots, at as generateChapters, au as generateEmbeddings, av as generateEngagementInsights, aw as generateVideoEmbeddings, ax as getModerationScores, ay as getSummaryAndTags, az as hasBurnedInCaptions, aA as mapShotsToHotspots, aB as normalizeTranslatedVtt, aC as profanityDetectionSchema, aD as questionAnswerSchema, aE as shouldSplitChunkTranslationError, aF as summarySchema, aG as transformCueText, aH as translateAudio, aI as translateCaptions, aJ as translationSchema, aK as validateNeverTranslateTerms, aL as verifyNeverTranslateTerms } from '../index-B5l0yXZD.js';
1
+ export { A as ASK_QUESTIONS_DEFAULT_MAX_ANSWER_OPTION_LENGTH, j as ASK_QUESTIONS_DEFAULT_MAX_FREE_FORM_ANSWER_LENGTH, k as ASK_QUESTIONS_MAX_QUESTION_LENGTH, l as AskQuestionsOptions, m as AskQuestionsResult, n as AskQuestionsType, o as AudioTranslationOptions, p as AudioTranslationResult, q as AutoCensorProfanityOptions, B as BurnedInCaptionsAnalysis, r as BurnedInCaptionsOptions, s as BurnedInCaptionsPromptOverrides, u as BurnedInCaptionsPromptSections, v as BurnedInCaptionsResult, C as CaptionReplacement, w as CensorMode, x as Chapter, y as ChapterSystemPromptSections, z as ChaptersOptions, D as ChaptersPromptOverrides, E as ChaptersPromptSections, F as ChaptersResult, G as ChaptersType, H as DEFAULT_DESCRIPTION_LENGTH, J as DEFAULT_SUMMARY_KEYWORD_LIMIT, K as DEFAULT_TITLE_LENGTH, M as EditCaptionsOptions, N as EditCaptionsResult, O as EmbeddingsOptions, P as EmbeddingsResult, Q as EngagementInsightsOptions, R as EngagementInsightsResult, T as GOOGLE_VISION_LIKELIHOOD_TO_SCORE, U as HIVE_SEXUAL_CATEGORIES, V as HIVE_VIOLENCE_CATEGORIES, W as HiveModerationOutput, X as HiveModerationSource, Y as ModerationOptions, Z as ModerationProvider, _ as ModerationResult, $ as MomentInsight, a0 as OverallInsight, a1 as ProfanityDetectionPayload, a2 as Question, a3 as QuestionAnswer, a4 as QuestionAnswerType, a5 as ReplacementRecord, a6 as StaticRenditionCleanupOutcome, a7 as SummarizationOptions, a8 as SummarizationPromptOverrides, a9 as SummarizationPromptSections, aa as SummaryAndTagsResult, ab as SummaryType, ac as ThumbnailModerationScore, ad as TranslationChunkingOptions, ae as TranslationOptions, af as TranslationPayload, ag as TranslationResult, ah as aggregateTokenUsage, ai as applyOverrideLists, aj as applyReplacements, ak as askQuestions, al as buildReplacementRegex, am as burnedInCaptionsSchema, an as censorVttContent, ao as chapterSchema, ap as chaptersSchema, aq as createReplacer, ar as editCaptions, as as extractTranscriptSegmentsForHotspots, at as generateChapters, au as generateEmbeddings, av as generateEngagementInsights, aw as generateVideoEmbeddings, ax as getModerationScores, ay as getSummaryAndTags, az as hasBurnedInCaptions, aA as mapShotsToHotspots, aB as normalizeTranslatedVtt, aC as profanityDetectionSchema, aD as questionAnswerSchema, aE as shouldSplitChunkTranslationError, aF as summarySchema, aG as transformCueText, aH as translateAudio, aI as translateCaptions, aJ as translationSchema, aK as validateNeverTranslateTerms, aL as verifyNeverTranslateTerms } from '../index-C2FORyvQ.js';
2
2
  import 'zod';
3
3
  import '@ai-sdk/anthropic';
4
4
  import '@ai-sdk/google';
5
5
  import '@ai-sdk/openai';
6
- import '../shots-BMbViFbZ.js';
6
+ import '../shots-CUI09Ohe.js';
7
7
  import '@mux/mux-node';
@@ -643,6 +643,22 @@ var CONTENT_POLICY_REASONS = /* @__PURE__ */ new Set([
643
643
  "SAFETY",
644
644
  "SPII"
645
645
  ]);
646
+ var IncompleteGenerationError = class extends MuxAiError {
647
+ constructor(finishReason, rawFinishReason, usage) {
648
+ const reason = rawFinishReason ?? finishReason;
649
+ 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}).`;
650
+ super(message, {
651
+ type: "processing_error",
652
+ retryable: finishReason !== "length"
653
+ });
654
+ this.finishReason = finishReason;
655
+ this.rawFinishReason = rawFinishReason;
656
+ this.usage = usage;
657
+ }
658
+ };
659
+ function isIncompleteGenerationError(error) {
660
+ return MuxAiError.is(error) && typeof error.finishReason === "string";
661
+ }
646
662
  async function withContentPolicyErrorHandling(operation) {
647
663
  try {
648
664
  return await operation();
@@ -669,6 +685,14 @@ function getGeneratedOutputWithContentPolicyHandling(response) {
669
685
  const reason = rawReason.success && isContentPolicyReason(rawReason.data) ? rawReason.data : "CONTENT_FILTER";
670
686
  throwContentPolicyError({ reason }, getErrorTokenUsage(response));
671
687
  }
688
+ if (response.finishReason !== "stop") {
689
+ const rawReason = PolicyTokenSchema.safeParse(response.rawFinishReason);
690
+ throw new IncompleteGenerationError(
691
+ response.finishReason,
692
+ rawReason.success ? rawReason.data : void 0,
693
+ getErrorTokenUsage(response)
694
+ );
695
+ }
672
696
  return response.output;
673
697
  }
674
698
  function throwContentPolicyError(block, usage) {
@@ -1611,9 +1635,12 @@ function toPlaybackAsset(asset) {
1611
1635
  const { id: playbackId, policy } = getPlaybackId(asset);
1612
1636
  return { asset, playbackId, policy };
1613
1637
  }
1614
- async function getPlaybackIdForAsset(assetId, credentials) {
1638
+ async function getPlaybackIdForAsset(assetId, credentials, assetSnapshot) {
1615
1639
  "use step";
1616
- const asset = await getMuxAsset(assetId, credentials);
1640
+ const asset = assetSnapshot ?? await getMuxAsset(assetId, credentials);
1641
+ if (asset.id !== assetId) {
1642
+ throw new MuxAiError("Asset snapshot does not match the requested asset ID.", { type: "validation_error" });
1643
+ }
1617
1644
  return toPlaybackAsset(asset);
1618
1645
  }
1619
1646
  async function getMuxAsset(assetId, credentials) {
@@ -2999,7 +3026,7 @@ async function askQuestionsInternal(assetId, questions, options, collectedUsage)
2999
3026
  model,
3000
3027
  provider
3001
3028
  });
3002
- const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials);
3029
+ const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials, options?.assetSnapshot);
3003
3030
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(assetData);
3004
3031
  const isAudioOnly = isAudioOnlyAsset(assetData);
3005
3032
  const effectiveScope = hasWorkflowScopeBoundaries(scope) ? scope : void 0;
@@ -3353,7 +3380,7 @@ async function hasBurnedInCaptionsInternal(assetId, options, collectedUsage) {
3353
3380
  model,
3354
3381
  provider
3355
3382
  });
3356
- const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials);
3383
+ const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials, options.assetSnapshot);
3357
3384
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(assetData);
3358
3385
  const storyboardScope = resolveRenderableVideoScope(
3359
3386
  scope,
@@ -3618,7 +3645,7 @@ async function generateChaptersInternal(assetId, options, collectedUsage) {
3618
3645
  model,
3619
3646
  provider
3620
3647
  });
3621
- const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials);
3648
+ const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials, options.assetSnapshot);
3622
3649
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(assetData);
3623
3650
  const effectiveScope = hasWorkflowScopeBoundaries(scope) ? scope : void 0;
3624
3651
  const resolvedScope = effectiveScope ? resolveWorkflowScope(effectiveScope, assetDurationSeconds) : void 0;
@@ -4314,7 +4341,7 @@ async function editCaptionsInternal(assetId, trackId, options, collectedUsage) {
4314
4341
  { type: "validation_error" }
4315
4342
  );
4316
4343
  }
4317
- const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials);
4344
+ const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials, options.assetSnapshot);
4318
4345
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(assetData);
4319
4346
  const signingContext = await resolveMuxSigningContext(credentials);
4320
4347
  if (policy === "signed" && !signingContext) {
@@ -4750,7 +4777,7 @@ async function generateEmbeddingsInternal(assetId, options, collectedUsage) {
4750
4777
  scope
4751
4778
  } = options;
4752
4779
  const embeddingModel = resolveEmbeddingModelConfig({ ...options, provider, model });
4753
- const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials);
4780
+ const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials, options.assetSnapshot);
4754
4781
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(assetData);
4755
4782
  const effectiveScope = hasWorkflowScopeBoundaries(scope) ? scope : void 0;
4756
4783
  if (effectiveScope) {
@@ -5370,7 +5397,7 @@ async function generateEngagementInsightsInternal(assetId, options, collectedUsa
5370
5397
  model,
5371
5398
  provider
5372
5399
  });
5373
- const { asset, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials);
5400
+ const { asset, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials, options.assetSnapshot);
5374
5401
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(asset);
5375
5402
  if (!assetDurationSeconds) {
5376
5403
  throw new MuxAiError(`Asset ${assetId} has no valid duration.`, { type: "validation_error" });
@@ -6128,7 +6155,7 @@ async function getModerationScores(assetId, options = {}) {
6128
6155
  scope
6129
6156
  } = options;
6130
6157
  const credentials = providedCredentials;
6131
- const { asset, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials);
6158
+ const { asset, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials, options.assetSnapshot);
6132
6159
  const videoTrackDurationSeconds = getVideoTrackDurationSecondsFromAsset(asset);
6133
6160
  const videoTrackFps = getVideoTrackMaxFrameRateFromAsset(asset);
6134
6161
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(asset);
@@ -6742,7 +6769,7 @@ async function getSummaryAndTagsInternal(assetId, options, collectedUsage) {
6742
6769
  provider
6743
6770
  });
6744
6771
  const workflowCredentials = credentials;
6745
- const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, workflowCredentials);
6772
+ const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, workflowCredentials, options?.assetSnapshot);
6746
6773
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(assetData);
6747
6774
  const isAudioOnly = isAudioOnlyAsset(assetData);
6748
6775
  const effectiveScope = hasWorkflowScopeBoundaries(scope) ? scope : void 0;
@@ -7189,7 +7216,7 @@ async function translateAudio(assetId, toLanguageCode, options = {}) {
7189
7216
  if (uploadToS3 && (!s3Endpoint || !s3Bucket || !effectiveStorageAdapter && (!s3AccessKeyId || !s3SecretAccessKey))) {
7190
7217
  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" });
7191
7218
  }
7192
- const { asset: initialAsset, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials);
7219
+ const { asset: initialAsset, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials, options.assetSnapshot);
7193
7220
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(initialAsset);
7194
7221
  let currentAsset = initialAsset;
7195
7222
  let createdStaticRenditionId;
@@ -7381,6 +7408,7 @@ import {
7381
7408
  APICallError as APICallError3,
7382
7409
  generateText as generateText7,
7383
7410
  NoObjectGeneratedError as NoObjectGeneratedError2,
7411
+ NoOutputGeneratedError as NoOutputGeneratedError2,
7384
7412
  Output as Output7,
7385
7413
  RetryError as RetryError2,
7386
7414
  TypeValidationError
@@ -7544,7 +7572,7 @@ function shouldSplitChunkTranslationError(error) {
7544
7572
  if (isProviderServiceError(error)) {
7545
7573
  return false;
7546
7574
  }
7547
- return NoObjectGeneratedError2.isInstance(error) || TypeValidationError.isInstance(error) || isTranslationChunkValidationError(error);
7575
+ return NoObjectGeneratedError2.isInstance(error) || NoOutputGeneratedError2.isInstance(error) || TypeValidationError.isInstance(error) || isIncompleteGenerationError(error) || isTranslationChunkValidationError(error);
7548
7576
  }
7549
7577
  function resolveTranslationChunkingOptions(options) {
7550
7578
  const targetChunkDurationSeconds = Math.max(
@@ -7641,9 +7669,13 @@ function buildTranslationChunkRequests(vttContent, assetDurationSeconds, chunkin
7641
7669
  if (typeof assetDurationSeconds !== "number" || assetDurationSeconds < resolvedChunking.minimumAssetDurationSeconds) {
7642
7670
  return {
7643
7671
  preamble,
7644
- chunks: [
7645
- createTranslationChunkRequest("chunk-0", cues, cueBlocks)
7646
- ]
7672
+ chunks: splitTranslationChunkRequestByBudget(
7673
+ "chunk-0",
7674
+ cues,
7675
+ cueBlocks,
7676
+ resolvedChunking.maxCuesPerChunk,
7677
+ resolvedChunking.maxCueTextTokensPerChunk
7678
+ )
7647
7679
  };
7648
7680
  }
7649
7681
  const targetChunkDurationSeconds = resolvedChunking.targetChunkDurationSeconds;
@@ -7904,7 +7936,11 @@ async function translateChunkWithFallback({
7904
7936
  );
7905
7937
  return {
7906
7938
  translatedVtt: concatenateVttSegments([leftResult.translatedVtt, rightResult.translatedVtt]),
7907
- usage: aggregateTokenUsage([leftResult.usage, rightResult.usage]),
7939
+ usage: aggregateTokenUsage([
7940
+ ...failedAttemptUsage ? [failedAttemptUsage] : [],
7941
+ leftResult.usage,
7942
+ rightResult.usage
7943
+ ]),
7908
7944
  scrubbedCueCounts: mergeScrubbedCueCounts(
7909
7945
  leftResult.scrubbedCueCounts,
7910
7946
  rightResult.scrubbedCueCounts
@@ -8050,7 +8086,7 @@ async function translateCaptionsInternal(assetId, trackId, toLanguageCode, optio
8050
8086
  if (uploadToS3 && (!s3Endpoint || !s3Bucket || !effectiveStorageAdapter && (!s3AccessKeyId || !s3SecretAccessKey))) {
8051
8087
  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" });
8052
8088
  }
8053
- const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials);
8089
+ const { asset: assetData, playbackId, policy } = await getPlaybackIdForAsset(assetId, credentials, options.assetSnapshot);
8054
8090
  const assetDurationSeconds = getAssetDurationSecondsFromAsset(assetData);
8055
8091
  const signingContext = await resolveMuxSigningContext(credentials);
8056
8092
  if (policy === "signed" && !signingContext) {