Skip to content

Commit 9b44642

Browse files
myxamediyarclaude
andcommitted
fix(video): send the model default for fal settings a frame change invalidates
Attaching or removing a start frame switches a fal model between its text-to-video and image-to-video endpoints, and the settings picked for one can be invalid on the other (Seedance 2.5 takes 16:9 from a prompt but only auto from a frame). The V3 block now drops any stored setting the selected endpoint does not accept, so the run uses the model default instead of failing validation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 63783d1 commit 9b44642

2 files changed

Lines changed: 86 additions & 9 deletions

File tree

‎apps/sim/blocks/blocks/video_generator.ts‎

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,33 @@ const LEGACY_FAL_SETTING_KEYS: Record<string, keyof FalVideoSettings> = {
140140
promptOptimizer: 'promptOptimizer',
141141
}
142142

143+
/**
144+
* Drops stored settings the endpoint a run calls does not accept, so the model default applies.
145+
* Attaching or removing a start frame switches endpoints without clearing the settings chosen for
146+
* the other one: Seedance 2.5 takes `16:9` from a prompt but only `auto` from a start frame.
147+
*/
148+
function keepFalSettingsAllowed(
149+
params: Record<string, unknown>,
150+
settings: FalVideoSettings | undefined
151+
) {
152+
const { duration, aspectRatio, resolution } = params
153+
const durations = settings?.durations?.map((value) => Number.parseFloat(String(value)))
154+
return {
155+
...params,
156+
duration: typeof duration === 'number' && durations?.includes(duration) ? duration : undefined,
157+
aspectRatio:
158+
typeof aspectRatio === 'string' && settings?.aspectRatios?.includes(aspectRatio)
159+
? aspectRatio
160+
: undefined,
161+
resolution:
162+
typeof resolution === 'string' && settings?.resolutions?.includes(resolution)
163+
? resolution
164+
: undefined,
165+
generateAudio: settings?.audioField ? params.generateAudio : undefined,
166+
promptOptimizer: settings?.promptOptimizer ? params.promptOptimizer : undefined,
167+
}
168+
}
169+
143170
function withFalVideoCatalog(subBlocks: SubBlockConfig[]): SubBlockConfig[] {
144171
return subBlocks.flatMap((subBlock) => {
145172
const condition = subBlock.condition
@@ -1976,16 +2003,12 @@ export const VideoGeneratorV3Block: BlockConfig = {
19762003
params: (params) => {
19772004
if (params.provider === 'falai') {
19782005
const falParams = VideoGeneratorV2Block.tools.config?.params?.(params) ?? params
1979-
if (!getFalVideoModel(params.model)?.image || !falParams.visualReference)
1980-
return { ...falParams, visualReference: undefined }
1981-
const image = getFalVideoVariant(params.model, true)
2006+
const model = getFalVideoModel(params.model)
2007+
if (!model) return { ...falParams, visualReference: undefined }
2008+
const withImage = Boolean(model.image && falParams.visualReference)
19822009
return {
1983-
...falParams,
1984-
duration: image?.durations ? falParams.duration : undefined,
1985-
aspectRatio: image?.aspectRatios ? falParams.aspectRatio : undefined,
1986-
resolution: image?.resolutions ? falParams.resolution : undefined,
1987-
generateAudio: image?.audioField ? falParams.generateAudio : undefined,
1988-
promptOptimizer: image?.promptOptimizer ? falParams.promptOptimizer : undefined,
2010+
...keepFalSettingsAllowed(falParams, getFalVideoVariant(params.model, withImage)),
2011+
visualReference: withImage ? falParams.visualReference : undefined,
19892012
}
19902013
}
19912014
const visualReference =

‎apps/sim/serializer/field-analysis.test.ts‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ vi.mock('@/blocks', () => ({
1616

1717
import { videoToolBodySchema } from '@/lib/api/contracts/tools/media/video'
1818
import { buildDirectVideoRequest } from '@/lib/internal/video/direct-request'
19+
import { buildFalVideoRequest } from '@/lib/internal/video/fal-request'
1920
import { VideoGeneratorV3Block } from '@/blocks/blocks/video_generator'
2021
import { collectBlockFieldIssues, extractBlockParams } from '@/serializer/index'
2122
import { getToolMetadata, getToolParams } from '@/tools/metadata'
@@ -208,6 +209,59 @@ describe('extractBlockParams', () => {
208209
expect(request.body).toMatchObject(payload)
209210
})
210211

212+
it.each([
213+
{
214+
name: 'a frame is attached after picking a prompt-only aspect ratio',
215+
model: 'bytedance/seedance-2.5/text-to-video',
216+
aspectRatio: '16:9',
217+
frame: true,
218+
endpoint: 'bytedance/seedance-2.5/image-to-video',
219+
},
220+
{
221+
name: 'the frame is removed after picking a frame-only aspect ratio',
222+
model: 'fal-ai/bytedance/seedance/v1/pro/text-to-video',
223+
aspectRatio: 'auto',
224+
frame: false,
225+
endpoint: 'fal-ai/bytedance/seedance/v1/pro/text-to-video',
226+
},
227+
])(
228+
'sends the model default for a fal setting the endpoint rejects when $name',
229+
({ model, aspectRatio, frame, endpoint }) => {
230+
svcConfig.value = VideoGeneratorV3Block
231+
const frameFile = {
232+
id: 'f',
233+
name: 'frame.png',
234+
url: '',
235+
size: 3,
236+
type: 'image/png',
237+
key: 'k',
238+
}
239+
const values = {
240+
provider: 'falai',
241+
apiKey: 'test-key',
242+
model,
243+
prompt: 'A cinematic sunrise',
244+
falAspectRatio: aspectRatio,
245+
...(frame ? { visualReferenceInput: frameFile } : {}),
246+
}
247+
const params = extractBlockParams(
248+
block({
249+
type: 'svc',
250+
subBlocks: Object.fromEntries(
251+
Object.entries(values).map(([id, value]) => [id, { id, type: 'short-input', value }])
252+
),
253+
})
254+
)
255+
const mapped = VideoGeneratorV3Block.tools.config?.params?.(params)
256+
const request = buildFalVideoRequest({
257+
...videoToolBodySchema.parse(mapped),
258+
provider: 'falai',
259+
})
260+
expect(request.endpoint).toBe(endpoint)
261+
expect(request.body).not.toHaveProperty('aspect_ratio')
262+
}
263+
)
264+
211265
it('resolves a canonical pair to its canonical id (advanced value wins when basic empty)', () => {
212266
svcConfig.value = config([
213267
{

0 commit comments

Comments
 (0)