mulmocast 1.2.44 → 1.2.46

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.
@@ -8,6 +8,7 @@ import { splitText } from "../utils/string.js";
8
8
  import { settings2GraphAIConfig, beatId, multiLingualObjectToArray } from "../utils/utils.js";
9
9
  import { getMultiLingual } from "../utils/context.js";
10
10
  import { currentMulmoScriptVersion } from "../utils/const.js";
11
+ import { translateApiKeyMissingError } from "../utils/error_cause.js";
11
12
  import { getOutputMultilingualFilePath, mkdir, writingMessage, hashSHA256 } from "../utils/file.js";
12
13
  import { translateSystemPrompt, translatePrompts } from "../utils/prompt.js";
13
14
  import { MulmoStudioContextMethods } from "../methods/mulmo_studio_context.js";
@@ -241,7 +242,7 @@ export const translateBeat = async (index, context, targetLangs, args) => {
241
242
  try {
242
243
  const { outputMultilingualFilePath } = getOutputMultilingualFilePathAndMkdir(context);
243
244
  const config = settings2GraphAIConfig(settings, process.env);
244
- assert(!!config?.openAIAgent?.apiKey, "The OPENAI_API_KEY environment variable is missing or empty"); // TODO: cause
245
+ assert(!!config?.openAIAgent?.apiKey, "The OPENAI_API_KEY environment variable is missing or empty", false, translateApiKeyMissingError());
245
246
  const graph = new GraphAI(beatGraph, { ...vanillaAgents, fileWriteAgent, openAIAgent }, { agentFilters, config });
246
247
  graph.injectValue("context", context);
247
248
  graph.injectValue("targetLangs", targetLangs);
@@ -276,7 +277,7 @@ export const translate = async (context, args) => {
276
277
  ? args?.targetLangs
277
278
  : [...new Set([context.lang, context.studio.script.captionParams?.lang].filter((x) => !isNull(x)))];
278
279
  const config = settings2GraphAIConfig(settings, process.env);
279
- assert(!!config?.openAIAgent?.apiKey, "The OPENAI_API_KEY environment variable is missing or empty"); // TODO: cause
280
+ assert(!!config?.openAIAgent?.apiKey, "The OPENAI_API_KEY environment variable is missing or empty", false, translateApiKeyMissingError());
280
281
  const graph = new GraphAI(translate_graph_data, { ...vanillaAgents, fileWriteAgent, openAIAgent }, { agentFilters, config });
281
282
  graph.injectValue("context", context);
282
283
  graph.injectValue("targetLangs", targetLangs);
@@ -2,14 +2,19 @@ import { GraphAILogger } from "graphai";
2
2
  import { FfmpegContextAddInput, FfmpegContextInit, FfmpegContextGenerateOutput, ffmpegGetMediaDuration } from "../utils/ffmpeg_utils.js";
3
3
  import { MulmoStudioContextMethods } from "../methods/mulmo_studio_context.js";
4
4
  import { isFile } from "../utils/file.js";
5
+ import { agentGenerationError, agentFileNotExistError, audioAction, audioFileTarget } from "../utils/error_cause.js";
5
6
  const addBGMAgent = async ({ namedInputs, params, }) => {
6
7
  const { voiceFile, outputFile, context } = namedInputs;
7
8
  const { musicFile } = params;
8
9
  if (!isFile(voiceFile)) {
9
- throw new Error(`AddBGMAgent voiceFile not exist: ${voiceFile}`);
10
+ throw new Error(`AddBGMAgent voiceFile not exist: ${voiceFile}`, {
11
+ cause: agentFileNotExistError("addBGMAgent", audioAction, audioFileTarget, voiceFile),
12
+ });
10
13
  }
11
14
  if (!musicFile.match(/^http/) && !isFile(musicFile)) {
12
- throw new Error(`AddBGMAgent musicFile not exist: ${musicFile}`);
15
+ throw new Error(`AddBGMAgent musicFile not exist: ${musicFile}`, {
16
+ cause: agentFileNotExistError("addBGMAgent", audioAction, audioFileTarget, musicFile),
17
+ });
13
18
  }
14
19
  const { duration: speechDuration } = await ffmpegGetMediaDuration(voiceFile);
15
20
  const introPadding = MulmoStudioContextMethods.getIntroPadding(context);
@@ -30,7 +35,9 @@ const addBGMAgent = async ({ namedInputs, params, }) => {
30
35
  }
31
36
  catch (e) {
32
37
  GraphAILogger.log(e);
33
- throw new Error(`AddBGMAgent ffmpeg run Error`);
38
+ throw new Error(`AddBGMAgent ffmpeg run Error`, {
39
+ cause: agentGenerationError("addBGMAgent", audioAction, audioFileTarget),
40
+ });
34
41
  }
35
42
  };
36
43
  const addBGMAgentInfo = {
@@ -1,6 +1,7 @@
1
1
  import fs from "fs";
2
2
  import { GraphAILogger } from "graphai";
3
3
  import { provider2ImageAgent } from "../utils/provider2agent.js";
4
+ import { apiKeyMissingError, agentGenerationError, agentInvalidResponseError, imageAction, imageFileTarget, hasCause } from "../utils/error_cause.js";
4
5
  import { GoogleGenAI, PersonGeneration } from "@google/genai";
5
6
  import { blankImagePath, blankSquareImagePath, blankVerticalImagePath } from "../utils/file.js";
6
7
  const getAspectRatio = (canvasSize) => {
@@ -20,7 +21,9 @@ export const imageGenAIAgent = async ({ namedInputs, params, config, }) => {
20
21
  const model = params.model ?? provider2ImageAgent["google"].defaultModel;
21
22
  const apiKey = config?.apiKey;
22
23
  if (!apiKey) {
23
- throw new Error("Google GenAI API key is required (GEMINI_API_KEY)");
24
+ throw new Error("Google GenAI API key is required (GEMINI_API_KEY)", {
25
+ cause: apiKeyMissingError("imageGenAIAgent", imageAction, "GEMINI_API_KEY"),
26
+ });
24
27
  }
25
28
  try {
26
29
  const ai = new GoogleGenAI({ apiKey });
@@ -44,7 +47,9 @@ export const imageGenAIAgent = async ({ namedInputs, params, config, }) => {
44
47
  });
45
48
  const response = await ai.models.generateContent({ model, contents });
46
49
  if (!response.candidates?.[0]?.content?.parts) {
47
- throw new Error("ERROR: generateContent returned no candidates");
50
+ throw new Error("ERROR: generateContent returned no candidates", {
51
+ cause: agentInvalidResponseError("imageGenAIAgent", imageAction, imageFileTarget),
52
+ });
48
53
  }
49
54
  for (const part of response.candidates[0].content.parts) {
50
55
  if (part.text) {
@@ -53,13 +58,17 @@ export const imageGenAIAgent = async ({ namedInputs, params, config, }) => {
53
58
  else if (part.inlineData) {
54
59
  const imageData = part.inlineData.data;
55
60
  if (!imageData) {
56
- throw new Error("ERROR: generateContent returned no image data");
61
+ throw new Error("ERROR: generateContent returned no image data", {
62
+ cause: agentInvalidResponseError("imageGenAIAgent", imageAction, imageFileTarget),
63
+ });
57
64
  }
58
65
  const buffer = Buffer.from(imageData, "base64");
59
66
  return { buffer };
60
67
  }
61
68
  }
62
- throw new Error("ERROR: generateContent returned no image data");
69
+ throw new Error("ERROR: generateContent returned no image data", {
70
+ cause: agentInvalidResponseError("imageGenAIAgent", imageAction, imageFileTarget),
71
+ });
63
72
  }
64
73
  else {
65
74
  const response = await ai.models.generateImages({
@@ -73,18 +82,27 @@ export const imageGenAIAgent = async ({ namedInputs, params, config, }) => {
73
82
  },
74
83
  });
75
84
  if (!response.generatedImages || response.generatedImages.length === 0) {
76
- throw new Error("ERROR: generateImage returned no generated images");
85
+ throw new Error("ERROR: generateImage returned no generated images", {
86
+ cause: agentInvalidResponseError("imageGenAIAgent", imageAction, imageFileTarget),
87
+ });
77
88
  }
78
89
  const image = response.generatedImages[0].image;
79
90
  if (image && image.imageBytes) {
80
91
  return { buffer: Buffer.from(image.imageBytes, "base64") };
81
92
  }
82
- throw new Error("ERROR: generateImage returned no image bytes");
93
+ throw new Error("ERROR: generateImage returned no image bytes", {
94
+ cause: agentInvalidResponseError("imageGenAIAgent", imageAction, imageFileTarget),
95
+ });
83
96
  }
84
97
  }
85
98
  catch (error) {
86
99
  GraphAILogger.info("Failed to generate image:", error);
87
- throw error;
100
+ if (hasCause(error) && error.cause) {
101
+ throw error;
102
+ }
103
+ throw new Error("Failed to generate image with Google GenAI", {
104
+ cause: agentGenerationError("imageGenAIAgent", imageAction, imageFileTarget),
105
+ });
88
106
  }
89
107
  };
90
108
  const imageGenAIAgentInfo = {
@@ -3,13 +3,16 @@ import path from "path";
3
3
  import { GraphAILogger } from "graphai";
4
4
  import OpenAI, { toFile } from "openai";
5
5
  import { provider2ImageAgent } from "../utils/provider2agent.js";
6
+ import { apiKeyMissingError, agentGenerationError, agentInvalidResponseError, imageAction, imageFileTarget } from "../utils/error_cause.js";
6
7
  // https://platform.openai.com/docs/guides/image-generation
7
8
  export const imageOpenaiAgent = async ({ namedInputs, params, config, }) => {
8
9
  const { prompt, referenceImages } = namedInputs;
9
10
  const { moderation, canvasSize, quality } = params;
10
11
  const { apiKey, baseURL } = { ...config };
11
12
  if (!apiKey) {
12
- throw new Error("OpenAI API key is required (OPENAI_API_KEY)");
13
+ throw new Error("OpenAI API key is required (OPENAI_API_KEY)", {
14
+ cause: apiKeyMissingError("imageOpenaiAgent", imageAction, "OPENAI_API_KEY"),
15
+ });
13
16
  }
14
17
  const model = params.model ?? provider2ImageAgent["openai"].defaultModel;
15
18
  const openai = new OpenAI({ apiKey, baseURL });
@@ -67,25 +70,33 @@ export const imageOpenaiAgent = async ({ namedInputs, params, config, }) => {
67
70
  }
68
71
  catch (error) {
69
72
  GraphAILogger.info("Failed to generate image:", error.message);
70
- throw error;
73
+ throw new Error("Failed to generate image with OpenAI", {
74
+ cause: agentGenerationError("imageOpenaiAgent", imageAction, imageFileTarget),
75
+ });
71
76
  }
72
77
  })();
73
78
  if (!response.data) {
74
- throw new Error(`response.data is undefined: ${response}`);
79
+ throw new Error(`response.data is undefined: ${response}`, {
80
+ cause: agentInvalidResponseError("imageOpenaiAgent", imageAction, imageFileTarget),
81
+ });
75
82
  }
76
83
  const url = response.data[0].url;
77
84
  if (!url) {
78
85
  // For gpt-image-1
79
86
  const image_base64 = response.data[0].b64_json;
80
87
  if (!image_base64) {
81
- throw new Error(`response.data[0].b64_json is undefined: ${response}`);
88
+ throw new Error(`response.data[0].b64_json is undefined: ${response}`, {
89
+ cause: agentInvalidResponseError("imageOpenaiAgent", imageAction, imageFileTarget),
90
+ });
82
91
  }
83
92
  return { buffer: Buffer.from(image_base64, "base64") };
84
93
  }
85
94
  // For dall-e-3
86
95
  const res = await fetch(url);
87
96
  if (!res.ok) {
88
- throw new Error(`Failed to fetch ${url}: ${res.status} ${res.statusText}`);
97
+ throw new Error(`Failed to fetch ${url}: ${res.status} ${res.statusText}`, {
98
+ cause: agentGenerationError("imageOpenaiAgent", imageAction, imageFileTarget),
99
+ });
89
100
  }
90
101
  // 2. Read the response as an ArrayBuffer
91
102
  const arrayBuffer = await res.arrayBuffer();
@@ -2,6 +2,7 @@ import { readFileSync } from "fs";
2
2
  import { GraphAILogger } from "graphai";
3
3
  import Replicate from "replicate";
4
4
  import { getAspectRatio } from "./movie_replicate_agent.js";
5
+ import { apiKeyMissingError, agentGenerationError, agentInvalidResponseError, imageAction, imageFileTarget, hasCause } from "../utils/error_cause.js";
5
6
  import { provider2ImageAgent } from "../utils/provider2agent.js";
6
7
  export const imageReplicateAgent = async ({ namedInputs, params, config, }) => {
7
8
  const { prompt, referenceImages } = namedInputs;
@@ -9,7 +10,9 @@ export const imageReplicateAgent = async ({ namedInputs, params, config, }) => {
9
10
  const model = params.model ?? provider2ImageAgent.replicate.defaultModel;
10
11
  const apiKey = config?.apiKey;
11
12
  if (!apiKey) {
12
- throw new Error("Replicate API key is required (REPLICATE_API_TOKEN)");
13
+ throw new Error("Replicate API key is required (REPLICATE_API_TOKEN)", {
14
+ cause: apiKeyMissingError("imageReplicateAgent", imageAction, "REPLICATE_API_TOKEN"),
15
+ });
13
16
  }
14
17
  const replicate = new Replicate({
15
18
  auth: apiKey,
@@ -31,17 +34,26 @@ export const imageReplicateAgent = async ({ namedInputs, params, config, }) => {
31
34
  const imageUrl = output[0].url();
32
35
  const imageResponse = await fetch(imageUrl);
33
36
  if (!imageResponse.ok) {
34
- throw new Error(`Error downloading video: ${imageResponse.status} - ${imageResponse.statusText}`);
37
+ throw new Error(`Error downloading image: ${imageResponse.status} - ${imageResponse.statusText}`, {
38
+ cause: agentGenerationError("imageReplicateAgent", imageAction, imageFileTarget),
39
+ });
35
40
  }
36
41
  const arrayBuffer = await imageResponse.arrayBuffer();
37
42
  const buffer = Buffer.from(arrayBuffer);
38
43
  return { buffer };
39
44
  }
40
- throw new Error("ERROR: generateImage returned undefined");
45
+ throw new Error("ERROR: generateImage returned undefined", {
46
+ cause: agentInvalidResponseError("imageReplicateAgent", imageAction, imageFileTarget),
47
+ });
41
48
  }
42
49
  catch (error) {
43
50
  GraphAILogger.info("Replicate generation error:", error);
44
- throw error;
51
+ if (hasCause(error) && error.cause) {
52
+ throw error;
53
+ }
54
+ throw new Error("Failed to generate image with Replicate", {
55
+ cause: agentGenerationError("imageReplicateAgent", imageAction, imageFileTarget),
56
+ });
45
57
  }
46
58
  };
47
59
  const imageReplicateAgentInfo = {
@@ -2,24 +2,31 @@ import { readFileSync, existsSync } from "fs";
2
2
  import { GraphAILogger } from "graphai";
3
3
  import Replicate from "replicate";
4
4
  import { provider2LipSyncAgent } from "../utils/provider2agent.js";
5
+ import { apiKeyMissingError, agentGenerationError, agentFileNotExistError, imageAction, movieFileTarget, audioFileTarget, hasCause, } from "../utils/error_cause.js";
5
6
  export const lipSyncReplicateAgent = async ({ namedInputs, params, config, }) => {
6
7
  const { movieFile, audioFile, imageFile } = namedInputs;
7
8
  const apiKey = config?.apiKey;
8
9
  const model = params.model ?? provider2LipSyncAgent.replicate.defaultModel;
9
10
  if (!apiKey) {
10
- throw new Error("Replicate API key is required (REPLICATE_API_TOKEN)");
11
+ throw new Error("Replicate API key is required (REPLICATE_API_TOKEN)", {
12
+ cause: apiKeyMissingError("lipSyncReplicateAgent", imageAction, "REPLICATE_API_TOKEN"),
13
+ });
11
14
  }
12
15
  const replicate = new Replicate({
13
16
  auth: apiKey,
14
17
  });
15
18
  if (!audioFile || !existsSync(audioFile)) {
16
- throw new Error(`lipSyncReplicateAgent audioFile not exist: ${audioFile}`);
19
+ throw new Error(`lipSyncReplicateAgent audioFile not exist: ${audioFile}`, {
20
+ cause: agentFileNotExistError("lipSyncReplicateAgent", imageAction, audioFileTarget, audioFile),
21
+ });
17
22
  }
18
23
  const audioBuffer = readFileSync(audioFile);
19
24
  const videoBuffer = movieFile ? readFileSync(movieFile) : undefined;
20
25
  const imageBuffer = imageFile ? readFileSync(imageFile) : undefined;
21
26
  if (!videoBuffer && !imageBuffer) {
22
- throw new Error("lipSyncReplicateAgent Either movieFile or imageFile is required");
27
+ throw new Error("lipSyncReplicateAgent Either movieFile or imageFile is required", {
28
+ cause: agentGenerationError("lipSyncReplicateAgent", imageAction, movieFileTarget),
29
+ });
23
30
  }
24
31
  const audioUri = `data:audio/wav;base64,${audioBuffer.toString("base64")}`;
25
32
  const videoUri = videoBuffer ? `data:video/quicktime;base64,${videoBuffer.toString("base64")}` : undefined;
@@ -35,7 +42,9 @@ export const lipSyncReplicateAgent = async ({ namedInputs, params, config, }) =>
35
42
  };
36
43
  const modelParams = provider2LipSyncAgent.replicate.modelParams[model];
37
44
  if (!modelParams) {
38
- throw new Error(`Model ${model} is not supported`);
45
+ throw new Error(`Model ${model} is not supported`, {
46
+ cause: agentGenerationError("lipSyncReplicateAgent", imageAction, movieFileTarget),
47
+ });
39
48
  }
40
49
  const videoParam = modelParams.video;
41
50
  const audioParam = modelParams.audio;
@@ -58,7 +67,9 @@ export const lipSyncReplicateAgent = async ({ namedInputs, params, config, }) =>
58
67
  const videoUrl = output.url();
59
68
  const videoResponse = await fetch(videoUrl);
60
69
  if (!videoResponse.ok) {
61
- throw new Error(`Error downloading video: ${videoResponse.status} - ${videoResponse.statusText}`);
70
+ throw new Error(`Error downloading video: ${videoResponse.status} - ${videoResponse.statusText}`, {
71
+ cause: agentGenerationError("lipSyncReplicateAgent", imageAction, movieFileTarget),
72
+ });
62
73
  }
63
74
  const arrayBuffer = await videoResponse.arrayBuffer();
64
75
  return { buffer: Buffer.from(arrayBuffer) };
@@ -67,7 +78,12 @@ export const lipSyncReplicateAgent = async ({ namedInputs, params, config, }) =>
67
78
  }
68
79
  catch (error) {
69
80
  GraphAILogger.info("Failed to generate lip sync:", error.message);
70
- throw error;
81
+ if (hasCause(error) && error.cause) {
82
+ throw error;
83
+ }
84
+ throw new Error("Failed to lipSync with Replicate", {
85
+ cause: agentGenerationError("lipSyncReplicateAgent", imageAction, movieFileTarget),
86
+ });
71
87
  }
72
88
  };
73
89
  const lipSyncReplicateAgentInfo = {
@@ -1,5 +1,6 @@
1
1
  import { readFileSync } from "fs";
2
2
  import { GraphAILogger, sleep } from "graphai";
3
+ import { apiKeyMissingError, agentGenerationError, agentInvalidResponseError, imageAction, movieFileTarget, hasCause } from "../utils/error_cause.js";
3
4
  import { GoogleGenAI, PersonGeneration } from "@google/genai";
4
5
  export const getAspectRatio = (canvasSize) => {
5
6
  if (canvasSize.width > canvasSize.height) {
@@ -19,7 +20,9 @@ export const movieGenAIAgent = async ({ namedInputs, params, config, }) => {
19
20
  const duration = params.duration ?? 8;
20
21
  const apiKey = config?.apiKey;
21
22
  if (!apiKey) {
22
- throw new Error("Google GenAI API key is required (GEMINI_API_KEY)");
23
+ throw new Error("Google GenAI API key is required (GEMINI_API_KEY)", {
24
+ cause: apiKeyMissingError("movieGenAIAgent", imageAction, "GEMINI_API_KEY"),
25
+ });
23
26
  }
24
27
  try {
25
28
  const ai = new GoogleGenAI({ apiKey });
@@ -55,11 +58,15 @@ export const movieGenAIAgent = async ({ namedInputs, params, config, }) => {
55
58
  response.operation = await ai.operations.getVideosOperation(response);
56
59
  }
57
60
  if (!response.operation.response?.generatedVideos) {
58
- throw new Error(`No video: ${JSON.stringify(response.operation, null, 2)}`);
61
+ throw new Error(`No video: ${JSON.stringify(response.operation, null, 2)}`, {
62
+ cause: agentInvalidResponseError("movieGenAIAgent", imageAction, movieFileTarget),
63
+ });
59
64
  }
60
65
  const video = response.operation.response.generatedVideos[0].video;
61
66
  if (!video) {
62
- throw new Error(`No video: ${JSON.stringify(response.operation, null, 2)}`);
67
+ throw new Error(`No video: ${JSON.stringify(response.operation, null, 2)}`, {
68
+ cause: agentInvalidResponseError("movieGenAIAgent", imageAction, movieFileTarget),
69
+ });
63
70
  }
64
71
  await ai.files.download({
65
72
  file: video,
@@ -70,7 +77,12 @@ export const movieGenAIAgent = async ({ namedInputs, params, config, }) => {
70
77
  }
71
78
  catch (error) {
72
79
  GraphAILogger.info("Failed to generate movie:", error.message);
73
- throw error;
80
+ if (hasCause(error) && error.cause) {
81
+ throw error;
82
+ }
83
+ throw new Error("Failed to generate movie with Google GenAI", {
84
+ cause: agentGenerationError("movieGenAIAgent", imageAction, movieFileTarget),
85
+ });
74
86
  }
75
87
  };
76
88
  const movieGenAIAgentInfo = {
@@ -1,6 +1,7 @@
1
1
  import { readFileSync } from "fs";
2
2
  import { GraphAILogger } from "graphai";
3
3
  import Replicate from "replicate";
4
+ import { apiKeyMissingError, agentGenerationError, agentInvalidResponseError, imageAction, movieFileTarget } from "../utils/error_cause.js";
4
5
  import { provider2MovieAgent } from "../utils/provider2agent.js";
5
6
  async function generateMovie(model, apiKey, prompt, imagePath, aspectRatio, duration) {
6
7
  const replicate = new Replicate({
@@ -28,7 +29,9 @@ async function generateMovie(model, apiKey, prompt, imagePath, aspectRatio, dura
28
29
  input[start_image] = base64Image;
29
30
  }
30
31
  else if (start_image === undefined) {
31
- throw new Error(`Model ${model} does not support image-to-video generation`);
32
+ throw new Error(`Model ${model} does not support image-to-video generation`, {
33
+ cause: agentGenerationError("movieReplicateAgent", imageAction, movieFileTarget),
34
+ });
32
35
  }
33
36
  else {
34
37
  input.image = base64Image;
@@ -41,7 +44,9 @@ async function generateMovie(model, apiKey, prompt, imagePath, aspectRatio, dura
41
44
  const videoUrl = output.url();
42
45
  const videoResponse = await fetch(videoUrl);
43
46
  if (!videoResponse.ok) {
44
- throw new Error(`Error downloading video: ${videoResponse.status} - ${videoResponse.statusText}`);
47
+ throw new Error(`Error downloading video: ${videoResponse.status} - ${videoResponse.statusText}`, {
48
+ cause: agentGenerationError("movieReplicateAgent", imageAction, movieFileTarget),
49
+ });
45
50
  }
46
51
  const arrayBuffer = await videoResponse.arrayBuffer();
47
52
  return Buffer.from(arrayBuffer);
@@ -71,7 +76,9 @@ export const movieReplicateAgent = async ({ namedInputs, params, config, }) => {
71
76
  const aspectRatio = getAspectRatio(params.canvasSize);
72
77
  const model = params.model ?? provider2MovieAgent.replicate.defaultModel;
73
78
  if (!provider2MovieAgent.replicate.modelParams[model]) {
74
- throw new Error(`Model ${model} is not supported`);
79
+ throw new Error(`Model ${model} is not supported`, {
80
+ cause: agentGenerationError("movieReplicateAgent", imageAction, movieFileTarget),
81
+ });
75
82
  }
76
83
  const duration = (() => {
77
84
  const durations = provider2MovieAgent.replicate.modelParams[model].durations;
@@ -84,23 +91,28 @@ export const movieReplicateAgent = async ({ namedInputs, params, config, }) => {
84
91
  }
85
92
  })();
86
93
  if (!provider2MovieAgent.replicate.modelParams[model].durations.includes(duration)) {
87
- throw new Error(`Duration ${duration} is not supported for model ${model}. Supported durations: ${provider2MovieAgent.replicate.modelParams[model].durations.join(", ")}`);
94
+ throw new Error(`Duration ${duration} is not supported for model ${model}. Supported durations: ${provider2MovieAgent.replicate.modelParams[model].durations.join(", ")}`, {
95
+ cause: agentGenerationError("movieReplicateAgent", imageAction, movieFileTarget),
96
+ });
88
97
  }
89
98
  const apiKey = config?.apiKey;
90
99
  if (!apiKey) {
91
- throw new Error("Replicate API key is required (REPLICATE_API_TOKEN)");
100
+ throw new Error("Replicate API key is required (REPLICATE_API_TOKEN)", {
101
+ cause: apiKeyMissingError("movieReplicateAgent", imageAction, "REPLICATE_API_TOKEN"),
102
+ });
92
103
  }
93
104
  try {
94
105
  const buffer = await generateMovie(model, apiKey, prompt, imagePath, aspectRatio, duration);
95
106
  if (buffer) {
96
107
  return { buffer };
97
108
  }
98
- throw new Error("ERROR: generateMovie returned undefined");
99
109
  }
100
110
  catch (error) {
101
111
  GraphAILogger.info("Failed to generate movie:", error.message);
102
- throw error;
103
112
  }
113
+ throw new Error("ERROR: generateMovie returned undefined", {
114
+ cause: agentInvalidResponseError("movieReplicateAgent", imageAction, movieFileTarget),
115
+ });
104
116
  };
105
117
  const movieReplicateAgentInfo = {
106
118
  name: "movieReplicateAgent",
@@ -2,12 +2,15 @@ import { readFileSync } from "fs";
2
2
  import { GraphAILogger } from "graphai";
3
3
  import Replicate from "replicate";
4
4
  import { provider2SoundEffectAgent } from "../utils/provider2agent.js";
5
+ import { apiKeyMissingError, agentGenerationError, imageAction, movieFileTarget, hasCause } from "../utils/error_cause.js";
5
6
  export const soundEffectReplicateAgent = async ({ namedInputs, params, config }) => {
6
7
  const { prompt, movieFile } = namedInputs;
7
8
  const apiKey = config?.apiKey;
8
9
  const model = params.model ?? provider2SoundEffectAgent.replicate.defaultModel;
9
10
  if (!apiKey) {
10
- throw new Error("Replicate API key is required (REPLICATE_API_TOKEN)");
11
+ throw new Error("Replicate API key is required (REPLICATE_API_TOKEN)", {
12
+ cause: apiKeyMissingError("soundEffectReplicateAgent", imageAction, "REPLICATE_API_TOKEN"),
13
+ });
11
14
  }
12
15
  const replicate = new Replicate({
13
16
  auth: apiKey,
@@ -32,7 +35,9 @@ export const soundEffectReplicateAgent = async ({ namedInputs, params, config })
32
35
  const videoUrl = output.url();
33
36
  const videoResponse = await fetch(videoUrl);
34
37
  if (!videoResponse.ok) {
35
- throw new Error(`Error downloading video: ${videoResponse.status} - ${videoResponse.statusText}`);
38
+ throw new Error(`Error downloading video: ${videoResponse.status} - ${videoResponse.statusText}`, {
39
+ cause: agentGenerationError("soundEffectReplicateAgent", imageAction, movieFileTarget),
40
+ });
36
41
  }
37
42
  const arrayBuffer = await videoResponse.arrayBuffer();
38
43
  return { buffer: Buffer.from(arrayBuffer) };
@@ -41,7 +46,12 @@ export const soundEffectReplicateAgent = async ({ namedInputs, params, config })
41
46
  }
42
47
  catch (error) {
43
48
  GraphAILogger.info("Failed to generate sound effect:", error.message);
44
- throw error;
49
+ if (hasCause(error) && error.cause) {
50
+ throw error;
51
+ }
52
+ throw new Error("Failed to generate sound effect with Replicate", {
53
+ cause: agentGenerationError("soundEffectReplicateAgent", imageAction, movieFileTarget),
54
+ });
45
55
  }
46
56
  };
47
57
  const soundEffectReplicateAgentInfo = {
@@ -1,5 +1,6 @@
1
1
  import { assert } from "graphai";
2
2
  import { tavily } from "@tavily/core";
3
+ import { apiKeyMissingError, agentGenerationError } from "../utils/error_cause.js";
3
4
  const getTavilyApiKey = (params, config) => {
4
5
  if (params?.apiKey) {
5
6
  return params.apiKey;
@@ -14,7 +15,7 @@ export const tavilySearchAgent = async ({ namedInputs, params, config, }) => {
14
15
  assert(!!query, "tavilySearchAgent: query is required! set inputs: { query: 'search terms' }");
15
16
  try {
16
17
  const apiKey = getTavilyApiKey(params, config);
17
- assert(apiKey, "Tavily API key is required. Please set the TAVILY_API_KEY environment variable or provide it in params/config.");
18
+ assert(apiKey, "Tavily API key is required. Please set the TAVILY_API_KEY environment variable or provide it in params/config.", false, apiKeyMissingError("tavilySearchAgent", "search", "TAVILY_API_KEY"));
18
19
  const tvly = tavily({ apiKey });
19
20
  // Convert params to SDK options format
20
21
  const sdkOptions = {};
@@ -30,7 +31,9 @@ export const tavilySearchAgent = async ({ namedInputs, params, config, }) => {
30
31
  return response;
31
32
  }
32
33
  catch (error) {
33
- throw new Error(`Tavily search failed: ${error instanceof Error ? error.message : String(error)}`);
34
+ throw new Error(`Tavily search failed: ${error instanceof Error ? error.message : String(error)}`, {
35
+ cause: agentGenerationError("tavilySearchAgent", "search", "searchResults"),
36
+ });
34
37
  }
35
38
  };
36
39
  const tavilySearchAgentInfo = {
@@ -1,14 +1,19 @@
1
1
  import { GraphAILogger } from "graphai";
2
2
  import { provider2TTSAgent } from "../utils/provider2agent.js";
3
+ import { apiKeyMissingError, agentGenerationError, audioAction, audioFileTarget } from "../utils/error_cause.js";
3
4
  export const ttsElevenlabsAgent = async ({ namedInputs, params, config, }) => {
4
5
  const { text } = namedInputs;
5
6
  const { voice, model, stability, similarityBoost, suppressError } = params;
6
7
  const apiKey = config?.apiKey;
7
8
  if (!apiKey) {
8
- throw new Error("ElevenLabs API key is required (ELEVENLABS_API_KEY)");
9
+ throw new Error("ElevenLabs API key is required (ELEVENLABS_API_KEY)", {
10
+ cause: apiKeyMissingError("ttsElevenlabsAgent", audioAction, "ELEVENLABS_API_KEY"),
11
+ });
9
12
  }
10
13
  if (!voice) {
11
- throw new Error("ELEVENLABS Voice ID is required");
14
+ throw new Error("ELEVENLABS Voice ID is required", {
15
+ cause: agentGenerationError("ttsElevenlabsAgent", audioAction, audioFileTarget),
16
+ });
12
17
  }
13
18
  try {
14
19
  const requestBody = {
@@ -30,7 +35,9 @@ export const ttsElevenlabsAgent = async ({ namedInputs, params, config, }) => {
30
35
  body: JSON.stringify(requestBody),
31
36
  });
32
37
  if (!response.ok) {
33
- throw new Error(`Eleven Labs API error: ${response.status} ${response.statusText}`);
38
+ throw new Error(`Eleven Labs API error: ${response.status} ${response.statusText}`, {
39
+ cause: agentGenerationError("ttsElevenlabsAgent", audioAction, audioFileTarget),
40
+ });
34
41
  }
35
42
  const arrayBuffer = await response.arrayBuffer();
36
43
  const buffer = Buffer.from(arrayBuffer);
@@ -43,7 +50,9 @@ export const ttsElevenlabsAgent = async ({ namedInputs, params, config, }) => {
43
50
  };
44
51
  }
45
52
  GraphAILogger.info(e);
46
- throw new Error("TTS Eleven Labs Error");
53
+ throw new Error("TTS Eleven Labs Error", {
54
+ cause: agentGenerationError("ttsElevenlabsAgent", audioAction, audioFileTarget),
55
+ });
47
56
  }
48
57
  };
49
58
  const ttsElevenlabsAgentInfo = {
@@ -1,5 +1,6 @@
1
1
  import { GraphAILogger } from "graphai";
2
2
  import * as textToSpeech from "@google-cloud/text-to-speech";
3
+ import { agentGenerationError, audioAction, audioFileTarget } from "../utils/error_cause.js";
3
4
  const client = new textToSpeech.TextToSpeechClient();
4
5
  export const ttsGoogleAgent = async ({ namedInputs, params }) => {
5
6
  const { text } = namedInputs;
@@ -33,7 +34,9 @@ export const ttsGoogleAgent = async ({ namedInputs, params }) => {
33
34
  };
34
35
  }
35
36
  GraphAILogger.info(e);
36
- throw new Error("TTS Google Error");
37
+ throw new Error("TTS Google Error", {
38
+ cause: agentGenerationError("ttsGoogleAgent", audioAction, audioFileTarget),
39
+ });
37
40
  }
38
41
  };
39
42
  const ttsGoogleAgentInfo = {
@@ -1,4 +1,5 @@
1
1
  import { GraphAILogger } from "graphai";
2
+ import { apiKeyMissingError, agentGenerationError, audioAction, audioFileTarget } from "../utils/error_cause.js";
2
3
  /*
3
4
  const errorMessage = [
4
5
  "TTS NijiVoice: No API key. ",
@@ -12,7 +13,9 @@ export const ttsNijivoiceAgent = async ({ params, namedInputs, config, }) => {
12
13
  const { apiKey } = config ?? {};
13
14
  const { text } = namedInputs;
14
15
  if (!apiKey) {
15
- throw new Error("NijiVoice API key is required (NIJIVOICE_API_KEY)");
16
+ throw new Error("NijiVoice API key is required (NIJIVOICE_API_KEY)", {
17
+ cause: apiKeyMissingError("ttsNijivoiceAgent", audioAction, "NIJIVOICE_API_KEY"),
18
+ });
16
19
  }
17
20
  const url = `https://api.nijivoice.com/api/platform/v1/voice-actors/${voice}/generate-voice`;
18
21
  const options = {
@@ -42,7 +45,9 @@ export const ttsNijivoiceAgent = async ({ params, namedInputs, config, }) => {
42
45
  };
43
46
  }
44
47
  GraphAILogger.info(voiceJson);
45
- throw new Error("TTS Nijivoice Error");
48
+ throw new Error("TTS Nijivoice Error", {
49
+ cause: agentGenerationError("ttsNijivoiceAgent", audioAction, audioFileTarget),
50
+ });
46
51
  }
47
52
  catch (e) {
48
53
  if (suppressError) {
@@ -51,7 +56,9 @@ export const ttsNijivoiceAgent = async ({ params, namedInputs, config, }) => {
51
56
  };
52
57
  }
53
58
  GraphAILogger.info(e);
54
- throw new Error("TTS Nijivoice Error");
59
+ throw new Error("TTS Nijivoice Error", {
60
+ cause: agentGenerationError("ttsNijivoiceAgent", audioAction, audioFileTarget),
61
+ });
55
62
  }
56
63
  };
57
64
  const ttsNijivoiceAgentInfo = {
@@ -1,12 +1,15 @@
1
1
  import { GraphAILogger } from "graphai";
2
2
  import OpenAI from "openai";
3
3
  import { provider2TTSAgent } from "../utils/provider2agent.js";
4
+ import { apiKeyMissingError, agentGenerationError, audioAction, audioFileTarget } from "../utils/error_cause.js";
4
5
  export const ttsOpenaiAgent = async ({ namedInputs, params, config, }) => {
5
6
  const { text } = namedInputs;
6
7
  const { model, voice, suppressError, instructions } = params;
7
8
  const { apiKey, baseURL } = config ?? {};
8
9
  if (!apiKey) {
9
- throw new Error("OpenAI API key is required (OPENAI_API_KEY)");
10
+ throw new Error("OpenAI API key is required (OPENAI_API_KEY)", {
11
+ cause: apiKeyMissingError("ttsOpenaiAgent", audioAction, "OPENAI_API_KEY"),
12
+ });
10
13
  }
11
14
  const openai = new OpenAI({ apiKey, baseURL });
12
15
  try {
@@ -33,12 +36,16 @@ export const ttsOpenaiAgent = async ({ namedInputs, params, config, }) => {
33
36
  if (e && typeof e === "object" && "error" in e) {
34
37
  GraphAILogger.info("tts_openai_agent: ");
35
38
  GraphAILogger.info(e.error);
36
- throw new Error("TTS OpenAI Error: " + JSON.stringify(e.error, null, 2));
39
+ throw new Error("TTS OpenAI Error: " + JSON.stringify(e.error, null, 2), {
40
+ cause: agentGenerationError("ttsOpenaiAgent", audioAction, audioFileTarget),
41
+ });
37
42
  }
38
43
  else if (e instanceof Error) {
39
44
  GraphAILogger.info("tts_openai_agent: ");
40
45
  GraphAILogger.info(e.message);
41
- throw new Error("TTS OpenAI Error: " + e.message);
46
+ throw new Error("TTS OpenAI Error: " + e.message, {
47
+ cause: agentGenerationError("ttsOpenaiAgent", audioAction, audioFileTarget),
48
+ });
42
49
  }
43
50
  }
44
51
  };
@@ -4,6 +4,7 @@ export * from "./utils/const.js";
4
4
  export * from "./utils/string.js";
5
5
  export * from "./utils/utils.js";
6
6
  export * from "./utils/prompt.js";
7
+ export * from "./utils/error_cause.js";
7
8
  export * from "./methods/mulmo_presentation_style.js";
8
9
  export * from "./methods/mulmo_script.js";
9
10
  export * from "./methods/mulmo_studio_context.js";
@@ -5,6 +5,7 @@ export * from "./utils/const.js";
5
5
  export * from "./utils/string.js";
6
6
  export * from "./utils/utils.js";
7
7
  export * from "./utils/prompt.js";
8
+ export * from "./utils/error_cause.js";
8
9
  export * from "./methods/mulmo_presentation_style.js";
9
10
  export * from "./methods/mulmo_script.js";
10
11
  export * from "./methods/mulmo_studio_context.js";
@@ -1,39 +1,113 @@
1
+ /**
2
+ * Error Definitions for i18n Notifications
3
+ * ----------------------------------------
4
+ * This file provides a set of standardized error action/type/target constants
5
+ * and factory functions that enrich error objects with structured metadata.
6
+ *
7
+ * ## Purpose
8
+ * - Attach `cause` data to `Error` objects for vue-i18n.
9
+ * - Generate consistent i18n keys in the form:
10
+ * notify.error.{action}.{type}[.{target}]
11
+ * - Provide contextual data (e.g., beatIndex, fileName, agentName) for use in
12
+ * translation strings.
13
+ *
14
+ * ## Constants
15
+ * - `type`: describes the error type (e.g., fileNotExist, urlFileNotFound).
16
+ * - `action`: the operation being performed (e.g., movie, image, audio).
17
+ * - `target`: the resource involved (e.g., audioFile, imageFile).
18
+ *
19
+ * ## Factory Functions
20
+ * Each factory function (e.g., getAudioInputIdsError, audioCheckerError) returns
21
+ * a plain object with:
22
+ * - `type` → error type constant
23
+ * - `action` → action constant
24
+ * - `target` → target constant (optional)
25
+ * - `agentName` → name of the agent/tool that produced the error
26
+ * - `beatIndex` → index of the beat in the current script
27
+ * - `fileName` → file name or identifier (if relevant)
28
+ *
29
+ * ## i18n Integration
30
+ * - The UI consumes the generated `{ action, type, target, ... }` to build the i18n key.
31
+ * - Example:
32
+ * notify.error.movie.fileNotExist.audioFile
33
+ * - Interpolation values (beatIndex, fileName, etc.) are passed as `data` for
34
+ * translations.
35
+ *
36
+ * ## Notes
37
+ * - If `target` is not required, omit it.
38
+ * - When adding new actions/types/targets, check for consistency with existing ones.
39
+ * - Use descriptive but concise names to avoid translation conflicts.
40
+ *
41
+ * ## Usage in Error Handling
42
+ * - When throwing manually:
43
+ * `throw new Error("message", { cause });`
44
+ * - When using assertions:
45
+ * `assert(condition, message, false, causeObject);`
46
+ * (set the 3rd parameter to `false` and pass the `cause` object as the 4th)
47
+ */
48
+ export declare const urlFileNotFoundType = "urlFileNotFound";
49
+ export declare const fileNotExistType = "fileNotExist";
50
+ export declare const unknownMediaType = "unknownMedia";
51
+ export declare const sourceUndefinedType = "undefinedSourceType";
52
+ export declare const apiErrorType = "apiError";
53
+ export declare const apiKeyMissingType = "apiKeyMissing";
54
+ export declare const invalidResponseType = "invalidResponse";
55
+ export declare const movieAction = "movie";
56
+ export declare const imageAction = "images";
57
+ export declare const audioAction = "audio";
58
+ export declare const imageReferenceAction = "imageReference";
59
+ export declare const translateAction = "translate";
60
+ export declare const audioFileTarget = "audioFile";
61
+ export declare const imageFileTarget = "imageFile";
62
+ export declare const movieFileTarget = "movieFile";
63
+ export declare const videoSourceTarget = "videoSource";
64
+ export declare const audioSourceTarget = "audioSource";
65
+ export declare const codeTextTarget = "codeText";
66
+ export declare const agentFileNotExistError: (agentName: string, action: string, target: string, fileName: string, beatIndex?: number) => {
67
+ beatIndex?: number | undefined;
68
+ type: string;
69
+ action: string;
70
+ target: string;
71
+ agentName: string;
72
+ fileName: string;
73
+ };
1
74
  export declare const getAudioInputIdsError: (index: number, fileName: string) => {
75
+ beatIndex?: number | undefined;
2
76
  type: string;
3
77
  action: string;
4
78
  target: string;
5
79
  agentName: string;
6
- beatIndex: number;
7
80
  fileName: string;
8
81
  };
9
82
  export declare const audioCheckerError: (index: number, fileName: string) => {
83
+ beatIndex?: number | undefined;
10
84
  type: string;
11
85
  action: string;
12
86
  target: string;
13
87
  agentName: string;
14
- beatIndex: number;
15
88
  fileName: string;
16
89
  };
17
- export declare const createVideoSourceError: (index: number) => {
90
+ export declare const createVideoFileError: (index: number, fileName: string) => {
91
+ beatIndex?: number | undefined;
18
92
  type: string;
19
93
  action: string;
94
+ target: string;
20
95
  agentName: string;
21
- beatIndex: number;
96
+ fileName: string;
22
97
  };
23
- export declare const invalidAudioSourceError: (beatIndex: number) => {
98
+ export declare const createVideoSourceError: (index: number) => {
24
99
  type: string;
25
100
  action: string;
26
101
  target: string;
27
102
  agentName: string;
28
103
  beatIndex: number;
29
104
  };
30
- export declare const createVideoFileError: (index: number, fileName: string) => {
105
+ export declare const invalidAudioSourceError: (beatIndex: number) => {
31
106
  type: string;
32
107
  action: string;
33
108
  target: string;
34
109
  agentName: string;
35
110
  beatIndex: number;
36
- fileName: string;
37
111
  };
38
112
  export declare const downLoadReferenceImageError: (key: string, url: string) => {
39
113
  type: string;
@@ -67,3 +141,32 @@ export declare const imagePluginUnknownMediaError: (imageType: string) => {
67
141
  action: string;
68
142
  target: string;
69
143
  };
144
+ export declare const apiKeyMissingError: (agentName: string, action: string, envVarName: string) => {
145
+ type: string;
146
+ action: string;
147
+ agentName: string;
148
+ envVarName: string;
149
+ };
150
+ export declare const agentGenerationError: (agentName: string, action: string, target: string, beatIndex?: number) => {
151
+ beatIndex?: number | undefined;
152
+ type: string;
153
+ action: string;
154
+ target: string;
155
+ agentName: string;
156
+ };
157
+ export declare const agentInvalidResponseError: (agentName: string, action: string, target: string, beatIndex?: number) => {
158
+ beatIndex?: number | undefined;
159
+ type: string;
160
+ action: string;
161
+ target: string;
162
+ agentName: string;
163
+ };
164
+ export declare const translateApiKeyMissingError: () => {
165
+ type: string;
166
+ action: string;
167
+ agentName: string;
168
+ envVarName: string;
169
+ };
170
+ export declare const hasCause: (err: unknown) => err is Error & {
171
+ cause: unknown;
172
+ };
@@ -1,35 +1,97 @@
1
- const urlFileNotFoundType = "urlFileNotFound";
2
- const fileNotExistType = "fileNotExist";
3
- const unknownMediaType = "unknownMedia";
4
- const sourceUndefinedType = "undefinedSourceType";
5
- const movieAction = "movie";
6
- const imageAction = "images";
7
- const aucioAction = "audio";
8
- const imageReferenceAction = "imageReference";
9
- export const getAudioInputIdsError = (index, fileName) => {
1
+ /**
2
+ * Error Definitions for i18n Notifications
3
+ * ----------------------------------------
4
+ * This file provides a set of standardized error action/type/target constants
5
+ * and factory functions that enrich error objects with structured metadata.
6
+ *
7
+ * ## Purpose
8
+ * - Attach `cause` data to `Error` objects for vue-i18n.
9
+ * - Generate consistent i18n keys in the form:
10
+ * notify.error.{action}.{type}[.{target}]
11
+ * - Provide contextual data (e.g., beatIndex, fileName, agentName) for use in
12
+ * translation strings.
13
+ *
14
+ * ## Constants
15
+ * - `type`: describes the error type (e.g., fileNotExist, urlFileNotFound).
16
+ * - `action`: the operation being performed (e.g., movie, image, audio).
17
+ * - `target`: the resource involved (e.g., audioFile, imageFile).
18
+ *
19
+ * ## Factory Functions
20
+ * Each factory function (e.g., getAudioInputIdsError, audioCheckerError) returns
21
+ * a plain object with:
22
+ * - `type` → error type constant
23
+ * - `action` → action constant
24
+ * - `target` → target constant (optional)
25
+ * - `agentName` → name of the agent/tool that produced the error
26
+ * - `beatIndex` → index of the beat in the current script
27
+ * - `fileName` → file name or identifier (if relevant)
28
+ *
29
+ * ## i18n Integration
30
+ * - The UI consumes the generated `{ action, type, target, ... }` to build the i18n key.
31
+ * - Example:
32
+ * notify.error.movie.fileNotExist.audioFile
33
+ * - Interpolation values (beatIndex, fileName, etc.) are passed as `data` for
34
+ * translations.
35
+ *
36
+ * ## Notes
37
+ * - If `target` is not required, omit it.
38
+ * - When adding new actions/types/targets, check for consistency with existing ones.
39
+ * - Use descriptive but concise names to avoid translation conflicts.
40
+ *
41
+ * ## Usage in Error Handling
42
+ * - When throwing manually:
43
+ * `throw new Error("message", { cause });`
44
+ * - When using assertions:
45
+ * `assert(condition, message, false, causeObject);`
46
+ * (set the 3rd parameter to `false` and pass the `cause` object as the 4th)
47
+ */
48
+ // Error Types
49
+ export const urlFileNotFoundType = "urlFileNotFound";
50
+ export const fileNotExistType = "fileNotExist";
51
+ export const unknownMediaType = "unknownMedia";
52
+ export const sourceUndefinedType = "undefinedSourceType";
53
+ export const apiErrorType = "apiError";
54
+ export const apiKeyMissingType = "apiKeyMissing";
55
+ export const invalidResponseType = "invalidResponse";
56
+ // Actions
57
+ export const movieAction = "movie";
58
+ export const imageAction = "images";
59
+ export const audioAction = "audio";
60
+ export const imageReferenceAction = "imageReference";
61
+ export const translateAction = "translate";
62
+ // Targets
63
+ export const audioFileTarget = "audioFile";
64
+ export const imageFileTarget = "imageFile";
65
+ export const movieFileTarget = "movieFile";
66
+ export const videoSourceTarget = "videoSource";
67
+ export const audioSourceTarget = "audioSource";
68
+ export const codeTextTarget = "codeText";
69
+ // Agent File Not Exist Errors
70
+ export const agentFileNotExistError = (agentName, action, target, fileName, beatIndex) => {
10
71
  return {
11
72
  type: fileNotExistType,
12
- action: movieAction,
13
- target: "audioFile",
14
- agentName: "combineAudioFiles",
15
- beatIndex: index,
73
+ action,
74
+ target,
75
+ agentName,
16
76
  fileName,
77
+ ...(beatIndex !== undefined && { beatIndex }),
17
78
  };
18
79
  };
80
+ export const getAudioInputIdsError = (index, fileName) => {
81
+ return agentFileNotExistError("combineAudioFiles", movieAction, audioFileTarget, fileName, index);
82
+ };
19
83
  export const audioCheckerError = (index, fileName) => {
20
- return {
21
- type: fileNotExistType,
22
- action: imageAction,
23
- target: "imageFile",
24
- agentName: "audioChecker",
25
- beatIndex: index,
26
- fileName,
27
- };
84
+ return agentFileNotExistError("audioChecker", imageAction, imageFileTarget, fileName, index);
28
85
  };
86
+ export const createVideoFileError = (index, fileName) => {
87
+ return agentFileNotExistError("createVideo", movieAction, imageFileTarget, fileName, index);
88
+ };
89
+ // undefinedSource
29
90
  export const createVideoSourceError = (index) => {
30
91
  return {
31
92
  type: sourceUndefinedType,
32
93
  action: movieAction,
94
+ target: videoSourceTarget,
33
95
  agentName: "createVideo",
34
96
  beatIndex: index,
35
97
  };
@@ -37,27 +99,18 @@ export const createVideoSourceError = (index) => {
37
99
  export const invalidAudioSourceError = (beatIndex) => {
38
100
  return {
39
101
  type: sourceUndefinedType,
40
- action: aucioAction,
41
- target: "audioSource",
102
+ action: audioAction,
103
+ target: audioSourceTarget,
42
104
  agentName: "getAudioPathOrUrl",
43
105
  beatIndex,
44
106
  };
45
107
  };
46
- export const createVideoFileError = (index, fileName) => {
47
- return {
48
- type: fileNotExistType,
49
- action: movieAction,
50
- target: "imageFile",
51
- agentName: "createVideo",
52
- beatIndex: index,
53
- fileName,
54
- };
55
- };
108
+ // 404
56
109
  export const downLoadReferenceImageError = (key, url) => {
57
110
  return {
58
111
  type: urlFileNotFoundType,
59
112
  action: imageReferenceAction,
60
- target: "imageFile",
113
+ target: imageFileTarget,
61
114
  agentName: "downloadUrl",
62
115
  key,
63
116
  url,
@@ -67,7 +120,7 @@ export const downloadImagePluginError = (url, imageType) => {
67
120
  return {
68
121
  type: urlFileNotFoundType,
69
122
  action: imageAction,
70
- target: imageType,
123
+ target: imageType === "image" ? imageFileTarget : movieFileTarget,
71
124
  agentName: "imagePlugin",
72
125
  url,
73
126
  };
@@ -76,11 +129,12 @@ export const getTextError = (url) => {
76
129
  return {
77
130
  type: urlFileNotFoundType,
78
131
  action: imageAction,
79
- target: "code",
132
+ target: codeTextTarget,
80
133
  agentName: "mermaid",
81
134
  url,
82
135
  };
83
136
  };
137
+ //
84
138
  export const imageReferenceUnknownMediaError = (key) => {
85
139
  return {
86
140
  type: unknownMediaType,
@@ -95,3 +149,44 @@ export const imagePluginUnknownMediaError = (imageType) => {
95
149
  target: imageType,
96
150
  };
97
151
  };
152
+ // Agent API Key Errors
153
+ export const apiKeyMissingError = (agentName, action, envVarName) => {
154
+ return {
155
+ type: apiKeyMissingType,
156
+ action,
157
+ agentName,
158
+ envVarName,
159
+ };
160
+ };
161
+ // Agent API/Generation Errors
162
+ export const agentGenerationError = (agentName, action, target, beatIndex) => {
163
+ return {
164
+ type: apiErrorType,
165
+ action,
166
+ target,
167
+ agentName,
168
+ ...(beatIndex !== undefined && { beatIndex }),
169
+ };
170
+ };
171
+ // Agent Invalid Response Errors
172
+ export const agentInvalidResponseError = (agentName, action, target, beatIndex) => {
173
+ return {
174
+ type: invalidResponseType,
175
+ action,
176
+ target,
177
+ agentName,
178
+ ...(beatIndex !== undefined && { beatIndex }),
179
+ };
180
+ };
181
+ // Translation Errors
182
+ export const translateApiKeyMissingError = () => {
183
+ return {
184
+ type: apiKeyMissingType,
185
+ action: translateAction,
186
+ agentName: "translate",
187
+ envVarName: "OPENAI_API_KEY",
188
+ };
189
+ };
190
+ export const hasCause = (err) => {
191
+ return err instanceof Error && "cause" in err;
192
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mulmocast",
3
- "version": "1.2.44",
3
+ "version": "1.2.46",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "lib/index.node.js",