Add first_frame_url, last_frame_url, and first_clip_url to the
singular-key checks in generateWithKie() so these params receive a
single string URL instead of being wrapped in an array.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
isImageInput() has permissive description heuristics (e.g. "data uri")
that false-positive on audio properties like audio_url whose description
mentions "base64 data URI". Reorder the checks so isAudioInput() — which
uses specific name patterns — runs first.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add AUDIO_INPUT_PATTERNS, isAudioInput() function modeled after
isImageInput(), and integrate into extractParametersFromSchema() to
detect audio inputs from model schemas. Audio inputs are sorted
between image and text inputs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add "audio-to-video" to ModelCapability union, extend ModelInput.type
and ModelInputDef.type with "audio", and include "audio-to-video" in
fal.ai RELEVANT_CATEGORIES for model discovery.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- GroupsOverlay: reset color picker when menu closes, guard locked groups
from drag/resize/rename
- AudioInputNode: add keyboard accessibility to dropzone (role, tabIndex,
onKeyDown)
- list-workflows: fix name regex to handle escaped quotes
- GroupsOverlay.test: add missing NBP Input menu item assertion
- WorkflowBrowserView: make relativePath required to match API contract
- WorkflowBrowserModal: add dialog role, aria-modal, aria-labelledby
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- cleanup-workflow.js: Filter only embedded data: images from outputGallery
instead of wiping entire array; preserve imageRef/video on output nodes
- workflow/route.ts: Validate parsed.version is number, nodes/edges are
arrays; sort candidates by mtime desc for deterministic file selection
- mediaStorage.ts: Guard against undefined mediaData in loadMediaById
before caching/returning
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add recursive directory scanning (up to 3 levels deep) to the
list-workflows API so projects organized into subdirectories are
visible in the workflow browser. Skips hidden dirs and node_modules.
Returns relativePath field displayed as the subtitle in the UI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of parsing entire workflow JSON files (which can be many MB with
embedded base64 data), read only the first 1KB to extract the name via
regex. Drop nodeCount from the listing. Probe all directories in parallel.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Scans subdirectories of a given parent path for valid workflow JSON files,
returning name, path, node count, and last modified time.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace browser file picker with the existing /api/browse-directory native
OS folder picker so loadWorkflow receives the actual filesystem path,
enabling media hydration from sibling inputs/ and generations/ folders.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use API response imageId instead of locally generated ID in
saveVideoAndGetRef/saveAudioAndGetRef (filename mismatch)
- Read result.video/result.audio instead of result.data in
loadMediaById (response field mismatch)
- Add audio extensions and MIME types to load-generation route
so audio files can be found and served
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Critical bug fix - the mediaStorage.ts functions were using incorrect
parameter names when calling the save-generation and load-generation APIs.
Fixed parameter mappings:
- workflowPath → directoryPath (API expects this name)
- id → imageId (API expects this name)
- data + type → video/audio (API expects media in named fields)
- Changed load from GET to POST with correct body structure
Also increased serverActions bodySizeLimit from 50mb to 100mb to handle
large video files during externalization.
This fixes the save failures when externalizing workflows with videos/audio.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add video, audio, text, 3d, easeCurve entries to EDGE_COLORS in SharedEdgeGradients
- Normalize handle type suffixes (e.g. image-0 -> image) in EditableEdge color lookup
- Gate Kie provider filter behind API key check (return 400 if missing)
- Fix getMediaDimensions to check URL pathname for image extensions before defaulting to video
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fal was unconditionally listed as available, which could surface
fal models to users without a fal API key configured.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The ModelSearchDialog only checked client-side localStorage keys to
determine available providers, missing providers configured via .env
server-side vars. Now the /api/models endpoint returns an
availableProviders array and the dialog merges both sources.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of an inline text field, negative prompt is now a proper text
handle on the node that can receive connections from prompt/LLM nodes.
Updates the API route to merge dynamicInputs.negative_prompt into the
Veo parameters, and aligns the model schema definition accordingly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add early validation for image-to-video models when no image is provided
- Wrap Veo generation/polling in try/catch with specific error messages
- Add 60s AbortController timeout to video download fetch
- Fix SwitchNode toggle knob not sliding (peer-checked on non-sibling)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The MAX_BASE64_SIZE check was returning the video URL with the API key
appended as a query parameter to the browser client for videos over 20MB.
Always encode to base64 instead since the buffer is already downloaded.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Import generateWithGeminiVideo and route Veo model requests (modelId
starting with 'veo-') to the video provider before falling through
to the existing image generation path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Veo video generation using @google/genai SDK with:
- Model ID mapping (veo-3.1/veo-3.1-fast to API model IDs)
- Async generation with polling (10s intervals, 5min timeout)
- Image-to-video support with base64 image input
- Video download and base64 encoding (URL fallback for >20MB)
- Configurable aspect ratio, duration, resolution, negative prompt, seed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add getGeminiVideoSchema() function returning parameter schemas (aspect
ratio, duration, resolution, negative prompt, seed) and input definitions
for all 4 Veo model variants. Wire into GET handler with gemini provider
support.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add GEMINI_VIDEO_MODELS array with 4 native Veo entries (3.1 and 3.1 Fast,
text-to-video and image-to-video variants) and include them in the GET
handler alongside existing Gemini image models.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Anthropic as a third LLM provider with Claude Opus 4.6, Sonnet 4.5,
and Haiku 4.5 models. Extend Google provider with Gemini 3.1 Pro.
Includes full API route support with multimodal content blocks,
provider settings UI, temperature clamping (Anthropic max 1.0),
header builder plumbing, and comprehensive test coverage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Nano Banana 2 (gemini-3.1-flash-image) supports a new searchTypes API
that allows enabling web search and image search independently. This adds
a useImageSearch toggle visible only for Nano Banana 2, while keeping the
existing Google Search toggle using the legacy format for Nano Banana Pro.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update expected model counts and sort order to account for the new
Nano Banana 2 Gemini model (3 Gemini models instead of 2).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Nano Banana 2 entry to GEMINI_IMAGE_MODELS in model registry
- Add model to GenerateImageNode dropdown with 512px resolution option
- Extend resolution/Google Search gates to support nano-banana-2
- Replace hardcoded model name ternaries with MODEL_DISPLAY_NAMES lookup
in workflowStore, nodeDefaults, and GenerateImageNode migration code
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Map nano-banana-2 to gemini-3.1-flash-image-preview API model.
Enable resolution control and Google Search grounding for nano-banana-2.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add resolvePropertyType() helper to extract effective type/format from
OpenAPI wrapper patterns (anyOf, oneOf, allOf, $ref) used by Pydantic
and other code generators. Update isImageInput() and convertSchemaProperty()
to use resolved types instead of reading prop.type directly.
This ensures nullable fields like `{anyOf: [{type: "string"}, {type: "null"}]}`
are correctly identified as image inputs when their name matches image patterns.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create validateWorkflowPath() utility to prevent path traversal attacks
- Reject non-absolute paths, traversal sequences, and dangerous system directories
- Apply validation to workflow and workflow-images POST/GET handlers
- Fix workflow-images ENOENT-specific catch block to match workflow route pattern
- Fix workflow mkdir failure status code from 400 to 500 (server error)
- Add comprehensive path traversal tests for both routes
- All malicious path attempts now return 400 Bad Request
- 3 tests per provider (Replicate, fal.ai): prompt included with dynamicInputs,
no duplication when dynamicInputs already has prompt, existing non-dynamicInputs path works
- Mock fetch intercepts provider API calls and captures request bodies
- Verifies the fix from the previous commit prevents "prompt is required" errors
- Include input.prompt in API request when dynamicInputs are present but don't contain a prompt key
- Use schema paramMap to resolve model-specific prompt parameter name
- Skip if dynamicInputs already provides a prompt value (no duplication)
- Remove Save As button and handler from Header (feature not ready)
- Remove Array node button from FloatingActionBar (not ready for release)
- Add error logging for failed Kie.ai tasks to aid debugging
- Add .superset/ to .gitignore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The old preview model ID (gemini-2.5-flash-preview-image-generation) was
deprecated. Updated to the current stable ID across provider, cost
calculator, tests, and docs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add path traversal guard to workflow-images GET handler (matching POST handler)
- Preserve stored prompt in generateAudioExecutor when connected text is null
- Reset conflicting isVideo/isAudio flags in kie.ts content-type detection
- Fix Infinity aspect ratio causing zero-height canvas in VideoStitchNode
- Check response content-type before trusting isAudioModel in fal.ts
- Move audio feeding inside inner try block in useStitchVideos for proper cleanup
- Add 30s seek timeout to frame extraction in videoProcessingExecutors
- Surface file-open errors via toast in Generate3DNode instead of failing silently
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract shared video-probing module (constants, helpers, probeVideoMetadata)
from useTrimVideo and useStitchVideos into src/lib/video-probing.ts
- Fix audio interleaving in useTrimVideo to feed audio before video frames,
matching useStitchVideos fix for Discord playback compatibility
- Fix blob URL leaks in VideoTrimNode and videoProcessingExecutors
- Fix nanoBananaExecutor: null coercion for non-string prompts, redact PII
in console.warn, remove duplicate dynamicInputs.prompt
- Fix generateAudioExecutor double updateNodeData on error paths
- Fix fal.ts media fetch ordering for 3D model detection
- Fix kie.ts and replicate.ts content-type detection for audio models
- Fix WorkflowCanvas connection drop menu wiring for generateAudio nodes
- Fix open-file route Windows path quoting
- Add path traversal protection to workflow-images route
- Add AudioInputNode onerror handler for metadata loading failures
- Fix useAudioPlayback uncaught play() promise rejection
- Add generateAudio case to regenerateNode in workflowStore
- Update placeholder Discord links to real invite URL
- Extract ProviderBadge into shared component in Generate3DNode
- Fix VideoTrimNode duration detection with proper cleanup and cancellation
- Fix GenerateAudioNode test fetch mock cleanup
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 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>
text-to-speech was already in RELEVANT_CATEGORIES but the test still
expected it to be filtered out. Update count and add assertion that
TTS models are mapped to text-to-audio capability.
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>
Replace 3 if-statements mapping fal audio categories to a single
record lookup, making it easier to add new audio categories.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Audio models (music, TTS, speech) were misclassified as text-to-image
because capability inference only checked for 3D and video keywords.
This caused audio models to not appear in GenerateAudio's model browser
and to create nanoBanana nodes instead of generateAudio nodes.
- Add audio keyword detection to inferReplicateCapabilities()
- Add audio keyword detection to inferWaveSpeedCapabilities()
- Add audio output handling to replicate.ts provider
- Add audio output handling to wavespeed.ts provider
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add text-to-music and text-to-sound-effects to fal.ai RELEVANT_CATEGORIES
so music/SFX models (MiniMax Music, Lyria 2, Stable Audio, etc.) appear
- Map new fal categories to text-to-audio capability in mapFalCategory
- Add ElevenLabs Sound Effects v2 model to KIE_MODELS registry
- Add parameter schemas for all 4 ElevenLabs models (turbo-v2.5,
multilingual-v2, text-to-dialogue-v3, sound-effect-v2) in getKieSchema
- Add model defaults for ElevenLabs TTS and SFX models
- Remap prompt->text field for ElevenLabs models (Kie API requirement)
- Add audio response detection in generateWithKie (capability, URL
extension, and content-type checks) so audio output is correctly
returned as type "audio" instead of being misclassified as "image"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fal returns audio in result.audio.url for TTS models, but the media URL
extraction chain didn't check for this field. Add audio URL extraction,
isAudioModel detection, and audio-specific output handling that returns
base64-encoded audio with type "audio".
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>