- Keep existing ModelType for backward compatibility
2. Update NanoBananaNodeData interface:
- Add optional `selectedModel?: SelectedModel` field
- Keep existing `model: ModelType` field for Gemini backward compatibility
3. Add "gemini" to ProviderType union if not already present (it should be the Gemini provider identifier)
WHY: NanoBananaNodeData needs to store either legacy Gemini model selection OR new multi-provider selection. The optional selectedModel field enables graceful migration.
Add SelectedModel interface:
```typescript
export interface SelectedModel {
provider: ProviderType;
modelId: string;
displayName: string;
}
```
Update NanoBananaNodeData to add optional selectedModel field (keep existing model field for Gemini backward compatibility).
Add "gemini" to ProviderType if not present.
</action>
<verify>npx tsc --noEmit passes</verify>
<done>Types compile, SelectedModel interface exists, NanoBananaNodeData has selectedModel field</done>
<verify>npx tsc --noEmit</verify>
<done>SelectedModel type exists, NanoBananaNodeData has selectedModel field, types compile</done>
</task>
<tasktype="auto">
<name>Task 2: Rename component to GenerateImageNode with model selector UI</name>
<name>Task 2: Create GenerateImageNode with provider/model selector</name>
- For gemini: hardcoded Nano Banana / Nano Banana Pro
- For replicate/fal: fetch from /api/models?provider=X&capabilities=text-to-image,image-to-image
5. Filter to image capabilities only (text-to-image, image-to-image)
6. Keep aspect ratio/resolution controls for Gemini, hide for others
7. Update index.ts exports:
```typescript
export { GenerateImageNode } from "./GenerateImageNode";
export { GenerateImageNode as NanoBananaNode } from "./GenerateImageNode";
```
WHY: The component rename reflects its image-specific purpose. Video generation will be a separate GenerateVideoNode in Phase 6. The alias maintains backward compatibility.
</action>
<verify>npm run build succeeds, component renders in browser</verify>
<done>GenerateImageNode.tsx exists, shows provider selector, model dropdown shows only image-capable models</done>
<verify>npm run build</verify>
<done>GenerateImageNode renders with provider/model dropdowns, shows only image models</done>
</task>
<tasktype="auto">
<name>Task 3: Update store and canvas references</name>
Add provider-specific execution logic to the generate API route for image generation.
Implement provider-specific image generation in API route.
Purpose: Enable the generate endpoint to route requests to the correct provider (Gemini, Replicate, fal.ai) based on the selected model, filtering to image outputs only.
Output: Updated /api/generate route that dispatches to provider-specific image generation logic.
Note: Video generation will use a separate endpoint in Phase 6.
Purpose: Route generation requests to correct provider (Gemini, Replicate, fal.ai) based on selected model.
Output: Working generate endpoint that dispatches to provider implementations.
</objective>
<execution_context>
@ -20,156 +18,82 @@ Note: Video generation will use a separate endpoint in Phase 6.
- Poll GET /predictions/{id} until status is "succeeded" or "failed"
- Convert output URL to base64 data URL
- Return in GenerationOutput format with type: "image"
4. Filter to image models only:
- Only accept models with text-to-image or image-to-image capabilities
- Return error if video model passed (video generation is Phase 6)
WHY: Replicate requires polling for async predictions. The generate() method encapsulates this complexity. Image-only filter keeps this endpoint focused.
Implement generate() that currently throws "not implemented":
1. POST to https://api.replicate.com/v1/predictions with { version: modelId, input: { prompt } }
2. Poll GET /predictions/{id} until status is "succeeded" or "failed"
3. Fetch output image URL and convert to base64 data URL
4. Return GenerationOutput with type: "image"
5. Skip image inputs for now (Phase 5 adds URL server)
</action>
<verify>TypeScript compiles, generate() method exists and doesn't throw immediately</verify>
<done>Replicate provider has working generate() method that calls prediction API for image models</done>
<verify>TypeScript compiles</verify>
<done>Replicate generate() calls prediction API and returns image</done>
</task>
<tasktype="auto">
<name>Task 2: Implement generate() method in fal.ai provider</name>
- Accept GenerationInput with model, prompt, images, parameters
- Call fal.ai's run endpoint: POST https://fal.run/{model.id}
- Include prompt and parameters in request body
- fal.ai is synchronous (waits for result)
2. Handle auth:
- Use "Key {apiKey}" header format (already established)
- API key optional but rate limited without it
3. Parse response:
- Extract image URL from response
- Convert to base64 data URL for consistency
- Handle images array output format
4. Filter to image models only:
- Only accept models with text-to-image or image-to-image capabilities
- Return error if video model passed (video generation is Phase 6)
WHY: fal.ai's synchronous API is simpler than Replicate. The generate() method normalizes the response format. Image-only filter keeps this endpoint focused.
Implement generate():
1. POST to https://fal.run/{modelId} with { prompt, ...parameters }
2. Use "Key {apiKey}" auth header
3. Extract image URL from response, convert to base64