@juspay/neurolink 9.22.2 → 9.23.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/adapters/video/directorPipeline.d.ts +31 -0
  3. package/dist/adapters/video/directorPipeline.js +516 -0
  4. package/dist/adapters/video/ffmpegAdapter.d.ts +78 -0
  5. package/dist/adapters/video/ffmpegAdapter.js +206 -0
  6. package/dist/adapters/video/frameExtractor.d.ts +28 -0
  7. package/dist/adapters/video/frameExtractor.js +143 -0
  8. package/dist/adapters/video/vertexVideoHandler.d.ts +25 -25
  9. package/dist/adapters/video/vertexVideoHandler.js +173 -42
  10. package/dist/adapters/video/videoMerger.d.ts +22 -0
  11. package/dist/adapters/video/videoMerger.js +171 -0
  12. package/dist/constants/index.d.ts +1 -0
  13. package/dist/constants/index.js +2 -0
  14. package/dist/constants/videoErrors.d.ts +45 -0
  15. package/dist/constants/videoErrors.js +46 -0
  16. package/dist/core/baseProvider.js +42 -1
  17. package/dist/lib/adapters/video/directorPipeline.d.ts +31 -0
  18. package/dist/lib/adapters/video/directorPipeline.js +517 -0
  19. package/dist/lib/adapters/video/ffmpegAdapter.d.ts +78 -0
  20. package/dist/lib/adapters/video/ffmpegAdapter.js +207 -0
  21. package/dist/lib/adapters/video/frameExtractor.d.ts +28 -0
  22. package/dist/lib/adapters/video/frameExtractor.js +144 -0
  23. package/dist/lib/adapters/video/vertexVideoHandler.d.ts +25 -25
  24. package/dist/lib/adapters/video/vertexVideoHandler.js +173 -42
  25. package/dist/lib/adapters/video/videoMerger.d.ts +22 -0
  26. package/dist/lib/adapters/video/videoMerger.js +172 -0
  27. package/dist/lib/constants/index.d.ts +1 -0
  28. package/dist/lib/constants/index.js +2 -0
  29. package/dist/lib/constants/videoErrors.d.ts +45 -0
  30. package/dist/lib/constants/videoErrors.js +47 -0
  31. package/dist/lib/core/baseProvider.js +42 -1
  32. package/dist/lib/types/content.d.ts +1 -1
  33. package/dist/lib/types/generateTypes.d.ts +18 -1
  34. package/dist/lib/types/multimodal.d.ts +64 -4
  35. package/dist/lib/types/multimodal.js +36 -1
  36. package/dist/lib/utils/parameterValidation.d.ts +8 -1
  37. package/dist/lib/utils/parameterValidation.js +80 -1
  38. package/dist/types/content.d.ts +1 -1
  39. package/dist/types/generateTypes.d.ts +18 -1
  40. package/dist/types/multimodal.d.ts +64 -4
  41. package/dist/types/multimodal.js +36 -1
  42. package/dist/utils/parameterValidation.d.ts +8 -1
  43. package/dist/utils/parameterValidation.js +80 -1
  44. package/package.json +1 -1
@@ -12,38 +12,17 @@
12
12
  import { readFile } from "node:fs/promises";
13
13
  import { ErrorCategory, ErrorSeverity } from "../../constants/enums.js";
14
14
  import { TIMEOUTS } from "../../constants/timeouts.js";
15
+ import { VIDEO_ERROR_CODES } from "../../constants/videoErrors.js";
15
16
  import { isAbortError, NeuroLinkError, withTimeout, } from "../../utils/errorHandling.js";
16
17
  import { logger } from "../../utils/logger.js";
17
18
  // ============================================================================
18
- // VIDEO ERROR CODES
19
+ // VIDEO ERROR CODES (Re-exported for backward compatibility)
19
20
  // ============================================================================
20
21
  /**
21
- * Video generation runtime error codes
22
- *
23
- * These are for runtime/execution errors during video generation.
24
- * Pure option/shape validation (missing image option, invalid config values, etc.)
25
- * is handled by parameterValidation.ts using ERROR_CODES from errorHandling.ts.
26
- *
27
- * Error categorization:
28
- * - INVALID_INPUT → ErrorCategory.execution (runtime I/O failures)
29
- * - parameterValidation errors → ErrorCategory.validation (schema/option issues)
30
- *
31
- * Following TTS pattern (TTS_ERROR_CODES + TTSError in ttsProcessor.ts)
22
+ * Video error codes - re-exported from constants module for backward compatibility.
23
+ * @see {@link VIDEO_ERROR_CODES} in constants/videoErrors.ts for definitions
32
24
  */
