- Add "video" to Output node's getNodeHandles inputs list
- Consistent with isValidConnection and findCompatibleHandle video->output handling
- Output node now properly accepts VideoStitch connections via all code paths
- Add video handle mapping for videoStitch, generateVideo, and output
- Add audio handle mapping for audioInput and videoStitch
- Connection drop now auto-connects for all handle types
- Detect audio file types in handleDragOver (audio/*)
- Handle audio files in handleDrop creating AudioInput nodes
- Show "Drop audio to create node" overlay for audio drag
- Add "audio" to dropType state union
Ensure handles render in all node states (disabled/checking/normal) by
extracting a shared renderHandles function. Move clipOrder syncing from
useMemo side-effect into a proper useEffect. Add dynamic video handle
resolution in WorkflowCanvas for indexed handles. Add VideoStitch
execution case in regenerateNode.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add level-based topological sort (groupNodesByLevel) to identify
nodes that can execute concurrently
- Change state from currentNodeId to currentNodeIds[] for tracking
multiple executing nodes
- Execute nodes in batches using Promise.allSettled with configurable
concurrency limit (default 3, adjustable 1-10)
- Integrate AbortController for fail-fast cancellation on errors
- Pass abort signals to API fetch calls for proper request cancellation
- Update UI: multiple nodes show execution border, FloatingActionBar
shows "N nodes" during parallel execution
- Add concurrency slider in Project Settings > Node Defaults tab
- Store concurrency preference in localStorage
Workflows with independent generate nodes (e.g., 3 parallel image
generations) now complete in ~20-25s instead of ~60-90s sequential.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
WorkflowCanvas.tsx:
- Import VideoStitchNode
- Add videoStitch to nodeTypes
- Add getNodeHandles case: inputs=["video", "audio"], outputs=["video"]
- Update isValidConnection to allow video→videoStitch connections
- Add minimap color: orange-500 (#f97316)
ConnectionDropMenu.tsx:
- Add videoStitch to VIDEO_TARGET_OPTIONS (first position)
- Add videoStitch to VIDEO_SOURCE_OPTIONS (produces video output)
- Add videoStitch to AUDIO_TARGET_OPTIONS (accepts audio input)
workflowStore.ts:
- Import VideoStitchNodeData type
- Add videoStitch to getSourceOutput (returns video type)
- Add executeWorkflow case for videoStitch with full stitching logic:
* Check encoder support
* Get connected inputs (videos, audio)
* Convert video data URLs to Blobs
* Prepare audio if connected (using prepareAudioAsync)
* Call stitchVideosAsync with progress callback
* Store output (blob URL for >20MB, data URL otherwise)
* Handle errors
Note: nodeDefaults.ts already had videoStitch dimensions and
createDefaultNodeData from Plan 02, so no changes needed there.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Component with encoder detection on mount (checkEncoderSupport)
- Dynamic video input handles (video-0, video-1, etc.) based on connections
- Audio input handle at bottom (violet color, matching AudioInput)
- Video output handle
- Filmstrip UI with thumbnail extraction (seek to 25% duration)
- Clip ordering via clipOrder array with drag-to-reorder support
- X button per clip to disconnect
- Processing trigger button (disabled until 2+ clips connected)
- Progress overlay during stitching (shows percentage)
- Output video preview on completion
- Disabled state when encoder not supported
- Export added to nodes/index.ts
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Added AudioInputNode export to nodes/index.ts
- Added audioInput to defaultNodeDimensions (300x200) and createDefaultNodeData
- Registered audioInput in WorkflowCanvas nodeTypes map
- Updated getHandleType to recognize audio handles
- Added audioInput to getNodeHandles (no inputs, audio output)
- Updated isValidConnection for audio-to-audio validation
- Added audio to ConnectionDropState handleType union
- Updated findCompatibleHandle to accept audio type
- Added AUDIO_SOURCE_OPTIONS and AUDIO_TARGET_OPTIONS to ConnectionDropMenu
- Added audio array to getConnectedInputs return type
- Updated getSourceOutput to handle audioInput nodes
- Added audioInput execution case (no-op, data source)
- Added AudioInputNodeData import to workflowStore
- Updated DEFAULT_DIMENSIONS in WorkflowCanvas and quickstart/validation.ts
- Updated createDefaultNodeData in quickstart/validation.ts
- Added violet minimap color (#a78bfa) for audioInput nodes
- File upload via drag-and-drop or click
- Waveform visualization using useAudioVisualization hook
- Play/pause controls with scrub bar
- Canvas-based rendering with ResizeObserver for responsive sizing
- Audio handle (purple/violet) on right side
- Min dimensions: 250px width, 150px height
- Remove button to clear audio file
- 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>
Add onKeyDown handler to PromptNode variable name input so Enter saves.
Add outputGallery, imageCompare, and promptConstructor to ConnectionDropMenu
handle mappings for auto-connect on drag-drop. For imageCompare, redirect
connections to the second handle (image-1) when the first is occupied.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Extract autocomplete logic to usePromptAutocomplete hook
- Add PromptConstructorEditorModal with portal rendering
- Sync PromptConstructor outputText reactively for downstream nodes
- Add headerButtons prop to BaseNode for custom header actions
- Rename Blank Canvas to New Project with ProjectSetupModal integration
- Auto-push generated images to connected OutputGallery nodes
- Deduplicate images in OutputGallery during workflow execution
- Move PromptNode variable button to header with hover animation
- Extract AvailableVariable interface to types/nodes.ts
- Update tests for onNewProject rename
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Two labeled image input handles: 'A' (top 35%) and 'B' (bottom 65%)
- Real-time image collection from connected nodes (same pattern as OutputGalleryNode)
- ReactCompareSlider with horizontal-only slider (portrait=false)
- Corner labels A and B on comparison view
- Placeholder states for 0 or 1 images with connection status feedback
- nodrag nopan nowheel classes for interaction isolation
- BaseNode wrapper with customizable title and comments
- Build verified: zero TypeScript errors
- Install react-compare-slider dependency
- Add imageCompare to NodeType union
- Add ImageCompareNodeData interface (imageA, imageB fields)
- Add to WorkflowNodeData union type
- Register in nodeDefaults with 400x360 dimensions
- Add to WorkflowCanvas nodeTypes and minimap (teal color)
- Add to ConnectionDropMenu IMAGE_TARGET_OPTIONS
- Add executeWorkflow case to assign images[0] to imageA, images[1] to imageB
- Export ImageCompareNode from components/nodes/index
- Add to validation.ts DEFAULT_DIMENSIONS and createDefaultNodeData
- Template textarea with @ autocomplete dropdown
- Detects @ typing and shows matching connected variable names
- Autocomplete dropdown shows @name and prompt value preview
- Arrow keys navigate, Enter/Tab select, Escape closes
- Client-side computation of unresolvedVars from @(\w+) patterns
- Warning badge displays unresolved @tags in amber
- Live preview tooltip on hover showing resolved template
- availableVariables computed from connected prompt nodes with variableName
- Text input handle (target, left) and text output handle (source, right)
- BaseNode wrapper with title 'Prompt Constructor'
- Sync template to store on blur (same pattern as PromptNode)
- Local state prevents cursor jumping during typing
- Filtered autocomplete based on typed characters after @
- Position autocomplete relative to textarea with line height calculation
- Add variableName field to PromptNodeData (optional, backward compatible)
- Add promptConstructor to NodeType union
- Add PromptConstructorNodeData interface (template, outputText, unresolvedVars)
- Add to WorkflowNodeData union type
- Add promptConstructor to defaultNodeDimensions (340x280)
- Add createDefaultNodeData case for promptConstructor
- Modified PromptNode with @ variable naming dialog using createPortal
- Variable name validation: alphanumeric + underscore, max 30 chars
- Blue @ icon when variableName set, dimmed when not set
- Dialog shows variable name input, preview, Save/Clear buttons
- Register PromptConstructorNode in WorkflowCanvas nodeTypes
- Add promptConstructor minimap color (#f472b6 pink)
- Add to TEXT_TARGET_OPTIONS and TEXT_SOURCE_OPTIONS in ConnectionDropMenu
- Add getConnectedInputs support for promptConstructor outputText
- Add executeWorkflow case for promptConstructor:
- Finds connected prompt nodes via text edges
- Builds variable map from variableName + prompt values
- Resolves template by replacing @variableName with values
- Tracks unresolved variables in unresolvedVars array
- Stores outputText and unresolvedVars on node data
- Export PromptConstructorNode from components/nodes/index.ts
- Update duplicate defaultDimensions in WorkflowCanvas and quickstart validation
- Create OutputGalleryNode.tsx with BaseNode wrapper
- Single image input handle (type target, id image)
- Real-time image collection from connected nodes (imageInput, annotation, nanoBanana)
- 3-column scrollable thumbnail grid with nowheel for scroll isolation
- Full-screen lightbox via createPortal with:
- Left/right arrow navigation
- Download button (saves as gallery-image-N.png)
- Close button (X icon, top-right)
- Click backdrop to close
- Keyboard support (Escape, ArrowLeft, ArrowRight)
- Image counter display (N / Total)
- Empty state placeholder when no images connected
- Fix validation.ts: add outputGallery dimensions and createDefaultNodeData case
- Build passes with zero errors
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add outputGallery to NodeType union in types/nodes.ts
- Add OutputGalleryNodeData interface with images array field
- Add outputGallery to WorkflowNodeData union
- Register in nodeDefaults: dimensions 320x360, default data with empty images array
- Export OutputGalleryNode from nodes/index.ts
- Register outputGallery in WorkflowCanvas nodeTypes with pink minimap color (#ec4899)
- Add outputGallery to ConnectionDropMenu IMAGE_TARGET_OPTIONS with grid icon
- Add outputGallery case to executeWorkflow in workflowStore
- Add outputGallery to getNodeHandles (image input, no outputs)
- Add outputGallery dimensions to keyboard shortcut default dimensions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add createdAt timestamp to WorkflowEdgeData interface
- Store createdAt on edge creation in onConnect and addEdgeWithType
- Add getImageSequenceNumber helper to EdgeToolbar
- Display "Image N" label for image connections with 2+ edges to same target
- Sequence numbers based on createdAt for stable ordering
- Single connections and text connections show no numbering
- Import stripBinaryData from contextBuilder
- Rewrite chatWorkflowState memo to use stripBinaryData for rich but compact node data
- Compute selectedNodeIds from nodes.filter(n => n.selected)
- Pass selectedNodeIds as new prop to ChatPanel
- Update ChatPanel to accept and forward selectedNodeIds in API requests
- Add dismissible "Focused on N selected nodes" chip above input when nodes selected
- Add error handling for oversized payloads with user-friendly message
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add execute functions to all three chat tools (pass-through pattern)
so AI SDK produces proper tool-call/tool-result pairs in conversation
history, fixing AI_MissingToolResultsError on subsequent messages
- Fix stale closure in ChatPanel customFetch by using a ref for
workflowState, ensuring current canvas state is sent with each request
- Add EDITABLE NODE PROPERTIES section to system prompt so LLM uses
correct data property names (e.g. "prompt" not "text" for prompt nodes)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add applyEditOperations to workflowStore for AI-driven workflow modifications.
Wire ChatPanel to process editWorkflow tool calls and apply operations via store.
Pass lightweight workflow state to chat API for context-aware assistance.
Changes:
- workflowStore: add applyEditOperations method and EditOperation import
- ChatPanel: add onApplyEdits prop, workflowState prop, custom fetch wrapper
- ChatPanel: process tool-invocation parts for editWorkflow and createWorkflow
- ChatPanel: render tool explanations in chat UI
- WorkflowCanvas: extract chatWorkflowState, create handleApplyEdits callback
- WorkflowCanvas: pass onApplyEdits and workflowState to ChatPanel
AI edits trigger captureSnapshot before applying (revert button support).
AI edits do NOT increment manualChangeCount (only manual edits clear snapshot).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Broaden the trailing-slash exemption to recognize both C:\ and C:/ as
drive roots. Tighten the client-side absolute path check to require a
separator after the drive letter and accept UNC paths (\\server\share).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
On macOS, osascript's folder picker can return hostname-prefixed paths
(e.g. "HOSTNAME/Users/...") for network-mounted volumes instead of
absolute POSIX paths, causing directory validation to fail.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use neutral-300 text, neutral-700/50 bg, and neutral-600 border
to make the button noticeable without clashing with the app style.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
loadWorkflow was unconditionally calling clearSnapshot(), wiping the
snapshot that captureSnapshot() just saved. Add preserveSnapshot
option to loadWorkflow and pass it from the AI build workflow path
so the Revert AI Changes button actually appears.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Updated last activity date and details in STATE.md to reflect completion of quick-001.
- Added recent decisions regarding dynamicInputs type and behavior.
- Enhanced tests in QuickstartTemplatesView to handle new download URL structure for community workflows, ensuring proper response handling for both API and direct download scenarios.
Update vulnerable react-dom dependency and next.js to patched versions.
Fix QuickstartTemplatesView test to mock two-step R2 download flow.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The proxy was downloading 80-275MB workflow files through a serverless
function, causing timeouts and failures. Now the proxy just returns the
presigned R2 URL and the client downloads directly from R2.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Kie.ai section in provider settings with API key input
- Add kie to env-status API for .env detection
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>
Add react-markdown to parse assistant responses so bold, italic,
lists, blockquotes, and code render properly instead of showing
raw asterisks and markdown syntax.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add trash icon button in chat header that clears all messages.
Only visible when messages exist. Uses setMessages([]) from
the AI SDK useChat hook.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Rewrite chat system prompt to be concise — bullet points over
paragraphs, 2-4 sentences per response. Make chat panel stretch
from top-16 to bottom-[220px] for near-full canvas height.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tasks 1 & 2: Complete AI workflow revert feature
Changes:
- WorkflowCanvas: Call captureSnapshot() before AI loadWorkflow
- Header: Add "Revert AI Changes" button with confirmation dialog
- Button visible only when previousWorkflowSnapshot exists
- Amber styling to distinguish safety feature from destructive actions
Snapshot capture ONLY in AI generation path (not file loads/templates).
Button auto-hides after revert or 3 manual changes (store handles this).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add handleBuildWorkflow function that calls /api/quickstart with conversation
description and loads the generated workflow. Includes error handling with toast
notifications and automatically closes chat panel on success.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add "Build Workflow" button that appears after conversation starts. Button
extracts user messages to form a description and passes to parent via callback.
Includes loading state support via isBuildingWorkflow prop.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add nowheel class to prevent React Flow from intercepting scroll
- Add touchAction: pan-y for proper touch gesture support
- Add onWheelCapture to stop event propagation to canvas
- Add isChatOpen state for chat visibility
- Add chat toggle button positioned above MiniMap
- Render ChatPanel conditionally when open
- Style toggle button with active/inactive states
- Add @ai-sdk/react package for useChat hook
- Create floating chat panel with streaming messages
- Display messages with role-based styling (user/assistant)
- Auto-scroll to bottom on new messages
- Show loading indicator during AI responses
- Dark theme matching app (neutral-800 bg)
LLMGenerateNode improvements:
- Add collapsible parameters section with temperature and max tokens sliders
- Add copy to clipboard button for output text
- Clean up UI organization
PromptNode improvements:
- Add text input handle to receive incoming text connections
- Auto-populate prompt when connected to a text source (e.g., another LLM)
ConnectionDropMenu:
- Add Prompt as a target option for text connections
ProjectSetupModal:
- Add max tokens slider for LLM default settings
Test updates:
- Update mocks to include edges and getConnectedInputs
- Fix tests for collapsible parameters section
- Update wrap-around test for new menu options
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
React Flow's internal bounds for nodes were undefined, causing certain nodes
to be incorrectly included in drag selections regardless of their position.
Added statistical outlier detection using IQR to identify and automatically
deselect nodes that are clearly outside the actual selection area.
Also includes:
- Clear selected state and validate position coordinates on workflow load
- Strip selected property when saving workflows (transient UI state)
- Enable prompt nodes to receive text input connections
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The PromptNode now uses local state and only updates on blur to prevent
cursor jumping. Update test to trigger blur after change.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update getHandleType() to recognize indexed handles (text-0, image-0)
used by external providers like Replicate and fal.ai
- Fix validateWorkflow() to accept indexed text handles for nanoBanana nodes
- Add validation for generateVideo nodes requiring text input
- Use local state pattern in PromptNode to prevent cursor jumping during typing
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>