@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.
@@ -1,114 +1,11 @@
1
1
  // src/workflows/ask-questions.ts
2
2
  import { generateText, Output } from "ai";
3
3
  import dedent2 from "dedent";
4
- import { z as z2 } from "zod";
4
+ import { z as z3 } from "zod";
5
5
 
6
- // src/lib/image-download.ts
7
- import pRetry, { AbortError } from "p-retry";
8
- var BASE64_CHUNK_SIZE = 32768;
9
- function bytesToBase64(bytes) {
10
- if (bytes.length === 0) {
11
- return "";
12
- }
13
- let binary = "";
14
- for (let i = 0; i < bytes.length; i += BASE64_CHUNK_SIZE) {
15
- const chunk = bytes.subarray(i, i + BASE64_CHUNK_SIZE);
16
- binary += String.fromCharCode(...chunk);
17
- }
18
- if (typeof globalThis.btoa !== "function") {
19
- throw new TypeError("Base64 encoder is not available in this environment.");
20
- }
21
- return globalThis.btoa(binary);
22
- }
23
- var DEFAULT_OPTIONS = {
24
- timeout: 1e4,
25
- retries: 3,
26
- retryDelay: 1e3,
27
- maxRetryDelay: 1e4,
28
- exponentialBackoff: true
29
- };
30
- async function downloadImageAsBase64(url, options = {}) {
31
- "use step";
32
- const opts = { ...DEFAULT_OPTIONS, ...options };
33
- let attemptCount = 0;
34
- return pRetry(
35
- async () => {
36
- attemptCount++;
37
- const controller = new AbortController();
38
- const timeoutId = setTimeout(() => controller.abort(), opts.timeout);
39
- try {
40
- const response = await fetch(url, {
41
- signal: controller.signal,
42
- headers: {
43
- "User-Agent": "@mux/ai image downloader"
44
- }
45
- });
46
- clearTimeout(timeoutId);
47
- if (!response.ok) {
48
- if (response.status >= 400 && response.status < 500 && response.status !== 429) {
49
- throw new AbortError(`HTTP ${response.status}: ${response.statusText}`);
50
- }
51
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
52
- }
53
- const contentType = response.headers.get("content-type");
54
- if (!contentType?.startsWith("image/")) {
55
- throw new AbortError(`Invalid content type: ${contentType}. Expected image/*`);
56
- }
57
- const arrayBuffer = await response.arrayBuffer();
58
- const buffer = new Uint8Array(arrayBuffer);
59
- if (buffer.length === 0) {
60
- throw new AbortError("Downloaded image is empty");
61
- }
62
- const base64Data = `data:${contentType};base64,${bytesToBase64(buffer)}`;
63
- return {
64
- base64Data,
65
- buffer,
66
- url,
67
- contentType,
68
- sizeBytes: buffer.length,
69
- attempts: attemptCount
70
- };
71
- } catch (error) {
72
- clearTimeout(timeoutId);
73
- if (error instanceof AbortError) {
74
- throw error;
75
- }
76
- if (error instanceof Error) {
77
- if (error.name === "AbortError") {
78
- throw new Error(`Request timeout after ${opts.timeout}ms`);
79
- }
80
- throw new Error(`Download failed: ${error.message}`);
81
- }
82
- throw new Error("Unknown download error");
83
- }
84
- },
85
- {
86
- retries: opts.retries,
87
- minTimeout: opts.retryDelay,
88
- maxTimeout: opts.maxRetryDelay,
89
- factor: opts.exponentialBackoff ? 2 : 1,
90
- randomize: true,
91
- // Add jitter to prevent thundering herd
92
- onFailedAttempt: (error) => {
93
- console.warn(`Image download attempt ${error.attemptNumber} failed for ${url}`);
94
- if (error.retriesLeft > 0) {
95
- console.warn(`Retrying... (${error.retriesLeft} attempts left)`);
96
- }
97
- }
98
- }
99
- );
100
- }
101
- async function downloadImagesAsBase64(urls, options = {}, maxConcurrent = 5) {
102
- "use step";
103
- const results = [];
104
- for (let i = 0; i < urls.length; i += maxConcurrent) {
105
- const batch = urls.slice(i, i + maxConcurrent);
106
- const batchPromises = batch.map((url) => downloadImageAsBase64(url, options));
107
- const batchResults = await Promise.all(batchPromises);
108
- results.push(...batchResults);
109
- }
110
- return results;
111
- }
6
+ // src/lib/content-policy-error.ts
7
+ import { APICallError, NoObjectGeneratedError, RetryError } from "ai";
8
+ import { z as z2 } from "zod";
112
9
 
113
10
  // src/lib/prompt-fragments.ts
114
11
  import dedent from "dedent";
