From f831e1210b49cbbfde1595d7babcdbea755618e7 Mon Sep 17 00:00:00 2001 From: Adir Amsalem Date: Mon, 9 Mar 2026 19:09:34 +0200 Subject: [PATCH] fix: make prompt required for lucy-2-v2v (can be empty string) Update lucy-2-v2v model schema to match API spec change where prompt is now a required field that accepts empty strings. Remove the 'at least one of prompt or reference_image' validation since prompt is always required. --- examples/sdk-core/video/video-editing.ts | 3 ++- packages/sdk/src/process/types.ts | 8 +++---- packages/sdk/src/shared/model.ts | 27 ++++++++++++------------ packages/sdk/tests/e2e.test.ts | 1 + packages/sdk/tests/unit.test.ts | 16 +++----------- 5 files changed, 22 insertions(+), 33 deletions(-) diff --git a/examples/sdk-core/video/video-editing.ts b/examples/sdk-core/video/video-editing.ts index 2382f70..c3ed692 100644 --- a/examples/sdk-core/video/video-editing.ts +++ b/examples/sdk-core/video/video-editing.ts @@ -26,10 +26,11 @@ run(async () => { }, }); - // Option 2: Use a reference image to guide the edit + // Option 2: Use a reference image to guide the edit (with empty prompt) // const referenceImage = fs.readFileSync("reference.png"); // const result = await client.queue.submitAndPoll({ // model: models.video("lucy-2-v2v"), + // prompt: "", // reference_image: new Blob([referenceImage]), // data: new Blob([inputVideo]), // onStatusChange: (job) => { diff --git a/packages/sdk/src/process/types.ts b/packages/sdk/src/process/types.ts index 5a6dc48..efa8a1f 100644 --- a/packages/sdk/src/process/types.ts +++ b/packages/sdk/src/process/types.ts @@ -95,16 +95,15 @@ export interface VideoEditInputs { /** * Model-specific input documentation for lucy-2-v2v. - * Requires at least one of prompt or reference_image. Both can be provided together. + * Requires prompt (can be empty string). Optional reference_image can also be provided. */ export interface VideoEdit2Inputs { /** - * Text description to use for the video editing. - * At least one of prompt or reference_image must be provided. + * Text prompt for the video editing. Send an empty string if you want no text prompt. * * See our [Prompt Engineering](https://docs.platform.decart.ai/models/video/video-generation#prompt-engineering) guide for how to write prompt for Decart video models effectively. */ - prompt?: string; + prompt: string; /** * Video file to process. * Can be a File, Blob, ReadableStream, URL, or string URL. @@ -112,7 +111,6 @@ export interface VideoEdit2Inputs { data: FileInput; /** * Optional reference image to guide what to add to the video. - * At least one of prompt or reference_image must be provided. * Can be a File, Blob, ReadableStream, URL, or string URL. */ reference_image?: FileInput; diff --git a/packages/sdk/src/shared/model.ts b/packages/sdk/src/shared/model.ts index 41fe3a6..280c998 100644 --- a/packages/sdk/src/shared/model.ts +++ b/packages/sdk/src/shared/model.ts @@ -195,20 +195,19 @@ export const modelInputSchemas = { .refine((data) => !(data.reference_image !== undefined && data.enhance_prompt !== undefined), { message: "'enhance_prompt' is only valid when using 'prompt', not 'reference_image'", }), - "lucy-2-v2v": z - .object({ - prompt: z.string().min(1).max(1000).optional().describe("Text prompt for the video editing"), - reference_image: fileInputSchema - .optional() - .describe("Optional reference image to guide the edit (File, Blob, ReadableStream, URL, or string URL)"), - data: fileInputSchema.describe("Video file to process (File, Blob, ReadableStream, URL, or string URL)"), - seed: z.number().optional().describe("The seed to use for the generation"), - resolution: proV2vResolutionSchema, - enhance_prompt: z.boolean().optional().describe("Whether to enhance the prompt"), - }) - .refine((data) => data.prompt !== undefined || data.reference_image !== undefined, { - message: "Must provide at least one of 'prompt' or 'reference_image'", - }), + "lucy-2-v2v": z.object({ + prompt: z + .string() + .max(1000) + .describe("Text prompt for the video editing. Send an empty string if you want no text prompt."), + reference_image: fileInputSchema + .optional() + .describe("Optional reference image to guide the edit (File, Blob, ReadableStream, URL, or string URL)"), + data: fileInputSchema.describe("Video file to process (File, Blob, ReadableStream, URL, or string URL)"), + seed: z.number().optional().describe("The seed to use for the generation"), + resolution: proV2vResolutionSchema, + enhance_prompt: z.boolean().optional().describe("Whether to enhance the prompt"), + }), } as const; export type ModelInputSchemas = typeof modelInputSchemas; diff --git a/packages/sdk/tests/e2e.test.ts b/packages/sdk/tests/e2e.test.ts index d0f0b21..0a91e44 100644 --- a/packages/sdk/tests/e2e.test.ts +++ b/packages/sdk/tests/e2e.test.ts @@ -185,6 +185,7 @@ describe.concurrent("E2E Tests", { timeout: TIMEOUT, retry: 2 }, () => { it("lucy-2-v2v: video editing (reference_image)", async () => { const result = await client.queue.submitAndPoll({ model: models.video("lucy-2-v2v"), + prompt: "", reference_image: imageBlob, data: videoBlob, seed: 42, diff --git a/packages/sdk/tests/unit.test.ts b/packages/sdk/tests/unit.test.ts index e99fda0..8f1a35c 100644 --- a/packages/sdk/tests/unit.test.ts +++ b/packages/sdk/tests/unit.test.ts @@ -520,7 +520,7 @@ describe("Queue API", () => { expect(dataFile).toBeInstanceOf(File); }); - it("submits lucy-2-v2v job with only reference_image (no prompt)", async () => { + it("submits lucy-2-v2v job with empty prompt and reference_image", async () => { server.use( http.post("http://localhost/v1/jobs/lucy-2-v2v", async ({ request }) => { lastRequest = request; @@ -537,13 +537,14 @@ describe("Queue API", () => { const result = await decart.queue.submit({ model: models.video("lucy-2-v2v"), + prompt: "", data: testVideoBlob, reference_image: testImageBlob, }); expect(result.job_id).toBe("job_lucy2_v2v_refonly"); expect(result.status).toBe("pending"); - expect(lastFormData?.get("prompt")).toBeNull(); + expect(lastFormData?.get("prompt")).toBe(""); const dataFile = lastFormData?.get("data") as File; expect(dataFile).toBeInstanceOf(File); @@ -552,17 +553,6 @@ describe("Queue API", () => { expect(refImageFile).toBeInstanceOf(File); }); - it("rejects lucy-2-v2v job when neither prompt nor reference_image is provided", async () => { - const testVideoBlob = new Blob(["test-video"], { type: "video/mp4" }); - - await expect( - decart.queue.submit({ - model: models.video("lucy-2-v2v"), - data: testVideoBlob, - } as Parameters[0]), - ).rejects.toThrow("Must provide at least one of 'prompt' or 'reference_image'"); - }); - it("submits lucy-2-v2v job with reference_image", async () => { server.use( http.post("http://localhost/v1/jobs/lucy-2-v2v", async ({ request }) => {