The collapsed composer should expand from the surrounding summary area, but the model label and generate button are explicit action targets. This keeps model selection and generation isolated while retaining one-click expansion from the remaining collapsed surface.
Constraint: Red-marked collapsed controls have dedicated product actions
Rejected: Treat the whole collapsed summary as one expand button | steals the model selector action
Confidence: high
Scope-risk: narrow
Directive: Do not bind collapsed-container expansion over buttons with dedicated actions
Tested: npm run test:run -- src/components/__tests__/GenerationComposer.test.tsx
Tested: npm run build
Not-tested: npm run lint | existing script calls unsupported next lint under Next 16
Not-tested: npx tsc --noEmit | existing unrelated test type errors remain
Users expect a collapsed bottom composer to expand from the visible summary itself, not only the small expand icon. The collapsed summary now acts as the expansion target while preserving the generate button's submit behavior, and a regression test locks the summary-click path.
Constraint: TEST-s deployment branch is used for the test server
Rejected: Keep model summary opening the model dialog while collapsed | conflicts with the requested one-click expand behavior
Confidence: high
Scope-risk: narrow
Directive: Keep collapsed summary clicks focused on expansion; preserve generate button isolation
Tested: npm run test:run -- src/components/__tests__/GenerationComposer.test.tsx
Tested: npm run build
Tested: Local browser check on http://localhost:3000/ collapsed summary click
Not-tested: npm run lint | existing script calls unsupported next lint under Next 16
Not-tested: npx tsc --noEmit | existing unrelated test type errors remain
The canvas needs to respect what users can see: media nodes should reflect the actual image ratio, and the connection menu should dismiss when the user clicks away instead of forcing a node choice. The fix stays inside the affected node/menu components and their regression tests.
Constraint: Windows pointer/canvas interactions can prevent bubble-phase outside-click handlers from seeing the click
Rejected: Add a modal/backdrop around the connection menu | heavier behavior change and unnecessary for a transient menu
Rejected: Add user-facing aspect-ratio controls | the media already exposes dimensions and should not need extra configuration
Confidence: high
Scope-risk: narrow
Directive: Keep connection-menu dismissal as capture-phase pointer handling unless Windows canvas behavior is revalidated
Tested: npm test -- --run src/components/__tests__/ConnectionDropMenu.test.tsx src/components/__tests__/ImageInputNode.test.tsx src/components/__tests__/GenerateImageNode.test.tsx
Tested: npm run build
Not-tested: Manual Windows PC browser run
The LLM selector exposed display-style Doubao model names that the NewApiWG test gateway cannot route. The UI now stores the gateway model ids returned by /models, while the API route maps legacy saved selector values to those ids so existing workflows do not keep failing.
Constraint: Preserve GPT-4.1 Mini as the NewApiWG default and keep old workflow JSON compatible.
Rejected: Remove Doubao from the LLM selector | the gateway exposes working Doubao chat model ids, so the issue is stale ids rather than product support.
Confidence: high
Scope-risk: narrow
Directive: LLM selector values must be callable provider ids; use labels only for display text.
Tested: Live NewApiWG chat completion with doubao-seed-2-0-lite-260428 and doubao-seed-2-0-pro-260215.
Tested: npm run test:run -- src/lib/__tests__/llmModels.test.ts src/app/api/llm/__tests__/route.test.ts src/components/__tests__/LLMGenerateNode.test.tsx src/store/utils/__tests__/nodeDefaults.test.ts
Tested: npm run build
Tested: git diff --check
P0 regressions showed several workflow paths needed to stay visible and deterministic: language switching had a hardcoded composer label, Video Trim hid controls before media loaded, and media handoffs to LLM needed real canvas edges rather than implicit conversion. P1 fixes keep canvas-owned structure by adding explicit image/video LLM handles, audio composer validation, 3D output/file routing, and Chat proposal cards that require user apply before mutating nodes.
Constraint: User asked to stop new feature work and only repair P0/P1 product-fit gaps.
Rejected: Auto-convert image or video directly into text for LLM | hides workflow structure and violates the visible-node product model.
Rejected: Let Chat tool calls silently add or edit nodes | canvas structure must be previewed and explicitly applied.
Confidence: high
Scope-risk: moderate
Directive: Keep media transformations represented by visible handles, nodes, and edges; do not add silent Chat or media mutation paths without product review.
Tested: Browser automation for language switch, video input to Generate Video, prompt to Generate Video, LLM default model, Video Trim controls, and video media to LLM input.
Tested: npm run test:run -- src/components/__tests__/ConnectionDropMenu.test.tsx src/components/__tests__/GenerationComposer.test.tsx src/components/__tests__/VideoTrimNode.test.tsx src/components/__tests__/LLMGenerateNode.test.tsx src/store/execution/__tests__/llmGenerateExecutor.test.ts src/app/api/llm/__tests__/route.test.ts src/store/execution/__tests__/generateAudioExecutor.test.ts src/store/execution/__tests__/generate3dExecutor.test.ts src/store/execution/__tests__/simpleNodeExecutors.test.ts src/components/__tests__/OutputNode.test.tsx src/components/__tests__/Generate3DNode.test.tsx src/components/__tests__/ChatPanel.test.tsx src/lib/chat/tools.test.ts src/lib/chat/editOperations.test.ts src/lib/__tests__/llmModels.test.ts src/store/utils/__tests__/nodeDefaults.test.ts
Tested: npm run build
Tested: git diff --cached --check
Not-tested: npm run lint, because the existing script calls removed Next.js lint command and exits with invalid project directory /lint.
Not-tested: Live paid provider calls for LLM, audio, and 3D generation.
The TEST-s branch renders the composer generate action with the English aria-label used by nearby tests. Updating the stale assertion keeps the test focused on image-count persistence instead of locale-specific text.
Constraint: TEST-s currently renders the generate button aria-label as Generate in this test setup
Rejected: Change composer runtime label for the test | would alter UI behavior to satisfy a stale assertion
Confidence: high
Scope-risk: narrow
Directive: Prefer stable accessible labels already used in adjacent composer tests
Tested: npm run test:run -- src/components/__tests__/GenerateImageNode.test.tsx src/components/__tests__/GenerationComposer.test.tsx src/app/api/generate/providers/__tests__/newapiwg.test.ts
Tested: git diff --check
Not-tested: Full browser locale sweep
NewApiWG Nano Banana models execute through the Gemini-native image path, where aspectRatio and imageSize/resolution are the effective product controls. The generic schema panel exposed size=1024x1024 alongside 16:9/2K, creating a misleading and potentially conflicting UI.
Constraint: NewApiWG Nano Banana schemas may expose generic size fields that are not the effective Gemini-native controls
Rejected: Keep both schema size and first-class ratio controls | presents contradictory settings to users
Confidence: high
Scope-risk: narrow
Directive: Gemini-native image models should use first-class aspect/resolution controls, not generic size schema fields
Tested: npm run test:run -- src/components/__tests__/GenerateImageNode.test.tsx src/components/__tests__/GenerationComposer.test.tsx src/app/api/generate/providers/__tests__/newapiwg.test.ts
Tested: npm run build
Tested: git diff --check
Not-tested: npm run lint | package script calls removed Next 16 next lint command
P0/P1 reports clustered around unavailable LLM defaults, video media connections, and missing controls on the generation surface. This routes the default NewApiWG LLM away from the unavailable Doubao channel, makes video a first-class schema and canvas connection type, carries request ids into node errors, and fills the composer, trim, audio, and 3D gaps without changing the canvas workflow model.
Constraint: NewApiWG Doubao channels are not reliably routed in the default gateway
Constraint: Video model schemas expose video fields that must not flow through image handles
Rejected: Continue accepting video through image handles | hides incorrect graph types and loses schema-specific dynamic inputs
Confidence: high
Scope-risk: moderate
Directive: Keep media handle types explicit; add schema mapping when adding a new connectable media type
Tested: npm run test:run -- src/store/execution/__tests__/generateVideoExecutor.test.ts src/store/utils/__tests__/connectedInputs.test.ts src/store/execution/__tests__/generateAudioExecutor.test.ts src/store/execution/__tests__/llmGenerateExecutor.test.ts src/store/__tests__/workflowStore.integration.test.ts src/lib/__tests__/llmModels.test.ts src/store/utils/__tests__/nodeDefaults.test.ts src/components/__tests__/GenerationComposer.test.tsx src/app/api/chat/__tests__/route.test.ts src/app/api/llm/__tests__/route.test.ts src/app/api/models/[modelId]/__tests__/route.test.ts src/app/api/generate/providers/__tests__/newapiwg.test.ts
Tested: npm run build
Tested: git diff --check
Not-tested: npm run lint | package script calls removed Next 16 next lint command
Not-tested: npx tsc --noEmit | existing test type errors remain; changed runtime files filtered clean
NewApiWG model discovery was allowing Doubao text models to appear in media-generation contexts, which made image nodes call a model with no generation channel. The change filters Doubao chat/vision model names out of generation capability inference, bumps model caches, and guards execution for stale saved workflows.
Constraint: NewApiWG /models may return chat models without explicit capability metadata
Rejected: Keep all unknown models visible | it lets text-only models fail inside media nodes
Confidence: high
Scope-risk: narrow
Directive: Do not classify chat/VLM models as media generators without explicit generation capability metadata
Tested: npm test -- src/app/api/generate/providers/__tests__/newapiwg.test.ts
Tested: npm test -- src/components/__tests__/ModelSearchDialog.test.tsx
Not-tested: Full tsc remains blocked by existing unrelated test type errors
The generation composer previously collapsed multiple reference images into a single thumbnail with a count badge. The composer now renders each reference thumbnail in sequence, keeps them scrollable in the toolbar, and lets editable drafts remove a specific image by position.
Constraint: Reference image ordering matters for multi-image generation context.
Rejected: Keep count badge overlay | it hides which images are attached and makes order ambiguous.
Confidence: high
Scope-risk: narrow
Tested: npm test -- --run src/components/__tests__/GenerationComposer.test.tsx
Tested: npx tsc --noEmit --pretty false filtered to GenerationComposer files
Not-tested: Full tsc remains blocked by existing unrelated test typing errors
The browser path helper briefly acted as a type predicate, which made existing non-browser path branches narrow to never under the production build. The callers now guard nullable paths explicitly while the helper stays a plain boolean check.
Constraint: ProjectSetupModal depends on checking both browserfs paths and regular filesystem strings in the same helper flow.
Confidence: high
Scope-risk: narrow
Tested: npm test -- --run src/components/__tests__/GenerateImageNode.test.tsx src/store/execution/__tests__/nanoBananaExecutor.test.ts src/components/__tests__/GenerationComposer.test.tsx
Tested: npx tsc --noEmit --pretty false filtered to touched browser path files
Not-tested: Full tsc remains blocked by existing test typing errors outside this change scope
Browser-local projects were deriving a null generations path, so carousel entries that only retained an image id could not resolve media during previous/next navigation. Generated images are now written into the browser-selected generations folder, project metadata keeps that browserfs generations path, and the image node can read browserfs generation files directly before falling back to the server load endpoint.
Constraint: Browser-selected folders cannot be read through server API routes.
Rejected: Keep relying on inline image history only | saved or migrated workflows can contain id-only history entries.
Confidence: high
Scope-risk: moderate
Directive: Browser-local media paths must stay on the File System Access API path, not server /api/load-generation.
Tested: npm test -- --run src/components/__tests__/GenerateImageNode.test.tsx src/store/execution/__tests__/nanoBananaExecutor.test.ts src/components/__tests__/GenerationComposer.test.tsx
Tested: npx tsc --noEmit --pretty false filtered to touched files
Not-tested: Full tsc remains blocked by existing test typing errors outside this change scope
Browser-local projects cannot load node carousel history through the server-side generations API. Each new image history entry now keeps the generated data URL for immediate in-session switching, while server-backed projects can still fall back to loading by generation id. Browser-local generation paths also skip /api/save-generation because that endpoint can only write server filesystem paths.
Constraint: Project storage can be browser-local and therefore unavailable to server filesystem APIs.
Rejected: Force carousel switching through /api/load-generation | browserfs paths cannot be resolved by the server and cause switching failures.
Confidence: high
Scope-risk: narrow
Directive: Keep carousel history able to switch without server round-trips when images were generated in the current session.
Tested: npm test -- --run src/components/__tests__/GenerateImageNode.test.tsx src/store/execution/__tests__/nanoBananaExecutor.test.ts
Tested: npx tsc --noEmit --pretty false filtered to changed production files
The hosted app should not save each operator's project into the shared test server filesystem when the browser can grant local folder access. Project creation now requires a browser-selected local folder in supported browsers, remembers that folder as the project browser root, and the workflow browser can list and load projects from File System Access handles. Server filesystem APIs remain as a fallback for unsupported browsers.
Constraint: Hosted users need per-operator local project storage instead of shared server paths.
Rejected: Keep manual absolute path entry on supported browsers | it can silently target the server filesystem in the deployed app.
Confidence: high
Scope-risk: moderate
Directive: Do not re-enable server path entry for hosted browsers without adding per-user isolation and auth boundaries.
Tested: npm test -- --run src/components/__tests__/ProjectSetupModal.test.tsx src/components/__tests__/QuickstartTemplatesView.test.tsx src/store/utils/__tests__/localStorage.test.ts
Tested: npx tsc --noEmit --pretty false filtered to changed files
This aligns image, video, and text defaults with the PopiArt NewApi gateway while keeping provider-specific escape hatches available. Chat now uses the OpenAI-compatible NewApiWG route so workflow editing and LLM generation share the same Doubao-first text default. The canvas composer and quick-add controls are tightened so visible actions map to real clickable behavior, while temporarily unused header actions stay hidden.
Constraint: Text/chat requests must prefer Doubao-Seed-2.0-lite through NewApiWG.
Constraint: Image and video defaults should prefer PopiArt NewApi gateway models when configured.
Rejected: Keep /api/chat on Gemini 3 Flash | conflicts with the requested NewApiWG text/chat default.
Rejected: Hand-roll AI SDK chat streaming | would risk tool-call and UI stream compatibility.
Confidence: high
Scope-risk: moderate
Directive: Do not add new text/chat defaults without updating src/lib/llmModels.ts and the chat route together.
Tested: npm test -- --run src/app/api/chat/__tests__/route.test.ts src/components/__tests__/LLMGenerateNode.test.tsx src/lib/__tests__/llmModels.test.ts src/store/utils/__tests__/nodeDefaults.test.ts src/components/__tests__/GenerationComposer.test.tsx src/lib/chat/tools.test.ts
Tested: npm test -- --run src/lib/__tests__/llmModels.test.ts src/store/utils/__tests__/nodeDefaults.test.ts src/components/__tests__/GenerationComposer.test.tsx src/lib/quickstart/__tests__/templates.test.ts src/lib/quickstart/__tests__/validation.test.ts src/lib/quickstart/__tests__/prompts.test.ts src/components/__tests__/ProjectSetupModal.test.tsx
Tested: npm test -- --run src/components/__tests__/WorkflowCanvas.test.tsx
Not-tested: Full suite; repository has pre-existing unrelated type/test warnings outside this change.
Provider video URLs can expire before users finish composing, and the bottom composer was too visually dominant for canvas work. This change keeps remote videos playable while background-localizing them, teaches video previews to use the media proxy, makes audio nodes first-class in the composer and executor, and adds a compact composer state for canvas visibility.
Constraint: Provider media URLs may be remote, signed, or CORS-restricted during playback and thumbnail extraction
Constraint: Audio generation nodes need to work from their internal prompt as well as connected text
Rejected: Store only provider URLs | remote URLs can expire and break later playback
Rejected: Treat audio nodes as unsupported composer nodes | it falls back to the image model and corrupts user intent
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep provider media playable through the resolver/proxy path and preserve local refs as the durable source when available
Tested: npm run test:run
Tested: npm run test:run -- src/components/__tests__/GenerationComposer.test.tsx src/store/execution/__tests__/generateAudioExecutor.test.ts src/store/execution/__tests__/generateVideoExecutor.test.ts src/components/__tests__/VideoStitchNode.test.tsx src/components/__tests__/GenerateVideoNode.test.tsx
Tested: npm run build
Not-tested: npm run lint currently fails because next lint is not supported by this Next.js setup
Not-tested: npx tsc --noEmit still reports pre-existing test typing errors outside this change
The bottom composer now treats video stitch and ease curve as processing-node inspectors instead of unsupported prompt editors. The connection menu also keeps video streams and ease-curve settings on separate handle paths so downstream creation matches the node graph semantics.
Constraint: Processing nodes should run existing local media operations and must not expose model or prompt controls
Constraint: Ease curve Settings handles carry curve parameters, not video media
Rejected: Let Settings handles reuse generic video/text drop options | creates misleading nodes and invalid graph intent
Rejected: Make Video Input a downstream target from Video Out | Video Input is an import/source node, not a processing destination
Confidence: high
Scope-risk: moderate
Directive: Keep media handles and settings handles separated in connection menus and validation
Tested: npm run test:run -- src/components/__tests__/ConnectionDropMenu.test.tsx
Tested: npm run test:run -- src/components/__tests__/GenerationComposer.test.tsx
Tested: npm run test:run -- src/components/__tests__/WorkflowCanvas.test.tsx
Tested: npm run build
Tested: git diff --check
Not-tested: npm run lint still uses the existing Next 16-incompatible next lint script
The bottom composer now edits and reruns the current generation node while canvas-visible actions own downstream node creation. NewApiWG media normalization, video frame extraction, and node quick-add keep generated media flows explicit and connected rather than hidden behind the prompt box.
Constraint: Composer must not call providers directly or create hidden downstream branches when a node is selected
Constraint: NewApiWG video families use inconsistent media schemas, so common media aliases are normalized in the provider adapter
Rejected: Let the bottom composer create next-step nodes from selected outputs | hides graph mutation and conflicts with the PRD source-of-truth rules
Rejected: Put NewApiWG model-family payload rules in the composer | provider-specific schemas would leak into UI state
Confidence: high
Scope-risk: moderate
Directive: Keep provider payload normalization in provider/executor layers; do not move it into GenerationComposer
Tested: npm run test:run -- src/components/__tests__/GenerationComposer.test.tsx
Tested: npm run test:run -- src/components/__tests__/WorkflowCanvas.test.tsx
Tested: npm run test:run -- src/components/__tests__/GenerateVideoNode.test.tsx
Tested: npm run test:run -- src/app/api/generate/providers/__tests__/newapiwg.test.ts src/app/api/generate/__tests__/route.test.ts
Tested: npm run test:run -- src/store/execution/__tests__/videoProcessingExecutors.test.ts
Tested: npm run build
Not-tested: npm run lint fails because next lint is incompatible with the current Next 16 script configuration
Server-side native folder pickers cannot select a Windows user's local directory when the app is deployed remotely. This adds a browser File System Access path for supported browsers so the user can choose a local folder, create the project subfolder, and save the workflow JSON directly from the client.
Constraint: File System Access handles are browser-only and cannot be passed to server filesystem APIs
Constraint: External media folder storage still depends on server filesystem endpoints, so browser-local projects keep media embedded or remote in the workflow JSON
Rejected: Make /api/browse-directory choose the user's Windows folder | that endpoint runs on the server, not in the browser
Confidence: medium
Scope-risk: moderate
Directive: Extend the browser filesystem utility for local media inputs/generations before enabling external media storage for browserfs paths
Tested: npx vitest run src/components/__tests__/ProjectSetupModal.test.tsx src/components/__tests__/Header.test.tsx
Tested: npm run build
Not-tested: Manual Chrome/Edge File System Access flow on Windows test server
NewApiWG image and video models need to work against the PopiArt test gateway, with generated remote media visible in the canvas and UI text localized for Chinese users. This wires the gateway-specific image/video paths, model fallback display, remote media proxying, and related i18n cleanup into one releaseable change.
Constraint: Test gateway exposes image and video models through mixed OpenAI-compatible and Gemini-native response shapes
Constraint: Browser video playback can fail when loading signed third-party media URLs directly
Rejected: Keep remote video URLs as direct <video> sources | CORS and range handling made successful generations appear unloaded
Confidence: high
Scope-risk: moderate
Directive: Do not remove the media proxy without validating remote video playback, trimming, and stitching against signed CDN URLs
Tested: npm run build
Tested: npx vitest run src/components/__tests__/OutputNode.test.tsx src/components/__tests__/GenerateVideoNode.test.tsx src/components/__tests__/VideoStitchNode.test.tsx
Tested: npx vitest run src/components/__tests__/WorkflowCanvas.test.tsx src/store/execution/__tests__/generateVideoExecutor.test.ts
Tested: npx vitest run src/app/api/generate/providers/__tests__/newapiwg.test.ts
Not-tested: Live browser replay after pushing to remote deployment
The input schema mapping was forcing all non-image inputs to "text",
misclassifying audio inputs. Now correctly maps audio type so handles
get the right data-handletype, CSS dot color, and label color.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
AudioInputNode, EaseCurveNode, and VideoStitchNode tests used manual
@xyflow/react mocks that didn't include useConnection, which is now
called by the useShowHandleLabels hook. Add the mock to fix all 40 tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Video handles/edges/labels were inconsistent — using white, green, blue,
and hardcoded purple across different files. Standardize all to pink and
use the CSS variable var(--handle-color-video) for labels. Also adds the
missing .react-flow__handle[data-handletype="video"] CSS rule.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add --handle-color-video CSS variable
- Fix tutorial overlay race conditions by reading nodes from store
directly and add keyboard accessibility to click-to-continue overlay
- Fix audio extraction in video stitching: defer silent buffer creation
until reference format is known, and only trust probed duration when
all blobs were successfully probed
- Clear saved filename/path when clearing 3D output
- Retry 429/408 transient errors during task polling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update all 18 node files to use the centralized HandleLabel component.
Labels now fade in/out with a 150ms opacity transition instead of
mounting/unmounting (pop-in). ~430 lines removed across 18 files.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extracts the repeated ~10-line handle label pattern into a reusable
component with opacity-based fade transition (150ms ease-in-out)
instead of mount/unmount pop-in.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add useShowHandleLabels hook that combines node selection state with
React Flow's useConnection to show handle labels only when relevant,
reducing visual clutter on the canvas.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- OutputNode download tests: add missing `ok: true` to fetch mock
responses so downloadMedia doesn't bail at the `!response.ok` check
- workflowStore integration test: update easeCurve bounding box
expectations from 480 to 280 to match actual default dimensions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- TutorialOverlay: move completeCurrentStep() inside setTimeout to prevent
cleanup from clearing the advance timeout, fixing stuck tutorial steps
- useStitchVideos: push silent AudioBuffer for clips with no/incompatible
audio instead of skipping, preventing audio-video timeline desync
- generate3dExecutor: clear savedFilename/savedFilePath on new generation
to prevent stale save metadata from previous runs
- pollTaskCompletion: restructure abort listener/timer cleanup to prevent
listener accumulation across polling iterations
- connectedInputs: exclude loop edges in validateWorkflowPure checks for
nanoBanana/generateVideo text inputs, matching runtime behavior
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolve conflicts in 4 executor files by combining develop's
runWithFallback structure with feature branch's client-side polling.
Both capabilities are now integrated: executors use runWithFallback
for model redundancy, and pollGenerateTask for long-running Kie tasks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- OutputGalleryNode: add aria-label to gallery tile buttons so screen
readers can identify video tiles (images already had alt via
AdaptiveGalleryThumbnail)
- OutputGalleryNode: add nodeData.imageRefs and nodeData.videoRefs to
removeMedia dependency array so splice operates on current refs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- OutputGalleryNode: splice imageRefs/videoRefs alongside images/videos
in removeMedia to keep arrays in lockstep
- TutorialOverlay: track and clean up actionCompleted advance timeout
via advanceTimeoutRef to prevent stale nextTutorialStep after skip
- TutorialOverlay: track and clean up populate-content nested timeouts
via populateTimeoutIds ref to prevent post-teardown state mutations
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- TutorialOverlay: track all nested setTimeout IDs and clear on cleanup
to prevent ghost animations when tutorial is skipped mid-demonstration
- FTUXReadyStep: use strict local interface requiring both callbacks
instead of optional FTUXStepProps
- FTUXModelDefaultsStep: replace hardcoded "Gemini nano-banana-pro" with
"None set" for the no-model-selected state
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- OutputGalleryNode: replace hardcoded .png/.mp4 download with shared
downloadMedia utility for correct MIME-based extensions
- OutputNode: wrap downloadMedia call in try/catch to prevent unhandled
rejection
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ModelSearchDialog: show "Remove fallback" button even when no models match
- Generate3DNode: reset settingsTab to "primary" when fallback is removed
- GenerateAudioNode: same settingsTab reset fix
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- runWithFallback: use "loading" (valid NodeStatus) instead of "running"
- WorkflowCanvas: clear fallbackParameters when selecting a new fallback model
- workflowStore: add response.ok check before reading tutorial image blob
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract shared downloadMedia utility from OutputNode and add download
buttons to ImageInput, VideoInput, Annotation, AudioInput, GenerateImage,
GenerateVideo, GenerateAudio, and GLBViewer nodes. Refactor OutputNode to
use the shared utility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reset fallbackParameters when saving a new fallback model provider to
prevent stale parameter values (e.g. temperature=1.5) being sent to a
provider with different valid ranges (e.g. Anthropic max=1).
Wire AbortController signal through mockTutorialExecution so clicking
Stop actually cancels the 5s delay, fetch request, and FileReader,
returning the node to idle state instead of completing silently.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Gemini image models (nano-banana, nano-banana-pro, nano-banana-2) were
not showing parameters when set as fallback models. Three root causes:
1. Schema API returned empty for Gemini image models — added
getGeminiImageSchema() with aspect ratio, resolution, and search
grounding parameters per model
2. ModelParameters had an early-return guard skipping all non-Veo Gemini
models — removed to make the component provider-agnostic
3. nanoBananaExecutor ignored parametersOverride for Gemini-specific
fields (aspectRatio, resolution, useGoogleSearch, useImageSearch) —
now reads from override when available
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Restore FTUX production logic (remove testing override)
- Fix generate3dExecutor clearOutput field and add modelId validation
- Remap startLevel index after loop partitioning in executeWorkflow
- Add missing mockTutorialExecution dep in FloatingActionBar
- Reset settingsTab to "primary" when fallbackModel is removed
- Clear orphaned fallbackParameters when removing fallback model
- Fix OutputGalleryNode removeMedia to splice single item, not all duplicates
- Add data-tutorial="save-button" to untitled save button in Header
- Move data-tutorial to layout-producing element in BaseNode
- Hydrate FTUXApiKeysStep localKeys from providerSettings
- Remove broken docs URL from ftuxStore tutorial steps
- Add error handling in loadTutorialSampleImage
- Fix mediaStorage ref array misalignment in outputGallery hydration
- Make OutputGalleryNodeData.videos optional to match usage
- Remove unused fitView destructuring from WorkflowCanvas
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Update fallback button icon and color scheme (emerald -> blue)
- Move fallback button into headerAction alongside browse button
- Add custom title prop to ModelSearchDialog for fallback context
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Adds SettingsTabBar to LLMGenerateNode with temperature and max tokens
controls for the fallback model. Updates llmGenerateExecutor to use
fallbackParameters override when running the fallback model.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Adds SettingsTabBar to all four generation nodes (image, video, audio, 3D).
When a fallback model is set, a tab bar appears to switch between primary
and fallback model parameter controls. Fallback tab renders ModelParameters
bound to nodeData.fallbackParameters.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Minimal pill-style tab bar for switching between primary and fallback
model parameter views inside the InlineParameterPanel.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Introduces a shared runWithFallback helper that wraps primary model
attempts with an optional fallback. On primary failure (non-abort),
the fallback runs once and metadata is stamped on the node so the UI
can render a "Fallback used" badge. Fallback is skipped when primary
and fallback resolve to the same provider/model to avoid double-billing.
Wired through all generation executors (nanoBanana, generateVideo,
generateAudio, generate3d, llmGenerate) with accompanying tests.
JSON-compatible with Node Banana Pro: fallbackModel and __-prefixed
metadata fields match NBP's shape for clean config round-trips.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>