From 3d784eedc71dac78340045de0e90a98842fcd762 Mon Sep 17 00:00:00 2001 From: ch-z-hc <45302000+ch-z-hc@users.noreply.github.com> Date: Wed, 14 Oct 2026 04:50:10 +0800 Subject: [PATCH] fix: validate configured Fast video model input --- src/commands/video/generate.ts | 2 +- test/commands/video/generate.test.ts | 55 +++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/commands/video/generate.ts b/src/commands/video/generate.ts index 438d0560..4c1e29ec 100644 --- a/src/commands/video/generate.ts +++ b/src/commands/video/generate.ts @@ -128,7 +128,7 @@ export default defineCommand({ } // MiniMax-Hailuo-2.3-Fast only supports I2V, not T2V - if (explicitModel === 'MiniMax-Hailuo-2.3-Fast' && !inputImage) { + if (model === 'MiniMax-Hailuo-2.3-Fast' && !inputImage) { throw new CLIError( 'MiniMax-Hailuo-2.3-Fast only supports I2V (image-to-video). Use --image to provide an input image.', ExitCode.USAGE, diff --git a/test/commands/video/generate.test.ts b/test/commands/video/generate.test.ts index 71cae547..21fd5422 100644 --- a/test/commands/video/generate.test.ts +++ b/test/commands/video/generate.test.ts @@ -1,11 +1,11 @@ -import { describe, it, expect } from 'bun:test'; +import { describe, it, expect, spyOn } from 'bun:test'; import { mkdtempSync, readFileSync, rmSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; import { default as generateCommand } from '../../../src/commands/video/generate'; import type { Config } from '../../../src/config/schema'; import type { GlobalFlags } from '../../../src/types/flags'; -import { createMockServer } from '../../helpers/mock-server'; +import { createMockServer, jsonResponse } from '../../helpers/mock-server'; const h3DryRunConfig: Config = { apiKey: 'test-key', @@ -581,4 +581,55 @@ describe('video generate command', () => { }), ).rejects.toThrow('MiniMax-Hailuo-2.3-Fast only supports I2V'); }); + + it('rejects a configured Fast model without an image before submitting a task', async () => { + let submissions = 0; + const server = createMockServer({ + routes: { + 'POST /v1/video_generation': () => { + submissions++; + return jsonResponse({ task_id: 'unexpected-task', base_resp: { status_code: 0 } }); + }, + }, + }); + try { + await expect(generateCommand.execute({ + ...h3DryRunConfig, + baseUrl: server.url, + defaultVideoModel: 'MiniMax-Hailuo-2.3-Fast', + dryRun: false, + async: true, + quiet: true, + }, { ...baseFlags, dryRun: false, prompt: 'A cat' })).rejects.toMatchObject({ + message: expect.stringContaining('MiniMax-Hailuo-2.3-Fast only supports I2V'), + exitCode: 2, + }); + expect(submissions).toBe(0); + } finally { + server.close(); + } + }); + + it.each([ + [{ image: 'https://example.com/first.png' }, 'MiniMax-Hailuo-2.3-Fast'], + [{ firstFrame: 'https://example.com/first.png' }, 'MiniMax-Hailuo-2.3-Fast'], + [{ model: 'MiniMax-Hailuo-2.3' }, 'MiniMax-Hailuo-2.3'], + [{ subjectImage: 'https://example.com/subject.png' }, 'S2V-01'], + [{ image: 'https://example.com/first.png', lastFrame: 'https://example.com/last.png' }, 'MiniMax-Hailuo-02'], + ])('preserves model resolution with a Fast default and %j', async (flags, model) => { + const log = spyOn(console, 'log').mockImplementation(() => {}); + try { + await generateCommand.execute({ + ...h3DryRunConfig, + defaultVideoModel: 'MiniMax-Hailuo-2.3-Fast', + }, { ...baseFlags, prompt: 'A cat', ...flags }); + const output = JSON.parse(log.mock.calls[0]![0]) as { request: { model: string; first_frame_image?: string } }; + expect(output.request.model).toBe(model); + if ('image' in flags || 'firstFrame' in flags) { + expect(output.request.first_frame_image).toBe('https://example.com/first.png'); + } + } finally { + log.mockRestore(); + } + }); });