Popi/NewAPIWG is now the primary gateway, so the UI and request paths need to avoid legacy provider assumptions while keeping local reference media usable for upstream calls. This change aligns model defaults, point display, inline node controls, and temporary reference image handling around that gateway boundary.
Constraint: Upstream providers cannot fetch localhost reference URLs, but large base64 payloads previously caused request/body reliability issues.
Constraint: Seedance point estimates depend on authenticated NewAPIWG /api/points/estimate responses rather than static catalog prices.
Rejected: Send all reference images directly as large data URLs | would reintroduce oversized JSON/request failures.
Rejected: Restore legacy per-provider key controls by default | current product direction is a single Popi/NewAPI gateway.
Confidence: high
Scope-risk: moderate
Directive: Do not pass /api/images localhost URLs to upstream generation APIs; resolve them server-side or fail before the upstream call.
Tested: npm run test:run -- src/app/api/generate/providers/__tests__/newapiwg.test.ts src/app/api/points/estimate/__tests__/route.test.ts src/lib/images/store.test.ts src/components/__tests__/GenerationComposer.test.tsx src/components/__tests__/ImageInputNode.test.tsx src/components/__tests__/PromptNode.test.tsx src/components/__tests__/ProjectSetupModal.test.tsx src/store/execution/__tests__/generateVideoExecutor.test.ts src/store/execution/__tests__/nanoBananaExecutor.test.ts src/store/utils/__tests__/nodeDefaults.test.ts
Tested: npm run build
Tested: git diff --check
Not-tested: npm run lint fails because next lint is parsed as a missing /lint project directory under Next 16.
Multi-image NewAPIWG generations were sending base64 reference images
inside the /api/generate JSON body. Two ordinary canvas references can
push that payload near the dev/server body boundary, leaving the route
to parse an incomplete JSON string and surface a raw syntax error.
Move large NewAPIWG references through the existing in-memory image
serving path: the browser uploads large data URLs as multipart image
files, sends short /api/images/{id} URLs in the generation request, and
the route resolves those temporary URLs back to server-local image data
before calling providers. The route also turns malformed/truncated JSON
into a readable validation error.
Constraint: Keep provider payload semantics unchanged after /api/generate receives the request
Constraint: Do not rely on request origin matching because Next dev can report 0.0.0.0 while the browser uses localhost
Rejected: Increase body size limits only | still sends multi-MB JSON and does not protect hosted/proxied environments
Rejected: Compress reference images client-side | changes model input fidelity and still leaves large JSON possible
Confidence: high
Scope-risk: moderate
Directive: Do not forward /api/images/{id} temporary URLs to external providers; resolve them server-side first
Tested: npm run test:run -- src/store/execution/__tests__/nanoBananaExecutor.test.ts src/app/api/generate/__tests__/route.test.ts
Tested: npm run build
Not-tested: Live NewAPIWG generation with the user's exact two images
The welcome screen now matches the Popi.TV brand and gives unauthenticated users two explicit paths: jump to the main-site login page or provide a Popi/NewAPI gateway key directly. The manually provided key is persisted in the local user store and forwarded through the NewAPI-backed generation, model, LLM, and chat routes without requiring a login token.
Constraint: Users need a usable local path when they are not logged into the main site.\nRejected: Keep the startup login modal for missing tokens | it blocked the in-welcome login/key choices.\nRejected: Rename internal workflow prompts and storage keys | those are compatibility/internal identifiers, not the visible brand surface.\nConfidence: high\nScope-risk: moderate\nDirective: Keep manual gateway-key access scoped to NewAPI-backed paths; non-NewAPI providers should continue requiring a login token.\nTested: npm run test:run -- src/app/api/models/__tests__/route.test.ts src/app/api/models/[modelId]/__tests__/route.test.ts src/app/api/llm/__tests__/route.test.ts src/app/api/chat/__tests__/route.test.ts src/app/api/generate/__tests__/route.test.ts\nTested: npm run test:run -- src/components/__tests__/QuickstartInitialView.test.tsx src/components/__tests__/WelcomeModal.test.tsx\nTested: npm run build\nTested: Browser verification for Popi.TV welcome title and two unauthenticated entry paths\nTested: git diff --cached --check\nNot-tested: Full test suite\nNot-tested: npm run lint still fails because the existing Next 16 next lint script resolves /lint as a project directory
The default Popi Models image route can return transient upstream overloads for apiyi_nano_banana_2 even when the gateway configuration is valid. The executor now uses gpt-image-2-all as an implicit same-gateway fallback only for overload-shaped errors, while preserving explicit fallback behavior and surfacing non-overload errors unchanged.
Constraint: The gateway can intermittently return system_disk_overloaded for the default image model
Rejected: Change the default model globally | would alter every new image node instead of only recovering transient failures
Rejected: Fallback on every error | would hide prompt, safety, or request-shape problems
Confidence: high
Scope-risk: moderate
Directive: Keep implicit fallback predicates narrow so user-actionable errors remain visible
Tested: npm run test:run
Tested: npm run build
Browser-file-system workflow saves were still bypassing external media storage, so local projects could keep large image, video, and audio data embedded instead of writing refs into the selected browser-backed workspace. The storage path now uses the browser file helpers for image, video, and audio refs and hydrates them back without API calls.
Constraint: Keep local browserfs storage on the existing external media storage path instead of adding a new persistence mode.
Rejected: Keep browserfs excluded from externalization | it preserves the old large-payload behavior for local projects.
Confidence: high
Scope-risk: moderate
Directive: Do not route browserfs media through server API endpoints; browserfs paths must stay client-local.
Tested: npm run test:run
Tested: npm run build
Tested: git diff --check -- src/store/workflowStore.ts src/utils/browserFileSystem.ts src/utils/mediaStorage.ts src/utils/__tests__/mediaStorage.browserfs.test.ts
Not-tested: npm run lint is blocked because next lint is no longer a valid Next 16 command in this repo
Not-tested: npx tsc --noEmit reports existing test-file type debt outside this change while next build TypeScript passes
Browser-file-system workflow saves were still bypassing external media storage, so local projects could keep large image, video, and audio data embedded instead of writing refs into the selected browser-backed workspace. The storage path now uses the browser file helpers for image, video, and audio refs and hydrates them back without API calls.
Constraint: Keep local browserfs storage on the existing external media storage path instead of adding a new persistence mode.
Rejected: Keep browserfs excluded from externalization | it preserves the old large-payload behavior for local projects.
Confidence: high
Scope-risk: moderate
Directive: Do not route browserfs media through server API endpoints; browserfs paths must stay client-local.
Tested: npm run test:run
Tested: npm run build
Tested: git diff --check -- src/store/workflowStore.ts src/utils/browserFileSystem.ts src/utils/mediaStorage.ts src/utils/__tests__/mediaStorage.browserfs.test.ts
Not-tested: npm run lint is blocked because next lint is no longer a valid Next 16 command in this repo
Not-tested: npx tsc --noEmit reports existing test-file type debt outside this change while next build TypeScript passes
Output nodes were collapsing multiple connected media inputs into one visible result, which made image/video/audio/3D connections look ignored. The node now preserves each connected media kind and presents explicit result switching with current/all download actions.
Constraint: Output node remains a result endpoint and does not transform media or create hidden downstream behavior
Rejected: Auto-merge media into one combined preview | would hide workflow structure and violate the endpoint-only product model
Confidence: high
Scope-risk: moderate
Directive: Keep output node behavior as explicit result display; route further processing through visible downstream nodes
Tested: npm test -- --run src/components/__tests__/OutputNode.test.tsx src/store/execution/__tests__/simpleNodeExecutors.test.ts
Tested: npm run build
Tested: npm run test:run
Tested: Playwright localhost smoke with no page or console errors
Vidu-style video models can load parameter schemas that change the Generate Video node height and trigger React Flow dimension updates. The fix keeps schema-driven resize notifications stable, skips no-op node height writes, and ignores duplicate React Flow node changes before they enter the workflow store.
It also preserves completed media outputs when a stopped or reloaded workflow still has transient loading/skipped state, so existing video results do not appear stuck after recovery.
Constraint: The crash was reported from a browser state where choosing Vidu hit React's maximum update depth in onNodesChange.
Rejected: Clear browser storage as the fix | it would hide persisted workflow loops without fixing the update path.
Rejected: Remove dynamic video handles | visible media/text inputs are product behavior and required for model-specific workflows.
Confidence: high
Scope-risk: moderate
Directive: Keep React Flow dimension and schema resize writes idempotent; new node resize paths should no-op when dimensions are already applied.
Tested: npm test -- --run src/components/__tests__/GenerateVideoNode.test.tsx -t 'should not resize repeatedly'
Tested: npm test -- --run src/components/__tests__/GenerateVideoNode.test.tsx src/components/__tests__/ModelParameters.test.tsx src/store/__tests__/workflowStore.integration.test.ts src/store/__tests__/skipPropagation.test.ts src/store/execution/__tests__/generateVideoExecutor.test.ts
Tested: npm run build
Tested: npm run test:run
The accumulated fixes move the test build toward the current product shape: Popi models are the default provider surface, remote community workflow APIs are removed from the local template flow, media nodes expose accurate preview/preview-modal behavior, and Generate Video owns first-class duration, resolution, and sound defaults instead of burying those values in provider schemas.
The test suite was brought back in line with the product mode split: Popi provider mode is the default runtime, while multi-provider model search remains covered explicitly under multi mode.
Constraint: Product direction is canvas-owned workflow structure with Popi Models as the tested default provider path.
Rejected: Keep legacy community workflow API surface | user requested removing remote data paths and retaining local templates.
Rejected: Treat video duration/resolution/sound as hidden provider params | these are user-facing Generate Video controls.
Confidence: high
Scope-risk: broad
Directive: Do not reintroduce remote community template loading without a product decision on hosted templates and i18n ownership.
Tested: npm test -- --run src/store/utils/__tests__/nodeDefaults.test.ts src/store/execution/__tests__/generateVideoExecutor.test.ts src/components/__tests__/GenerateVideoNode.test.tsx src/components/__tests__/GenerationComposer.test.tsx
Tested: npm run build
Tested: npm test -- --run src/components/__tests__/ModelSearchDialog.test.tsx src/store/utils/__tests__/localStorage.test.ts
Tested: npm run test:run
Not-tested: Live provider generation calls against paid external APIs.
New users now land on Popi gateway defaults that match the tested production-style path: APIYI Nano Banana 2 for images, Doubao Seedance for video, and Doubao Seed 2.0 Lite for LLM chat/tool use. Settings and FTUX screens render these effective defaults instead of empty placeholders, while existing local node defaults keep taking precedence.
The same pass keeps provider-overload errors user-facing by formatting the model name that the node currently displays, so fallback and switched-model failures are easier to understand across media nodes.
Constraint: Popi mode should hide internal NewApiWG naming and default to models available through the Popi gateway.
Rejected: Persist default values into localStorage for every new user | would make future system default changes harder and could overwrite explicit user preferences.
Confidence: high
Scope-risk: moderate
Directive: Do not change these defaults without checking the Popi gateway model ids and www.popi.art login/model-routing assumptions.
Tested: npm run test:run -- src/lib/__tests__/llmModels.test.ts src/store/utils/__tests__/nodeDefaults.test.ts src/store/execution/__tests__/generateVideoExecutor.test.ts src/components/__tests__/ProjectSetupModal.test.tsx src/components/__tests__/GenerationComposer.test.tsx src/app/api/chat/__tests__/route.test.ts src/components/__tests__/LLMGenerateNode.test.tsx src/utils/__tests__/userFacingErrors.test.ts
Tested: PROVIDER_MODE=popi NEXT_PUBLIC_PROVIDER_MODE=popi npm run build
Tested: git diff --check
Not-tested: npm run lint currently fails because next lint is no longer a valid project command in this Next.js setup
Default provider mode now exposes only Popi Models while preserving the existing multi-provider implementation behind an explicit multi mode. The model browser, project settings, onboarding, node badges, and model API all share the same provider-mode decision so the test deployment matches the www.popi.art login-aligned direction.
This also includes the pending UI and i18n node-label changes already present in the tracked worktree so the committed state matches the verified build.
Constraint: Product entry must align with www.popi.art by exposing Popi Models instead of internal NewApiWG naming
Constraint: Test deployment should match the full tracked working tree that passed build
Rejected: Delete legacy provider code | multi-provider internals remain useful behind PROVIDER_MODE=multi
Rejected: UI-only hiding | API and store layers now enforce Popi mode too
Confidence: high
Scope-risk: broad
Reversibility: clean
Directive: Keep NewApiWG as the internal provider id unless the gateway API/env contract is migrated
Tested: npm run test:run -- src/components/__tests__/ProjectSetupModal.test.tsx src/app/api/models/__tests__/route.test.ts src/lib/__tests__/llmModels.test.ts
Tested: npm run test:run -- src/components/__tests__/GenerateImageNode.test.tsx src/components/__tests__/GenerateVideoNode.test.tsx src/components/__tests__/GenerateAudioNode.test.tsx src/components/__tests__/Generate3DNode.test.tsx src/components/__tests__/LLMGenerateNode.test.tsx
Tested: npm run test:run -- src/lib/chat/tools.test.ts
Tested: PROVIDER_MODE=popi NEXT_PUBLIC_PROVIDER_MODE=popi npm run build
Tested: Browser smoke on http://localhost:3000 verified Project Settings and Model Search only expose Popi Models
Not-tested: Direct npx tsc --noEmit remains blocked by pre-existing test typing errors outside this change
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.
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
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
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 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
- 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>
- 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>
All executors that call /api/generate now check for the polling flag
and enter the pollGenerateTask loop for long-running Kie tasks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After the initial /api/generate response, check for polling flag and
enter pollGenerateTask loop instead of waiting on a single long request.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shared polling utility that calls /api/generate/poll with short-lived
requests (3-8s interval with linear backoff). Handles abort signals,
network error retries, and 10-minute client-side timeout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- copyLoopOutput: add console.warn for unrecognized target node types
- connectedInputs: exclude loop edges from easeCurve edge lookup
- mediaStorage: trim gallery image/video refs to match actual array
lengths after item deletion
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>
1. Normalize and clamp loopCount at execution time (1-100 range)
- Validates imported/malformed values are finite numbers
- Falls back to default of 3 if invalid
- Prevents NaN, Infinity, or extreme values from bypassing setLoopCount validation
2. Fix resume logic for nodes inside loop bodies
- Compute loopStartLevel when startFromNodeId is in loopLevels
- On first iteration, start from that level instead of level 0
- On subsequent iterations, start from level 0 as normal
- Preserves existing copyLoopOutput skip on first iteration
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>
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>
Updates runOnce in all four generation executors to accept an optional
parametersOverride argument. When running the fallback model, the
executor uses fallbackParameters from node data instead of the primary
model's parameters.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>