33
- export const VIDEO_ERROR_CODES = {
34
- /** Video generation API call failed */
35
- GENERATION_FAILED: "VIDEO_GENERATION_FAILED",
36
- /** Provider (Vertex AI) not properly configured */
37
- PROVIDER_NOT_CONFIGURED: "VIDEO_PROVIDER_NOT_CONFIGURED",
38
- /** Polling for video completion timed out */
39
- POLL_TIMEOUT: "VIDEO_POLL_TIMEOUT",
40
- /**
41
- * Runtime I/O error during input processing.
42
- * Used for: failed URL fetch, failed file read, corrupt/unreadable buffer.
43
- * NOT for: missing options or invalid config shapes (use parameterValidation).
44
- */
45
- INVALID_INPUT: "VIDEO_INVALID_INPUT",
46
- };
25
+ export { VIDEO_ERROR_CODES };
47
26
  /**
48
27
  * Video generation error class
49
28
  * Extends NeuroLinkError for consistent error handling across the SDK
@@ -71,6 +50,8 @@ const VIDEO_GENERATION_TIMEOUT_MS = 180000;
71
50
  const POLL_INTERVAL_MS = 5000;
72
51
  /** Full model name for Veo 3.1 (IMPORTANT: not just "veo-3.1") */
73
52
  const VEO_MODEL = "veo-3.1-generate-001";
53
+ /** Full model name for Veo 3.1 Fast (used for transitions) */
54
+ const VEO_FAST_MODEL = "veo-3.1-fast-generate-001";
74
55
  /** Default location for Vertex AI */
75
56
  const DEFAULT_LOCATION = "us-central1";
76
57
  // ============================================================================
