@mux/ai 0.31.0 → 0.32.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/README.md +37 -12
- package/dist/{index-ooikuED7.d.ts → index-D_nj_Nr4.d.ts} +18 -14
- package/dist/{index-CJtQiGj7.d.ts → index-SjpXUdXl.d.ts} +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +372 -132
- package/dist/index.js.map +1 -1
- package/dist/primitives/index.d.ts +2 -2
- package/dist/primitives/index.js +45 -3
- package/dist/primitives/index.js.map +1 -1
- package/dist/{shots-Bh0GrvLx.d.ts → shots-BMbViFbZ.d.ts} +12 -0
- package/dist/workflows/index.d.ts +2 -2
- package/dist/workflows/index.js +369 -131
- package/dist/workflows/index.js.map +1 -1
- package/package.json +2 -1
package/dist/workflows/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import dedent2 from "dedent";
|
|
|
4
4
|
import { z as z3 } from "zod";
|
|
5
5
|
|
|
6
6
|
// src/lib/content-policy-error.ts
|
|
7
|
-
import { APICallError, NoObjectGeneratedError, RetryError } from "ai";
|
|
7
|
+
import { APICallError as APICallError2, NoObjectGeneratedError, RetryError } from "ai";
|
|
8
8
|
import { z as z2 } from "zod";
|
|
9
9
|
|
|
10
10
|
// src/lib/prompt-fragments.ts
|
|
@@ -79,6 +79,43 @@ var EnvSchema = z.object({
|
|
|
79
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')"),
|
|
80
80
|
// AI Providers
|
|
81
81
|
OPENAI_API_KEY: optionalString("OpenAI API key for OpenAI-backed workflows.", "OpenAI API key"),
|
|
82
|
+
BASETEN_API_KEY: optionalString("Baseten API key for Baseten-backed workflows.", "Baseten API key"),
|
|
83
|
+
BASETEN_URL: optionalString(
|
|
84
|
+
"Optional Baseten language endpoint URL: a dedicated deployment's /sync/v1 URL (such as https://model-{MODEL_ID}.api.baseten.co/environments/production/sync/v1) or a shared OpenAI-compatible base URL. Omit to use Baseten Model APIs.",
|
|
85
|
+
"Baseten URL"
|
|
86
|
+
),
|
|
87
|
+
BASETEN_EMBEDDING_URL: optionalString(
|
|
88
|
+
"Baseten dedicated embedding deployment URL, such as https://model-{MODEL_ID}.api.baseten.co/environments/production/sync. Required for Baseten embeddings.",
|
|
89
|
+
"Baseten embedding URL"
|
|
90
|
+
),
|
|
91
|
+
BASETEN_MODEL: optionalString(
|
|
92
|
+
"Default Baseten language model identifier used when provider='baseten' and no explicit model is passed.",
|
|
93
|
+
"Baseten model"
|
|
94
|
+
),
|
|
95
|
+
BASETEN_EMBEDDING_MODEL: optionalString(
|
|
96
|
+
"Default Baseten embedding model identifier used when provider='baseten' and no explicit model is passed.",
|
|
97
|
+
"Baseten embedding model"
|
|
98
|
+
),
|
|
99
|
+
OPENAI_COMPATIBLE_API_KEY: optionalString(
|
|
100
|
+
"Optional API key for OpenAI-compatible endpoints. Some local or self-hosted endpoints do not require one.",
|
|
101
|
+
"OpenAI-compatible API key"
|
|
102
|
+
),
|
|
103
|
+
OPENAI_COMPATIBLE_BASE_URL: optionalString(
|
|
104
|
+
"Base URL of an OpenAI-compatible API, such as https://my-endpoint.example.com/v1.",
|
|
105
|
+
"OpenAI-compatible base URL"
|
|
106
|
+
),
|
|
107
|
+
OPENAI_COMPATIBLE_EMBEDDING_BASE_URL: optionalString(
|
|
108
|
+
"Optional embedding-specific OpenAI-compatible base URL. Falls back to OPENAI_COMPATIBLE_BASE_URL.",
|
|
109
|
+
"OpenAI-compatible embedding base URL"
|
|
110
|
+
),
|
|
111
|
+
OPENAI_COMPATIBLE_MODEL: optionalString(
|
|
112
|
+
"Default language model identifier used when provider='openai-compatible' and no explicit model is passed.",
|
|
113
|
+
"OpenAI-compatible model"
|
|
114
|
+
),
|
|
115
|
+
OPENAI_COMPATIBLE_EMBEDDING_MODEL: optionalString(
|
|
116
|
+
"Default embedding model identifier used when provider='openai-compatible' and no explicit model is passed.",
|
|
117
|
+
"OpenAI-compatible embedding model"
|
|
118
|
+
),
|
|
82
119
|
ANTHROPIC_API_KEY: optionalString("Anthropic API key for Claude-backed workflows.", "Anthropic API key"),
|
|
83
120
|
GOOGLE_GENERATIVE_AI_API_KEY: optionalString("Google Generative AI API key for Gemini-backed workflows.", "Google Generative AI API key"),
|
|
84
121
|
ELEVENLABS_API_KEY: optionalString("ElevenLabs API key for audio translation.", "ElevenLabs API key"),
|
|
@@ -507,6 +544,67 @@ function wrapError(error, message) {
|
|
|
507
544
|
throw wrapped;
|
|
508
545
|
}
|
|
509
546
|
|
|
547
|
+
// src/lib/retry.ts
|
|
548
|
+
import { APICallError, DownloadError, NoOutputGeneratedError } from "ai";
|
|
549
|
+
var DEFAULT_RETRY_OPTIONS = {
|
|
550
|
+
maxRetries: 3,
|
|
551
|
+
baseDelay: 2e3,
|
|
552
|
+
maxDelay: 1e4
|
|
553
|
+
};
|
|
554
|
+
function defaultShouldRetry(error, _attempt) {
|
|
555
|
+
if (error.message.includes("Timeout while downloading")) {
|
|
556
|
+
return true;
|
|
557
|
+
}
|
|
558
|
+
if (NoOutputGeneratedError.isInstance(error) || error.name === "AI_NoOutputGeneratedError" || error.name === "AI_NoObjectGeneratedError") {
|
|
559
|
+
return true;
|
|
560
|
+
}
|
|
561
|
+
if (APICallError.isInstance(error) || error.name === "AI_APICallError") {
|
|
562
|
+
const apiError = error;
|
|
563
|
+
if (typeof apiError.isRetryable === "boolean") {
|
|
564
|
+
return apiError.isRetryable;
|
|
565
|
+
}
|
|
566
|
+
return apiError.statusCode === 408 || apiError.statusCode === 409 || apiError.statusCode === 429 || apiError.statusCode !== void 0 && apiError.statusCode >= 500;
|
|
567
|
+
}
|
|
568
|
+
const isDownloadError = DownloadError.isInstance(error);
|
|
569
|
+
const isSerializedDownloadError = error.name === "AI_DownloadError";
|
|
570
|
+
if (!isDownloadError && !isSerializedDownloadError) {
|
|
571
|
+
return false;
|
|
572
|
+
}
|
|
573
|
+
const statusCode = error.statusCode;
|
|
574
|
+
return statusCode === void 0 || statusCode === 408 || statusCode === 425 || statusCode === 429 || statusCode >= 500;
|
|
575
|
+
}
|
|
576
|
+
function calculateDelay(attempt, baseDelay, maxDelay) {
|
|
577
|
+
const exponentialDelay = baseDelay * 2 ** (attempt - 1);
|
|
578
|
+
const delayWithJitter = exponentialDelay * (0.5 + Math.random() * 0.5);
|
|
579
|
+
return Math.min(delayWithJitter, maxDelay);
|
|
580
|
+
}
|
|
581
|
+
async function withRetry(fn, {
|
|
582
|
+
maxRetries = DEFAULT_RETRY_OPTIONS.maxRetries,
|
|
583
|
+
baseDelay = DEFAULT_RETRY_OPTIONS.baseDelay,
|
|
584
|
+
maxDelay = DEFAULT_RETRY_OPTIONS.maxDelay,
|
|
585
|
+
shouldRetry = defaultShouldRetry
|
|
586
|
+
} = {}) {
|
|
587
|
+
let lastError;
|
|
588
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
589
|
+
try {
|
|
590
|
+
return await fn();
|
|
591
|
+
} catch (error) {
|
|
592
|
+
lastError = error;
|
|
593
|
+
const retryError = error instanceof Error ? error : new Error(String(error));
|
|
594
|
+
const isLastAttempt = attempt === maxRetries;
|
|
595
|
+
if (isLastAttempt || !shouldRetry(retryError, attempt + 1)) {
|
|
596
|
+
throw error;
|
|
597
|
+
}
|
|
598
|
+
const delay = calculateDelay(attempt + 1, baseDelay, maxDelay);
|
|
599
|
+
console.warn(
|
|
600
|
+
`Attempt ${attempt + 1} failed: ${retryError.message}. Retrying in ${Math.round(delay)}ms...`
|
|
601
|
+
);
|
|
602
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
throw lastError ?? new Error("Retry failed with unknown error");
|
|
606
|
+
}
|
|
607
|
+
|
|
510
608
|
// src/lib/content-policy-error.ts
|
|
511
609
|
var PolicyTokenSchema = z2.string().trim().min(1).max(64).regex(/^[A-Z0-9_]+$/);
|
|
512
610
|
var SafetyRatingSchema = z2.object({
|
|
@@ -552,6 +650,12 @@ async function withContentPolicyErrorHandling(operation) {
|
|
|
552
650
|
rethrowContentPolicyError(error);
|
|
553
651
|
}
|
|
554
652
|
}
|
|
653
|
+
async function withContentPolicyAwareRetry(operation, retryOptions) {
|
|
654
|
+
return withRetry(
|
|
655
|
+
() => withContentPolicyErrorHandling(operation),
|
|
656
|
+
retryOptions
|
|
657
|
+
);
|
|
658
|
+
}
|
|
555
659
|
function rethrowContentPolicyError(error) {
|
|
556
660
|
const block = extractContentPolicyBlock(error);
|
|
557
661
|
if (!block) {
|
|
@@ -588,7 +692,7 @@ function extractContentPolicyBlock(error) {
|
|
|
588
692
|
if (NoObjectGeneratedError.isInstance(error) && error.finishReason === "content-filter") {
|
|
589
693
|
return { reason: "CONTENT_FILTER" };
|
|
590
694
|
}
|
|
591
|
-
if (!
|
|
695
|
+
if (!APICallError2.isInstance(error) || !error.responseBody) {
|
|
592
696
|
return void 0;
|
|
593
697
|
}
|
|
594
698
|
try {
|
|
@@ -627,7 +731,7 @@ function getContentPolicyTokenUsage(error) {
|
|
|
627
731
|
if (RetryError.isInstance(error)) {
|
|
628
732
|
return getContentPolicyTokenUsage(error.lastError);
|
|
629
733
|
}
|
|
630
|
-
if (!
|
|
734
|
+
if (!APICallError2.isInstance(error) || !error.responseBody) {
|
|
631
735
|
return void 0;
|
|
632
736
|
}
|
|
633
737
|
try {
|
|
@@ -765,6 +869,7 @@ async function downloadImagesAsBase64(urls, options = {}, maxConcurrent = 5) {
|
|
|
765
869
|
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
766
870
|
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
767
871
|
import { createOpenAI } from "@ai-sdk/openai";
|
|
872
|
+
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
|
768
873
|
|
|
769
874
|
// src/lib/workflow-crypto.ts
|
|
770
875
|
import { gcm } from "@noble/ciphers/aes.js";
|
|
@@ -1051,6 +1156,7 @@ async function resolveMuxClient(credentials) {
|
|
|
1051
1156
|
function resolveProviderApiKeyFromCredentials(provider, resolved) {
|
|
1052
1157
|
const record = resolved;
|
|
1053
1158
|
const openaiApiKey = readString(record, "openaiApiKey");
|
|
1159
|
+
const basetenApiKey = readString(record, "basetenApiKey");
|
|
1054
1160
|
const anthropicApiKey = readString(record, "anthropicApiKey");
|
|
1055
1161
|
const googleApiKey = readString(record, "googleApiKey");
|
|
1056
1162
|
const googleVisionApiKey = readString(record, "googleVisionApiKey");
|
|
@@ -1058,6 +1164,7 @@ function resolveProviderApiKeyFromCredentials(provider, resolved) {
|
|
|
1058
1164
|
const elevenLabsApiKey = readString(record, "elevenLabsApiKey");
|
|
1059
1165
|
const apiKeyMap = {
|
|
1060
1166
|
"openai": openaiApiKey ?? env_default.OPENAI_API_KEY,
|
|
1167
|
+
"baseten": basetenApiKey ?? env_default.BASETEN_API_KEY,
|
|
1061
1168
|
"anthropic": anthropicApiKey ?? env_default.ANTHROPIC_API_KEY,
|
|
1062
1169
|
"google": googleApiKey ?? env_default.GOOGLE_GENERATIVE_AI_API_KEY,
|
|
1063
1170
|
"google-vision-api": googleVisionApiKey ?? env_default.GOOGLE_VISION_API_KEY,
|
|
@@ -1068,6 +1175,7 @@ function resolveProviderApiKeyFromCredentials(provider, resolved) {
|
|
|
1068
1175
|
if (!apiKey) {
|
|
1069
1176
|
const envVarNames = {
|
|
1070
1177
|
"openai": "OPENAI_API_KEY",
|
|
1178
|
+
"baseten": "BASETEN_API_KEY",
|
|
1071
1179
|
"anthropic": "ANTHROPIC_API_KEY",
|
|
1072
1180
|
"google": "GOOGLE_GENERATIVE_AI_API_KEY",
|
|
1073
1181
|
"google-vision-api": "GOOGLE_VISION_API_KEY",
|
|
@@ -1106,6 +1214,60 @@ var DEFAULT_EMBEDDING_MODELS = {
|
|
|
1106
1214
|
openai: "text-embedding-3-small",
|
|
1107
1215
|
google: "gemini-embedding-001"
|
|
1108
1216
|
};
|
|
1217
|
+
function resolveBasetenLanguageModelId(model) {
|
|
1218
|
+
const resolved = model ?? env_default.BASETEN_MODEL;
|
|
1219
|
+
if (!resolved) {
|
|
1220
|
+
throw new Error(
|
|
1221
|
+
'Baseten model is required. Pass `model` when provider is "baseten" or set BASETEN_MODEL.'
|
|
1222
|
+
);
|
|
1223
|
+
}
|
|
1224
|
+
return resolved;
|
|
1225
|
+
}
|
|
1226
|
+
function resolveBasetenEmbeddingModelId(model) {
|
|
1227
|
+
const resolved = model ?? env_default.BASETEN_EMBEDDING_MODEL;
|
|
1228
|
+
if (!resolved) {
|
|
1229
|
+
throw new Error(
|
|
1230
|
+
'Baseten embedding model is required. Pass `model` when provider is "baseten" or set BASETEN_EMBEDDING_MODEL.'
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
return resolved;
|
|
1234
|
+
}
|
|
1235
|
+
function resolveOpenAICompatibleLanguageModelId(model) {
|
|
1236
|
+
const resolved = model ?? env_default.OPENAI_COMPATIBLE_MODEL;
|
|
1237
|
+
if (!resolved) {
|
|
1238
|
+
throw new Error(
|
|
1239
|
+
'OpenAI-compatible model is required. Pass `model` when provider is "openai-compatible" or set OPENAI_COMPATIBLE_MODEL.'
|
|
1240
|
+
);
|
|
1241
|
+
}
|
|
1242
|
+
return resolved;
|
|
1243
|
+
}
|
|
1244
|
+
function resolveOpenAICompatibleEmbeddingModelId(model) {
|
|
1245
|
+
const resolved = model ?? env_default.OPENAI_COMPATIBLE_EMBEDDING_MODEL;
|
|
1246
|
+
if (!resolved) {
|
|
1247
|
+
throw new Error(
|
|
1248
|
+
'OpenAI-compatible embedding model is required. Pass `model` when provider is "openai-compatible" or set OPENAI_COMPATIBLE_EMBEDDING_MODEL.'
|
|
1249
|
+
);
|
|
1250
|
+
}
|
|
1251
|
+
return resolved;
|
|
1252
|
+
}
|
|
1253
|
+
function getDefaultLanguageModel(provider) {
|
|
1254
|
+
if (provider === "baseten") {
|
|
1255
|
+
return resolveBasetenLanguageModelId();
|
|
1256
|
+
}
|
|
1257
|
+
if (provider === "openai-compatible") {
|
|
1258
|
+
return resolveOpenAICompatibleLanguageModelId();
|
|
1259
|
+
}
|
|
1260
|
+
return DEFAULT_LANGUAGE_MODELS[provider];
|
|
1261
|
+
}
|
|
1262
|
+
function getDefaultEmbeddingModel(provider) {
|
|
1263
|
+
if (provider === "baseten") {
|
|
1264
|
+
return resolveBasetenEmbeddingModelId();
|
|
1265
|
+
}
|
|
1266
|
+
if (provider === "openai-compatible") {
|
|
1267
|
+
return resolveOpenAICompatibleEmbeddingModelId();
|
|
1268
|
+
}
|
|
1269
|
+
return DEFAULT_EMBEDDING_MODELS[provider];
|
|
1270
|
+
}
|
|
1109
1271
|
var LANGUAGE_MODELS = {
|
|
1110
1272
|
openai: ["gpt-5.6-luna", "gpt-5.1", "gpt-5-mini"],
|
|
1111
1273
|
anthropic: ["claude-sonnet-4-5"],
|
|
@@ -1171,7 +1333,7 @@ function getDefaultEvalModelConfigs() {
|
|
|
1171
1333
|
function getAllEvalModelConfigs() {
|
|
1172
1334
|
return Object.entries(LANGUAGE_MODELS).flatMap(([provider, models]) => models.map((modelId) => ({ provider, modelId })));
|
|
1173
1335
|
}
|
|
1174
|
-
function
|
|
1336
|
+
function isSupportedEvalProvider(value) {
|
|
1175
1337
|
return value === "openai" || value === "anthropic" || value === "google";
|
|
1176
1338
|
}
|
|
1177
1339
|
function parseEvalModelPair(value) {
|
|
@@ -1184,7 +1346,10 @@ function parseEvalModelPair(value) {
|
|
|
1184
1346
|
`Invalid eval model pair "${value}". Use "provider:model" (example: "openai:gpt-5.6-luna").`
|
|
1185
1347
|
);
|
|
1186
1348
|
}
|
|
1187
|
-
if (
|
|
1349
|
+
if (provider === "baseten" || provider === "openai-compatible") {
|
|
1350
|
+
return void 0;
|
|
1351
|
+
}
|
|
1352
|
+
if (!isSupportedEvalProvider(provider)) {
|
|
1188
1353
|
throw new Error(
|
|
1189
1354
|
`Unsupported eval provider "${provider}" in "${value}". Supported providers: ${Object.keys(LANGUAGE_MODELS).join(", ")}.`
|
|
1190
1355
|
);
|
|
@@ -1205,7 +1370,7 @@ function resolveEvalModelConfigs(options = {}) {
|
|
|
1205
1370
|
const explicitPairs = options.modelPairs?.map((value) => value.trim()).filter(Boolean) ?? [];
|
|
1206
1371
|
if (explicitPairs.length > 0) {
|
|
1207
1372
|
const dedupedPairs = Array.from(new Set(explicitPairs));
|
|
1208
|
-
return dedupedPairs.map(parseEvalModelPair);
|
|
1373
|
+
return dedupedPairs.map(parseEvalModelPair).filter((config) => Boolean(config));
|
|
1209
1374
|
}
|
|
1210
1375
|
const selection = options.selection ?? "default";
|
|
1211
1376
|
if (selection === "all") {
|
|
@@ -1238,30 +1403,140 @@ function resolveEvalModelConfigsFromEnv(environment = env_default) {
|
|
|
1238
1403
|
var EVAL_MODEL_CONFIGS = resolveEvalModelConfigsFromEnv();
|
|
1239
1404
|
function resolveLanguageModelConfig(options = {}) {
|
|
1240
1405
|
const provider = options.provider || "openai";
|
|
1241
|
-
const modelId = options.model ||
|
|
1406
|
+
const modelId = options.model || getDefaultLanguageModel(provider);
|
|
1242
1407
|
maybeWarnOrThrowForDeprecatedLanguageModel(provider, modelId);
|
|
1243
1408
|
return { provider, modelId };
|
|
1244
1409
|
}
|
|
1245
1410
|
function resolveEmbeddingModelConfig(options = {}) {
|
|
1246
1411
|
const provider = options.provider || "openai";
|
|
1247
|
-
const modelId = options.model ||
|
|
1412
|
+
const modelId = options.model || getDefaultEmbeddingModel(provider);
|
|
1248
1413
|
return { provider, modelId };
|
|
1249
1414
|
}
|
|
1415
|
+
var BASETEN_MODEL_APIS_BASE_URL = "https://inference.baseten.co/v1";
|
|
1416
|
+
function readCredentialString(record, key) {
|
|
1417
|
+
const value = record?.[key];
|
|
1418
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
1419
|
+
}
|
|
1420
|
+
function normalizeBaseUrl(value) {
|
|
1421
|
+
const trimmed = value?.trim();
|
|
1422
|
+
if (!trimmed) {
|
|
1423
|
+
return void 0;
|
|
1424
|
+
}
|
|
1425
|
+
return trimmed.replace(/\/(chat\/completions|responses|embeddings)\/?$/, "").replace(/\/$/, "");
|
|
1426
|
+
}
|
|
1427
|
+
function isDedicatedBasetenModelUrl(value) {
|
|
1428
|
+
return Boolean(value && (value.includes("/sync") || value.includes("/predict")));
|
|
1429
|
+
}
|
|
1430
|
+
function validateDedicatedBasetenUrl(url, kind) {
|
|
1431
|
+
if (kind === "language") {
|
|
1432
|
+
if (!url.includes("/sync/v1")) {
|
|
1433
|
+
throw new Error(
|
|
1434
|
+
`Baseten dedicated deployment URLs must be /sync/v1 endpoints for language models ("/predict" URLs are not supported). Update BASETEN_URL (or basetenUrl in credentials) to the deployment's /sync/v1 URL.`
|
|
1435
|
+
);
|
|
1436
|
+
}
|
|
1437
|
+
return url;
|
|
1438
|
+
}
|
|
1439
|
+
if (!url.includes("/sync")) {
|
|
1440
|
+
throw new Error(
|
|
1441
|
+
"Baseten embeddings require a dedicated /sync or /sync/v1 deployment URL. Set BASETEN_EMBEDDING_URL or provide basetenEmbeddingUrl in credentials."
|
|
1442
|
+
);
|
|
1443
|
+
}
|
|
1444
|
+
return url;
|
|
1445
|
+
}
|
|
1446
|
+
function basetenEndpointBaseUrl(url, kind) {
|
|
1447
|
+
if (kind === "embedding" && !url.includes("/sync/v1")) {
|
|
1448
|
+
return `${url}/v1`;
|
|
1449
|
+
}
|
|
1450
|
+
return url;
|
|
1451
|
+
}
|
|
1452
|
+
function basetenBaseUrlFromUrl(url, kind) {
|
|
1453
|
+
const normalized = normalizeBaseUrl(url);
|
|
1454
|
+
if (!normalized) {
|
|
1455
|
+
if (kind === "embedding") {
|
|
1456
|
+
throw new Error(
|
|
1457
|
+
"Baseten embedding URL is required. Set BASETEN_EMBEDDING_URL or provide basetenEmbeddingUrl in credentials."
|
|
1458
|
+
);
|
|
1459
|
+
}
|
|
1460
|
+
return BASETEN_MODEL_APIS_BASE_URL;
|
|
1461
|
+
}
|
|
1462
|
+
if (isDedicatedBasetenModelUrl(normalized)) {
|
|
1463
|
+
return basetenEndpointBaseUrl(validateDedicatedBasetenUrl(normalized, kind), kind);
|
|
1464
|
+
}
|
|
1465
|
+
if (kind === "embedding") {
|
|
1466
|
+
throw new Error(
|
|
1467
|
+
"Baseten embeddings require a dedicated /sync or /sync/v1 deployment URL. Set BASETEN_EMBEDDING_URL or provide basetenEmbeddingUrl in credentials."
|
|
1468
|
+
);
|
|
1469
|
+
}
|
|
1470
|
+
return normalized;
|
|
1471
|
+
}
|
|
1472
|
+
function resolveBasetenBaseUrlFromRecord(record, kind) {
|
|
1473
|
+
if (kind === "embedding") {
|
|
1474
|
+
return basetenBaseUrlFromUrl(
|
|
1475
|
+
readCredentialString(record, "basetenEmbeddingUrl") ?? env_default.BASETEN_EMBEDDING_URL,
|
|
1476
|
+
kind
|
|
1477
|
+
);
|
|
1478
|
+
}
|
|
1479
|
+
return basetenBaseUrlFromUrl(
|
|
1480
|
+
readCredentialString(record, "basetenUrl") ?? env_default.BASETEN_URL,
|
|
1481
|
+
kind
|
|
1482
|
+
);
|
|
1483
|
+
}
|
|
1484
|
+
function resolveOpenAICompatibleSettingsFromRecord(record, kind) {
|
|
1485
|
+
const apiKey = readCredentialString(record, "openaiCompatibleApiKey") ?? env_default.OPENAI_COMPATIBLE_API_KEY;
|
|
1486
|
+
const sharedBaseUrl = readCredentialString(record, "openaiCompatibleBaseUrl") ?? env_default.OPENAI_COMPATIBLE_BASE_URL;
|
|
1487
|
+
const baseUrl = normalizeBaseUrl(
|
|
1488
|
+
kind === "embedding" ? readCredentialString(record, "openaiCompatibleEmbeddingBaseUrl") ?? env_default.OPENAI_COMPATIBLE_EMBEDDING_BASE_URL ?? sharedBaseUrl : sharedBaseUrl
|
|
1489
|
+
);
|
|
1490
|
+
if (!baseUrl) {
|
|
1491
|
+
throw new Error(
|
|
1492
|
+
"OpenAI-compatible base URL is required. Set OPENAI_COMPATIBLE_BASE_URL or provide openaiCompatibleBaseUrl in credentials."
|
|
1493
|
+
);
|
|
1494
|
+
}
|
|
1495
|
+
return { apiKey, baseURL: baseUrl };
|
|
1496
|
+
}
|
|
1497
|
+
function createBasetenProvider(apiKey, baseURL) {
|
|
1498
|
+
return createOpenAICompatible({
|
|
1499
|
+
name: "baseten",
|
|
1500
|
+
apiKey,
|
|
1501
|
+
baseURL,
|
|
1502
|
+
supportsStructuredOutputs: true
|
|
1503
|
+
});
|
|
1504
|
+
}
|
|
1505
|
+
function createGenericOpenAICompatibleProvider(settings) {
|
|
1506
|
+
return createOpenAICompatible({
|
|
1507
|
+
name: "openai-compatible",
|
|
1508
|
+
...settings,
|
|
1509
|
+
supportsStructuredOutputs: true
|
|
1510
|
+
});
|
|
1511
|
+
}
|
|
1250
1512
|
async function createLanguageModelFromConfig(provider, modelId, credentials) {
|
|
1251
1513
|
maybeWarnOrThrowForDeprecatedLanguageModel(provider, modelId);
|
|
1514
|
+
const resolvedCredentials = await resolveWorkflowCredentials(credentials);
|
|
1515
|
+
const credentialsRecord = resolvedCredentials;
|
|
1252
1516
|
switch (provider) {
|
|
1253
1517
|
case "openai": {
|
|
1254
|
-
const apiKey =
|
|
1518
|
+
const apiKey = resolveProviderApiKeyFromCredentials("openai", resolvedCredentials);
|
|
1255
1519
|
const openai = createOpenAI({ apiKey });
|
|
1256
1520
|
return openai(modelId);
|
|
1257
1521
|
}
|
|
1522
|
+
case "baseten": {
|
|
1523
|
+
const apiKey = resolveProviderApiKeyFromCredentials("baseten", resolvedCredentials);
|
|
1524
|
+
const baseten = createBasetenProvider(apiKey, resolveBasetenBaseUrlFromRecord(credentialsRecord, "language"));
|
|
1525
|
+
return baseten.chatModel(modelId);
|
|
1526
|
+
}
|
|
1527
|
+
case "openai-compatible": {
|
|
1528
|
+
const compatible = createGenericOpenAICompatibleProvider(
|
|
1529
|
+
resolveOpenAICompatibleSettingsFromRecord(credentialsRecord, "language")
|
|
1530
|
+
);
|
|
1531
|
+
return compatible.chatModel(modelId);
|
|
1532
|
+
}
|
|
1258
1533
|
case "anthropic": {
|
|
1259
|
-
const apiKey =
|
|
1534
|
+
const apiKey = resolveProviderApiKeyFromCredentials("anthropic", resolvedCredentials);
|
|
1260
1535
|
const anthropic = createAnthropic({ apiKey });
|
|
1261
1536
|
return anthropic(modelId);
|
|
1262
1537
|
}
|
|
1263
1538
|
case "google": {
|
|
1264
|
-
const apiKey =
|
|
1539
|
+
const apiKey = resolveProviderApiKeyFromCredentials("google", resolvedCredentials);
|
|
1265
1540
|
const google = createGoogleGenerativeAI({ apiKey });
|
|
1266
1541
|
return google(modelId);
|
|
1267
1542
|
}
|
|
@@ -1272,14 +1547,27 @@ async function createLanguageModelFromConfig(provider, modelId, credentials) {
|
|
|
1272
1547
|
}
|
|
1273
1548
|
}
|
|
1274
1549
|
async function createEmbeddingModelFromConfig(provider, modelId, credentials) {
|
|
1550
|
+
const resolvedCredentials = await resolveWorkflowCredentials(credentials);
|
|
1551
|
+
const credentialsRecord = resolvedCredentials;
|
|
1275
1552
|
switch (provider) {
|
|
1276
1553
|
case "openai": {
|
|
1277
|
-
const apiKey =
|
|
1554
|
+
const apiKey = resolveProviderApiKeyFromCredentials("openai", resolvedCredentials);
|
|
1278
1555
|
const openai = createOpenAI({ apiKey });
|
|
1279
1556
|
return openai.embedding(modelId);
|
|
1280
1557
|
}
|
|
1558
|
+
case "baseten": {
|
|
1559
|
+
const apiKey = resolveProviderApiKeyFromCredentials("baseten", resolvedCredentials);
|
|
1560
|
+
const baseten = createBasetenProvider(apiKey, resolveBasetenBaseUrlFromRecord(credentialsRecord, "embedding"));
|
|
1561
|
+
return baseten.textEmbeddingModel(modelId);
|
|
1562
|
+
}
|
|
1563
|
+
case "openai-compatible": {
|
|
1564
|
+
const compatible = createGenericOpenAICompatibleProvider(
|
|
1565
|
+
resolveOpenAICompatibleSettingsFromRecord(credentialsRecord, "embedding")
|
|
1566
|
+
);
|
|
1567
|
+
return compatible.textEmbeddingModel(modelId);
|
|
1568
|
+
}
|
|
1281
1569
|
case "google": {
|
|
1282
|
-
const apiKey =
|
|
1570
|
+
const apiKey = resolveProviderApiKeyFromCredentials("google", resolvedCredentials);
|
|
1283
1571
|
const google = createGoogleGenerativeAI({ apiKey });
|
|
1284
1572
|
return google.textEmbeddingModel(modelId);
|
|
1285
1573
|
}
|
|
@@ -1429,57 +1717,6 @@ function createLanguageSection(languageName) {
|
|
|
1429
1717
|
};
|
|
1430
1718
|
}
|
|
1431
1719
|
|
|
1432
|
-
// src/lib/retry.ts
|
|
1433
|
-
import { DownloadError } from "ai";
|
|
1434
|
-
var DEFAULT_RETRY_OPTIONS = {
|
|
1435
|
-
maxRetries: 3,
|
|
1436
|
-
baseDelay: 2e3,
|
|
1437
|
-
maxDelay: 1e4
|
|
1438
|
-
};
|
|
1439
|
-
function defaultShouldRetry(error, _attempt) {
|
|
1440
|
-
if (error.message.includes("Timeout while downloading")) {
|
|
1441
|
-
return true;
|
|
1442
|
-
}
|
|
1443
|
-
const isDownloadError = DownloadError.isInstance(error);
|
|
1444
|
-
const isSerializedDownloadError = error.name === "AI_DownloadError";
|
|
1445
|
-
if (!isDownloadError && !isSerializedDownloadError) {
|
|
1446
|
-
return false;
|
|
1447
|
-
}
|
|
1448
|
-
const statusCode = error.statusCode;
|
|
1449
|
-
return statusCode === void 0 || statusCode === 408 || statusCode === 425 || statusCode === 429 || statusCode >= 500;
|
|
1450
|
-
}
|
|
1451
|
-
function calculateDelay(attempt, baseDelay, maxDelay) {
|
|
1452
|
-
const exponentialDelay = baseDelay * 2 ** (attempt - 1);
|
|
1453
|
-
const delayWithJitter = exponentialDelay * (0.5 + Math.random() * 0.5);
|
|
1454
|
-
return Math.min(delayWithJitter, maxDelay);
|
|
1455
|
-
}
|
|
1456
|
-
async function withRetry(fn, {
|
|
1457
|
-
maxRetries = DEFAULT_RETRY_OPTIONS.maxRetries,
|
|
1458
|
-
baseDelay = DEFAULT_RETRY_OPTIONS.baseDelay,
|
|
1459
|
-
maxDelay = DEFAULT_RETRY_OPTIONS.maxDelay,
|
|
1460
|
-
shouldRetry = defaultShouldRetry
|
|
1461
|
-
} = {}) {
|
|
1462
|
-
let lastError;
|
|
1463
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
1464
|
-
try {
|
|
1465
|
-
return await fn();
|
|
1466
|
-
} catch (error) {
|
|
1467
|
-
lastError = error;
|
|
1468
|
-
const retryError = error instanceof Error ? error : new Error(String(error));
|
|
1469
|
-
const isLastAttempt = attempt === maxRetries;
|
|
1470
|
-
if (isLastAttempt || !shouldRetry(retryError, attempt + 1)) {
|
|
1471
|
-
throw error;
|
|
1472
|
-
}
|
|
1473
|
-
const delay = calculateDelay(attempt + 1, baseDelay, maxDelay);
|
|
1474
|
-
console.warn(
|
|
1475
|
-
`Attempt ${attempt + 1} failed: ${retryError.message}. Retrying in ${Math.round(delay)}ms...`
|
|
1476
|
-
);
|
|
1477
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
|
-
throw lastError ?? new Error("Retry failed with unknown error");
|
|
1481
|
-
}
|
|
1482
|
-
|
|
1483
1720
|
// src/lib/workflow-scope.ts
|
|
1484
1721
|
function hasWorkflowScopeBoundaries(scope) {
|
|
1485
1722
|
return scope?.startTime !== void 0 || scope?.endTime !== void 0;
|
|
@@ -2642,8 +2879,9 @@ async function analyzeQuestions({
|
|
|
2642
2879
|
normalizedQuestions,
|
|
2643
2880
|
maxFreeFormAnswerLength
|
|
2644
2881
|
);
|
|
2645
|
-
const response = await
|
|
2882
|
+
const response = await withContentPolicyAwareRetry(() => generateText({
|
|
2646
2883
|
model,
|
|
2884
|
+
maxRetries: 0,
|
|
2647
2885
|
output: Output.object({ schema: responseSchema }),
|
|
2648
2886
|
experimental_telemetry: { isEnabled: true },
|
|
2649
2887
|
messages: [
|
|
@@ -2842,18 +3080,16 @@ async function askQuestionsInternal(assetId, questions, options, collectedUsage)
|
|
|
2842
3080
|
credentials
|
|
2843
3081
|
});
|
|
2844
3082
|
} else {
|
|
2845
|
-
analysisResponse = await
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
})
|
|
2856
|
-
);
|
|
3083
|
+
analysisResponse = await analyzeQuestions({
|
|
3084
|
+
provider: modelConfig.provider,
|
|
3085
|
+
modelId: modelConfig.modelId,
|
|
3086
|
+
userPrompt,
|
|
3087
|
+
systemPrompt,
|
|
3088
|
+
normalizedQuestions,
|
|
3089
|
+
maxFreeFormAnswerLength,
|
|
3090
|
+
imageDataUrl: storyboardUrl,
|
|
3091
|
+
credentials
|
|
3092
|
+
});
|
|
2857
3093
|
}
|
|
2858
3094
|
}
|
|
2859
3095
|
} catch (error) {
|
|
@@ -3055,8 +3291,9 @@ async function analyzeStoryboard({
|
|
|
3055
3291
|
}) {
|
|
3056
3292
|
"use step";
|
|
3057
3293
|
const model = await createLanguageModelFromConfig(provider, modelId, credentials);
|
|
3058
|
-
const response = await
|
|
3294
|
+
const response = await withContentPolicyAwareRetry(() => generateText2({
|
|
3059
3295
|
model,
|
|
3296
|
+
maxRetries: 0,
|
|
3060
3297
|
output: Output2.object({ schema: burnedInCaptionsSchema }),
|
|
3061
3298
|
experimental_telemetry: { isEnabled: true },
|
|
3062
3299
|
messages: [
|
|
@@ -3146,14 +3383,14 @@ async function hasBurnedInCaptionsInternal(assetId, options, collectedUsage) {
|
|
|
3146
3383
|
credentials
|
|
3147
3384
|
});
|
|
3148
3385
|
} else {
|
|
3149
|
-
analysisResponse = await
|
|
3386
|
+
analysisResponse = await analyzeStoryboard({
|
|
3150
3387
|
imageDataUrl: imageUrl,
|
|
3151
3388
|
provider: modelConfig.provider,
|
|
3152
3389
|
modelId: modelConfig.modelId,
|
|
3153
3390
|
userPrompt,
|
|
3154
3391
|
systemPrompt: SYSTEM_PROMPT2,
|
|
3155
3392
|
credentials
|
|
3156
|
-
})
|
|
3393
|
+
});
|
|
3157
3394
|
}
|
|
3158
3395
|
collectedUsage.push(analysisResponse.usage);
|
|
3159
3396
|
if (!analysisResponse.result) {
|
|
@@ -3204,24 +3441,21 @@ async function generateChaptersWithAI({
|
|
|
3204
3441
|
}) {
|
|
3205
3442
|
"use step";
|
|
3206
3443
|
const model = await createLanguageModelFromConfig(provider, modelId, credentials);
|
|
3207
|
-
const response = await
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
})
|
|
3223
|
-
)
|
|
3224
|
-
);
|
|
3444
|
+
const response = await withContentPolicyAwareRetry(() => generateText3({
|
|
3445
|
+
model,
|
|
3446
|
+
maxRetries: 0,
|
|
3447
|
+
output: Output3.object({ schema: chaptersSchema }),
|
|
3448
|
+
messages: [
|
|
3449
|
+
{
|
|
3450
|
+
role: "system",
|
|
3451
|
+
content: systemPrompt
|
|
3452
|
+
},
|
|
3453
|
+
{
|
|
3454
|
+
role: "user",
|
|
3455
|
+
content: userPrompt
|
|
3456
|
+
}
|
|
3457
|
+
]
|
|
3458
|
+
}));
|
|
3225
3459
|
const output = getGeneratedOutputWithContentPolicyHandling(response);
|
|
3226
3460
|
const unexpectedRootKeys = detectUnexpectedKeysFromRawText(
|
|
3227
3461
|
response.text,
|
|
@@ -3962,8 +4196,9 @@ async function identifyProfanityWithAI({
|
|
|
3962
4196
|
tag: "transcript",
|
|
3963
4197
|
content: plainText
|
|
3964
4198
|
});
|
|
3965
|
-
const response = await
|
|
4199
|
+
const response = await withContentPolicyAwareRetry(() => generateText4({
|
|
3966
4200
|
model,
|
|
4201
|
+
maxRetries: 0,
|
|
3967
4202
|
output: Output4.object({ schema: profanityDetectionSchema }),
|
|
3968
4203
|
messages: [
|
|
3969
4204
|
{
|
|
@@ -4488,9 +4723,10 @@ async function generateSingleChunkEmbedding({
|
|
|
4488
4723
|
}) {
|
|
4489
4724
|
"use step";
|
|
4490
4725
|
const model = await createEmbeddingModelFromConfig(provider, modelId, credentials);
|
|
4491
|
-
const response = await
|
|
4726
|
+
const response = await withContentPolicyAwareRetry(
|
|
4492
4727
|
() => embed({
|
|
4493
4728
|
model,
|
|
4729
|
+
maxRetries: 0,
|
|
4494
4730
|
value: chunk.text
|
|
4495
4731
|
})
|
|
4496
4732
|
);
|
|
@@ -5055,28 +5291,25 @@ async function fetchEngagementData(assetId, options) {
|
|
|
5055
5291
|
async function generateInsightsWithAI(provider, modelId, systemPrompt, userPrompt, imageUrls, credentials) {
|
|
5056
5292
|
"use step";
|
|
5057
5293
|
const model = await createLanguageModelFromConfig(provider, modelId, credentials);
|
|
5058
|
-
const response = await
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
...imageUrls.map((url) => ({ type: "image", image: url }))
|
|
5074
|
-
]
|
|
5075
|
-
}
|
|
5294
|
+
const response = await withContentPolicyAwareRetry(() => generateText5({
|
|
5295
|
+
model,
|
|
5296
|
+
maxRetries: 0,
|
|
5297
|
+
output: Output5.object({ schema: engagementInsightsSchema }),
|
|
5298
|
+
experimental_telemetry: { isEnabled: true },
|
|
5299
|
+
messages: [
|
|
5300
|
+
{
|
|
5301
|
+
role: "system",
|
|
5302
|
+
content: systemPrompt
|
|
5303
|
+
},
|
|
5304
|
+
{
|
|
5305
|
+
role: "user",
|
|
5306
|
+
content: [
|
|
5307
|
+
{ type: "text", text: userPrompt },
|
|
5308
|
+
...imageUrls.map((url) => ({ type: "image", image: url }))
|
|
5076
5309
|
]
|
|
5077
|
-
}
|
|
5078
|
-
|
|
5079
|
-
);
|
|
5310
|
+
}
|
|
5311
|
+
]
|
|
5312
|
+
}));
|
|
5080
5313
|
const output = getGeneratedOutputWithContentPolicyHandling(response);
|
|
5081
5314
|
if (!output) {
|
|
5082
5315
|
throw new Error("AI returned empty or unparseable response");
|
|
@@ -5396,6 +5629,7 @@ async function getThumbnailUrls(playbackId, duration, options = {}) {
|
|
|
5396
5629
|
timestamps.push(time);
|
|
5397
5630
|
}
|
|
5398
5631
|
}
|
|
5632
|
+
timestamps = [...new Set(timestamps)];
|
|
5399
5633
|
if (maxSamples !== void 0 && timestamps.length > maxSamples) {
|
|
5400
5634
|
const newTimestamps = [];
|
|
5401
5635
|
newTimestamps.push(resolvedScope.startTime);
|
|
@@ -5874,8 +6108,8 @@ async function getThumbnailUrlsFromTimestamps(playbackId, timestampsMs, options)
|
|
|
5874
6108
|
"use step";
|
|
5875
6109
|
const { width, shouldSign, credentials } = options;
|
|
5876
6110
|
const baseUrl = getMuxThumbnailBaseUrl(playbackId);
|
|
5877
|
-
const
|
|
5878
|
-
|
|
6111
|
+
const times = [...new Set(timestampsMs.map(toThumbnailTimeSeconds))];
|
|
6112
|
+
const urlPromises = times.map(async (time) => {
|
|
5879
6113
|
const url = shouldSign ? await signUrl(baseUrl, playbackId, "thumbnail", { time, width }, credentials) : `${baseUrl}?time=${time}&width=${width}`;
|
|
5880
6114
|
return { url, time };
|
|
5881
6115
|
});
|
|
@@ -6361,8 +6595,9 @@ async function analyzeStoryboard2(imageDataUrl, provider, modelId, userPrompt, s
|
|
|
6361
6595
|
"use step";
|
|
6362
6596
|
const model = await createLanguageModelFromConfig(provider, modelId, credentials);
|
|
6363
6597
|
const schema = buildSummarySchema(descriptionLength);
|
|
6364
|
-
const response = await
|
|
6598
|
+
const response = await withContentPolicyAwareRetry(() => generateText6({
|
|
6365
6599
|
model,
|
|
6600
|
+
maxRetries: 0,
|
|
6366
6601
|
output: Output6.object({
|
|
6367
6602
|
name: "summary_metadata",
|
|
6368
6603
|
description: "Structured summary with title, description, and keywords.",
|
|
@@ -6408,8 +6643,9 @@ async function analyzeAudioOnly(provider, modelId, userPrompt, systemPrompt, des
|
|
|
6408
6643
|
"use step";
|
|
6409
6644
|
const model = await createLanguageModelFromConfig(provider, modelId, credentials);
|
|
6410
6645
|
const schema = buildSummarySchema(descriptionLength);
|
|
6411
|
-
const response = await
|
|
6646
|
+
const response = await withContentPolicyAwareRetry(() => generateText6({
|
|
6412
6647
|
model,
|
|
6648
|
+
maxRetries: 0,
|
|
6413
6649
|
output: Output6.object({
|
|
6414
6650
|
name: "summary_metadata",
|
|
6415
6651
|
description: "Structured summary with title, description, and keywords.",
|
|
@@ -6592,7 +6828,7 @@ async function getSummaryAndTagsInternal(assetId, options, collectedUsage) {
|
|
|
6592
6828
|
workflowCredentials
|
|
6593
6829
|
);
|
|
6594
6830
|
} else {
|
|
6595
|
-
analysisResponse = await
|
|
6831
|
+
analysisResponse = await analyzeStoryboard2(
|
|
6596
6832
|
storyboardUrl,
|
|
6597
6833
|
modelConfig.provider,
|
|
6598
6834
|
modelConfig.modelId,
|
|
@@ -6600,7 +6836,7 @@ async function getSummaryAndTagsInternal(assetId, options, collectedUsage) {
|
|
|
6600
6836
|
systemPrompt,
|
|
6601
6837
|
effectiveDescriptionLength,
|
|
6602
6838
|
workflowCredentials
|
|
6603
|
-
)
|
|
6839
|
+
);
|
|
6604
6840
|
}
|
|
6605
6841
|
}
|
|
6606
6842
|
} catch (error) {
|
|
@@ -7106,7 +7342,7 @@ async function translateAudio(assetId, toLanguageCode, options = {}) {
|
|
|
7106
7342
|
|
|
7107
7343
|
// src/workflows/translate-captions.ts
|
|
7108
7344
|
import {
|
|
7109
|
-
APICallError as
|
|
7345
|
+
APICallError as APICallError3,
|
|
7110
7346
|
generateText as generateText7,
|
|
7111
7347
|
NoObjectGeneratedError as NoObjectGeneratedError2,
|
|
7112
7348
|
Output as Output7,
|
|
@@ -7185,7 +7421,7 @@ function isProviderServiceError(error) {
|
|
|
7185
7421
|
if (RetryError2.isInstance(error)) {
|
|
7186
7422
|
return isProviderServiceError(error.lastError);
|
|
7187
7423
|
}
|
|
7188
|
-
if (
|
|
7424
|
+
if (APICallError3.isInstance(error)) {
|
|
7189
7425
|
return true;
|
|
7190
7426
|
}
|
|
7191
7427
|
if (error instanceof Error && "cause" in error) {
|
|
@@ -7358,8 +7594,9 @@ async function translateVttWithAI({
|
|
|
7358
7594
|
"use step";
|
|
7359
7595
|
const model = await createLanguageModelFromConfig(provider, modelId, credentials);
|
|
7360
7596
|
const sanitisedVttContent = stripVttMetadataBlocks(vttContent);
|
|
7361
|
-
const response = await
|
|
7597
|
+
const response = await withContentPolicyAwareRetry(() => generateText7({
|
|
7362
7598
|
model,
|
|
7599
|
+
maxRetries: 0,
|
|
7363
7600
|
output: Output7.object({ schema: translationSchema }),
|
|
7364
7601
|
messages: [
|
|
7365
7602
|
{
|
|
@@ -7424,8 +7661,9 @@ async function translateCueChunkWithAI({
|
|
|
7424
7661
|
endTime: cue.endTime,
|
|
7425
7662
|
text: cue.text
|
|
7426
7663
|
}));
|
|
7427
|
-
const response = await
|
|
7664
|
+
const response = await withContentPolicyAwareRetry(() => generateText7({
|
|
7428
7665
|
model,
|
|
7666
|
+
maxRetries: 0,
|
|
7429
7667
|
output: Output7.object({ schema }),
|
|
7430
7668
|
messages: [
|
|
7431
7669
|
{
|