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>
- Import extractSubgraph from subgraphExtractor
- Parse selectedNodeIds from request body
- Call extractSubgraph before building workflow context
- Pass subgraph.selectedNodes and selectedEdges to buildWorkflowContext
- Update buildEditSystemPrompt to accept optional restSummary parameter
- Add WORKFLOW CONTEXT (SELECTED SUBSET) section when scoped
- Include rest-of-workflow summary with type breakdown and boundary connections
- Add metadata placeholder note to system prompt
- Enhance error handling to return 413 for oversized payloads
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>
Rewrite /api/chat route to accept workflow context from client and use
AI SDK tool calling for multi-modal agent routing.
Changes:
- Accept optional workflowState (nodes/edges) in request body
- Build workflow context using buildWorkflowContext from contextBuilder
- Generate context-aware system prompt using buildEditSystemPrompt
- Create chat tools (answerQuestion, createWorkflow, editWorkflow) with
current node IDs for validation
- Configure streamText with tools, toolChoice: 'auto', and stopWhen for
multi-step reasoning (up to 3 steps)
- Stream results back via toUIMessageStreamResponse for useChat hook
compatibility
LLM now automatically routes to the correct tool based on user intent.
Tool results stream back to client for application in Plan 03.
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>
- 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>
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>
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 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>
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>
- Import convertToModelMessages and UIMessage from ai
- Convert incoming messages for useChat hook compatibility
- Return toUIMessageStreamResponse() instead of toTextStreamResponse()
- POST /api/chat with Vercel AI SDK streamText
- Node Banana domain expertise in system prompt
- Conversational workflow planning assistant
- Uses createGoogleGenerativeAI with GEMINI_API_KEY
Add POST endpoint that generates WorkflowProposal JSON from a description:
- Validates description (min 3 chars)
- Calls Gemini with buildProposalPrompt
- Parses JSON with repair logic from validation.ts
- Validates response matches WorkflowProposal structure
- Returns { success: true, proposal } or { success: false, error }
Uses same patterns as /api/quickstart:
- maxDuration = 60
- Temperature 0.3 for consistent output
- Request ID logging
- Rate limit (429) handling
- gemini-3-flash-preview model
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove configurable COMMUNITY_WORKFLOWS_API_URL env var that caused
errors when users copied the placeholder from .env.example.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Validate presigned URLs before fetching by checking:
- Protocol is https
- Hostname ends with .r2.cloudflarestorage.com
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update the community workflow API to fetch presigned URLs from
node-banana-pro, then download workflows directly from R2. This
avoids timeouts when fetching large workflow files (275MB+).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update API routes to fetch from nodebananapro.com
- Remove local workflow JSON files (now hosted on R2)
- Remove LFS tracking (.gitattributes)
- Remove local communityWorkflows.ts metadata (now on server)
- Add COMMUNITY_WORKFLOWS_API_URL env variable option
Co-Authored-By: Claude Opus 4.5 <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>
Add fetchFalPricing() to batch-fetch pricing from fal.ai API:
- GET /v1/models/pricing?endpoint_id={ids}
- Maps "image" unit -> per-run, others -> per-second
- Best-effort: errors logged but don't fail model fetching
Pricing is merged into ProviderModel after fetching fal.ai models.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add pricing field to GEMINI_IMAGE_MODELS array:
- nano-banana: $0.039 per-run
- nano-banana-pro: $0.134 per-run
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Security & API route fixes:
- Remove API key query param support in fal/models route to prevent credential leakage
- Fix MIME type fallback in save-generation route (now uses prefix-based fallback: image/* -> png, video/* -> mp4, unknown -> bin)
- Add timeout (60s) and size limits (500MB) for remote fetch in save-generation route using AbortController
CSS fix:
- Consolidate duplicate :root blocks in globals.css
- Change handle selector from data-handletype="prompt" to data-handletype="text"
- Update --handle-color-text CSS variable from #a3a3a3 to #3b82f6
Test file global mock isolation:
- Fix useAnnotationStore mock to support Zustand selector pattern
- Use vi.stubGlobal() instead of direct global assignments to prevent test leakage
- Restore global.Image in afterAll hook in AnnotationModal.test.tsx
- Wrap async Done assertion in waitFor() in AnnotationModal.test.tsx
- Use idiomatic fireEvent.dragOver() in AnnotationNode.test.tsx
- Fix global.confirm stub with proper beforeAll/afterAll lifecycle in CostDialog.test.tsx
- Import ReactNode type properly in EdgeToolbar.test.tsx
- Update save-generation route test to expect AbortController signal in fetch call
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>
- Add GEMINI_IMAGE_MODELS constant with nano-banana and nano-banana-pro
- Update GET handler to include Gemini models in response
- Support provider=gemini filter (returns only Gemini models)
- Gemini models appear first in 'all providers' results
- No API key needed for Gemini (always available)
Add tests verifying the parameters field (UI settings) is passed to
provider APIs:
- Replicate: parameters passed to prediction input
- Replicate: dynamicInputs take precedence when merging
- fal.ai: parameters passed to request body
- fal.ai: dynamicInputs take precedence when merging
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive tests for /api/models route covering:
- Basic functionality: fal.ai without key, both providers with keys
- Provider filtering by query param
- Capabilities filtering
- Search query param (client-side for Replicate, server-side for fal.ai)
- Caching behavior: cache hits, cache misses, refresh bypass
- Error handling: partial provider failures, all providers failing
- Pagination for both Replicate and fal.ai (max 15 pages)
- Capability inference for Replicate models (video keywords, i2v keywords)
- fal.ai category mapping to ModelCapability
- Model sorting by provider then name
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive tests for /api/generate fal.ai path:
- Image generation success (images array response)
- Video generation success (video object response)
- Works without API key (unauthenticated allowed)
- Rate limit (429) handling with and without key
- Various response formats (image, images, video, output)
- Large video (>20MB) returns URL instead of base64
- Empty dynamicInputs values are filtered
- Dynamic inputs passed to fal.ai request
- Environment variable API key fallback
- Error response formats (error.message, detail array)
- No media URL in response handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>