@@ -592,35 +573,185 @@ async function makePollRequest(pollEndpoint, operationName, accessToken, timeout
592
573
  * @throws {VideoError} On API error, timeout, or missing video data
593
574
  */
594
575
  async function pollVideoOperation(operationName, accessToken, project, location, timeoutMs) {
576
+ return pollOperation(VEO_MODEL, operationName, accessToken, project, location, timeoutMs);
577
+ }
578
+ // ============================================================================
579
+ // TRANSITION GENERATION (Director Mode)
580
+ // ============================================================================
581
+ /**
582
+ * Generate a transition clip using Veo 3.1 Fast's first-and-last-frame interpolation.
583
+ *
584
+ * This calls the Veo API with both `image` (first frame) and `lastFrame` (last frame),
585
+ * producing a video that smoothly interpolates between the two frames.
586
+ *
587
+ * @param firstFrame - JPEG buffer of the first frame (last frame of clip N)
588
+ * @param lastFrame - JPEG buffer of the last frame (first frame of clip N+1)
589
+ * @param prompt - Transition prompt describing desired visual flow
590
+ * @param options - Video output options (resolution, aspect ratio, audio)
591
+ * @param durationSeconds - Duration of the transition clip (4, 6, or 8)
592
+ * @param region - Vertex AI region override
593
+ * @returns Video buffer of the transition clip
594
+ *
595
+ * @throws {VideoError} When API returns an error or polling times out
596
+ */
597
+ export async function generateTransitionWithVertex(firstFrame, lastFrame, prompt, options = {}, durationSeconds = 4, region) {
598
+ if (!isVertexVideoConfigured()) {
599
+ throw new VideoError({
600
+ code: VIDEO_ERROR_CODES.PROVIDER_NOT_CONFIGURED,
601
+ message: "Vertex AI credentials not configured for transition generation.",
602
+ category: ErrorCategory.CONFIGURATION,
603
+ severity: ErrorSeverity.HIGH,
604
+ retriable: false,
605
+ });
606
+ }
607
+ const config = await getVertexConfig();
608
+ const project = config.project;
609
+ const location = region || config.location;
595
610
  const startTime = Date.now();
596
- // Use fetchPredictOperation endpoint - this is MODEL-SPECIFIC
597
- const pollEndpoint = `https://${location}-aiplatform.googleapis.com/v1/projects/${project}/locations/${location}/publishers/google/models/${VEO_MODEL}:fetchPredictOperation`;
611
+ const aspectRatio = options.aspectRatio || "16:9";
612
+ const resolution = options.resolution || "720p";
613
+ const generateAudio = options.audio ?? true;
614
+ logger.debug("Starting transition clip generation", {
615
+ model: VEO_FAST_MODEL,
616
+ durationSeconds,
617
+ firstFrameSize: firstFrame.length,
618
+ lastFrameSize: lastFrame.length,
619
+ promptLength: prompt.length,
620
+ });
621
+ try {
622
+ const firstFrameBase64 = firstFrame.toString("base64");
623
+ const lastFrameBase64 = lastFrame.toString("base64");
624
+ const firstMime = detectMimeType(firstFrame);
625
+ const lastMime = detectMimeType(lastFrame);
626
+ const accessToken = await getAccessToken();
627
+ // Use Veo 3.1 Fast for transitions (faster with minimal quality difference)
628
+ const endpoint = `https://${location}-aiplatform.googleapis.com/v1/projects/${project}/locations/${location}/publishers/google/models/${VEO_FAST_MODEL}:predictLongRunning`;
629
+ const requestBody = {
630
+ instances: [
631
+ {
632
+ prompt: prompt,
633
+ image: {
634
+ bytesBase64Encoded: firstFrameBase64,
635
+ mimeType: firstMime,
636
+ },
637
+ lastFrame: {
638
+ bytesBase64Encoded: lastFrameBase64,
639
+ mimeType: lastMime,
640
+ },
641
+ },
642
+ ],
643
+ parameters: {
644
+ sampleCount: 1,
645
+ durationSeconds: durationSeconds,
646
+ aspectRatio: aspectRatio,
647
+ resolution: resolution,
648
+ generateAudio: generateAudio,
649
+ },
650
+ };
651
+ const controller = new AbortController();
652
+ const requestTimeout = setTimeout(() => controller.abort(), 30000);
653
+ let response;
654
+ try {
655
+ response = await fetch(endpoint, {
656
+ method: "POST",
657
+ headers: {
658
+ Authorization: `Bearer ${accessToken}`,
659
+ "Content-Type": "application/json; charset=utf-8",
660
+ },
661
+ body: JSON.stringify(requestBody),
662
+ signal: controller.signal,
663
+ });
664
+ }
665
+ catch (error) {
666
+ clearTimeout(requestTimeout);
667
+ if (isAbortError(error)) {
668
+ throw new VideoError({
669
+ code: VIDEO_ERROR_CODES.DIRECTOR_TRANSITION_FAILED,
670
+ message: "Transition generation request timed out after 30 seconds",
671
+ category: ErrorCategory.EXECUTION,
672
+ severity: ErrorSeverity.MEDIUM,
673
+ retriable: true,
674
+ });
675
+ }
676
+ throw error;
677
+ }
678
+ clearTimeout(requestTimeout);
679
+ if (!response.ok) {
680
+ const errorText = await response.text();
681
+ throw new VideoError({
682
+ code: VIDEO_ERROR_CODES.DIRECTOR_TRANSITION_FAILED,
683
+ message: `Transition API error: ${response.status} - ${errorText}`,
684
+ category: ErrorCategory.EXECUTION,
685
+ severity: ErrorSeverity.MEDIUM,
686
+ retriable: response.status >= 500,
687
+ context: { status: response.status, error: errorText },
688
+ });
689
+ }
690
+ const operation = await response.json();
691
+ const operationName = operation.name;
692
+ if (!operationName) {
693
+ throw new VideoError({
694
+ code: VIDEO_ERROR_CODES.DIRECTOR_TRANSITION_FAILED,
695
+ message: "Transition API did not return an operation name",
696
+ category: ErrorCategory.EXECUTION,
697
+ severity: ErrorSeverity.MEDIUM,
698
+ retriable: false,
699
+ });
700
+ }
701
+ // Poll with Veo Fast model endpoint
702
+ const remainingTime = VIDEO_GENERATION_TIMEOUT_MS - (Date.now() - startTime);
703
+ const videoBuffer = await pollTransitionOperation(operationName, accessToken, project, location, Math.max(1000, remainingTime));
704
+ logger.debug("Transition clip generated", {
705
+ processingTime: Date.now() - startTime,
706
+ videoSize: videoBuffer.length,
707
+ });
708
+ return videoBuffer;
709
+ }
710
+ catch (error) {
711
+ if (error instanceof VideoError) {
712
+ throw error;
713
+ }
714
+ throw new VideoError({
715
+ code: VIDEO_ERROR_CODES.DIRECTOR_TRANSITION_FAILED,
716
+ message: `Transition generation failed: ${error instanceof Error ? error.message : String(error)}`,
717
+ category: ErrorCategory.EXECUTION,
718
+ severity: ErrorSeverity.MEDIUM,
719
+ retriable: true,
720
+ originalError: error instanceof Error ? error : undefined,
721
+ });
722
+ }
723
+ }
724
+ /**
725
+ * Common polling helper that handles both video and transition operations.
726
+ * Accepts a model name to construct the appropriate endpoint.
727
+ */
728
+ async function pollOperation(modelOrEndpoint, operationName, accessToken, project, location, timeoutMs) {
729
+ const startTime = Date.now();
730
+ const pollEndpoint = `https://${location}-aiplatform.googleapis.com/v1/projects/${project}/locations/${location}/publishers/google/models/${modelOrEndpoint}:fetchPredictOperation`;
598
731
  while (Date.now() - startTime < timeoutMs) {
599
732
  const result = await makePollRequest(pollEndpoint, operationName, accessToken);
600
733
  if (result.done) {
601
734
  return extractVideoFromResult(result, operationName);
602
735
  }
603
- const elapsed = Date.now() - startTime;
604
- logger.debug("Polling video operation...", {
736
+ logger.debug("Polling operation...", {
605
737
  operationName,
606
- elapsed,
607
- remainingMs: timeoutMs - elapsed,
738
+ elapsed: Date.now() - startTime,
608
739
  });
609
- // Wait before next poll
610
740
  await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
611
741
  }
612
- // Timeout reached
613
742
  throw new VideoError({
614
743
  code: VIDEO_ERROR_CODES.POLL_TIMEOUT,
615
- message: `Video generation timed out after ${Math.round(timeoutMs / 1000)}s while polling for completion`,
744
+ message: `Operation timed out after ${Math.round(timeoutMs / 1000)}s`,
616
745
  category: ErrorCategory.TIMEOUT,
617
- severity: ErrorSeverity.HIGH,
746
+ severity: ErrorSeverity.MEDIUM,
618
747
  retriable: true,
619
- context: {
620
- operationName,
621
- timeoutMs,
622
- provider: "vertex",
623
- suggestion: "Try again - video generation can take 1-3 minutes. Consider using a shorter duration or lower resolution.",
624
- },
748
+ context: { operationName, timeoutMs },
625
749
  });
626
750
  }
751
+ /**
752
+ * Poll Vertex AI operation for transition clip completion.
753
+ * Uses the Veo Fast model fetchPredictOperation endpoint.
754
+ */
755
+ async function pollTransitionOperation(operationName, accessToken, project, location, timeoutMs) {
756
+ return pollOperation(VEO_FAST_MODEL, operationName, accessToken, project, location, timeoutMs);
757
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Video Merger for Director Mode
3
+ *
4
+ * Concatenates multiple MP4 video buffers into a single MP4 using FFmpeg's
5
+ * concat demuxer for lossless concatenation when codecs match.
6
+ *
7
+ * Uses the shared FFmpeg adapter for binary resolution, temp file management,
8
+ * and process execution — following the adapter pattern in `adapters/tts/`.
9
+ *
10
+ * @module adapters/video/videoMerger
11
+ */
12
+ /**
13
+ * Merge multiple MP4 video buffers into a single MP4.
14
+ *
15
+ * Uses FFmpeg concat demuxer for lossless concatenation. If codecs don't match
16
+ * (unlikely since all clips come from Veo), falls back to re-encoding with H.264.
17
+ *
18
+ * @param videoBuffers - Array of MP4 video buffers to concatenate in order
19
+ * @returns Merged MP4 video buffer
20
+ * @throws {VideoError} If merge fails or no valid buffers provided
21
+ */
22
+ export declare function mergeVideoBuffers(videoBuffers: Buffer[]): Promise<Buffer>;
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Video Merger for Director Mode
3
+ *
4
+ * Concatenates multiple MP4 video buffers into a single MP4 using FFmpeg's
5
+ * concat demuxer for lossless concatenation when codecs match.
6
+ *
7
+ * Uses the shared FFmpeg adapter for binary resolution, temp file management,
8
+ * and process execution — following the adapter pattern in `adapters/tts/`.
9
+ *
10
+ * @module adapters/video/videoMerger
11
+ */
12
+ import { ErrorCategory, ErrorSeverity } from "../../constants/enums.js";
13
+ import { logger } from "../../utils/logger.js";
14
+ import { cleanupTempFiles, createTrackedTempDir, FFMPEG_MERGE_MAX_BUFFER, FFMPEG_MERGE_TIMEOUT_MS, isValidMp4Buffer, join, readFile, runFfmpeg, writeFile, } from "./ffmpegAdapter.js";
15
+ import { VIDEO_ERROR_CODES } from "../../constants/videoErrors.js";
16
+ import { VideoError } from "./vertexVideoHandler.js";
17
+ // ============================================================================
18
+ // INTERNAL HELPERS
19
+ // ============================================================================
20
+ /**
21
+ * Write clip buffers to temp files and build the FFmpeg concat list.
22
+ *
23
+ * @returns Paths of all written clip files
24
+ */
25
+ async function writeClipsAndBuildConcatList(videoBuffers, tempDir, concatListPath) {
26
+ const inputPaths = [];
27
+ const concatLines = [];
28
+ for (let i = 0; i < videoBuffers.length; i++) {
29
+ const inputPath = join(tempDir, `clip_${i}.mp4`);
30
+ await writeFile(inputPath, videoBuffers[i]);
31
+ inputPaths.push(inputPath);
32
+ // Normalize backslashes to forward slashes for FFmpeg, then escape single quotes
33
+ const safePath = inputPath.replace(/\\/g, "/").replace(/'/g, "'\\''");
34
+ concatLines.push(`file '${safePath}'`);
35
+ }
36
+ await writeFile(concatListPath, concatLines.join("\n"));
37
+ return inputPaths;
38
+ }
39
+ /**
40
+ * Attempt lossless concat, falling back to H.264 re-encode on failure.
41
+ */
42
+ async function concatWithFallback(concatListPath, outputPath) {
43
+ const ffmpegOpts = {
44
+ timeoutMs: FFMPEG_MERGE_TIMEOUT_MS,
45
+ maxBuffer: FFMPEG_MERGE_MAX_BUFFER,
46
+ };
47
+ try {
48
+ // Try lossless concat first (fastest — no re-encoding)
49
+ await runFfmpeg([
50
+ "-y",
51
+ "-f",
52
+ "concat",
53
+ "-safe",
54
+ "0",
55
+ "-i",
56
+ concatListPath,
57
+ "-c",
58
+ "copy",
59
+ outputPath,
60
+ ], ffmpegOpts);
61
+ }
62
+ catch (concatError) {
63
+ // Fallback: re-encode with H.264 if codecs mismatch
64
+ logger.warn("Lossless concat failed, falling back to H.264 re-encoding", {
65
+ error: concatError instanceof Error
66
+ ? concatError.message
67
+ : String(concatError),
68
+ });
69
+ await runFfmpeg([
70
+ "-y",
71
+ "-f",
72
+ "concat",
73
+ "-safe",
74
+ "0",
75
+ "-i",
76
+ concatListPath,
77
+ "-c:v",
78
+ "libx264",
79
+ "-preset",
80
+ "fast",
81
+ "-crf",
82
+ "18",
83
+ "-c:a",
84
+ "aac",
85
+ "-b:a",
86
+ "192k",
87
+ "-movflags",
88
+ "+faststart",
89
+ outputPath,
90
+ ], ffmpegOpts);
91
+ }
92
+ }
93
+ // ============================================================================
94
+ // PUBLIC API
95
+ // ============================================================================
96
+ /**
97
+ * Merge multiple MP4 video buffers into a single MP4.
98
+ *
99
+ * Uses FFmpeg concat demuxer for lossless concatenation. If codecs don't match
100
+ * (unlikely since all clips come from Veo), falls back to re-encoding with H.264.
101
+ *
102
+ * @param videoBuffers - Array of MP4 video buffers to concatenate in order
103
+ * @returns Merged MP4 video buffer
104
+ * @throws {VideoError} If merge fails or no valid buffers provided
105
+ */
106
+ export async function mergeVideoBuffers(videoBuffers) {
107
+ if (videoBuffers.length === 0) {
108
+ throw new VideoError({
109
+ code: VIDEO_ERROR_CODES.DIRECTOR_MERGE_FAILED,
110
+ message: "No video buffers provided to merge",
111
+ category: ErrorCategory.VALIDATION,
112
+ severity: ErrorSeverity.HIGH,
113
+ retriable: false,
114
+ });
115
+ }
116
+ // Validate each input buffer
117
+ for (let i = 0; i < videoBuffers.length; i++) {
118
+ if (!isValidMp4Buffer(videoBuffers[i])) {
119
+ throw new VideoError({
120
+ code: VIDEO_ERROR_CODES.DIRECTOR_MERGE_FAILED,
121
+ message: `Clip ${i} is not a valid MP4 buffer (missing ftyp header or too small)`,
122
+ category: ErrorCategory.VALIDATION,
123
+ severity: ErrorSeverity.HIGH,
124
+ retriable: false,
125
+ context: {
126
+ clipIndex: i,
127
+ bufferSize: videoBuffers[i].length,
128
+ headerHex: videoBuffers[i].subarray(0, 12).toString("hex"),
129
+ },
130
+ });
131
+ }
132
+ }
133
+ if (videoBuffers.length === 1) {
134
+ return videoBuffers[0];
135
+ }
136
+ const startTime = Date.now();
137
+ const tempDir = await createTrackedTempDir("merge");
138
+ const concatListPath = join(tempDir, "concat.txt");
139
+ const outputPath = join(tempDir, "merged.mp4");
140
+ let inputPaths = [];
141
+ try {
142
+ inputPaths = await writeClipsAndBuildConcatList(videoBuffers, tempDir, concatListPath);
143
+ await concatWithFallback(concatListPath, outputPath);
144
+ const mergedBuffer = await readFile(outputPath);
145
+ logger.info("Video merge complete", {
146
+ inputClips: videoBuffers.length,
147
+ totalInputSize: videoBuffers.reduce((sum, b) => sum + b.length, 0),
148
+ outputSize: mergedBuffer.length,
149
+ elapsedMs: Date.now() - startTime,
150
+ });
151
+ return mergedBuffer;
152
+ }
153
+ catch (error) {
154
+ // Re-throw VideoErrors as-is
155
+ if (error instanceof VideoError) {
156
+ throw error;
157
+ }
158
+ throw new VideoError({
159
+ code: VIDEO_ERROR_CODES.DIRECTOR_MERGE_FAILED,
160
+ message: `Video merge failed: ${error instanceof Error ? error.message : String(error)}`,
161
+ category: ErrorCategory.EXECUTION,
162
+ severity: ErrorSeverity.HIGH,
163
+ retriable: false,
164
+ context: { clipCount: videoBuffers.length },
165
+ originalError: error instanceof Error ? error : undefined,
166
+ });
167
+ }
168
+ finally {
169
+ await cleanupTempFiles(tempDir, concatListPath, outputPath, ...inputPaths);
170
+ }
171
+ }
@@ -191,4 +191,5 @@ export declare const CONSTANTS_METADATA: {
191
191
  readonly COMPATIBILITY: "backward_compatible";
192
192
  };
193
193
  export { AIProviderName, OpenRouterModels, BedrockModels, OpenAIModels, AzureOpenAIModels, VertexModels, GoogleAIModels, AnthropicModels, MistralModels, OllamaModels, LiteLLMModels, HuggingFaceModels, SageMakerModels, APIVersions, ErrorCategory, ErrorSeverity, AnthropicBetaFeature, TOKEN_EXPIRY_BUFFER_MS, } from "./enums.js";
194
+ export { VIDEO_ERROR_CODES } from "./videoErrors.js";
194
195
  export type { ClaudeSubscriptionTier, AnthropicAuthMethod, } from "../types/subscriptionTypes.js";
@@ -203,3 +203,5 @@ ErrorCategory, ErrorSeverity,
203
203
  AnthropicBetaFeature,
204
204
  // OAuth Constants
205
205
  TOKEN_EXPIRY_BUFFER_MS, } from "./enums.js";
206
+ // ===== ERROR CODES =====
207
+ export { VIDEO_ERROR_CODES } from "./videoErrors.js";
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Video Generation Error Codes
3
+ *
4
+ * Centralized error codes for video generation operations.
5
+ * These are for runtime/execution errors during video generation.
6
+ *
7
+ * Pure option/shape validation (missing image option, invalid config values, etc.)
8
+ * is handled by parameterValidation.ts using ERROR_CODES from errorHandling.ts.
9
+ *
10
+ * Error categorization:
11
+ * - INVALID_INPUT → ErrorCategory.execution (runtime I/O failures)
12
+ * - parameterValidation errors → ErrorCategory.validation (schema/option issues)
13
+ *
14
+ * @module constants/videoErrors
15
+ */
16
+ export declare const VIDEO_ERROR_CODES: {
17
+ /** Video generation API call failed */
18
+ readonly GENERATION_FAILED: "VIDEO_GENERATION_FAILED";
19
+ /** Provider (Vertex AI) not properly configured */
20
+ readonly PROVIDER_NOT_CONFIGURED: "VIDEO_PROVIDER_NOT_CONFIGURED";
21
+ /** Polling for video completion timed out */
22
+ readonly POLL_TIMEOUT: "VIDEO_POLL_TIMEOUT";
23
+ /**
24
+ * Runtime I/O error during input processing.
25
+ * Used for: failed URL fetch, failed file read, corrupt/unreadable buffer.
26
+ * NOT for: missing options or invalid config shapes (use parameterValidation).
27
+ */
28
+ readonly INVALID_INPUT: "VIDEO_INVALID_INPUT";
29
+ /** Invalid segment structure (missing prompt or image) */
30
+ readonly DIRECTOR_SEGMENT_MISMATCH: "DIRECTOR_SEGMENT_MISMATCH";
31
+ /** Too many segments requested */
32
+ readonly DIRECTOR_SEGMENT_LIMIT_EXCEEDED: "DIRECTOR_SEGMENT_LIMIT_EXCEEDED";
33
+ /** Invalid transition duration (must be 4, 6, or 8) */
34
+ readonly DIRECTOR_INVALID_TRANSITION_DURATION: "DIRECTOR_INVALID_TRANSITION_DURATION";
35
+ /** A main clip generation call failed (fatal) */
36
+ readonly DIRECTOR_CLIP_FAILED: "DIRECTOR_CLIP_FAILED";
37
+ /** Frame extraction from clip failed */
38
+ readonly DIRECTOR_FRAME_EXTRACTION_FAILED: "DIRECTOR_FRAME_EXTRACTION_FAILED";
39
+ /** Transition clip generation failed (non-fatal, falls back to hard cut) */
40
+ readonly DIRECTOR_TRANSITION_FAILED: "DIRECTOR_TRANSITION_FAILED";
41
+ /** Video merge/concatenation failed */
42
+ readonly DIRECTOR_MERGE_FAILED: "DIRECTOR_MERGE_FAILED";
43
+ /** Pipeline timeout (overall) */
44
+ readonly DIRECTOR_PIPELINE_TIMEOUT: "DIRECTOR_PIPELINE_TIMEOUT";
45
+ };
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Video Generation Error Codes
3
+ *
4
+ * Centralized error codes for video generation operations.
5
+ * These are for runtime/execution errors during video generation.
6
+ *
7
+ * Pure option/shape validation (missing image option, invalid config values, etc.)
8
+ * is handled by parameterValidation.ts using ERROR_CODES from errorHandling.ts.
9
+ *
10
+ * Error categorization:
11
+ * - INVALID_INPUT → ErrorCategory.execution (runtime I/O failures)
12
+ * - parameterValidation errors → ErrorCategory.validation (schema/option issues)
13
+ *
14
+ * @module constants/videoErrors
15
+ */
16
+ export const VIDEO_ERROR_CODES = {
17
+ /** Video generation API call failed */
18
+ GENERATION_FAILED: "VIDEO_GENERATION_FAILED",
19
+ /** Provider (Vertex AI) not properly configured */
20
+ PROVIDER_NOT_CONFIGURED: "VIDEO_PROVIDER_NOT_CONFIGURED",
21
+ /** Polling for video completion timed out */
22
+ POLL_TIMEOUT: "VIDEO_POLL_TIMEOUT",
23
+ /**
24
+ * Runtime I/O error during input processing.
25
+ * Used for: failed URL fetch, failed file read, corrupt/unreadable buffer.
26
+ * NOT for: missing options or invalid config shapes (use parameterValidation).
27
+ */
28
+ INVALID_INPUT: "VIDEO_INVALID_INPUT",
29
+ // Director Mode error codes
30
+ /** Invalid segment structure (missing prompt or image) */
31
+ DIRECTOR_SEGMENT_MISMATCH: "DIRECTOR_SEGMENT_MISMATCH",
32
+ /** Too many segments requested */
33
+ DIRECTOR_SEGMENT_LIMIT_EXCEEDED: "DIRECTOR_SEGMENT_LIMIT_EXCEEDED",
34
+ /** Invalid transition duration (must be 4, 6, or 8) */
35
+ DIRECTOR_INVALID_TRANSITION_DURATION: "DIRECTOR_INVALID_TRANSITION_DURATION",
36
+ /** A main clip generation call failed (fatal) */
37
+ DIRECTOR_CLIP_FAILED: "DIRECTOR_CLIP_FAILED",
38
+ /** Frame extraction from clip failed */
39
+ DIRECTOR_FRAME_EXTRACTION_FAILED: "DIRECTOR_FRAME_EXTRACTION_FAILED",
40
+ /** Transition clip generation failed (non-fatal, falls back to hard cut) */
41
+ DIRECTOR_TRANSITION_FAILED: "DIRECTOR_TRANSITION_FAILED",
42
+ /** Video merge/concatenation failed */
43
+ DIRECTOR_MERGE_FAILED: "DIRECTOR_MERGE_FAILED",
44
+ /** Pipeline timeout (overall) */
45
+ DIRECTOR_PIPELINE_TIMEOUT: "DIRECTOR_PIPELINE_TIMEOUT",
46
+ };
@@ -1055,7 +1055,7 @@ export class BaseProvider {
1055
1055
  async handleVideoGeneration(options, startTime) {
1056
1056
  // Dynamic imports to avoid loading video dependencies unless needed
1057
1057
  const { generateVideoWithVertex, VideoError, VIDEO_ERROR_CODES } = await import("../adapters/video/vertexVideoHandler.js");
1058
- const { validateVideoGenerationInput, validateImageForVideo } = await import("../utils/parameterValidation.js");
1058
+ const { validateVideoGenerationInput, validateImageForVideo, validateDirectorModeInput, } = await import("../utils/parameterValidation.js");
1059
1059
  const { ErrorFactory } = await import("../utils/errorHandling.js");
1060
1060
  // Build GenerateOptions for validation
1061
1061
  const generateOptions = {
@@ -1064,6 +1064,47 @@ export class BaseProvider {
1064
1064
  provider: options.provider,
1065
1065
  model: options.model,
1066
1066
  };
1067
+ // ===== DIRECTOR MODE =====
1068
+ // Route to Director pipeline when segments are provided
1069
+ if (generateOptions.input?.segments &&
1070
+ Array.isArray(generateOptions.input.segments) &&
1071
+ generateOptions.input.segments.length > 0) {
1072
+ // Type narrowing: segments is guaranteed to exist here
1073
+ const segments = generateOptions.input.segments;
1074
+ const directorValidation = validateDirectorModeInput(generateOptions);
1075
+ if (!directorValidation.isValid) {
1076
+ throw ErrorFactory.invalidParameters("director-mode", new Error(directorValidation.errors
1077
+ .map((e) => e.message)
1078
+ .join("; ")), { errors: directorValidation.errors });
1079
+ }
1080
+ if (directorValidation.warnings.length > 0) {
1081
+ for (const warning of directorValidation.warnings) {
1082
+ logger.warn(`Director Mode warning: ${warning}`);
1083
+ }
1084
+ }
1085
+ const { executeDirectorPipeline, DIRECTOR_PIPELINE_TIMEOUT_MS } = await import("../adapters/video/directorPipeline.js");
1086
+ // Use caller's timeout if provided, otherwise use default Director timeout
1087
+ const directorTimeout = options.timeout ?? DIRECTOR_PIPELINE_TIMEOUT_MS;
1088
+ const videoResult = await this.executeWithTimeout(() => executeDirectorPipeline(segments, generateOptions.output?.video ?? {}, generateOptions.output?.director ?? {}, options.region), { timeout: directorTimeout, operationType: "generate" });
1089
+ // Build content summary with metadata
1090
+ const joinedPrompts = generateOptions.input.segments
1091
+ .map((s) => s.prompt)
1092
+ .join(" → ");
1093
+ const segmentCount = videoResult.metadata?.segmentCount ??
1094
+ generateOptions.input.segments.length;
1095
+ const transitionCount = videoResult.metadata?.transitionCount ?? Math.max(0, segmentCount - 1);
1096
+ const totalDuration = videoResult.metadata?.duration ?? 0;
1097
+ const contentSummary = `${joinedPrompts} — duration: ${totalDuration}s, segments: ${segmentCount}, transitions: ${transitionCount}`;
1098
+ const baseResult = {
1099
+ content: contentSummary,
1100
+ provider: "vertex",
1101
+ model: options.model || "veo-3.1-generate-001",
1102
+ usage: { input: 0, output: 0, total: 0 },
1103
+ video: videoResult,
1104
+ };
1105
+ return await this.enhanceResult(baseResult, options, startTime);
1106
+ }
1107
+ // ===== STANDARD SINGLE-CLIP VIDEO GENERATION =====
1067
1108
  // Validate video generation input
1068
1109
  const validation = validateVideoGenerationInput(generateOptions);
1069
1110
  if (!validation.isValid) {
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Director Mode Pipeline Orchestrator
3
+ *
4
+ * Orchestrates multi-segment video generation: parallel clip generation,
5
+ * parallel frame extraction + transition generation, and sequential merge.
6
+ *
7
+ * Error severity semantics:
8
+ * - HIGH: Fatal — clip generation / merge failures that abort the pipeline
9
+ * - MEDIUM: Non-fatal — transition / frame-extraction failures that degrade
10
+ * to a hard cut but do not abort the pipeline
11
+ *
12
+ * @module adapters/video/directorPipeline
13
+ */
14
+ import type { DirectorModeOptions, DirectorSegment, VideoGenerationResult, VideoOutputOptions } from "../../types/multimodal.js";
15
+ /** Default timeout for entire Director Mode pipeline (10 minutes) */
16
+ export declare const DIRECTOR_PIPELINE_TIMEOUT_MS = 600000;
17
+ /**
18
+ * Execute the full Director Mode pipeline.
19
+ *
20
+ * Pipeline stages:
21
+ * 1. Parallel clip generation (concurrency = 2, circuit breaker after 2 failures)
22
+ * 2. Parallel frame extraction + transition generation
23
+ * 3. Sequential merge into single MP4
24
+ *
25
+ * @param segments - Array of DirectorSegment objects (2-10)
26
+ * @param videoOptions - Video output options (resolution, length, aspectRatio, audio)
27
+ * @param directorOptions - Director Mode options (transition prompts/durations)
28
+ * @param region - Vertex AI region override
29
+ * @returns VideoGenerationResult with merged video and Director metadata
30
+ */
31
+ export declare function executeDirectorPipeline(segments: DirectorSegment[], videoOptions?: VideoOutputOptions, directorOptions?: DirectorModeOptions, region?: string): Promise<VideoGenerationResult>;