Local reference images were reaching the gateway as localhost URLs, and selected image/video nodes still exposed duplicate inline settings while the composer is the active control surface. This keeps gateway media inputs self-contained, maps GPT Image 2 sizes from the actual aspect ratio controls, and keeps node bodies focused on preview/output state.
Constraint: NewApiWG upstream cannot fetch browser-local /api/images URLs.
Constraint: Selected-node composer owns image and video generation controls.
Rejected: Keep localhost reference URLs | remote gateway requests cannot dereference local browser routes.
Rejected: Keep duplicate inline settings | it creates conflicting controls with the composer.
Confidence: high
Scope-risk: moderate
Directive: Do not send /api/images temporary URLs to NewApiWG upstream; resolve them to data URLs before provider calls.
Tested: npm run test:run -- src/app/api/generate/providers/__tests__/newapiwg.test.ts src/app/api/generate/__tests__/route.test.ts src/components/__tests__/GenerateImageNode.test.tsx src/components/__tests__/GenerateVideoNode.test.tsx src/components/__tests__/PromptNode.test.tsx src/lib/__tests__/llmModels.test.ts src/store/__tests__/workflowStore.integration.test.ts
Tested: npm run build
Tested: git diff --check
Not-tested: npm run lint still fails because next lint resolves to a nonexistent lint directory under Next 16.
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 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