@mux/ai 0.29.0 → 0.30.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.
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.29.0";
8
+ var version = "0.30.0";
9
9
 
10
10
  // src/lib/language-codes.ts
11
11
  var ISO639_1_TO_3 = {
@@ -247,7 +247,7 @@ var EnvSchema = z.object({
247
247
  MUX_TEST_ASSET_ID_VIOLENT_AUDIO_ONLY: optionalString("Mux test asset ID for audio-only assets with violent content.", "Mux test asset id for audio-only assets with violent content for testing"),
248
248
  // Eval config
249
249
  MUX_AI_EVAL_MODEL_SET: optionalString("Eval model selection mode.", "Choose between 'default' (provider defaults only) or 'all' (all configured models)"),
250
- MUX_AI_EVAL_MODELS: optionalString("Comma-separated eval model pairs.", "Comma-separated provider:model pairs (e.g. 'openai:gpt-5.1,anthropic:claude-sonnet-4-5,google:gemini-3-flash-preview')"),
250
+ MUX_AI_EVAL_MODELS: optionalString("Comma-separated eval model pairs.", "Comma-separated provider:model pairs (e.g. 'openai:gpt-5.6-luna,anthropic:claude-sonnet-4-5,google:gemini-3-flash-preview')"),
251
251
  // AI Providers
252
252
  OPENAI_API_KEY: optionalString("OpenAI API key for OpenAI-backed workflows.", "OpenAI API key"),
253
253
  ANTHROPIC_API_KEY: optionalString("Anthropic API key for Claude-backed workflows.", "Anthropic API key"),
@@ -566,7 +566,8 @@ var TOKEN_USAGE_FIELDS = [
566
566
  "outputTokens",
567
567
  "totalTokens",
568
568
  "reasoningTokens",
569
- "cachedInputTokens"
569
+ "cachedInputTokens",
570
+ "cacheWriteTokens"
570
571
  ];
571
572
  function isDefinedTokenUsageValue(value) {
572
573
  return typeof value === "number";
@@ -608,6 +609,12 @@ function getErrorTokenUsage(error) {
608
609
  extracted.cachedInputTokens = cacheReadTokens;
609
610
  }
610
611
  }
612
+ if (extracted.cacheWriteTokens === void 0) {
613
+ const cacheWriteTokens = source.inputTokenDetails?.cacheWriteTokens;
614
+ if (typeof cacheWriteTokens === "number") {
615
+ extracted.cacheWriteTokens = cacheWriteTokens;
616
+ }
617
+ }
611
618
  return Object.keys(extracted).length > 0 ? extracted : void 0;
612
619
  }
613
620
  function rethrowWithTokenUsage(error, collectedUsage) {
@@ -633,6 +640,9 @@ var MuxAiError = class extends Error {
633
640
  this.publicMessage = message;
634
641
  this.retryable = opts?.retryable ?? false;
635
642
  }
643
+ static is(value) {
644
+ return typeof value === "object" && value !== null && "__robots_error" in value && value.__robots_error === true;
645
+ }
636
646
  };
637
647
  function extractErrorDetail(error) {
638
648
  if (error instanceof Error && error.message) {
@@ -650,7 +660,7 @@ function extractErrorDetail(error) {
650
660
  return "Unknown error";
651
661
  }
652
662
  function wrapError(error, message) {
653
- if (error instanceof MuxAiError) {
663
+ if (MuxAiError.is(error)) {
654
664
  throw error;
655
665
  }
656
666
  const rawDetail = extractErrorDetail(error);
@@ -1401,7 +1411,8 @@ import { createAnthropic } from "@ai-sdk/anthropic";
1401
1411
  import { createGoogleGenerativeAI } from "@ai-sdk/google";
1402
1412
  import { createOpenAI } from "@ai-sdk/openai";
1403
1413
  var DEFAULT_LANGUAGE_MODELS = {
1404
- openai: "gpt-5.1",
1414
+ // GPT-5.6 models default to medium reasoning when no effort is specified.
1415
+ openai: "gpt-5.6-luna",
1405
1416
  anthropic: "claude-sonnet-4-5",
1406
1417
  google: "gemini-3-flash-preview"
1407
1418
  };
@@ -1410,11 +1421,20 @@ var DEFAULT_EMBEDDING_MODELS = {
1410
1421
  google: "gemini-embedding-001"
1411
1422
  };
1412
1423
  var LANGUAGE_MODELS = {
1413
- openai: ["gpt-5.1", "gpt-5-mini"],
1424
+ openai: ["gpt-5.6-luna", "gpt-5.1", "gpt-5-mini"],
1414
1425
  anthropic: ["claude-sonnet-4-5"],
1415
1426
  google: ["gemini-3-flash-preview", "gemini-3.1-flash-lite", "gemini-2.5-flash"]
1416
1427
  };
1417
1428
  var LANGUAGE_MODEL_DEPRECATIONS = [
1429
+ {
1430
+ provider: "openai",
1431
+ modelId: "gpt-5.1",
1432
+ replacementModelId: "gpt-5.6-luna",
1433
+ phase: "warn",
1434
+ deprecatedOn: "2026-08-01",
1435
+ sunsetOn: "2026-10-01",
1436
+ reason: "GPT-5.6 Luna with its default medium reasoning effort is the new OpenAI default."
1437
+ },
1418
1438
  {
1419
1439
  provider: "google",
1420
1440
  modelId: "gemini-2.5-flash",
@@ -1475,7 +1495,7 @@ function parseEvalModelPair(value) {
1475
1495
  const modelId = modelIdRaw?.trim();
1476
1496
  if (!provider || !modelId) {
1477
1497
  throw new Error(
1478
- `Invalid eval model pair "${value}". Use "provider:model" (example: "openai:gpt-5.1").`
1498
+ `Invalid eval model pair "${value}". Use "provider:model" (example: "openai:gpt-5.6-luna").`
1479
1499
  );
1480
1500
  }
1481
1501
  if (!isSupportedProvider(provider)) {
@@ -2765,6 +2785,9 @@ async function fetchTranscriptForAsset(asset, playbackId, options = {}) {
2765
2785
  // src/workflows/index.ts
2766
2786
  var workflows_exports = {};
2767
2787
  __export(workflows_exports, {
2788
+ ASK_QUESTIONS_DEFAULT_MAX_ANSWER_OPTION_LENGTH: () => ASK_QUESTIONS_DEFAULT_MAX_ANSWER_OPTION_LENGTH,
2789
+ ASK_QUESTIONS_DEFAULT_MAX_FREE_FORM_ANSWER_LENGTH: () => ASK_QUESTIONS_DEFAULT_MAX_FREE_FORM_ANSWER_LENGTH,
2790
+ ASK_QUESTIONS_MAX_QUESTION_LENGTH: () => ASK_QUESTIONS_MAX_QUESTION_LENGTH,
2768
2791
  DEFAULT_DESCRIPTION_LENGTH: () => DEFAULT_DESCRIPTION_LENGTH,
2769
2792
  DEFAULT_SUMMARY_KEYWORD_LIMIT: () => DEFAULT_SUMMARY_KEYWORD_LIMIT,
2770
2793
  DEFAULT_TITLE_LENGTH: () => DEFAULT_TITLE_LENGTH,
@@ -2805,7 +2828,156 @@ __export(workflows_exports, {
2805
2828
  // src/workflows/ask-questions.ts
2806
2829
  import { generateText, Output } from "ai";
2807
2830
  import dedent2 from "dedent";
2831
+ import { z as z3 } from "zod";
2832
+
2833
+ // src/lib/content-policy-error.ts
2834
+ import { APICallError, NoObjectGeneratedError, RetryError } from "ai";
2808
2835
  import { z as z2 } from "zod";
2836
+ var PolicyTokenSchema = z2.string().trim().min(1).max(64).regex(/^[A-Z0-9_]+$/);
2837
+ var SafetyRatingSchema = z2.object({
2838
+ category: PolicyTokenSchema.nullish(),
2839
+ blocked: z2.boolean().nullish()
2840
+ });
2841
+ var ContentPolicyResponseSchema = z2.object({
2842
+ promptFeedback: z2.object({
2843
+ blockReason: PolicyTokenSchema.nullish(),
2844
+ safetyRatings: z2.array(SafetyRatingSchema).max(32).nullish()
2845
+ }).nullish(),
2846
+ candidates: z2.array(z2.object({
2847
+ finishReason: PolicyTokenSchema.nullish(),
2848
+ safetyRatings: z2.array(SafetyRatingSchema).max(32).nullish()
2849
+ })).max(8).nullish()
2850
+ });
2851
+ var ContentPolicyUsageResponseSchema = z2.object({
2852
+ usageMetadata: z2.object({
2853
+ promptTokenCount: z2.number().finite().nonnegative().nullish(),
2854
+ candidatesTokenCount: z2.number().finite().nonnegative().nullish(),
2855
+ totalTokenCount: z2.number().finite().nonnegative().nullish(),
2856
+ cachedContentTokenCount: z2.number().finite().nonnegative().nullish(),
2857
+ thoughtsTokenCount: z2.number().finite().nonnegative().nullish()
2858
+ }).nullish()
2859
+ });
2860
+ var CONTENT_POLICY_REASONS = /* @__PURE__ */ new Set([
2861
+ "BLOCKLIST",
2862
+ "ESCALATION",
2863
+ "IMAGE_PROHIBITED_CONTENT",
2864
+ "IMAGE_RECITATION",
2865
+ "IMAGE_SAFETY",
2866
+ "JAILBREAK",
2867
+ "MODEL_ARMOR",
2868
+ "PROHIBITED_CONTENT",
2869
+ "RECITATION",
2870
+ "SAFETY",
2871
+ "SPII"
2872
+ ]);
2873
+ async function withContentPolicyErrorHandling(operation) {
2874
+ try {
2875
+ return await operation();
2876
+ } catch (error) {
2877
+ rethrowContentPolicyError(error);
2878
+ }
2879
+ }
2880
+ function rethrowContentPolicyError(error) {
2881
+ const block = extractContentPolicyBlock(error);
2882
+ if (!block) {
2883
+ throw error;
2884
+ }
2885
+ throwContentPolicyError(block, getContentPolicyTokenUsage(error));
2886
+ }
2887
+ function getGeneratedOutputWithContentPolicyHandling(response) {
2888
+ if (response.finishReason === "content-filter") {
2889
+ const rawReason = PolicyTokenSchema.safeParse(response.rawFinishReason);
2890
+ const reason = rawReason.success && isContentPolicyReason(rawReason.data) ? rawReason.data : "CONTENT_FILTER";
2891
+ throwContentPolicyError({ reason }, getErrorTokenUsage(response));
2892
+ }
2893
+ return response.output;
2894
+ }
2895
+ function throwContentPolicyError(block, usage) {
2896
+ const category = block.category ? `; category: ${block.category}` : "";
2897
+ const contentPolicyError = new MuxAiError(
2898
+ `The supplied content was blocked by a content policy (reason: ${block.reason}${category}).`,
2899
+ {
2900
+ type: "content_policy_error",
2901
+ retryable: false
2902
+ }
2903
+ );
2904
+ if (usage) {
2905
+ contentPolicyError.usage = usage;
2906
+ }
2907
+ throw contentPolicyError;
2908
+ }
2909
+ function extractContentPolicyBlock(error) {
2910
+ if (RetryError.isInstance(error)) {
2911
+ return extractContentPolicyBlock(error.lastError);
2912
+ }
2913
+ if (NoObjectGeneratedError.isInstance(error) && error.finishReason === "content-filter") {
2914
+ return { reason: "CONTENT_FILTER" };
2915
+ }
2916
+ if (!APICallError.isInstance(error) || !error.responseBody) {
2917
+ return void 0;
2918
+ }
2919
+ try {
2920
+ const parsed = ContentPolicyResponseSchema.safeParse(JSON.parse(error.responseBody));
2921
+ if (!parsed.success) {
2922
+ return void 0;
2923
+ }
2924
+ const promptReason = parsed.data.promptFeedback?.blockReason;
2925
+ if (isContentPolicyReason(promptReason)) {
2926
+ return {
2927
+ reason: promptReason,
2928
+ category: findBlockedCategory(parsed.data.promptFeedback?.safetyRatings)
2929
+ };
2930
+ }
2931
+ for (const candidate of parsed.data.candidates ?? []) {
2932
+ if (isContentPolicyReason(candidate.finishReason)) {
2933
+ return {
2934
+ reason: candidate.finishReason,
2935
+ category: findBlockedCategory(candidate.safetyRatings)
2936
+ };
2937
+ }
2938
+ }
2939
+ } catch {
2940
+ return void 0;
2941
+ }
2942
+ return void 0;
2943
+ }
2944
+ function isContentPolicyReason(reason) {
2945
+ return Boolean(reason && CONTENT_POLICY_REASONS.has(reason));
2946
+ }
2947
+ function getContentPolicyTokenUsage(error) {
2948
+ const errorUsage = getErrorTokenUsage(error);
2949
+ if (errorUsage) {
2950
+ return errorUsage;
2951
+ }
2952
+ if (RetryError.isInstance(error)) {
2953
+ return getContentPolicyTokenUsage(error.lastError);
2954
+ }
2955
+ if (!APICallError.isInstance(error) || !error.responseBody) {
2956
+ return void 0;
2957
+ }
2958
+ try {
2959
+ const parsed = ContentPolicyUsageResponseSchema.safeParse(JSON.parse(error.responseBody));
2960
+ const usage = parsed.success ? parsed.data.usageMetadata : void 0;
2961
+ if (!usage) {
2962
+ return void 0;
2963
+ }
2964
+ const inputTokens = usage.promptTokenCount ?? 0;
2965
+ const reasoningTokens = usage.thoughtsTokenCount ?? 0;
2966
+ const outputTokens = (usage.candidatesTokenCount ?? 0) + reasoningTokens;
2967
+ return {
2968
+ inputTokens,
2969
+ outputTokens,
2970
+ totalTokens: usage.totalTokenCount ?? inputTokens + outputTokens,
2971
+ reasoningTokens,
2972
+ cachedInputTokens: usage.cachedContentTokenCount ?? 0
2973
+ };
2974
+ } catch {
2975
+ return void 0;
2976
+ }
2977
+ }
2978
+ function findBlockedCategory(ratings) {
2979
+ return ratings?.find((rating) => rating.blocked === true)?.category ?? void 0;
2980
+ }
2809
2981
 
2810
2982
  // src/lib/image-download.ts
2811
2983
  import pRetry, { AbortError } from "p-retry";
@@ -3019,33 +3191,37 @@ async function withRetry(fn, {
3019
3191
  try {
3020
3192
  return await fn();
3021
3193
  } catch (error) {
3022
- lastError = error instanceof Error ? error : new Error(String(error));
3194
+ lastError = error;
3195
+ const retryError = error instanceof Error ? error : new Error(String(error));
3023
3196
  const isLastAttempt = attempt === maxRetries;
3024
- if (isLastAttempt || !shouldRetry(lastError, attempt + 1)) {
3025
- throw lastError;
3197
+ if (isLastAttempt || !shouldRetry(retryError, attempt + 1)) {
3198
+ throw error;
3026
3199
  }
3027
3200
  const delay = calculateDelay(attempt + 1, baseDelay, maxDelay);
3028
3201
  console.warn(
3029
- `Attempt ${attempt + 1} failed: ${lastError.message}. Retrying in ${Math.round(delay)}ms...`
3202
+ `Attempt ${attempt + 1} failed: ${retryError.message}. Retrying in ${Math.round(delay)}ms...`
3030
3203
  );
3031
3204
  await new Promise((resolve) => setTimeout(resolve, delay));
3032
3205
  }
3033
3206
  }
3034
- throw lastError || new Error("Retry failed with unknown error");
3207
+ throw lastError ?? new Error("Retry failed with unknown error");
3035
3208
  }
3036
3209
 
3037
3210
  // src/workflows/ask-questions.ts
3038
- var questionAnswerSchema = z2.object({
3039
- question: z2.string().describe("The full text of the original question"),
3040
- answer: z2.string().nullable(),
3041
- confidence: z2.number(),
3042
- reasoning: z2.string().max(1e3),
3043
- skipped: z2.boolean()
3211
+ var ASK_QUESTIONS_MAX_QUESTION_LENGTH = 600;
3212
+ var ASK_QUESTIONS_DEFAULT_MAX_ANSWER_OPTION_LENGTH = 150;
3213
+ var ASK_QUESTIONS_DEFAULT_MAX_FREE_FORM_ANSWER_LENGTH = 500;
3214
+ var questionAnswerSchema = z3.object({
3215
+ question: z3.string().describe("The full text of the original question"),
3216
+ answer: z3.string().nullable(),
3217
+ confidence: z3.number(),
3218
+ reasoning: z3.string().max(1e3),
3219
+ skipped: z3.boolean()
3044
3220
  });
3045
3221
  var SKIP_SENTINEL = "__SKIPPED__";
3046
3222
  function createAskQuestionsSchema(answerSchema) {
3047
- return z2.object({
3048
- answers: z2.array(
3223
+ return z3.object({
3224
+ answers: z3.array(
3049
3225
  questionAnswerSchema.extend({
3050
3226
  answer: answerSchema
3051
3227
  })
@@ -3395,12 +3571,12 @@ function buildResponseSchemaForQuestions(normalizedQuestions, maxFreeFormAnswerL
3395
3571
  SKIP_SENTINEL.length,
3396
3572
  longestConstrained
3397
3573
  );
3398
- return createAskQuestionsSchema(z2.string().min(1).max(schemaMax));
3574
+ return createAskQuestionsSchema(z3.string().min(1).max(schemaMax));
3399
3575
  }
3400
3576
  const allowed = Array.from(
3401
3577
  new Set(normalizedQuestions.flatMap(allowedAnswersForQuestion))
3402
3578
  );
3403
- return createAskQuestionsSchema(z2.enum([...allowed, SKIP_SENTINEL]));
3579
+ return createAskQuestionsSchema(z3.enum([...allowed, SKIP_SENTINEL]));
3404
3580
  }
3405
3581
  async function analyzeQuestions({
3406
3582
  provider,
@@ -3418,7 +3594,7 @@ async function analyzeQuestions({
3418
3594
  normalizedQuestions,
3419
3595
  maxFreeFormAnswerLength
3420
3596
  );
3421
- const response = await generateText({
3597
+ const response = await withContentPolicyErrorHandling(() => generateText({
3422
3598
  model,
3423
3599
  output: Output.object({ schema: responseSchema }),
3424
3600
  experimental_telemetry: { isEnabled: true },
@@ -3435,11 +3611,12 @@ async function analyzeQuestions({
3435
3611
  ] : userPrompt
3436
3612
  }
3437
3613
  ]
3438
- });
3439
- if (!response.output) {
3614
+ }));
3615
+ const output = getGeneratedOutputWithContentPolicyHandling(response);
3616
+ if (!output) {
3440
3617
  throw new Error("Ask-questions output missing");
3441
3618
  }
3442
- const parsed = responseSchema.parse(response.output);
3619
+ const parsed = responseSchema.parse(output);
3443
3620
  const unexpectedRootKeys = detectUnexpectedKeysFromRawText(
3444
3621
  response.text,
3445
3622
  responseSchema.keyof().options
@@ -3461,7 +3638,8 @@ async function analyzeQuestions({
3461
3638
  outputTokens: response.usage.outputTokens,
3462
3639
  totalTokens: response.usage.totalTokens,
3463
3640
  reasoningTokens: response.usage.reasoningTokens,
3464
- cachedInputTokens: response.usage.cachedInputTokens
3641
+ cachedInputTokens: response.usage.cachedInputTokens,
3642
+ cacheWriteTokens: response.usage.inputTokenDetails?.cacheWriteTokens
3465
3643
  },
3466
3644
  unexpectedRootKeys,
3467
3645
  unexpectedAnswerKeys
@@ -3480,7 +3658,6 @@ async function askQuestionsInternal(assetId, questions, options, collectedUsage)
3480
3658
  if (!questions || questions.length === 0) {
3481
3659
  throw new MuxAiError("At least one question must be provided.", { type: "validation_error" });
3482
3660
  }
3483
- const MAX_QUESTION_LENGTH = 500;
3484
3661
  questions.forEach((q, idx) => {
3485
3662
  if (!q.question || typeof q.question !== "string" || !q.question.trim()) {
3486
3663
  throw new MuxAiError(
@@ -3488,15 +3665,14 @@ async function askQuestionsInternal(assetId, questions, options, collectedUsage)
3488
3665
  { type: "validation_error" }
3489
3666
  );
3490
3667
  }
3491
- if (q.question.length > MAX_QUESTION_LENGTH) {
3668
+ if (q.question.length > ASK_QUESTIONS_MAX_QUESTION_LENGTH) {
3492
3669
  throw new MuxAiError(
3493
- `Question at index ${idx} exceeds the ${MAX_QUESTION_LENGTH}-character limit (received ${q.question.length}).`,
3670
+ `Question at index ${idx} exceeds the ${ASK_QUESTIONS_MAX_QUESTION_LENGTH}-character limit (received ${q.question.length}).`,
3494
3671
  { type: "validation_error" }
3495
3672
  );
3496
3673
  }
3497
3674
  });
3498
- const DEFAULT_MAX_ANSWER_OPTION_LENGTH = 150;
3499
- const maxAnswerOptionLength = options?.maxAnswerOptionLength ?? DEFAULT_MAX_ANSWER_OPTION_LENGTH;
3675
+ const maxAnswerOptionLength = options?.maxAnswerOptionLength ?? ASK_QUESTIONS_DEFAULT_MAX_ANSWER_OPTION_LENGTH;
3500
3676
  if (!Number.isFinite(maxAnswerOptionLength) || maxAnswerOptionLength <= 0) {
3501
3677
  throw new MuxAiError(
3502
3678
  `maxAnswerOptionLength must be a positive number (received ${maxAnswerOptionLength}).`,
@@ -3515,8 +3691,7 @@ async function askQuestionsInternal(assetId, questions, options, collectedUsage)
3515
3691
  }
3516
3692
  }
3517
3693
  });
3518
- const DEFAULT_MAX_FREE_FORM_ANSWER_LENGTH = 500;
3519
- const maxFreeFormAnswerLength = options?.maxFreeFormAnswerLength ?? DEFAULT_MAX_FREE_FORM_ANSWER_LENGTH;
3694
+ const maxFreeFormAnswerLength = options?.maxFreeFormAnswerLength ?? ASK_QUESTIONS_DEFAULT_MAX_FREE_FORM_ANSWER_LENGTH;
3520
3695
  if (!Number.isFinite(maxFreeFormAnswerLength) || maxFreeFormAnswerLength <= 0) {
3521
3696
  throw new MuxAiError(
3522
3697
  `maxFreeFormAnswerLength must be a positive number (received ${maxFreeFormAnswerLength}).`,
@@ -3718,11 +3893,11 @@ async function askQuestionsInternal(assetId, questions, options, collectedUsage)
3718
3893
  // src/workflows/burned-in-captions.ts
3719
3894
  import { generateText as generateText2, Output as Output2 } from "ai";
3720
3895
  import dedent3 from "dedent";
3721
- import { z as z3 } from "zod";
3722
- var burnedInCaptionsSchema = z3.object({
3723
- hasBurnedInCaptions: z3.boolean(),
3724
- confidence: z3.number(),
3725
- detectedLanguage: z3.string().max(100).nullable()
3896
+ import { z as z4 } from "zod";
3897
+ var burnedInCaptionsSchema = z4.object({
3898
+ hasBurnedInCaptions: z4.boolean(),
3899
+ confidence: z4.number(),
3900
+ detectedLanguage: z4.string().max(100).nullable()
3726
3901
  });
3727
3902
  var SYSTEM_PROMPT2 = promptDedent`
3728
3903
  <role>
@@ -3832,7 +4007,7 @@ async function analyzeStoryboard({
3832
4007
  }) {
3833
4008
  "use step";
3834
4009
  const model = await createLanguageModelFromConfig(provider, modelId, credentials);
3835
- const response = await generateText2({
4010
+ const response = await withContentPolicyErrorHandling(() => generateText2({
3836
4011
  model,
3837
4012
  output: Output2.object({ schema: burnedInCaptionsSchema }),
3838
4013
  experimental_telemetry: { isEnabled: true },
@@ -3849,22 +4024,24 @@ async function analyzeStoryboard({
3849
4024
  ]
3850
4025
  }
3851
4026
  ]
3852
- });
4027
+ }));
4028
+ const output = getGeneratedOutputWithContentPolicyHandling(response);
3853
4029
  const unexpectedKeys = detectUnexpectedKeysFromRawText(
3854
4030
  response.text,
3855
4031
  burnedInCaptionsSchema.keyof().options
3856
4032
  );
3857
4033
  return {
3858
4034
  result: {
3859
- ...response.output,
3860
- confidence: Math.min(1, Math.max(0, response.output.confidence))
4035
+ ...output,
4036
+ confidence: Math.min(1, Math.max(0, output.confidence))
3861
4037
  },
3862
4038
  usage: {
3863
4039
  inputTokens: response.usage.inputTokens,
3864
4040
  outputTokens: response.usage.outputTokens,
3865
4041
  totalTokens: response.usage.totalTokens,
3866
4042
  reasoningTokens: response.usage.reasoningTokens,
3867
- cachedInputTokens: response.usage.cachedInputTokens
4043
+ cachedInputTokens: response.usage.cachedInputTokens,
4044
+ cacheWriteTokens: response.usage.inputTokenDetails?.cacheWriteTokens
3868
4045
  },
3869
4046
  unexpectedKeys
3870
4047
  };
@@ -3962,13 +4139,13 @@ async function hasBurnedInCaptionsInternal(assetId, options, collectedUsage) {
3962
4139
  // src/workflows/chapters.ts
3963
4140
  import { generateText as generateText3, Output as Output3 } from "ai";
3964
4141
  import dedent4 from "dedent";
3965
- import { z as z4 } from "zod";
3966
- var chapterSchema = z4.object({
3967
- startTime: z4.number(),
3968
- title: z4.string().max(300)
4142
+ import { z as z5 } from "zod";
4143
+ var chapterSchema = z5.object({
4144
+ startTime: z5.number(),
4145
+ title: z5.string().max(300)
3969
4146
  });
3970
- var chaptersSchema = z4.object({
3971
- chapters: z4.array(chapterSchema)
4147
+ var chaptersSchema = z5.object({
4148
+ chapters: z5.array(chapterSchema)
3972
4149
  });
3973
4150
  async function generateChaptersWithAI({
3974
4151
  provider,
@@ -3980,21 +4157,24 @@ async function generateChaptersWithAI({
3980
4157
  "use step";
3981
4158
  const model = await createLanguageModelFromConfig(provider, modelId, credentials);
3982
4159
  const response = await withRetry(
3983
- () => generateText3({
3984
- model,
3985
- output: Output3.object({ schema: chaptersSchema }),
3986
- messages: [
3987
- {
3988
- role: "system",
3989
- content: systemPrompt
3990
- },
3991
- {
3992
- role: "user",
3993
- content: userPrompt
3994
- }
3995
- ]
3996
- })
4160
+ () => withContentPolicyErrorHandling(
4161
+ () => generateText3({
4162
+ model,
4163
+ output: Output3.object({ schema: chaptersSchema }),
4164
+ messages: [
4165
+ {
4166
+ role: "system",
4167
+ content: systemPrompt
4168
+ },
4169
+ {
4170
+ role: "user",
4171
+ content: userPrompt
4172
+ }
4173
+ ]
4174
+ })
4175
+ )
3997
4176
  );
4177
+ const output = getGeneratedOutputWithContentPolicyHandling(response);
3998
4178
  const unexpectedRootKeys = detectUnexpectedKeysFromRawText(
3999
4179
  response.text,
4000
4180
  chaptersSchema.keyof().options
@@ -4010,13 +4190,14 @@ async function generateChaptersWithAI({
4010
4190
  } catch {
4011
4191
  }
4012
4192
  return {
4013
- chapters: response.output,
4193
+ chapters: output,
4014
4194
  usage: {
4015
4195
  inputTokens: response.usage.inputTokens,
4016
4196
  outputTokens: response.usage.outputTokens,
4017
4197
  totalTokens: response.usage.totalTokens,
4018
4198
  reasoningTokens: response.usage.reasoningTokens,
4019
- cachedInputTokens: response.usage.cachedInputTokens
4199
+ cachedInputTokens: response.usage.cachedInputTokens,
4200
+ cacheWriteTokens: response.usage.inputTokenDetails?.cacheWriteTokens
4020
4201
  },
4021
4202
  unexpectedRootKeys,
4022
4203
  unexpectedChapterKeys
@@ -4272,7 +4453,7 @@ async function generateChaptersInternal(assetId, options, collectedUsage) {
4272
4453
 
4273
4454
  // src/workflows/edit-captions.ts
4274
4455
  import { generateText as generateText4, Output as Output4 } from "ai";
4275
- import { z as z5 } from "zod";
4456
+ import { z as z6 } from "zod";
4276
4457
 
4277
4458
  // src/lib/mux-tracks.ts
4278
4459
  async function fetchVttFromMux(vttUrl) {
@@ -4343,8 +4524,8 @@ async function createPresignedGetUrlWithStorageAdapter(input, adapter) {
4343
4524
  }
4344
4525
 
4345
4526
  // src/workflows/edit-captions.ts
4346
- var profanityDetectionSchema = z5.object({
4347
- profanity: z5.array(z5.string().max(100)).describe(
4527
+ var profanityDetectionSchema = z6.object({
4528
+ profanity: z6.array(z6.string().max(100)).describe(
4348
4529
  "Unique profane words or short phrases exactly as they appear in the transcript text. Include each distinct form only once (e.g., if 'fuck' and 'fucking' both appear, list both)."
4349
4530
  )
4350
4531
  });
@@ -4521,7 +4702,7 @@ async function identifyProfanityWithAI({
4521
4702
  tag: "transcript",
4522
4703
  content: plainText
4523
4704
  });
4524
- const response = await generateText4({
4705
+ const response = await withContentPolicyErrorHandling(() => generateText4({
4525
4706
  model,
4526
4707
  output: Output4.object({ schema: profanityDetectionSchema }),
4527
4708
  messages: [
@@ -4536,19 +4717,21 @@ async function identifyProfanityWithAI({
4536
4717
  ${transcriptSection}`
4537
4718
  }
4538
4719
  ]
4539
- });
4720
+ }));
4721
+ const output = getGeneratedOutputWithContentPolicyHandling(response);
4540
4722
  const unexpectedKeys = detectUnexpectedKeysFromRawText(
4541
4723
  response.text,
4542
4724
  profanityDetectionSchema.keyof().options
4543
4725
  );
4544
4726
  return {
4545
- profanity: response.output.profanity,
4727
+ profanity: output.profanity,
4546
4728
  usage: {
4547
4729
  inputTokens: response.usage.inputTokens,
4548
4730
  outputTokens: response.usage.outputTokens,
4549
4731
  totalTokens: response.usage.totalTokens,
4550
4732
  reasoningTokens: response.usage.reasoningTokens,
4551
- cachedInputTokens: response.usage.cachedInputTokens
4733
+ cachedInputTokens: response.usage.cachedInputTokens,
4734
+ cacheWriteTokens: response.usage.inputTokenDetails?.cacheWriteTokens
4552
4735
  },
4553
4736
  unexpectedKeys
4554
4737
  };
@@ -4951,21 +5134,21 @@ async function generateVideoEmbeddings(assetId, options = {}) {
4951
5134
  // src/workflows/engagement-insights.ts
4952
5135
  import { generateText as generateText5, Output as Output5 } from "ai";
4953
5136
  import dedent5 from "dedent";
4954
- import { z as z6 } from "zod";
4955
- var aiMomentInsightSchema = z6.object({
4956
- hotspotIndex: z6.number(),
4957
- startMs: z6.number(),
4958
- endMs: z6.number(),
4959
- timestamp: z6.string(),
4960
- engagementScore: z6.number(),
4961
- insight: z6.string().max(1e3)
5137
+ import { z as z7 } from "zod";
5138
+ var aiMomentInsightSchema = z7.object({
5139
+ hotspotIndex: z7.number(),
5140
+ startMs: z7.number(),
5141
+ endMs: z7.number(),
5142
+ timestamp: z7.string(),
5143
+ engagementScore: z7.number(),
5144
+ insight: z7.string().max(1e3)
4962
5145
  });
4963
- var aiOverallInsightSchema = z6.object({
4964
- summary: z6.string().max(2e3),
4965
- trends: z6.array(z6.string().max(500))
5146
+ var aiOverallInsightSchema = z7.object({
5147
+ summary: z7.string().max(2e3),
5148
+ trends: z7.array(z7.string().max(500))
4966
5149
  });
4967
- var engagementInsightsSchema = z6.object({
4968
- momentInsights: z6.array(aiMomentInsightSchema),
5150
+ var engagementInsightsSchema = z7.object({
5151
+ momentInsights: z7.array(aiMomentInsightSchema),
4969
5152
  overallInsight: aiOverallInsightSchema
4970
5153
  });
4971
5154
  var SYSTEM_PROMPT4 = promptDedent`
@@ -5227,26 +5410,29 @@ async function generateInsightsWithAI(provider, modelId, systemPrompt, userPromp
5227
5410
  "use step";
5228
5411
  const model = await createLanguageModelFromConfig(provider, modelId, credentials);
5229
5412
  const response = await withRetry(
5230
- () => generateText5({
5231
- model,
5232
- output: Output5.object({ schema: engagementInsightsSchema }),
5233
- experimental_telemetry: { isEnabled: true },
5234
- messages: [
5235
- {
5236
- role: "system",
5237
- content: systemPrompt
5238
- },
5239
- {
5240
- role: "user",
5241
- content: [
5242
- { type: "text", text: userPrompt },
5243
- ...imageUrls.map((url) => ({ type: "image", image: url }))
5244
- ]
5245
- }
5246
- ]
5247
- })
5413
+ () => withContentPolicyErrorHandling(
5414
+ () => generateText5({
5415
+ model,
5416
+ output: Output5.object({ schema: engagementInsightsSchema }),
5417
+ experimental_telemetry: { isEnabled: true },
5418
+ messages: [
5419
+ {
5420
+ role: "system",
5421
+ content: systemPrompt
5422
+ },
5423
+ {
5424
+ role: "user",
5425
+ content: [
5426
+ { type: "text", text: userPrompt },
5427
+ ...imageUrls.map((url) => ({ type: "image", image: url }))
5428
+ ]
5429
+ }
5430
+ ]
5431
+ })
5432
+ )
5248
5433
  );
5249
- if (!response.output) {
5434
+ const output = getGeneratedOutputWithContentPolicyHandling(response);
5435
+ if (!output) {
5250
5436
  throw new Error("AI returned empty or unparseable response");
5251
5437
  }
5252
5438
  const unexpectedRootKeys = detectUnexpectedKeysFromRawText(
@@ -5269,13 +5455,14 @@ async function generateInsightsWithAI(provider, modelId, systemPrompt, userPromp
5269
5455
  } catch {
5270
5456
  }
5271
5457
  return {
5272
- result: response.output,
5458
+ result: output,
5273
5459
  usage: {
5274
5460
  inputTokens: response.usage.inputTokens,
5275
5461
  outputTokens: response.usage.outputTokens,
5276
5462
  totalTokens: response.usage.totalTokens,
5277
5463
  reasoningTokens: response.usage.reasoningTokens,
5278
- cachedInputTokens: response.usage.cachedInputTokens
5464
+ cachedInputTokens: response.usage.cachedInputTokens,
5465
+ cacheWriteTokens: response.usage.inputTokenDetails?.cacheWriteTokens
5279
5466
  },
5280
5467
  unexpectedRootKeys,
5281
5468
  unexpectedMomentKeys,
@@ -6189,7 +6376,7 @@ async function getModerationScores(assetId, options = {}) {
6189
6376
  // src/workflows/summarization.ts
6190
6377
  import { generateText as generateText6, Output as Output6 } from "ai";
6191
6378
  import dedent6 from "dedent";
6192
- import { z as z7 } from "zod";
6379
+ import { z as z8 } from "zod";
6193
6380
 
6194
6381
  // src/lib/markdown-normalization.ts
6195
6382
  var ESCAPED_LINE_BREAK_REGEX = /\\r\\n|\\n|\\r/g;
@@ -6202,17 +6389,17 @@ function normalizeMarkdownDescription(description) {
6202
6389
  var DEFAULT_SUMMARY_KEYWORD_LIMIT = 10;
6203
6390
  var DEFAULT_TITLE_LENGTH = 10;
6204
6391
  var DEFAULT_DESCRIPTION_LENGTH = 50;
6205
- var summarySchema = z7.object({
6206
- keywords: z7.array(z7.string().max(200)),
6207
- title: z7.string().max(500),
6208
- description: z7.string().max(1e4)
6392
+ var summarySchema = z8.object({
6393
+ keywords: z8.array(z8.string().max(200)),
6394
+ title: z8.string().max(500),
6395
+ description: z8.string().max(1e4)
6209
6396
  });
6210
6397
  function buildSummarySchema(descriptionLength) {
6211
6398
  const descriptionMaxChars = Math.max(2e3, descriptionLength * 15);
6212
- return z7.object({
6213
- keywords: z7.array(z7.string().max(200)),
6214
- title: z7.string().max(500),
6215
- description: z7.string().max(descriptionMaxChars)
6399
+ return z8.object({
6400
+ keywords: z8.array(z8.string().max(200)),
6401
+ title: z8.string().max(500),
6402
+ description: z8.string().max(descriptionMaxChars)
6216
6403
  });
6217
6404
  }
6218
6405
  var VALID_TONES = ["neutral", "playful", "professional"];
@@ -6488,7 +6675,7 @@ async function analyzeStoryboard2(imageDataUrl, provider, modelId, userPrompt, s
6488
6675
  "use step";
6489
6676
  const model = await createLanguageModelFromConfig(provider, modelId, credentials);
6490
6677
  const schema = buildSummarySchema(descriptionLength);
6491
- const response = await generateText6({
6678
+ const response = await withContentPolicyErrorHandling(() => generateText6({
6492
6679
  model,
6493
6680
  output: Output6.object({
6494
6681
  name: "summary_metadata",
@@ -6508,11 +6695,12 @@ async function analyzeStoryboard2(imageDataUrl, provider, modelId, userPrompt, s
6508
6695
  ]
6509
6696
  }
6510
6697
  ]
6511
- });
6512
- if (!response.output) {
6698
+ }));
6699
+ const output = getGeneratedOutputWithContentPolicyHandling(response);
6700
+ if (!output) {
6513
6701
  throw new Error("Summarization output missing");
6514
6702
  }
6515
- const parsed = schema.parse(response.output);
6703
+ const parsed = schema.parse(output);
6516
6704
  const unexpectedKeys = detectUnexpectedKeysFromRawText(
6517
6705
  response.text,
6518
6706
  schema.keyof().options
@@ -6524,7 +6712,8 @@ async function analyzeStoryboard2(imageDataUrl, provider, modelId, userPrompt, s
6524
6712
  outputTokens: response.usage.outputTokens,
6525
6713
  totalTokens: response.usage.totalTokens,
6526
6714
  reasoningTokens: response.usage.reasoningTokens,
6527
- cachedInputTokens: response.usage.cachedInputTokens
6715
+ cachedInputTokens: response.usage.cachedInputTokens,
6716
+ cacheWriteTokens: response.usage.inputTokenDetails?.cacheWriteTokens
6528
6717
  },
6529
6718
  unexpectedKeys
6530
6719
  };
@@ -6533,7 +6722,7 @@ async function analyzeAudioOnly(provider, modelId, userPrompt, systemPrompt, des
6533
6722
  "use step";
6534
6723
  const model = await createLanguageModelFromConfig(provider, modelId, credentials);
6535
6724
  const schema = buildSummarySchema(descriptionLength);
6536
- const response = await generateText6({
6725
+ const response = await withContentPolicyErrorHandling(() => generateText6({
6537
6726
  model,
6538
6727
  output: Output6.object({
6539
6728
  name: "summary_metadata",
@@ -6550,11 +6739,12 @@ async function analyzeAudioOnly(provider, modelId, userPrompt, systemPrompt, des
6550
6739
  content: userPrompt
6551
6740
  }
6552
6741
  ]
6553
- });
6554
- if (!response.output) {
6742
+ }));
6743
+ const output = getGeneratedOutputWithContentPolicyHandling(response);
6744
+ if (!output) {
6555
6745
  throw new Error("Summarization output missing");
6556
6746
  }
6557
- const parsed = schema.parse(response.output);
6747
+ const parsed = schema.parse(output);
6558
6748
  const unexpectedKeys = detectUnexpectedKeysFromRawText(
6559
6749
  response.text,
6560
6750
  schema.keyof().options
@@ -6566,7 +6756,8 @@ async function analyzeAudioOnly(provider, modelId, userPrompt, systemPrompt, des
6566
6756
  outputTokens: response.usage.outputTokens,
6567
6757
  totalTokens: response.usage.totalTokens,
6568
6758
  reasoningTokens: response.usage.reasoningTokens,
6569
- cachedInputTokens: response.usage.cachedInputTokens
6759
+ cachedInputTokens: response.usage.cachedInputTokens,
6760
+ cacheWriteTokens: response.usage.inputTokenDetails?.cacheWriteTokens
6570
6761
  },
6571
6762
  unexpectedKeys
6572
6763
  };
@@ -7137,16 +7328,16 @@ async function translateAudio(assetId, toLanguageCode, options = {}) {
7137
7328
 
7138
7329
  // src/workflows/translate-captions.ts
7139
7330
  import {
7140
- APICallError,
7331
+ APICallError as APICallError2,
7141
7332
  generateText as generateText7,
7142
- NoObjectGeneratedError,
7333
+ NoObjectGeneratedError as NoObjectGeneratedError2,
7143
7334
  Output as Output7,
7144
- RetryError,
7335
+ RetryError as RetryError2,
7145
7336
  TypeValidationError
7146
7337
  } from "ai";
7147
- import { z as z8 } from "zod";
7148
- var translationSchema = z8.object({
7149
- translation: z8.string()
7338
+ import { z as z9 } from "zod";
7339
+ var translationSchema = z9.object({
7340
+ translation: z9.string()
7150
7341
  });
7151
7342
  var SYSTEM_PROMPT6 = promptDedent`
7152
7343
  You are a subtitle translation expert. Translate VTT subtitle files to the target language specified by the user.
@@ -7213,10 +7404,10 @@ function isProviderServiceError(error) {
7213
7404
  if (!error) {
7214
7405
  return false;
7215
7406
  }
7216
- if (RetryError.isInstance(error)) {
7407
+ if (RetryError2.isInstance(error)) {
7217
7408
  return isProviderServiceError(error.lastError);
7218
7409
  }
7219
- if (APICallError.isInstance(error)) {
7410
+ if (APICallError2.isInstance(error)) {
7220
7411
  return true;
7221
7412
  }
7222
7413
  if (error instanceof Error && "cause" in error) {
@@ -7228,7 +7419,7 @@ function shouldSplitChunkTranslationError(error) {
7228
7419
  if (isProviderServiceError(error)) {
7229
7420
  return false;
7230
7421
  }
7231
- return NoObjectGeneratedError.isInstance(error) || TypeValidationError.isInstance(error) || isTranslationChunkValidationError(error);
7422
+ return NoObjectGeneratedError2.isInstance(error) || TypeValidationError.isInstance(error) || isTranslationChunkValidationError(error);
7232
7423
  }
7233
7424
  function resolveTranslationChunkingOptions(options) {
7234
7425
  const targetChunkDurationSeconds = Math.max(
@@ -7389,7 +7580,7 @@ async function translateVttWithAI({
7389
7580
  "use step";
7390
7581
  const model = await createLanguageModelFromConfig(provider, modelId, credentials);
7391
7582
  const sanitisedVttContent = stripVttMetadataBlocks(vttContent);
7392
- const response = await generateText7({
7583
+ const response = await withContentPolicyErrorHandling(() => generateText7({
7393
7584
  model,
7394
7585
  output: Output7.object({ schema: translationSchema }),
7395
7586
  messages: [
@@ -7404,8 +7595,9 @@ async function translateVttWithAI({
7404
7595
  ${sanitisedVttContent}`
7405
7596
  }
7406
7597
  ]
7407
- });
7408
- const translated = normalizeTranslatedVtt(response.output.translation);
7598
+ }));
7599
+ const output = getGeneratedOutputWithContentPolicyHandling(response);
7600
+ const translated = normalizeTranslatedVtt(output.translation);
7409
7601
  const leakReason = detectLeakReason(translated);
7410
7602
  const safeTranslated = leakReason !== null ? vttContent : translated;
7411
7603
  if (leakReason !== null) {
@@ -7430,7 +7622,8 @@ ${sanitisedVttContent}`
7430
7622
  outputTokens: response.usage.outputTokens,
7431
7623
  totalTokens: response.usage.totalTokens,
7432
7624
  reasoningTokens: response.usage.reasoningTokens,
7433
- cachedInputTokens: response.usage.cachedInputTokens
7625
+ cachedInputTokens: response.usage.cachedInputTokens,
7626
+ cacheWriteTokens: response.usage.inputTokenDetails?.cacheWriteTokens
7434
7627
  }
7435
7628
  };
7436
7629
  }
@@ -7444,8 +7637,8 @@ async function translateCueChunkWithAI({
7444
7637
  }) {
7445
7638
  "use step";
7446
7639
  const model = await createLanguageModelFromConfig(provider, modelId, credentials);
7447
- const schema = z8.object({
7448
- translations: z8.array(z8.string().min(1).max(2e3)).length(cues.length)
7640
+ const schema = z9.object({
7641
+ translations: z9.array(z9.string().min(1).max(2e3)).length(cues.length)
7449
7642
  });
7450
7643
  const cuePayload = cues.map((cue, index) => ({
7451
7644
  index,
@@ -7453,7 +7646,7 @@ async function translateCueChunkWithAI({
7453
7646
  endTime: cue.endTime,
7454
7647
  text: cue.text
7455
7648
  }));
7456
- const response = await generateText7({
7649
+ const response = await withContentPolicyErrorHandling(() => generateText7({
7457
7650
  model,
7458
7651
  output: Output7.object({ schema }),
7459
7652
  messages: [
@@ -7469,7 +7662,8 @@ Return exactly ${cues.length} translated cues in the same order as the input.
7469
7662
  ${JSON.stringify(cuePayload, null, 2)}`
7470
7663
  }
7471
7664
  ]
7472
- });
7665
+ }));
7666
+ const output = getGeneratedOutputWithContentPolicyHandling(response);
7473
7667
  const unexpectedKeys = detectUnexpectedKeysFromRawText(
7474
7668
  response.text,
7475
7669
  schema.keyof().options
@@ -7480,13 +7674,14 @@ ${JSON.stringify(cuePayload, null, 2)}`
7480
7674
  );
7481
7675
  }
7482
7676
  return {
7483
- translations: response.output.translations,
7677
+ translations: output.translations,
7484
7678
  usage: {
7485
7679
  inputTokens: response.usage.inputTokens,
7486
7680
  outputTokens: response.usage.outputTokens,
7487
7681
  totalTokens: response.usage.totalTokens,
7488
7682
  reasoningTokens: response.usage.reasoningTokens,
7489
- cachedInputTokens: response.usage.cachedInputTokens
7683
+ cachedInputTokens: response.usage.cachedInputTokens,
7684
+ cacheWriteTokens: response.usage.inputTokenDetails?.cacheWriteTokens
7490
7685
  },
7491
7686
  unexpectedKeyCount: unexpectedKeys.length
7492
7687
  };