- Add generateAudio and videoFrameGrab cases to executeNode dispatcher
- Add selectedModel null guards in route.ts for all non-Gemini providers
- Fix ConnectionDropMenu wrap-around test (5->6 items after generateAudio)
- Fix audio duration edge cases (NaN guard in formatTime, truthiness check)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Resolve prompt from dynamicInputs.prompt in Gemini code path as fallback
- Return clear 400 error when prompt is provided but is not a string (corrupted data)
- Improve parallel batch error logging to include nodeId and nodeType for diagnosis
- Replace find() with for-loop to preserve index mapping between results and batch nodes
The helper returned string[] which didn't satisfy the ModelCapability[]
type in GenerationInput. Import and use the proper type.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Deduplicate the media response block (3d/video/audio/image) that was
copy-pasted across all 4 provider branches, and the mediaType-to-
capabilities ternary chain repeated 4 times.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add text-to-audio capability routing in all 4 provider blocks of
/api/generate, handle audio output type responses, and add audio
MIME type mappings and extraction logic to /api/save-generation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix 3D viewport not filling node by adding resize={{ offsetSize: true }} for correct measurement in CSS-transformed React Flow nodes
- Replace grid/axis indicators with spot light for cleaner scene
- Add labeled input (3D) and output (Image) handles matching generate node style
- Add native wheel event listener to prevent graph zoom/pan while scrolling to zoom 3D model
- Remove redundant CSS workarounds (absolute positioning style, extra relative wrapper)
- Add edge-to-edge viewport via contentClassName (removes default padding when GLB loaded)
- Overlay controls bar on viewport with gradient background
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Providers:
- replicate: add SSRF validation on mediaUrl before fetch
- fal/kie/replicate/wavespeed: large-video returns data="" with url set
instead of putting raw URL in data field (violates GenerationOutput.data semantic)
- kie: remove stale WaveSpeed JSDoc block from kie provider file
- route.ts: update all output handling to support data="" + url for large videos
Executors:
- generateVideoExecutor/nanoBananaExecutor: track save-generation fetch in
pendingImageSyncs via new trackSaveGeneration context method so auto-save
waits for server ID resolution
- videoProcessingExecutors: throw errors instead of returning in validation
branches (encoderSupported, insufficient videos, no video connected) so
Promise.allSettled sees rejections
- types.ts: add trackSaveGeneration to NodeExecutionContext interface
- workflowStore: wire trackSaveGeneration into both execution context sites
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move generateWithFalQueue, generateWithKie, generateWithWaveSpeed and all
their helpers into providers/fal.ts, providers/kie.ts, providers/wavespeed.ts.
Add barrel export at providers/index.ts.
route.ts reduced from 2,838 to 518 lines (POST handler + routing only).
Re-export clearFalInputMappingCache from route.ts for test backward compat.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move generateWithReplicate() into providers/replicate.ts.
It imports schema utilities from schemaUtils.ts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move MODEL_MAP and generateWithGemini() into providers/gemini.ts.
Remove unused imports (GoogleGenAI, uploadImageForUrl, shouldUseImageUrl,
deleteImages, ProviderModel) from route.ts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract INPUT_PATTERNS, InputMapping, ParameterTypeInfo, getParameterTypesFromSchema,
coerceParameterTypes, and getInputMappingFromSchema into schemaUtils.ts with 23 new tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Validate uploadUrl and fileUrl from fal CDN initiate response through
validateMediaUrl() and HTTPS check before performing the PUT request.
Throws if either URL is missing or fails validation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Validate fal-provided status_url and response_url against validateMediaUrl()
and domain allowlist (queue.fal.run) before using them for polling. Falls back
to constructed URLs on validation failure.
Also updates mockFalCdnUpload test helper to match the two-step CDN upload
flow (initiate + PUT) introduced in 3fea13e.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
WaveSpeed's CloudFront CDN returns `binary/octet-stream` which wasn't
caught by the old `!== "application/octet-stream"` check, producing
unplayable data URLs. Now only accepts content types starting with
`video/` or `image/`, falling back to `video/mp4` or `image/png`.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The old single-POST endpoint (fal.ai/api/storage/upload) returns 404.
Switched to the current fal.ai upload API: initiate via
rest.alpha.fal.ai/storage/upload/initiate, then PUT binary data to
the returned signed URL.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Delete unused generateWithFal function (replaced by generateWithFalQueue)
- Add 20MB size guard in uploadImageToFal to prevent memory spikes
- Add refresh button to ModelSearchDialog that clears model and schema
localStorage caches plus in-memory fetch cache
- Wire "Try Again" error button to also clear stale caches
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace blocking fal.run endpoint with async queue.fal.run + 1s polling
to match Replicate/WaveSpeed behavior. Upload base64 images to fal CDN
before queue submission to avoid large inline payloads. Cache schema
mappings in-memory (30min TTL) to eliminate redundant API calls per
generation. Also fix localStorage cache leaking between tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Derive provider capabilities from mediaType instead of hardcoding
text-to-image, so isVideoModel is correct for video generations.
Treat application/octet-stream as unhelpful content-type and fall back
to video/mp4 or image/png based on model type. Add safety net in
save-generation to override .bin extension when media type is known.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Veo 3 and Veo 3 Fast models (text-to-video + image-to-video) with
custom API integration using Kie's /api/v1/veo/ endpoints and numeric
successFlag polling. Also document Kie model integration SOP in CLAUDE.md.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Refactor executeSingleNode error paths to throw instead of setting global
isRunning/currentNodeIds state, which corrupted sibling nodes running in
parallel via Promise.allSettled
- Validate WaveSpeed providedPollUrl with SSRF check before use
- Sanitize WaveSpeed taskId in provider with path-traversal validation
- Revoke blob URLs (URL.revokeObjectURL) before replacing outputVideo to
prevent memory leaks from large video files
- Move pause edge cleanup to outer executeWorkflow loop
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add validateMediaUrl() utility to block private IPs, localhost, and
non-HTTP protocols before server-side fetches (with tests)
- URL-encode Kie taskId in poll URL to prevent injection
- Validate WaveSpeed modelId against path traversal in both route.ts
and wavespeed.ts provider
- Add 500MB Content-Length check before downloading media at all 3
fetch sites (Kie, WaveSpeed route, WaveSpeed provider)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update stale test mocks from currentNodeId to currentNodeIds in
AudioInputNode, EaseCurveNode, and VideoStitchNode tests. Replace
hard 401 return for missing FAL API key with console.warn, allowing
requests to proceed without auth (rate-limited) since
generateWithFal() already handles null keys gracefully.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add nano-banana-pro model to Kie provider with schema and image input key
- Reorder Kie generation to process dynamicInputs before fallback image
uploads, preventing double-uploads when schema-mapped connections exist
- Update test mocks for deduplicatedFetch, useProviderApiKeys, and static
handle changes across GenerateImageNode, GenerateVideoNode,
ModelParameters, and ModelSearchDialog tests
- Add test commands to CLAUDE.md
- Fix SplitGridSettingsModal grid preview count (5 → 6 options)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove 36 unsupported Kie.ai models (14 image, 22 video) and add 2 new
ones (kling-2.6/motion-control, topaz/video-upscale), bringing the total
to 22 models. Fix parameter schemas to match official Kie.ai docs:
seedream quality param, flux-2 input_urls, grok-imagine video mode/duration,
kling sound param, wan resolution param, and singular vs array image keys.
Remove dead Veo/Kontext/Runway helper functions and endpoint branching —
all remaining models use the standard createTask endpoint.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add ~38 new image/video models (Imagen 4, FLUX.2, Flux Kontext,
Grok Imagine, Ideogram, Qwen, Runway, Hailuo, Seedance variants,
Kling older, Wan older) with schemas and endpoint routing for
dedicated APIs (Flux Kontext, Runway). Add pageUrl to all Kie
models and update ModelSearchDialog to use it.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Added validation to ensure fal.ai API key is provided in requests, returning a 401 status with an appropriate error message if not configured.
- Updated related tests to reflect the new API key requirement and adjusted assertions for expected responses.
- Modified documentation to clarify that fal.ai API key is now mandatory for model access.
GPT Image 1.5 only supports 'aspect_ratio', not 'size'.
Remove stale 'size' values from old workflow data before sending.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix Kie.ai GPT Image 1.5 failing to retrieve output URL by parsing
resultJson as JSON string (was treated as object incorrectly)
- Add 1x5 grid option to SplitGridNode for vertical contact sheets
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update dynamicInputs type from Record<string, string> to Record<string, string | string[]> in 4 locations
- Fix getConnectedInputs to aggregate same-key values into arrays instead of overwriting
- Fix dynamicInputs.prompt access to handle array case
- Fix hasPrompt check in POST handler to handle array-typed prompt
- Update processedDynamicInputs type in both Replicate and fal blocks
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update dynamicInputs type from Record<string, string> to Record<string, string | string[]> in 4 locations
- Fix getConnectedInputs to aggregate same-key values into arrays instead of overwriting
- Fix dynamicInputs.prompt access to handle array case
- Fix hasPrompt check in POST handler to handle array-typed prompt
- Update processedDynamicInputs type in both Replicate and fal blocks
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Kie API returns HTTP 200 even on errors, with error code in the JSON body.
Now properly checks createResult.code !== 200 and returns the actual error
message from the API instead of generic "No task ID in response".
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Some Kie.ai models (like gpt-image/1.5-text-to-image) require certain
parameters to be present even if not user-specified (e.g., aspect_ratio,
quality). Add getKieModelDefaults() function that provides model-specific
defaults which are merged with user-provided parameters.
Also skip file logging on Vercel since filesystem is read-only.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use multipart/form-data for file upload with 'file' and 'uploadPath' fields
- Extract download URL from data.downloadUrl in upload response
- Wrap parameters in 'input' object for standard models
- Use flat structure with camelCase for Veo models
- Extract results from resultJson.resultUrls in poll response
Co-Authored-By: Claude <noreply@anthropic.com>
Add Kie.ai as a new provider for image and video generation:
Image models (8):
- z-image, seedream/4.5-text-to-image, seedream/4.5-edit
- nano-banana-pro, gpt-image/1.5-text-to-image, gpt-image/1.5-image-to-image
- google/nano-banana, google/nano-banana-edit
Video models (11):
- sora-2-text-to-video, sora-2-image-to-video
- sora-2-pro-text-to-video, sora-2-pro-image-to-video
- veo3_fast, veo3, bytedance/seedance-1.5-pro
- kling-2.6/text-to-video, kling-2.6/image-to-video
- wan/2-6-text-to-video, wan/2-6-image-to-video
Key changes:
- Add "kie" to ProviderType union
- Add generateWithKie() with image upload and task polling
- Add hardcoded model list and schemas (no discovery API)
- Update workflow store for API key handling
- Update UI components with Kie provider badge
Co-Authored-By: Claude <noreply@anthropic.com>
## Template Explorer Enhancements
- Add rich metadata and thumbnails for community workflows
- Create communityWorkflows.ts config for workflow metadata
- Reuse TemplateCard for community workflows with tag filtering
- Search now includes workflow descriptions
## Comment Navigation System
- Add comment navigation icon in header with unviewed count badge
- Navigate between nodes with comments using prev/next controls
- Tooltips show comment preview on hover
## Output Node Improvements
- Add custom filename and createDirectory options for output saves
- Remove default React Flow styling from output nodes
- Fix video output node connections
- Preserve node height on resize
## Image Handling Fixes
- Resolve image history race condition and duplicate images on save
- Preserve image history IDs when saving to new directory
- Verify outputImageRef matches selected history index on save
- Persist useExternalImageStorage setting in workflow config
- Paste images directly into selected imageInput nodes
## Model & Generation Fixes
- Use selectedModel.modelId for Gemini generation
- Return 200 with notFound flag instead of 404 for missing files
## Other
- Add git-lfs tracking for large workflow files
- Remove deprecated example workflows
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes issues with external provider models (e.g., seedream-4.5) where:
- Boolean/integer params with "image" in name were misclassified as image inputs
- Array params without items.type specification were incorrectly rejected
- Handle ID mismatch between node components (image-0) and store (image)
- dynamicInputs not passed to API in node regeneration code path
Changes:
- Update isImageInput() to check schema types, not just names
- Map both indexed (image-0) and legacy (image) handle IDs to schema names
- Add dynamicInputs to nanoBanana regeneration request body
- Add hidden backward-compat handles for edge routing
- Add comprehensive tests for schema classification and handle mapping
- Fix Toast test to use specific selector for close button
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create server.js with extended requestTimeout (10 min) for long-running fal.ai video generation
- Update package.json dev script to use custom server
- Add comments explaining why queue API is not used (file size limitations)
- Use WHATWG URL API instead of deprecated url.parse()
- Added support for long-running video generation using a queue system with a 10-minute timeout.
- Updated maxDuration constant to reflect the new timeout for video generation.
- Enhanced API request handling to accommodate video generation, including error handling and polling for completion.
- Updated model retrieval tests to reflect the inclusion of additional models and improved provider filtering.
- Modified component tests to track model usage and reflect changes in the UI for provider selection.
When providers like fal.ai or Replicate expect array parameters (e.g.,
image_urls), single values from dynamicInputs are now automatically
wrapped in arrays based on the OpenAPI schema's type property.
Changes:
- Add isArray field to ModelInput type for schema detection
- Update getFalInputMapping() to return schemaArrayParams
- Update getInputMappingFromSchema() to return schemaArrayParams
- Apply array wrapping in both fal.ai and Replicate handlers
- Add tests for array wrapping behavior
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix isImageInput() to use word-boundary checks instead of substring
matching, preventing num_images from being misclassified as image input
- Fix stale node data in workflow execution by getting fresh data from
store instead of using captured array references
- Add missing parameters to regenerateNode request bodies for both
nanoBanana and generateVideo nodes
- Update fal.ai schema fetch to use Model Search API endpoint
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Group file operations (save, open folder) together with subtle separator
- Separate settings button with visual spacing
- Add hover background states to icon buttons for better interactivity
- Improve unsaved indicator with ring outline for better visibility
- Use consistent padding (p-1.5) and rounded corners
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Updated .env.example to include new API keys for OpenAI, Replicate, and fal.ai.
- Modified API routes to prioritize user-provided API keys over environment variables for Gemini and OpenAI.
- Improved error messages for missing API keys to guide users on configuration.
- Enhanced ProjectSetupModal to support OpenAI provider and manage API key overrides.
- Updated workflow store to handle new provider settings and API key integration for OpenAI.
- Added functionality to auto-save generated images and videos to the specified directory.
- Introduced a model search dialog for selecting external models in GenerateImageNode and GenerateVideoNode.
- Updated node titles to reflect selected models dynamically.
- Improved parameter handling by expanding the ModelParameters component to notify parent nodes on schema load.
- Adjusted handle positions and styles for better alignment and visual consistency.
- Enhanced input validation and processing for dynamic inputs across the workflow.
- Render dynamic input handles from model schema (GenerateImage/VideoNode)
- Update connection validation with getHandleType() helper
- Add dynamicInputs to getConnectedInputs() return value
- Pass dynamicInputs through generation pipeline (workflowStore -> API)
- Update generateWithFal/Replicate to use dynamic inputs
- Process large images in dynamicInputs to URLs for external providers
- Support prompt from dynamicInputs when top-level prompt is empty
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add modelsFetchError state with retry button in GenerateImage/VideoNode
- Show clear errors when model list fails to load (API key issues, connection)
- Improve API route error messages to include model name
- Add rate limit handling (429) with user-friendly messages
- Parse provider-specific error responses for better detail
- Improve timeout message for video generation