Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/commands/video/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
55 changes: 53 additions & 2 deletions test/commands/video/generate.test.ts
Original file line number Diff line number Diff line change
@@ -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',
Expand Down Expand Up @@ -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();
}
});
});