Veo models (veo-3.1, veo-3.1-fast) showed no user-configurable
parameters in the UI. Follows the established pattern from
GenerateImageNode where Gemini model parameters are hardcoded in the
component rather than fetched via the schema API. Adds aspect ratio,
duration, resolution, negative prompt, and seed controls.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The dimming algorithm processed potentially-dimmed nodes in arbitrary
order, causing nodes downstream of a rescued convergence point to stay
dimmed. Fix by topologically sorting the candidate set (upstream-first)
and checking finalDimmed instead of potentiallyDimmed, so rescued nodes
properly propagate their active status downstream.
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>
Adds an evaluationPaused flag that lets users reset evaluation state
and un-dim all downstream paths. The flag auto-resets on workflow
execution or manual rule edits.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The useMemo for incomingText depended on edges (from useEdges), which
doesn't change when upstream node data changes. On re-runs, the memo
returned stale text and the useEffect overwrote correct execution
results. Replace with a Zustand store selector using
getConnectedInputsPure that recomputes when upstream node data changes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The customTitle and comment fields are typed as string | undefined in
ConditionalSwitchNodeData. The null values were masked by an 'as' cast
but caused strict type errors. These fields are optional and don't need
explicit defaults.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The customTitle and comment fields are typed as string | undefined, not
string | null. Remove them from the quickstart default data to fix the
TypeScript build error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The inline defaultDimensions record in the keyboard shortcut handler was
missing the conditionalSwitch entry, causing a TypeScript build error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The createDefaultNodeData function in validation.ts had cases for router
and switch but was missing conditionalSwitch, despite it being listed in
VALID_NODE_TYPES and DEFAULT_DIMENSIONS.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add guard in handleDelete and hide the delete button when only one
switch remains, matching ConditionalSwitchNode's existing behavior.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The same 20-line block for evaluating rules and updating node data before
executing a ConditionalSwitch appeared in both executeWorkflow and
executeSelectedNodes. Extract to evaluateAndExecuteConditionalSwitch helper.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Identical rule evaluation logic existed in ConditionalSwitchNode.tsx and
workflowStore.ts. Extract to src/store/utils/ruleEvaluation.ts and
import from both locations.
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>
ConditionalSwitch should act as a gate/trigger, not a data router.
Active outputs now trigger downstream execution without forwarding
the upstream text through the connection.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace static pixel math with useLayoutEffect + offsetTop measurement to
position output handles at the actual vertical center of their corresponding
rule/default rows. This is robust against header height, padding, and text
preview variations that caused the previous static offset to misalign.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolve three issues with the Conditional Switch node:
- Add fromHandleType resolution for conditionalSwitch in handleConnectEnd so
the connection drop menu appears when dragging from rule/default outputs
- Align output handles with visual rule rows by accounting for the text preview
height in baseOffset and using fixed h-8 rows matching handleSpacing=32
- Move "Add Rule" button after the Default row so the default handle aligns
with its visual row instead of being displaced
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add geminiApiKey to useProviderApiKeys hook. Update GenerateVideoNode to
include Gemini as a provider when API key is configured, and pass the
X-Gemini-API-Key header when fetching models.
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 Pro supports 1K/2K/4K, while Nano Banana 2 also supports 512.
Split the shared RESOLUTIONS constant into RESOLUTIONS_PRO and RESOLUTIONS_NB2,
and use the correct list based on the selected model in both GenerateImageNode
and SplitGridSettingsModal. Also normalize aspect ratio and resolution to valid
defaults when switching models in the SplitGrid modal.
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>
Make aspect ratio dropdowns model-aware: nano-banana-2 shows 14 ratios
while other models keep showing the base 10. Also add nano-banana-2 to
the SplitGrid settings model list.
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>
- Remove router/switch/conditionalSwitch entries from WorkflowCanvas
defaultDimensions and validation.ts (these types only exist on develop)
- Add ModelType import and cast in nodeDefaults.ts for type safety
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pre-existing type error — conditionalSwitch was missing from the
createDefaultNodeData switch in validation.ts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pre-existing type error — conditionalSwitch was added to NodeType but the
local defaultDimensions map in keyboard shortcut handler was not updated.
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>
Add per-resolution pricing for nano-banana-2 (512/1K/2K/4K).
Add 512px tier to all model pricing tables.
Use MODEL_DISPLAY_NAMES lookup instead of ternaries.
Add getPricing fallback for nano-banana-2 / gemini-3.1-flash-image-preview.
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 "nano-banana-2" to ModelType union for Gemini 3.1 Flash Image Preview.
Add "512" resolution tier. Add MODEL_DISPLAY_NAMES lookup to replace ternaries.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Conditional Switch was missing from the text target connection drop menu
and incorrectly present in the image source menu.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Import ConditionalSwitchNodeData type in dimmingUtils.ts
- Add conditionalSwitch block to collect potentially dimmed nodes
- Non-matching rules (isMatched=false) trigger downstream dimming
- Default output dims when ANY rule matches (inactive when no match)
- Extend smart cascade blockedTypes collection
- Check conditionalSwitch rules for match status
- Add inactive outputs to blockedTypes
- Extend hasReplacementInput check to skip non-matching outputs
- Guard conditionalSwitch nodes from dimming in WorkflowCanvas
- Updated guard: if (node.type === "switch" || node.type === "conditionalSwitch")
Phase 44's dimming system now handles both Switch and Conditional Switch.
- Import executeConditionalSwitch in workflowStore
- Add evaluateRuleMatch helper function for rule evaluation
- Add conditionalSwitch case to executeWorkflow with fresh match evaluation
- Add conditionalSwitch case to regenerateNode with same pattern
- Import ConditionalSwitchNodeData and MatchMode in connectedInputs
- Add conditionalSwitch passthrough in getConnectedInputsPure
- Block non-active outputs (isMatched=false) from data flow
- Default output active when no rules match
- Active outputs recursively get upstream text
- Import and add ConditionalSwitchNode to nodeTypes map
- Add getNodeHandles case with text input and dynamic outputs
- Add cyan-500 (#06b6d4) minimap color distinct from Router/Switch
- Add isValidConnection text-only validation
- Add handleMenuSelect with text handle and first rule/default source
- Add findCompatibleHandle for text input and rule outputs
- Add ConditionalSwitch to TEXT_TARGET_OPTIONS and TEXT_SOURCE_OPTIONS with filter icon
- Positioned after Switch entry in both menus
- Text input handle on left (blue, text type)
- Text preview section showing truncated incoming text (50 chars)
- Rule rows with:
- Match status indicator (green checkmark when matched, gray dot when not)
- Up/down arrow buttons for reordering rules
- Editable label (double-click to edit, inline editing pattern from SwitchNode)
- Mode dropdown (exact, contains, starts-with, ends-with)
- Value text field (comma-separated match values)
- Delete button (hidden if only one rule to prevent empty state)
- Add rule button (creates new rule with auto-generated label)
- Default output row (always at bottom, not editable/deletable)
- Active (green) when NO rules match, inactive (gray) otherwise
- Dynamic output handles per rule + default handle (all text type)
- Non-matching rule handles at 30% opacity (same as Switch disabled pattern)
- evaluateRule function: case-insensitive, multi-value OR logic, all 4 modes
- Match status updates reactively via useEffect watching incoming text
- Dynamic handle sync via useUpdateNodeInternals on rule count change
- Auto-resize height based on rule count
- Teal/cyan theme (bg-teal-950/50 border-teal-600) to differentiate from Router/Switch
- Add MatchMode type (exact, contains, starts-with, ends-with)
- Add ConditionalSwitchRule interface with id, value, mode, label, isMatched
- Add ConditionalSwitchNodeData interface with incomingText and rules array
- Add conditionalSwitch to NodeType union (after switch)
- Add ConditionalSwitchNodeData to WorkflowNodeData union
- Add default data with single rule (mode: contains, empty value)
- Add default dimensions (260x180, wider than Switch for mode dropdown)
- Add executeConditionalSwitch passthrough executor
- Add conditionalSwitch to VALID_NODE_TYPES in validation
- Export ConditionalSwitchNode from components index (component created in next task)
When paths reconverge downstream of a Switch, dimmed nodes (from disabled
outputs) still held stale data from previous runs. getConnectedInputs now
accepts dimmedNodeIds and skips any source node in the dimmed set, preventing
disabled Switch paths from leaking data into downstream nodes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
A Prompt (text) connecting to a Generate node shouldn't prevent dimming
when the image input from a disabled Switch is blocked. The cascade now
only un-dims a node if an active input provides the same data type as
the blocked path (e.g., another image source replaces a disabled image).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The menu path calls onConnect() directly, bypassing handleConnect's
resolveSwitchHandle. This left edges with targetHandle "generic-input"
instead of the actual type, causing inputType to be invalid, handles
to render without color, and downstream connections to fail validation.
- Set targetHandleId to actual type in handleMenuSelect Switch case
- Update Switch inputType immediately when created from menu
- Filter "generic-input" in derivedInputType as safety net
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Switch output handles use dynamic IDs (random strings) that getHandleType()
can't resolve. Now falls back to the Switch node's inputType field so dragging
from a Switch output shows the correct type-specific connection menu.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>