@@ -179,7 +76,7 @@ var EnvSchema = z.object({
179
76
  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"),
180
77
  // Eval config
181
78
  MUX_AI_EVAL_MODEL_SET: optionalString("Eval model selection mode.", "Choose between 'default' (provider defaults only) or 'all' (all configured models)"),
182
- 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')"),
79
+ 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')"),
183
80
  // AI Providers
184
81
  OPENAI_API_KEY: optionalString("OpenAI API key for OpenAI-backed workflows.", "OpenAI API key"),
185
82
  ANTHROPIC_API_KEY: optionalString("Anthropic API key for Claude-backed workflows.", "Anthropic API key"),
@@ -498,7 +395,8 @@ var TOKEN_USAGE_FIELDS = [
498
395
  "outputTokens",
499
396
  "totalTokens",
500
397
  "reasoningTokens",
501
- "cachedInputTokens"
398
+ "cachedInputTokens",
399
+ "cacheWriteTokens"
502
400
  ];
503
401
  function isDefinedTokenUsageValue(value) {
504
402
  return typeof value === "number";
@@ -540,6 +438,12 @@ function getErrorTokenUsage(error) {
540
438
  extracted.cachedInputTokens = cacheReadTokens;
541
439
  }
542
440
  }
441
+ if (extracted.cacheWriteTokens === void 0) {
442
+ const cacheWriteTokens = source.inputTokenDetails?.cacheWriteTokens;
443
+ if (typeof cacheWriteTokens === "number") {
444
+ extracted.cacheWriteTokens = cacheWriteTokens;
445
+ }
446
+ }
543
447
  return Object.keys(extracted).length > 0 ? extracted : void 0;
544
448
  }
545
449
  function rethrowWithTokenUsage(error, collectedUsage) {
@@ -565,6 +469,9 @@ var MuxAiError = class extends Error {
565
469
  this.publicMessage = message;
566
470
  this.retryable = opts?.retryable ?? false;
567
471
  }
472
+ static is(value) {
473
+ return typeof value === "object" && value !== null && "__robots_error" in value && value.__robots_error === true;
474
+ }
568
475
  };
569
476
  function extractErrorDetail(error) {
570
477
  if (error instanceof Error && error.message) {
@@ -582,7 +489,7 @@ function extractErrorDetail(error) {
582
489
  return "Unknown error";
583
490
  }
584
491
  function wrapError(error, message) {
585
- if (error instanceof MuxAiError) {
492
+ if (MuxAiError.is(error)) {
586
493
  throw error;
587
494
  }
588
495
  const rawDetail = extractErrorDetail(error);
@@ -600,6 +507,260 @@ function wrapError(error, message) {
600
507
  throw wrapped;
601
508
  }
602
509
 
510
+ // src/lib/content-policy-error.ts
511
+ var PolicyTokenSchema = z2.string().trim().min(1).max(64).regex(/^[A-Z0-9_]+$/);
512
+ var SafetyRatingSchema = z2.object({
513
+ category: PolicyTokenSchema.nullish(),
514
+ blocked: z2.boolean().nullish()
515
+ });
516
+ var ContentPolicyResponseSchema = z2.object({
517
+ promptFeedback: z2.object({
518
+ blockReason: PolicyTokenSchema.nullish(),
519
+ safetyRatings: z2.array(SafetyRatingSchema).max(32).nullish()
520
+ }).nullish(),
521
+ candidates: z2.array(z2.object({
522
+ finishReason: PolicyTokenSchema.nullish(),
523
+ safetyRatings: z2.array(SafetyRatingSchema).max(32).nullish()
524
+ })).max(8).nullish()
525
+ });
526
+ var ContentPolicyUsageResponseSchema = z2.object({
527
+ usageMetadata: z2.object({
528
+ promptTokenCount: z2.number().finite().nonnegative().nullish(),
529
+ candidatesTokenCount: z2.number().finite().nonnegative().nullish(),
530
+ totalTokenCount: z2.number().finite().nonnegative().nullish(),
531
+ cachedContentTokenCount: z2.number().finite().nonnegative().nullish(),
532
+ thoughtsTokenCount: z2.number().finite().nonnegative().nullish()
533
+ }).nullish()
534
+ });
535
+ var CONTENT_POLICY_REASONS = /* @__PURE__ */ new Set([
536
+ "BLOCKLIST",
537
+ "ESCALATION",
538
+ "IMAGE_PROHIBITED_CONTENT",
539
+ "IMAGE_RECITATION",
540
+ "IMAGE_SAFETY",
541
+ "JAILBREAK",
542
+ "MODEL_ARMOR",
543
+ "PROHIBITED_CONTENT",
544
+ "RECITATION",
545
+ "SAFETY",
546
+ "SPII"
547
+ ]);
548
+ async function withContentPolicyErrorHandling(operation) {
549
+ try {
550
+ return await operation();
551
+ } catch (error) {
552
+ rethrowContentPolicyError(error);
553
+ }
554
+ }
555
+ function rethrowContentPolicyError(error) {
556
+ const block = extractContentPolicyBlock(error);
557
+ if (!block) {
558
+ throw error;
559
+ }
560
+ throwContentPolicyError(block, getContentPolicyTokenUsage(error));
561
+ }
562
+ function getGeneratedOutputWithContentPolicyHandling(response) {
563
+ if (response.finishReason === "content-filter") {
564
+ const rawReason = PolicyTokenSchema.safeParse(response.rawFinishReason);
565
+ const reason = rawReason.success && isContentPolicyReason(rawReason.data) ? rawReason.data : "CONTENT_FILTER";
566
+ throwContentPolicyError({ reason }, getErrorTokenUsage(response));
567
+ }
568
+ return response.output;
569
+ }
570
+ function throwContentPolicyError(block, usage) {
571
+ const category = block.category ? `; category: ${block.category}` : "";
572
+ const contentPolicyError = new MuxAiError(
573
+ `The supplied content was blocked by a content policy (reason: ${block.reason}${category}).`,
574
+ {
575
+ type: "content_policy_error",
576
+ retryable: false
577
+ }
578
+ );
579
+ if (usage) {
580
+ contentPolicyError.usage = usage;
581
+ }
582
+ throw contentPolicyError;
583
+ }
584
+ function extractContentPolicyBlock(error) {
585
+ if (RetryError.isInstance(error)) {
586
+ return extractContentPolicyBlock(error.lastError);
587
+ }
588
+ if (NoObjectGeneratedError.isInstance(error) && error.finishReason === "content-filter") {
589
+ return { reason: "CONTENT_FILTER" };
590
+ }
591
+ if (!APICallError.isInstance(error) || !error.responseBody) {
592
+ return void 0;
593
+ }
594
+ try {
595
+ const parsed = ContentPolicyResponseSchema.safeParse(JSON.parse(error.responseBody));
596
+ if (!parsed.success) {
597
+ return void 0;
598
+ }
599
+ const promptReason = parsed.data.promptFeedback?.blockReason;
600
+ if (isContentPolicyReason(promptReason)) {
601
+ return {
602
+ reason: promptReason,
603
+ category: findBlockedCategory(parsed.data.promptFeedback?.safetyRatings)
604
+ };
605
+ }
606
+ for (const candidate of parsed.data.candidates ?? []) {
607
+ if (isContentPolicyReason(candidate.finishReason)) {
608
+ return {
609
+ reason: candidate.finishReason,
610
+ category: findBlockedCategory(candidate.safetyRatings)
611
+ };
612
+ }
613
+ }
614
+ } catch {
615
+ return void 0;
616
+ }
617
+ return void 0;
618
+ }
619
+ function isContentPolicyReason(reason) {
620
+ return Boolean(reason && CONTENT_POLICY_REASONS.has(reason));
621
+ }
622
+ function getContentPolicyTokenUsage(error) {
623
+ const errorUsage = getErrorTokenUsage(error);
624
+ if (errorUsage) {
625
+ return errorUsage;
626
+ }
627
+ if (RetryError.isInstance(error)) {
628
+ return getContentPolicyTokenUsage(error.lastError);
629
+ }
630
+ if (!APICallError.isInstance(error) || !error.responseBody) {
631
+ return void 0;
632
+ }
633
+ try {
634
+ const parsed = ContentPolicyUsageResponseSchema.safeParse(JSON.parse(error.responseBody));
635
+ const usage = parsed.success ? parsed.data.usageMetadata : void 0;
636
+ if (!usage) {
637
+ return void 0;
638
+ }
639
+ const inputTokens = usage.promptTokenCount ?? 0;
640
+ const reasoningTokens = usage.thoughtsTokenCount ?? 0;
641
+ const outputTokens = (usage.candidatesTokenCount ?? 0) + reasoningTokens;
642
+ return {
643
+ inputTokens,
644
+ outputTokens,
645
+ totalTokens: usage.totalTokenCount ?? inputTokens + outputTokens,
646
+ reasoningTokens,
647
+ cachedInputTokens: usage.cachedContentTokenCount ?? 0
648
+ };
649
+ } catch {
650
+ return void 0;
651
+ }
652
+ }
653
+ function findBlockedCategory(ratings) {
654
+ return ratings?.find((rating) => rating.blocked === true)?.category ?? void 0;
655
+ }
656
+
657
+ // src/lib/image-download.ts
658
+ import pRetry, { AbortError } from "p-retry";
659
+ var BASE64_CHUNK_SIZE = 32768;
660
+ function bytesToBase64(bytes) {
661
+ if (bytes.length === 0) {
662
+ return "";
663
+ }
664
+ let binary = "";
665
+ for (let i = 0; i < bytes.length; i += BASE64_CHUNK_SIZE) {
666
+ const chunk = bytes.subarray(i, i + BASE64_CHUNK_SIZE);
667
+ binary += String.fromCharCode(...chunk);
668
+ }
669
+ if (typeof globalThis.btoa !== "function") {
670
+ throw new TypeError("Base64 encoder is not available in this environment.");
671
+ }
672
+ return globalThis.btoa(binary);
673
+ }
674
+ var DEFAULT_OPTIONS = {
675
+ timeout: 1e4,
676
+ retries: 3,
677
+ retryDelay: 1e3,
678
+ maxRetryDelay: 1e4,
679
+ exponentialBackoff: true
680
+ };
681
+ async function downloadImageAsBase64(url, options = {}) {
682
+ "use step";
683
+ const opts = { ...DEFAULT_OPTIONS, ...options };
684
+ let attemptCount = 0;
685
+ return pRetry(
686
+ async () => {
687
+ attemptCount++;
688
+ const controller = new AbortController();
689
+ const timeoutId = setTimeout(() => controller.abort(), opts.timeout);
690
+ try {
691
+ const response = await fetch(url, {
692
+ signal: controller.signal,
693
+ headers: {
694
+ "User-Agent": "@mux/ai image downloader"
695
+ }
696
+ });
697
+ clearTimeout(timeoutId);
698
+ if (!response.ok) {
699
+ if (response.status >= 400 && response.status < 500 && response.status !== 429) {
700
+ throw new AbortError(`HTTP ${response.status}: ${response.statusText}`);
701
+ }
702
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
703
+ }
704
+ const contentType = response.headers.get("content-type");
705
+ if (!contentType?.startsWith("image/")) {
706
+ throw new AbortError(`Invalid content type: ${contentType}. Expected image/*`);
707
+ }
708
+ const arrayBuffer = await response.arrayBuffer();
709
+ const buffer = new Uint8Array(arrayBuffer);
710
+ if (buffer.length === 0) {
711
+ throw new AbortError("Downloaded image is empty");
712
+ }
713
+ const base64Data = `data:${contentType};base64,${bytesToBase64(buffer)}`;
714
+ return {
715
+ base64Data,
716
+ buffer,
717
+ url,
718
+ contentType,
719
+ sizeBytes: buffer.length,
720
+ attempts: attemptCount
721
+ };
722
+ } catch (error) {
723
+ clearTimeout(timeoutId);
724
+ if (error instanceof AbortError) {
725
+ throw error;
726
+ }
727
+ if (error instanceof Error) {
728
+ if (error.name === "AbortError") {
729
+ throw new Error(`Request timeout after ${opts.timeout}ms`);
730
+ }
731
+ throw new Error(`Download failed: ${error.message}`);
732
+ }
733
+ throw new Error("Unknown download error");
734
+ }
735
+ },
736
+ {
737
+ retries: opts.retries,
738
+ minTimeout: opts.retryDelay,
739
+ maxTimeout: opts.maxRetryDelay,
740
+ factor: opts.exponentialBackoff ? 2 : 1,
741
+ randomize: true,
742
+ // Add jitter to prevent thundering herd
743
+ onFailedAttempt: (error) => {
744
+ console.warn(`Image download attempt ${error.attemptNumber} failed for ${url}`);
745
+ if (error.retriesLeft > 0) {
746
+ console.warn(`Retrying... (${error.retriesLeft} attempts left)`);
747
+ }
748
+ }
749
+ }
750
+ );
751
+ }
752
+ async function downloadImagesAsBase64(urls, options = {}, maxConcurrent = 5) {
753
+ "use step";
754
+ const results = [];
755
+ for (let i = 0; i < urls.length; i += maxConcurrent) {
756
+ const batch = urls.slice(i, i + maxConcurrent);
757
+ const batchPromises = batch.map((url) => downloadImageAsBase64(url, options));
758
+ const batchResults = await Promise.all(batchPromises);
759
+ results.push(...batchResults);
760
+ }
761
+ return results;
762
+ }
763
+
603
764
  // src/lib/providers.ts
604
765
  import { createAnthropic } from "@ai-sdk/anthropic";
605
766
  import { createGoogleGenerativeAI } from "@ai-sdk/google";
@@ -936,7 +1097,8 @@ async function resolveMuxSigningContext(credentials) {
936
1097
 
937
1098
  // src/lib/providers.ts
938
1099
  var DEFAULT_LANGUAGE_MODELS = {
939
- openai: "gpt-5.1",
1100
+ // GPT-5.6 models default to medium reasoning when no effort is specified.
1101
+ openai: "gpt-5.6-luna",
940
1102
  anthropic: "claude-sonnet-4-5",
941
1103
  google: "gemini-3-flash-preview"
942
1104
  };
@@ -945,11 +1107,20 @@ var DEFAULT_EMBEDDING_MODELS = {
945
1107
  google: "gemini-embedding-001"
946
1108
  };
947
1109
  var LANGUAGE_MODELS = {
948
- openai: ["gpt-5.1", "gpt-5-mini"],
1110
+ openai: ["gpt-5.6-luna", "gpt-5.1", "gpt-5-mini"],
949
1111
  anthropic: ["claude-sonnet-4-5"],
950
1112
  google: ["gemini-3-flash-preview", "gemini-3.1-flash-lite", "gemini-2.5-flash"]
951
1113
  };
952
1114
  var LANGUAGE_MODEL_DEPRECATIONS = [
1115
+ {
1116
+ provider: "openai",
1117
+ modelId: "gpt-5.1",
1118
+ replacementModelId: "gpt-5.6-luna",
1119
+ phase: "warn",
1120
+ deprecatedOn: "2026-08-01",
1121
+ sunsetOn: "2026-10-01",
1122
+ reason: "GPT-5.6 Luna with its default medium reasoning effort is the new OpenAI default."
1123
+ },
953
1124
  {
954
1125
  provider: "google",
955
1126
  modelId: "gemini-2.5-flash",
@@ -1010,7 +1181,7 @@ function parseEvalModelPair(value) {
1010
1181
  const modelId = modelIdRaw?.trim();
1011
1182
  if (!provider || !modelId) {
1012
1183
  throw new Error(
1013
- `Invalid eval model pair "${value}". Use "provider:model" (example: "openai:gpt-5.1").`
1184
+ `Invalid eval model pair "${value}". Use "provider:model" (example: "openai:gpt-5.6-luna").`
1014
1185
  );
1015
1186
  }
1016
1187
  if (!isSupportedProvider(provider)) {
@@ -1283,19 +1454,20 @@ async function withRetry(fn, {
1283
1454
  try {
1284
1455
  return await fn();
1285
1456
  } catch (error) {
1286
- lastError = error instanceof Error ? error : new Error(String(error));
1457
+ lastError = error;
1458
+ const retryError = error instanceof Error ? error : new Error(String(error));
1287
1459
  const isLastAttempt = attempt === maxRetries;
1288
- if (isLastAttempt || !shouldRetry(lastError, attempt + 1)) {
1289
- throw lastError;
1460
+ if (isLastAttempt || !shouldRetry(retryError, attempt + 1)) {
1461
+ throw error;
1290
1462
  }
1291
1463
  const delay = calculateDelay(attempt + 1, baseDelay, maxDelay);
1292
1464
  console.warn(
1293
- `Attempt ${attempt + 1} failed: ${lastError.message}. Retrying in ${Math.round(delay)}ms...`
1465
+ `Attempt ${attempt + 1} failed: ${retryError.message}. Retrying in ${Math.round(delay)}ms...`
1294
1466
  );
1295
1467
  await new Promise((resolve) => setTimeout(resolve, delay));
1296
1468
  }
1297
1469
  }
1298
- throw lastError || new Error("Retry failed with unknown error");
1470
+ throw lastError ?? new Error("Retry failed with unknown error");
1299
1471
  }
1300
1472
 
1301
1473
  // src/lib/workflow-scope.ts
@@ -2074,17 +2246,20 @@ async function fetchTranscriptForAsset(asset, playbackId, options = {}) {
2074
2246
  }
2075
2247
 
2076
2248
  // src/workflows/ask-questions.ts
2077
- var questionAnswerSchema = z2.object({
2078
- question: z2.string().describe("The full text of the original question"),
2079
- answer: z2.string().nullable(),
2080
- confidence: z2.number(),
2081
- reasoning: z2.string().max(1e3),
2082
- skipped: z2.boolean()
2249
+ var ASK_QUESTIONS_MAX_QUESTION_LENGTH = 600;
2250
+ var ASK_QUESTIONS_DEFAULT_MAX_ANSWER_OPTION_LENGTH = 150;
2251
+ var ASK_QUESTIONS_DEFAULT_MAX_FREE_FORM_ANSWER_LENGTH = 500;
2252
+ var questionAnswerSchema = z3.object({
2253
+ question: z3.string().describe("The full text of the original question"),
2254
+ answer: z3.string().nullable(),
2255
+ confidence: z3.number(),
2256
+ reasoning: z3.string().max(1e3),
2257
+ skipped: z3.boolean()
2083
2258
  });
2084
2259
  var SKIP_SENTINEL = "__SKIPPED__";
2085
2260
  function createAskQuestionsSchema(answerSchema) {
2086
- return z2.object({
2087
- answers: z2.array(
2261
+ return z3.object({
2262
+ answers: z3.array(
2088
2263
  questionAnswerSchema.extend({
2089
2264
  answer: answerSchema
2090
2265
  })
@@ -2434,12 +2609,12 @@ function buildResponseSchemaForQuestions(normalizedQuestions, maxFreeFormAnswerL
2434
2609
  SKIP_SENTINEL.length,
2435
2610
  longestConstrained
2436
2611
  );
2437
- return createAskQuestionsSchema(z2.string().min(1).max(schemaMax));
2612
+ return createAskQuestionsSchema(z3.string().min(1).max(schemaMax));
2438
2613
  }
2439
2614
  const allowed = Array.from(
2440
2615
  new Set(normalizedQuestions.flatMap(allowedAnswersForQuestion))
2441
2616
  );
2442
- return createAskQuestionsSchema(z2.enum([...allowed, SKIP_SENTINEL]));
2617
+ return createAskQuestionsSchema(z3.enum([...allowed, SKIP_SENTINEL]));
2443
2618
  }
2444
2619
  async function analyzeQuestions({
2445
2620
  provider,
@@ -2457,7 +2632,7 @@ async function analyzeQuestions({
2457
2632
  normalizedQuestions,
2458
2633
  maxFreeFormAnswerLength
2459
2634
  );
2460
- const response = await generateText({
2635
+ const response = await withContentPolicyErrorHandling(() => generateText({
2461
2636
  model,
2462
2637
  output: Output.object({ schema: responseSchema }),
2463
2638
  experimental_telemetry: { isEnabled: true },
@@ -2474,11 +2649,12 @@ async function analyzeQuestions({
2474
2649
  ] : userPrompt
2475
2650
  }
2476
2651
  ]
2477
- });
2478
- if (!response.output) {
2652
+ }));
2653
+ const output = getGeneratedOutputWithContentPolicyHandling(response);
2654
+ if (!output) {
2479
2655
  throw new Error("Ask-questions output missing");
2480
2656
  }
2481
- const parsed = responseSchema.parse(response.output);
2657
+ const parsed = responseSchema.parse(output);
2482
2658
  const unexpectedRootKeys = detectUnexpectedKeysFromRawText(
2483
2659
  response.text,
2484
2660
  responseSchema.keyof().options
@@ -2500,7 +2676,8 @@ async function analyzeQuestions({
2500
2676
  outputTokens: response.usage.outputTokens,
2501
2677
  totalTokens: response.usage.totalTokens,
2502
2678
  reasoningTokens: response.usage.reasoningTokens,
2503
- cachedInputTokens: response.usage.cachedInputTokens
2679
+ cachedInputTokens: response.usage.cachedInputTokens,
2680
+ cacheWriteTokens: response.usage.inputTokenDetails?.cacheWriteTokens
2504
2681
  },
2505
2682
  unexpectedRootKeys,
2506
2683
  unexpectedAnswerKeys
@@ -2519,7 +2696,6 @@ async function askQuestionsInternal(assetId, questions, options, collectedUsage)
2519
2696
  if (!questions || questions.length === 0) {
2520
2697
  throw new MuxAiError("At least one question must be provided.", { type: "validation_error" });
2521
2698
  }
2522
- const MAX_QUESTION_LENGTH = 500;
2523
2699
  questions.forEach((q, idx) => {
2524
2700
  if (!q.question || typeof q.question !== "string" || !q.question.trim()) {
2525
2701
  throw new MuxAiError(
@@ -2527,15 +2703,14 @@ async function askQuestionsInternal(assetId, questions, options, collectedUsage)
2527
2703
  { type: "validation_error" }
2528
2704
  );
2529
2705
  }
2530
- if (q.question.length > MAX_QUESTION_LENGTH) {
2706
+ if (q.question.length > ASK_QUESTIONS_MAX_QUESTION_LENGTH) {
2531
2707
  throw new MuxAiError(
2532
- `Question at index ${idx} exceeds the ${MAX_QUESTION_LENGTH}-character limit (received ${q.question.length}).`,
2708
+ `Question at index ${idx} exceeds the ${ASK_QUESTIONS_MAX_QUESTION_LENGTH}-character limit (received ${q.question.length}).`,
2533
2709
  { type: "validation_error" }
2534
2710
  );
2535
2711
  }
2536
2712
  });
2537
- const DEFAULT_MAX_ANSWER_OPTION_LENGTH = 150;
2538
- const maxAnswerOptionLength = options?.maxAnswerOptionLength ?? DEFAULT_MAX_ANSWER_OPTION_LENGTH;
2713
+ const maxAnswerOptionLength = options?.maxAnswerOptionLength ?? ASK_QUESTIONS_DEFAULT_MAX_ANSWER_OPTION_LENGTH;
2539
2714
  if (!Number.isFinite(maxAnswerOptionLength) || maxAnswerOptionLength <= 0) {
2540
2715
  throw new MuxAiError(
2541
2716
  `maxAnswerOptionLength must be a positive number (received ${maxAnswerOptionLength}).`,
@@ -2554,8 +2729,7 @@ async function askQuestionsInternal(assetId, questions, options, collectedUsage)
2554
2729
  }
2555
2730
  }
2556
2731
  });
2557
- const DEFAULT_MAX_FREE_FORM_ANSWER_LENGTH = 500;
2558
- const maxFreeFormAnswerLength = options?.maxFreeFormAnswerLength ?? DEFAULT_MAX_FREE_FORM_ANSWER_LENGTH;
2732
+ const maxFreeFormAnswerLength = options?.maxFreeFormAnswerLength ?? ASK_QUESTIONS_DEFAULT_MAX_FREE_FORM_ANSWER_LENGTH;
2559
2733
  if (!Number.isFinite(maxFreeFormAnswerLength) || maxFreeFormAnswerLength <= 0) {
2560
2734
  throw new MuxAiError(
2561
2735
  `maxFreeFormAnswerLength must be a positive number (received ${maxFreeFormAnswerLength}).`,
@@ -2757,11 +2931,11 @@ async function askQuestionsInternal(assetId, questions, options, collectedUsage)
2757
2931
  // src/workflows/burned-in-captions.ts
2758
2932
  import { generateText as generateText2, Output as Output2 } from "ai";
2759
2933
  import dedent3 from "dedent";
2760
- import { z as z3 } from "zod";
2761
- var burnedInCaptionsSchema = z3.object({
2762
- hasBurnedInCaptions: z3.boolean(),
2763
- confidence: z3.number(),
2764
- detectedLanguage: z3.string().max(100).nullable()
2934
+ import { z as z4 } from "zod";
2935
+ var burnedInCaptionsSchema = z4.object({
2936
+ hasBurnedInCaptions: z4.boolean(),
2937
+ confidence: z4.number(),
2938
+ detectedLanguage: z4.string().max(100).nullable()
2765
2939
  });
2766
2940
  var SYSTEM_PROMPT2 = promptDedent`
2767
2941
  <role>
@@ -2871,7 +3045,7 @@ async function analyzeStoryboard({
2871
3045
  }) {
2872
3046
  "use step";
2873
3047
  const model = await createLanguageModelFromConfig(provider, modelId, credentials);
2874
- const response = await generateText2({
3048
+ const response = await withContentPolicyErrorHandling(() => generateText2({
2875
3049
  model,
2876
3050
  output: Output2.object({ schema: burnedInCaptionsSchema }),
2877
3051
  experimental_telemetry: { isEnabled: true },
@@ -2888,22 +3062,24 @@ async function analyzeStoryboard({
2888
3062
  ]
2889
3063
  }
2890
3064
  ]
2891
- });
3065
+ }));
3066
+ const output = getGeneratedOutputWithContentPolicyHandling(response);
2892
3067
  const unexpectedKeys = detectUnexpectedKeysFromRawText(
2893
3068
  response.text,
2894
3069
  burnedInCaptionsSchema.keyof().options
2895
3070
  );
2896
3071
  return {
2897
3072
  result: {
2898
- ...response.output,
2899
- confidence: Math.min(1, Math.max(0, response.output.confidence))
3073
+ ...output,
3074
+ confidence: Math.min(1, Math.max(0, output.confidence))
2900
3075
  },
2901
3076
  usage: {
2902
3077
  inputTokens: response.usage.inputTokens,
2903
3078
  outputTokens: response.usage.outputTokens,
2904
3079
  totalTokens: response.usage.totalTokens,
2905
3080
  reasoningTokens: response.usage.reasoningTokens,
2906
- cachedInputTokens: response.usage.cachedInputTokens
3081
+ cachedInputTokens: response.usage.cachedInputTokens,
3082
+ cacheWriteTokens: response.usage.inputTokenDetails?.cacheWriteTokens
2907
3083
  },
2908
3084
  unexpectedKeys
2909
3085
  };
@@ -3001,13 +3177,13 @@ async function hasBurnedInCaptionsInternal(assetId, options, collectedUsage) {
3001
3177
  // src/workflows/chapters.ts
3002
3178
  import { generateText as generateText3, Output as Output3 } from "ai";
3003
3179
  import dedent4 from "dedent";
3004
- import { z as z4 } from "zod";
3005
- var chapterSchema = z4.object({
3006
- startTime: z4.number(),
3007
- title: z4.string().max(300)
3180
+ import { z as z5 } from "zod";
3181
+ var chapterSchema = z5.object({
3182
+ startTime: z5.number(),
3183
+ title: z5.string().max(300)
3008
3184
  });
3009
- var chaptersSchema = z4.object({
3010
- chapters: z4.array(chapterSchema)
3185
+ var chaptersSchema = z5.object({
3186
+ chapters: z5.array(chapterSchema)
3011
3187
  });
3012
3188
  async function generateChaptersWithAI({
3013
3189
  provider,
@@ -3019,21 +3195,24 @@ async function generateChaptersWithAI({
3019
3195
  "use step";
3020
3196
  const model = await createLanguageModelFromConfig(provider, modelId, credentials);
3021
3197
  const response = await withRetry(
3022
- () => generateText3({
3023
- model,
3024
- output: Output3.object({ schema: chaptersSchema }),
3025
- messages: [
3026
- {
3027
- role: "system",
3028
- content: systemPrompt
3029
- },
3030
- {
3031
- role: "user",
3032
- content: userPrompt
3033
- }
3034
- ]
3035
- })
3198
+ () => withContentPolicyErrorHandling(
3199
+ () => generateText3({
3200
+ model,
3201
+ output: Output3.object({ schema: chaptersSchema }),
3202
+ messages: [
3203
+ {
3204
+ role: "system",
3205
+ content: systemPrompt
3206
+ },
3207
+ {
3208
+ role: "user",
3209
+ content: userPrompt
3210
+ }
3211
+ ]
3212
+ })
3213
+ )
3036
3214
  );
3215
+ const output = getGeneratedOutputWithContentPolicyHandling(response);
3037
3216
  const unexpectedRootKeys = detectUnexpectedKeysFromRawText(
3038
3217
  response.text,
3039
3218
  chaptersSchema.keyof().options
@@ -3049,13 +3228,14 @@ async function generateChaptersWithAI({
3049
3228
  } catch {
3050
3229
  }
3051
3230
  return {
3052
- chapters: response.output,
3231
+ chapters: output,
3053
3232
  usage: {
3054
3233
  inputTokens: response.usage.inputTokens,
3055
3234
  outputTokens: response.usage.outputTokens,
3056
3235
  totalTokens: response.usage.totalTokens,
3057
3236
  reasoningTokens: response.usage.reasoningTokens,
3058
- cachedInputTokens: response.usage.cachedInputTokens
3237
+ cachedInputTokens: response.usage.cachedInputTokens,
3238
+ cacheWriteTokens: response.usage.inputTokenDetails?.cacheWriteTokens
3059
3239
  },
3060
3240
  unexpectedRootKeys,
3061
3241
  unexpectedChapterKeys
@@ -3311,7 +3491,7 @@ async function generateChaptersInternal(assetId, options, collectedUsage) {
3311
3491
 
3312
3492
  // src/workflows/edit-captions.ts
3313
3493
  import { generateText as generateText4, Output as Output4 } from "ai";
3314
- import { z as z5 } from "zod";
3494
+ import { z as z6 } from "zod";
3315
3495
 
3316
3496
  // src/lib/mux-tracks.ts
3317
3497
  async function fetchVttFromMux(vttUrl) {
@@ -3594,8 +3774,8 @@ async function createPresignedGetUrlWithStorageAdapter(input, adapter) {
3594
3774
  }
3595
3775
 
3596
3776
  // src/workflows/edit-captions.ts
3597
- var profanityDetectionSchema = z5.object({
3598
- profanity: z5.array(z5.string().max(100)).describe(
3777
+ var profanityDetectionSchema = z6.object({
3778
+ profanity: z6.array(z6.string().max(100)).describe(
3599
3779
  "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)."
3600
3780
  )
3601
3781
  });
@@ -3772,7 +3952,7 @@ async function identifyProfanityWithAI({
3772
3952
  tag: "transcript",
3773
3953
  content: plainText
3774
3954
  });
3775
- const response = await generateText4({
3955
+ const response = await withContentPolicyErrorHandling(() => generateText4({
3776
3956
  model,
3777
3957
  output: Output4.object({ schema: profanityDetectionSchema }),
3778
3958
  messages: [
@@ -3787,19 +3967,21 @@ async function identifyProfanityWithAI({
3787
3967
  ${transcriptSection}`
3788
3968
  }
3789
3969
  ]
3790
- });
3970
+ }));
3971
+ const output = getGeneratedOutputWithContentPolicyHandling(response);
3791
3972
  const unexpectedKeys = detectUnexpectedKeysFromRawText(
3792
3973
  response.text,
3793
3974
  profanityDetectionSchema.keyof().options
3794
3975
  );
3795
3976
  return {
3796
- profanity: response.output.profanity,
3977
+ profanity: output.profanity,
3797
3978
  usage: {
3798
3979
  inputTokens: response.usage.inputTokens,
3799
3980
  outputTokens: response.usage.outputTokens,
3800
3981
  totalTokens: response.usage.totalTokens,
3801
3982
  reasoningTokens: response.usage.reasoningTokens,
3802
- cachedInputTokens: response.usage.cachedInputTokens
3983
+ cachedInputTokens: response.usage.cachedInputTokens,
3984
+ cacheWriteTokens: response.usage.inputTokenDetails?.cacheWriteTokens
3803
3985
  },
3804
3986
  unexpectedKeys
3805
3987
  };
@@ -4442,7 +4624,7 @@ async function generateVideoEmbeddings(assetId, options = {}) {
4442
4624
  // src/workflows/engagement-insights.ts
4443
4625
  import { generateText as generateText5, Output as Output5 } from "ai";
4444
4626
  import dedent5 from "dedent";
4445
- import { z as z6 } from "zod";
4627
+ import { z as z7 } from "zod";
4446
4628
 
4447
4629
  // src/primitives/heatmap.ts
4448
4630
  async function getHeatmapForAsset(assetId, options = {}) {
@@ -4589,20 +4771,20 @@ async function getShotsForAsset(assetId, options = {}) {
4589
4771
  }
4590
4772
 
4591
4773
  // src/workflows/engagement-insights.ts
4592
- var aiMomentInsightSchema = z6.object({
4593
- hotspotIndex: z6.number(),
4594
- startMs: z6.number(),
4595
- endMs: z6.number(),
4596
- timestamp: z6.string(),
4597
- engagementScore: z6.number(),
4598
- insight: z6.string().max(1e3)
4774
+ var aiMomentInsightSchema = z7.object({
4775
+ hotspotIndex: z7.number(),
4776
+ startMs: z7.number(),
4777
+ endMs: z7.number(),
4778
+ timestamp: z7.string(),
4779
+ engagementScore: z7.number(),
4780
+ insight: z7.string().max(1e3)
4599
4781
  });
4600
- var aiOverallInsightSchema = z6.object({
4601
- summary: z6.string().max(2e3),
4602
- trends: z6.array(z6.string().max(500))
4782
+ var aiOverallInsightSchema = z7.object({
4783
+ summary: z7.string().max(2e3),
4784
+ trends: z7.array(z7.string().max(500))
4603
4785
  });
4604
- var engagementInsightsSchema = z6.object({
4605
- momentInsights: z6.array(aiMomentInsightSchema),
4786
+ var engagementInsightsSchema = z7.object({
4787
+ momentInsights: z7.array(aiMomentInsightSchema),
4606
4788
  overallInsight: aiOverallInsightSchema
4607
4789
  });
4608
4790
  var SYSTEM_PROMPT4 = promptDedent`
@@ -4864,26 +5046,29 @@ async function generateInsightsWithAI(provider, modelId, systemPrompt, userPromp
4864
5046
  "use step";
4865
5047
  const model = await createLanguageModelFromConfig(provider, modelId, credentials);
4866
5048
  const response = await withRetry(
4867
- () => generateText5({
4868
- model,
4869
- output: Output5.object({ schema: engagementInsightsSchema }),
4870
- experimental_telemetry: { isEnabled: true },
4871
- messages: [
4872
- {
4873
- role: "system",
4874
- content: systemPrompt
4875
- },
4876
- {
4877
- role: "user",
4878
- content: [
4879
- { type: "text", text: userPrompt },
4880
- ...imageUrls.map((url) => ({ type: "image", image: url }))
4881
- ]
4882
- }
4883
- ]
4884
- })
5049
+ () => withContentPolicyErrorHandling(
5050
+ () => generateText5({
5051
+ model,
5052
+ output: Output5.object({ schema: engagementInsightsSchema }),
5053
+ experimental_telemetry: { isEnabled: true },
5054
+ messages: [
5055
+ {
5056
+ role: "system",
5057
+ content: systemPrompt
5058
+ },
5059
+ {
5060
+ role: "user",
5061
+ content: [
5062
+ { type: "text", text: userPrompt },
5063
+ ...imageUrls.map((url) => ({ type: "image", image: url }))
5064
+ ]
5065
+ }
5066
+ ]
5067
+ })
5068
+ )
4885
5069
  );
4886
- if (!response.output) {
5070
+ const output = getGeneratedOutputWithContentPolicyHandling(response);
5071
+ if (!output) {
4887
5072
  throw new Error("AI returned empty or unparseable response");
4888
5073
  }
4889
5074
  const unexpectedRootKeys = detectUnexpectedKeysFromRawText(
@@ -4906,13 +5091,14 @@ async function generateInsightsWithAI(provider, modelId, systemPrompt, userPromp
4906
5091
  } catch {
4907
5092
  }
4908
5093
  return {
4909
- result: response.output,
5094
+ result: output,
4910
5095
  usage: {
4911
5096
  inputTokens: response.usage.inputTokens,
4912
5097
  outputTokens: response.usage.outputTokens,
4913
5098
  totalTokens: response.usage.totalTokens,
4914
5099
  reasoningTokens: response.usage.reasoningTokens,
4915
- cachedInputTokens: response.usage.cachedInputTokens
5100
+ cachedInputTokens: response.usage.cachedInputTokens,
5101
+ cacheWriteTokens: response.usage.inputTokenDetails?.cacheWriteTokens
4916
5102
  },
4917
5103
  unexpectedRootKeys,
4918
5104
  unexpectedMomentKeys,
@@ -5866,7 +6052,7 @@ async function getModerationScores(assetId, options = {}) {
5866
6052
  // src/workflows/summarization.ts
5867
6053
  import { generateText as generateText6, Output as Output6 } from "ai";
5868
6054
  import dedent6 from "dedent";
5869
- import { z as z7 } from "zod";
6055
+ import { z as z8 } from "zod";
5870
6056
 
5871
6057
  // src/lib/markdown-normalization.ts
5872
6058
  var ESCAPED_LINE_BREAK_REGEX = /\\r\\n|\\n|\\r/g;
@@ -5879,17 +6065,17 @@ function normalizeMarkdownDescription(description) {
5879
6065
  var DEFAULT_SUMMARY_KEYWORD_LIMIT = 10;
5880
6066
  var DEFAULT_TITLE_LENGTH = 10;
5881
6067
  var DEFAULT_DESCRIPTION_LENGTH = 50;
5882
- var summarySchema = z7.object({
5883
- keywords: z7.array(z7.string().max(200)),
5884
- title: z7.string().max(500),
5885
- description: z7.string().max(1e4)
6068
+ var summarySchema = z8.object({
6069
+ keywords: z8.array(z8.string().max(200)),
6070
+ title: z8.string().max(500),
6071
+ description: z8.string().max(1e4)
5886
6072
  });
5887
6073
  function buildSummarySchema(descriptionLength) {
5888
6074
  const descriptionMaxChars = Math.max(2e3, descriptionLength * 15);
5889
- return z7.object({
5890
- keywords: z7.array(z7.string().max(200)),
5891
- title: z7.string().max(500),
5892
- description: z7.string().max(descriptionMaxChars)
6075
+ return z8.object({
6076
+ keywords: z8.array(z8.string().max(200)),
6077
+ title: z8.string().max(500),
6078
+ description: z8.string().max(descriptionMaxChars)
5893
6079
  });
5894
6080
  }
5895
6081
  var VALID_TONES = ["neutral", "playful", "professional"];
@@ -6165,7 +6351,7 @@ async function analyzeStoryboard2(imageDataUrl, provider, modelId, userPrompt, s
6165
6351
  "use step";
6166
6352
  const model = await createLanguageModelFromConfig(provider, modelId, credentials);
6167
6353
  const schema = buildSummarySchema(descriptionLength);
6168
- const response = await generateText6({
6354
+ const response = await withContentPolicyErrorHandling(() => generateText6({
6169
6355
  model,
6170
6356
  output: Output6.object({
6171
6357
  name: "summary_metadata",
@@ -6185,11 +6371,12 @@ async function analyzeStoryboard2(imageDataUrl, provider, modelId, userPrompt, s
6185
6371
  ]
6186
6372
  }
6187
6373
  ]
6188
- });
6189
- if (!response.output) {
6374
+ }));
6375
+ const output = getGeneratedOutputWithContentPolicyHandling(response);
6376
+ if (!output) {
6190
6377
  throw new Error("Summarization output missing");
6191
6378
  }
6192
- const parsed = schema.parse(response.output);
6379
+ const parsed = schema.parse(output);
6193
6380
  const unexpectedKeys = detectUnexpectedKeysFromRawText(
6194
6381
  response.text,
6195
6382
  schema.keyof().options
@@ -6201,7 +6388,8 @@ async function analyzeStoryboard2(imageDataUrl, provider, modelId, userPrompt, s
6201
6388
  outputTokens: response.usage.outputTokens,
6202
6389
  totalTokens: response.usage.totalTokens,
6203
6390
  reasoningTokens: response.usage.reasoningTokens,
6204
- cachedInputTokens: response.usage.cachedInputTokens
6391
+ cachedInputTokens: response.usage.cachedInputTokens,
6392
+ cacheWriteTokens: response.usage.inputTokenDetails?.cacheWriteTokens
6205
6393
  },
6206
6394
  unexpectedKeys
6207
6395
  };
@@ -6210,7 +6398,7 @@ async function analyzeAudioOnly(provider, modelId, userPrompt, systemPrompt, des
6210
6398
  "use step";
6211
6399
  const model = await createLanguageModelFromConfig(provider, modelId, credentials);
6212
6400
  const schema = buildSummarySchema(descriptionLength);
6213
- const response = await generateText6({
6401
+ const response = await withContentPolicyErrorHandling(() => generateText6({
6214
6402
  model,
6215
6403
  output: Output6.object({
6216
6404
  name: "summary_metadata",
@@ -6227,11 +6415,12 @@ async function analyzeAudioOnly(provider, modelId, userPrompt, systemPrompt, des
6227
6415
  content: userPrompt
6228
6416
  }
6229
6417
  ]
6230
- });
6231
- if (!response.output) {
6418
+ }));
6419
+ const output = getGeneratedOutputWithContentPolicyHandling(response);
6420
+ if (!output) {
6232
6421
  throw new Error("Summarization output missing");
6233
6422
  }
6234
- const parsed = schema.parse(response.output);
6423
+ const parsed = schema.parse(output);
6235
6424
  const unexpectedKeys = detectUnexpectedKeysFromRawText(
6236
6425
  response.text,
6237
6426
  schema.keyof().options
@@ -6243,7 +6432,8 @@ async function analyzeAudioOnly(provider, modelId, userPrompt, systemPrompt, des
6243
6432
  outputTokens: response.usage.outputTokens,
6244
6433
  totalTokens: response.usage.totalTokens,
6245
6434
  reasoningTokens: response.usage.reasoningTokens,
6246
- cachedInputTokens: response.usage.cachedInputTokens
6435
+ cachedInputTokens: response.usage.cachedInputTokens,
6436
+ cacheWriteTokens: response.usage.inputTokenDetails?.cacheWriteTokens
6247
6437
  },
6248
6438
  unexpectedKeys
6249
6439
  };
@@ -6814,16 +7004,16 @@ async function translateAudio(assetId, toLanguageCode, options = {}) {
6814
7004
 
6815
7005
  // src/workflows/translate-captions.ts
6816
7006
  import {
6817
- APICallError,
7007
+ APICallError as APICallError2,
6818
7008
  generateText as generateText7,
6819
- NoObjectGeneratedError,
7009
+ NoObjectGeneratedError as NoObjectGeneratedError2,
6820
7010
  Output as Output7,
6821
- RetryError,
7011
+ RetryError as RetryError2,
6822
7012
  TypeValidationError
6823
7013
  } from "ai";
6824
- import { z as z8 } from "zod";
6825
- var translationSchema = z8.object({
6826
- translation: z8.string()
7014
+ import { z as z9 } from "zod";
7015
+ var translationSchema = z9.object({
7016
+ translation: z9.string()
6827
7017
  });
6828
7018
  var SYSTEM_PROMPT6 = promptDedent`
6829
7019
  You are a subtitle translation expert. Translate VTT subtitle files to the target language specified by the user.
@@ -6890,10 +7080,10 @@ function isProviderServiceError(error) {
6890
7080
  if (!error) {
6891
7081
  return false;
6892
7082
  }
6893
- if (RetryError.isInstance(error)) {
7083
+ if (RetryError2.isInstance(error)) {
6894
7084
  return isProviderServiceError(error.lastError);
6895
7085
  }
6896
- if (APICallError.isInstance(error)) {
7086
+ if (APICallError2.isInstance(error)) {
6897
7087
  return true;
6898
7088
  }
6899
7089
  if (error instanceof Error && "cause" in error) {
@@ -6905,7 +7095,7 @@ function shouldSplitChunkTranslationError(error) {
6905
7095
  if (isProviderServiceError(error)) {
6906
7096
  return false;
6907
7097
  }
6908
- return NoObjectGeneratedError.isInstance(error) || TypeValidationError.isInstance(error) || isTranslationChunkValidationError(error);
7098
+ return NoObjectGeneratedError2.isInstance(error) || TypeValidationError.isInstance(error) || isTranslationChunkValidationError(error);
6909
7099
  }
6910
7100
  function resolveTranslationChunkingOptions(options) {
6911
7101
  const targetChunkDurationSeconds = Math.max(
@@ -7066,7 +7256,7 @@ async function translateVttWithAI({
7066
7256
  "use step";
7067
7257
  const model = await createLanguageModelFromConfig(provider, modelId, credentials);
7068
7258
  const sanitisedVttContent = stripVttMetadataBlocks(vttContent);
7069
- const response = await generateText7({
7259
+ const response = await withContentPolicyErrorHandling(() => generateText7({
7070
7260
  model,
7071
7261
  output: Output7.object({ schema: translationSchema }),
7072
7262
  messages: [
@@ -7081,8 +7271,9 @@ async function translateVttWithAI({
7081
7271
  ${sanitisedVttContent}`
7082
7272
  }
7083
7273
  ]
7084
- });
7085
- const translated = normalizeTranslatedVtt(response.output.translation);
7274
+ }));
7275
+ const output = getGeneratedOutputWithContentPolicyHandling(response);
7276
+ const translated = normalizeTranslatedVtt(output.translation);
7086
7277
  const leakReason = detectLeakReason(translated);
7087
7278
  const safeTranslated = leakReason !== null ? vttContent : translated;
7088
7279
  if (leakReason !== null) {
@@ -7107,7 +7298,8 @@ ${sanitisedVttContent}`
7107
7298
  outputTokens: response.usage.outputTokens,
7108
7299
  totalTokens: response.usage.totalTokens,
7109
7300
  reasoningTokens: response.usage.reasoningTokens,
7110
- cachedInputTokens: response.usage.cachedInputTokens
7301
+ cachedInputTokens: response.usage.cachedInputTokens,
7302
+ cacheWriteTokens: response.usage.inputTokenDetails?.cacheWriteTokens
7111
7303
  }
7112
7304
  };
7113
7305
  }
@@ -7121,8 +7313,8 @@ async function translateCueChunkWithAI({
7121
7313
  }) {
7122
7314
  "use step";
7123
7315
  const model = await createLanguageModelFromConfig(provider, modelId, credentials);
7124
- const schema = z8.object({
7125
- translations: z8.array(z8.string().min(1).max(2e3)).length(cues.length)
7316
+ const schema = z9.object({
7317
+ translations: z9.array(z9.string().min(1).max(2e3)).length(cues.length)
7126
7318
  });
7127
7319
  const cuePayload = cues.map((cue, index) => ({
7128
7320
  index,
@@ -7130,7 +7322,7 @@ async function translateCueChunkWithAI({
7130
7322
  endTime: cue.endTime,
7131
7323
  text: cue.text
7132
7324
  }));
7133
- const response = await generateText7({
7325
+ const response = await withContentPolicyErrorHandling(() => generateText7({
7134
7326
  model,
7135
7327
  output: Output7.object({ schema }),
7136
7328
  messages: [
@@ -7146,7 +7338,8 @@ Return exactly ${cues.length} translated cues in the same order as the input.
7146
7338
  ${JSON.stringify(cuePayload, null, 2)}`
7147
7339
  }
7148
7340
  ]
7149
- });
7341
+ }));
7342
+ const output = getGeneratedOutputWithContentPolicyHandling(response);
7150
7343
  const unexpectedKeys = detectUnexpectedKeysFromRawText(
7151
7344
  response.text,
7152
7345
  schema.keyof().options
@@ -7157,13 +7350,14 @@ ${JSON.stringify(cuePayload, null, 2)}`
7157
7350
  );
7158
7351
  }
7159
7352
  return {
7160
- translations: response.output.translations,
7353
+ translations: output.translations,
7161
7354
  usage: {
7162
7355
  inputTokens: response.usage.inputTokens,
7163
7356
  outputTokens: response.usage.outputTokens,
7164
7357
  totalTokens: response.usage.totalTokens,
7165
7358
  reasoningTokens: response.usage.reasoningTokens,
7166
- cachedInputTokens: response.usage.cachedInputTokens
7359
+ cachedInputTokens: response.usage.cachedInputTokens,
7360
+ cacheWriteTokens: response.usage.inputTokenDetails?.cacheWriteTokens
7167
7361
  },
7168
7362
  unexpectedKeyCount: unexpectedKeys.length
7169
7363
  };
@@ -7526,6 +7720,9 @@ async function translateCaptionsInternal(assetId, trackId, toLanguageCode, optio
7526
7720
  };
7527
7721
  }
7528
7722
  export {
7723
+ ASK_QUESTIONS_DEFAULT_MAX_ANSWER_OPTION_LENGTH,
7724
+ ASK_QUESTIONS_DEFAULT_MAX_FREE_FORM_ANSWER_LENGTH,
7725
+ ASK_QUESTIONS_MAX_QUESTION_LENGTH,
7529
7726
  DEFAULT_DESCRIPTION_LENGTH,
7530
7727
  DEFAULT_SUMMARY_KEYWORD_LIMIT,
7531
7728
  DEFAULT_TITLE_LENGTH,