dev/openapi-path
696 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
af37c2330e |
Docs: Housekeeping + Remove docs-old (#9166)
* chore(docs): remove old docs directory * chore(docs): transition tests, generators to new docs Focuses on continuing the move away from the old docs configuration by removing legacy packages, tests and generate scripts, and replacing them with new scripts for the new docs.ma - Adds docs commands to Makefile - Removes old docs tests - Removes old docs generate scripts - Removes docstring and mkfile usage - Regenerated UV lockfile * feat(docs): improve config organization Pulls out the long parts of the astro config into dedicated files located in a new `config/` directory. * feat(docs): add pages for contributing to docs * feat(docs): add image section describe how to add images to your docs pages in an organized fashion. * feat(docs): add guide for docs translations * feat(docs): add cover image * fix(docs): add social image metadata * fix(docs): pages in wrong locations also updated some orderings and frontmatter * chore(docs): upgrade deps * feat(docs): add missing docs pages * fix(docs): docs fixes - fix redirects - improve canvas projects docs - improve models docs --------- Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> |
||
|
|
811103e1c3 |
fix(fp8): route ModelMixin through hook-based path to survive partial load (#9231)
Diffusers' enable_layerwise_casting() installs a LayerwiseCastingHook that (a) only casts dtype in pre_forward, not device, and (b) replaces Linear.forward with an instance-level wrapper that calls the original Linear.forward captured before the hook was installed. ModelCache.put() later runs apply_custom_layers_to_model, which constructs a new CustomLinear sharing the original Linear's __dict__ — so the diffusers wrapper carries over and routes calls to the captured original forward, silently bypassing CustomLinear.forward and its cast_to_device autocast. With partial loading (e.g. FLUX.2 Klein 9B on a constrained GPU), some Linear weights stay on CPU. The diffusers pre_forward only casts dtype, so F.linear then sees input on cuda:0 and weight on cpu and raises "Expected all tensors to be on the same device". Route every nn.Module — including ModelMixin — through _apply_fp8_to_nn_module, which uses register_forward_pre_hook / register_forward_hook(always_call=True). nn.Module._call_impl dispatches these around forward without replacing it, so CustomLinear.forward is still reached and cast_to_device moves the weight to the input device. Lose diffusers' _disable_peft_input_autocast in the process, which is irrelevant — InvokeAI patches LoRAs through CustomLinear's _patches_and_weights, not PEFT BaseTunerLayer. Add regression test that asserts the ModelMixin branch calls _apply_fp8_to_nn_module and not enable_layerwise_casting. Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> |
||
|
|
7859d3fc91 |
feat(nodes): add Save Image (Gallery + File Export) node (#9077)
* feat(nodes): add Save Image (Gallery + File Export) node
Saves an image to the gallery and additionally exports a copy to the
filesystem with a custom filename using prefix and suffix around the
gallery UUID.
- Filename pattern: {prefix}{uuid}{suffix}.{png|jpg|webp}
- UUID matches the gallery entry so exported files can be matched back
- Quality input (1-100) for JPG/WEBP, ignored for PNG
- Board and Metadata inputs behave like the standard Save Image node
- Output directory restricted to subfolders of the InvokeAI outputs
folder; absolute paths and path traversal are rejected
* Chore Ruff
* Chore Typegen
* Chore Typegen
* Fix Linux CI Test
* update schema
---------
Co-authored-by: dunkeroni <dunkeroni@gmail.com>
|
||
|
|
3e72b88839 |
Harden/router auth and bugfixes (#9200)
* harden(api): enforce auth on 4 routers, fix 4 router bugs, add route tests Add auth dependencies to download_queue, style_presets, model_relationships, and utilities routers, which previously had none — under multiuser=True these endpoints were anonymously reachable. CurrentUserOrDefault for read/per-resource routes; AdminUserOrDefault for global actions (prune/cancel-all downloads, style preset import/export, model relationship add/remove). Single-user mode behavior is unchanged. Fix four bugs in the same routers: - model_relationships: HTTPException(400) from the self-relationship check was caught by `except Exception` and re-raised as 500. Move the check before the try-block and drop the broad except so the 400 reaches the client. - style_presets update_style_preset: image was persisted before json.loads could fail, leaving the preset image partially updated on bad payloads. Validate `data` first, then mutate image state. - style_presets create/update: json.JSONDecodeError was not caught alongside pydantic.ValidationError; malformed JSON surfaced as 500. Catch both → 400. - download_queue download(): `Path(dest)` with no validation. Reject absolute paths, '..' segments, and empty strings with 400 before the service is called. Add shared multiuser test fixtures in tests/app/routers/conftest.py and new route-level tests for download_queue, style_presets, model_relationships, utilities, and virtual_boards covering anonymous-rejection, role gating, and the four bug regressions. Enable --cov=invokeai in pytest addopts so the existing fail_under = 85 threshold is actually enforced. * Ruff * chore: openapi.json * harden(api): enforce auth on 4 routers, fix 4 router bugs, scope style presets per-user, add route tests Add auth dependencies to download_queue, style_presets, model_relationships, and utilities routers, which previously had none — under multiuser=True these endpoints were anonymously reachable. CurrentUserOrDefault for read/per-resource routes; AdminUserOrDefault for global actions (prune/cancel-all downloads, style preset import/export, model relationship add/remove). Single-user mode behavior is unchanged. Fix four bugs in the same routers: - model_relationships: HTTPException(400) from the self-relationship check was caught by `except Exception` and re-raised as 500. Move the check before the try-block and drop the broad except so the 400 reaches the client. - style_presets update_style_preset: image was persisted before json.loads could fail, leaving the preset image partially updated on bad payloads. Validate `data` first, then mutate image state. - style_presets create/update: json.JSONDecodeError was not caught alongside pydantic.ValidationError; malformed JSON surfaced as 500. Catch both -> 400. - download_queue download(): `Path(dest)` with no validation. Reject absolute paths, '..' segments, and empty strings with 400 before the service is called. Scope style presets per-user. Migration 27 added `user_id` and `is_public` columns months ago, but the service layer never read or wrote them — every authenticated user saw and could mutate every preset. This commit wires them up: - StylePresetRecordDTO gains `user_id`; StylePresetWithoutId / StylePresetChanges / StylePresetFormData gain `is_public`. - SqliteStylePresetRecordsStorage.create / create_many / _sync_default_style_presets write user_id (system for defaults). get_many takes user_id + is_admin and filters SQL to: admin sees all, otherwise own ∪ default ∪ public. - style_presets router gains _assert_preset_read / _assert_preset_write helpers mirroring _assert_image_owner in routers/images.py. Get/update/delete/image load the record first, then enforce: 403 for non-owner on private presets, 403 for non-admin attempting to mutate a Default preset, 403 for non-admin trying to create a Default preset. Add shared multiuser test fixtures in tests/app/routers/conftest.py: enable_multiuser patches ApiDependencies across the relevant router modules and swaps None-valued services for MagicMock, plus wires a real SqliteStylePresetRecordsStorage on the in-memory DB so cross-user SQL filtering is actually exercised. Add route-level tests for download_queue, style_presets, model_relationships, utilities, and virtual_boards covering anonymous-rejection, role gating, the four bug regressions, and the full ownership matrix for style presets (own/public/default/admin) on get, list, update, delete, image fetch, and is_public flip. Rename tests/app/routers/test_download_queue.py to test_download_queue_router.py to avoid a pytest collection collision with the long-standing tests/app/services/download/test_download_queue.py. Enable --cov=invokeai in pytest addopts so the existing fail_under = 85 threshold is actually enforced. * chore(pytest): drop --cov=invokeai from this PR Reviewer pointed out that current full-suite coverage is ~48% while fail_under is set to 85, so activating --cov=invokeai on this PR would trip CI the moment it lands. Tests added in this PR remain (they cover the bug regressions and auth gating). Coverage-gate activation will be bundled into a follow-up PR together with whatever additional tests are needed to clear the threshold. * refactor(api): share access helpers, tighten conftest, polish review nits Address remaining feedback from the code review (issues 9200#issuecomment-4480805221): - Extract _assert_image_owner / _assert_image_read_access / _assert_board_read_access from routers/images.py into a new routers/_access.py module (functions exported without the underscore prefix). routers/images.py keeps local _assert_* aliases so its 13 internal call sites stay untouched. routers/utilities.py imports the helper at module top instead of reaching into routers/images.py privates from inside image_to_prompt. - Reorder current_user to come before the body parameter in expand_prompt and image_to_prompt, matching the convention used by the rest of the routers in this PR and by routers/images.py. - Simplify _validate_dest: '..' in posix.parts or '..' in windows.parts is more direct than the set-union allocation. - Harden tests/app/routers/conftest.py: pull the eight monkeypatched module paths into a _PATCHED_API_DEPENDENCIES_MODULES tuple so adding a new router is one list entry instead of one more setattr call. Add two WARNING blocks to the module docstring — one calling out the unconditional MagicMock replacements (style_preset_records is the one real-SQLite exception), and one reminding future authors that new routers must be appended to the tuple. - test_multiuser_authorization.py: its local enable_multiuser fixture now also patches routers/_access.ApiDependencies, since the image read-access check used by its image-mutation tests now resolves names in _access's globals. * chore: openapi.json and typegen * Chore Ruff --------- Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com> Co-authored-by: JPPhoto <jpollack@jpollackphoto.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> |
||
|
|
19007a1f5c |
Add universal noise and optional denoiser noise inputs (#9044)
* add universal noise and optional denoiser noise inputs * Document scheduler parity limitations * Clarify external noise integration rules * chore: typegen * Fix external noise handling regressions * chore: typegen * Fix stale FLUX.2 scheduler mu test * chore: typegen * chore: typegen * chore: typegen * Fold universal noise into noise node * Address PR review cleanup comments * remove num_channels from noise shape validation * restore internal piping for cogview and sd3 channels * chore: ruff --------- Co-authored-by: Alexander Eichhorn <alex@eichhorn.dev> Co-authored-by: dunkeroni <dunkeroni@gmail.com> |
||
|
|
028c976ea4 |
fix(external-providers): admin guard, validation, locale keys (#9171)
* fix(external-providers): admin guard, validation, locale keys
- Require AdminUserOrDefault on POST/DELETE /external_providers/config/{id}
so non-admins in multiuser mode can no longer set/reset shared credentials
- Reject Seedream batch requests where references + init + outputs > 15
before posting, surfacing ExternalProviderCapabilityError instead of a
provider-side 400
- Surface Seedream batch item errors via provider_metadata.partial_failures
and raise when every item failed, instead of silently dropping filtered
results
- Set max_reference_images=3 on Qwen Image Edit Max so the central validator
enforces the documented limit before hitting DashScope
- Add missing parameters.* locale keys (quality, background, inputFidelity,
temperature, thinkingLevel, watermark, optimizePrompt) so the OpenAI,
Gemini, and Seedream option panels render their labels without fallbacks
* i18n(external): localise OpenAI/Gemini select option labels
Wrap the visible <option> text in OpenAIProviderOptions and
GeminiProviderOptions with t(...) so non-English locales translate
the values alongside their <FormLabel> (previously the labels
translated but Auto/High/Medium/Low/Transparent/Opaque/Default/
Minimal stayed English). Adds the matching
parameters.{quality,background,inputFidelity,thinkingLevel}Options
keys to en.json and a colocated vitest guard that fails if any
<FormLabel> or <option> in External/*ProviderOptions.tsx contains
a raw literal instead of a {t(...)} expression.
* fix(canvas): gate drop tiles by current model's supported entity types
The Canvas drop area registered every <DndDropTarget> as long as the
canvas wasn't busy, so dragging an image onto the "Regional Reference
Image" tile created a regional_guidance layer even when the active
model didn't support it (e.g. OpenAI/Gemini/Seedream). The
layer-creation menu already disables those entries via
useIsEntityTypeEnabled, but the drop tiles bypassed that check.
Pull useIsEntityTypeEnabled into CanvasDropArea and OR each tile's
isDisabled with !isEnabled for its entity type. Same fix closes the
symmetric gaps for SD3 / CogView4 / Flux Kontext on the control-layer
and inpaint-mask tiles, mirroring the menu in one place.
* Chore Ruff Format
* chore: openapi
---------
Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com>
Co-authored-by: JPPhoto <jpollack@jpollackphoto.com>
|
||
|
|
61d1eaa5c5 |
feat(anima): Make Anima respect the precision property in Invoke.yaml (#9183)
* feat(devices): add choose_anima_inference_dtype honoring config.precision When precision='auto', delegates to the existing choose_bfloat16_safe_dtype probe. When set to a specific value (float16/bfloat16/float32), returns that dtype directly so the user's config choice is honored. Anima call sites will migrate to this helper in a follow-up commit. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(anima): honor config.precision at the three Anima dtype call sites Swaps choose_bfloat16_safe_dtype for choose_anima_inference_dtype at: - _run_diffusion (transformer / latents / LoRA dtype) - anima_text_encoder (text-encoder LoRA dtype) - model_loaders/anima (transformer load dtype) precision='auto' preserves the current bf16-probe fallback; specific values are now honored end-to-end. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Your Name <you@example.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com> |
||
|
|
8f46d8bf13 |
fix(qwen): fix ghosting artifacts Qwen Image Edit (#9155)
* fix(qwen): use distinct img_shapes for reference latents in Qwen Image Edit Qwen Image Edit was applying identical RoPE positions to the noisy and reference latent segments (both packed at the noisy latent's dimensions), so cross-attention couldn't disentangle them — reference content bled into the generation as a faintly offset ghost across the whole frame, outside the masked edit region. The denoise now keeps reference latents at their own (H, W) and uses those dims in the reference segment of img_shapes, matching diffusers' QwenImageEditPipeline / QwenImageEditPlusPipeline. The reference qwen_image_i2l is resized to ~1024² area preserving aspect ratio (matching diffusers' VAE_IMAGE_SIZE) so the reference token sequence stays in the distribution the model was trained on. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(qwen): clamp reference latents to VAE_IMAGE_SIZE in denoise The frontend resizes the reference image to ~1024² area before VAE encoding, but direct API callers and older graph JSON can wire qwen_image_i2l → qwen_image_denoise without explicit width/height, sending a native-resolution reference latent into the transformer. Without the clamp the model receives an out-of-distribution sequence length (artifact returns, VRAM spikes). Mirror diffusers' QwenImageEdit(Plus) VAE_IMAGE_SIZE behavior in latent space: bilinear-downscale the reference latent to calculate_dimensions(1024², aspect_ratio) snapped to multiples of 32 in pixel space (= multiples of 4 in latent space, so always packable). In-budget latents pass through untouched. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com> |
||
|
|
6f42ad0ee7 |
feat: add per-model FP8 layerwise casting for VRAM reduction (#8945)
* feat: add per-model FP8 layerwise casting for VRAM reduction Add fp8_storage option to model default settings that enables diffusers' enable_layerwise_casting() to store weights in FP8 (float8_e4m3fn) while casting to fp16/bf16 during inference. This reduces VRAM usage by ~50% per model with minimal quality loss. Supported: SD1/SD2/SDXL/SD3, Flux, Flux2, CogView4, Z-Image, VAE (diffusers-based), ControlNet, T2IAdapter. Not applicable: Text Encoders, LoRA, GGUF, BnB, custom classes * feat: add FP8 storage option to Model Manager UI Add per-model FP8 storage toggle in Model Manager default settings for both main models and control adapter models. When enabled, model weights are stored in FP8 format in VRAM (~50% savings) and cast layer-by-layer to compute precision during inference via diffusers' enable_layerwise_casting(). Backend: add fp8_storage field to MainModelDefaultSettings and ControlAdapterDefaultSettings, apply FP8 layerwise casting in all relevant model loaders (SD, SDXL, FLUX, CogView4, Z-Image, ControlNet, T2IAdapter, VAE). Gracefully skips non-ModelMixin models (custom checkpoint loaders, GGUF, BnB). Frontend: add FP8 Storage switch to model default settings panels with InformationalPopover, translation keys, and proper form handling. * ruff format * fix: enable FP8 layerwise casting for checkpoint Flux models FluxCheckpointModel and Flux2CheckpointModel were missing the _apply_fp8_layerwise_casting call. Additionally, the FP8 casting only worked for diffusers ModelMixin models. Add manual layerwise casting via forward hooks for plain nn.Module (custom Flux class). Also simplify FP8 UI toggle from dual-slider to single switch, matching the CPU-only toggle pattern per review feedback on #8945. * fix: exclude Z-Image from FP8 due to diffusers layerwise casting bug Z-Image's transformer has dtype mismatches with diffusers' enable_layerwise_casting: skipped modules (t_embedder, cap_embedder) stay in bf16 while hooked modules cast to fp16, causing crashes in attention layers. Also hide the FP8 toggle in the UI for Z-Image models. * fix: detect model dtype for FP8 compute instead of using global dtype Models like Flux are loaded in bf16 but the global torch dtype is fp16, causing dtype mismatches during FP8 layerwise casting. Detect the model's actual parameter dtype and use it as compute_dtype for both diffusers ModelMixin and plain nn.Module models. * Remove call for _should_use_fp8 in z-image * Merge branch 'main' + exclude VAEs from FP8 layerwise casting Resolve merge conflict in vae.py by keeping upstream's Anima/QwenImage VAE loader paths and dropping the FP8 call from the AutoencoderKL checkpoint path. Exclude VAEs from FP8 layerwise casting in _should_use_fp8 (both standalone ModelType.VAE and the VAE/VAEDecoder/VAEEncoder submodel types of Main models). FP8 storage causes noticeable quality degradation on VAE decode. * fix(fp8): invalidate cache on settings change, exception-safe nn.Module fallback, hide ControlLoRA toggle - Add ModelCache.drop_model() and call it from update_model_record when fp8_storage or cpu_only change. These settings are baked into the loaded nn.Module at load time, so toggling them was silently a no-op until the cache entry was evicted by other means. - Replace the pre-hook/post-hook pair in _apply_fp8_to_nn_module with a forward wrapper using try/finally. register_forward_hook only fires on successful forward, so an exception left params in compute dtype and defeated the FP8 storage savings. - Hide the FP8 toggle in the UI for ControlLoRA and exclude LoRA/ControlLoRA in _should_use_fp8. LoRAs are patched into base models rather than run as a standalone forward pass, so layerwise-casting hooks would never fire. - Add tests for drop_model, the exception-safe FP8 wrapper, the ControlLoRA/LoRA exclusion, and the _load_settings_changed predicate. * fix(fp8): honor class swap for LoRA patches, evict stale locked entries, skip precision-sensitive layers - _wrap_forward_with_fp8_cast now dispatches via type(module).forward at call time instead of capturing the bound method. ModelCache.put() swaps nn.Linear.__class__ to CustomLinear (sharing __dict__), which would otherwise leave our instance forward shadowing CustomLinear.forward and silently bypass LoRA/ControlLoRA patch dispatch on FP8 checkpoints. - drop_model() now marks locked entries is_stale instead of skipping them silently; unlock() evicts stale entries once the last lock releases. Without this, a setting toggled during an in-flight generation survived on the locked entry and the next generation reused the pre-change module. - _apply_fp8_to_nn_module mirrors diffusers' apply_layerwise_casting: only the supported layer classes (Linear/Conv*/Embedding) get cast, and module paths matching norm/pos_embed/patch_embed/proj_in/proj_out are skipped. FLUX RMSNorm.scale and similar precision-sensitive scalars are no longer crushed to FP8. - drop_model() and the unlock-stale path now update stats.cleared and fire on_cache_models_cleared callbacks, matching _make_room_internal so the UI stats panel and observers don't miss invalidations. - Add 14 tests: class-swap dispatch, norm/pos_embed/proj_in_out skip, unsupported-type skip, stale-marking, multi-lock release, stats and callback firing for both paths, no-op silence. * fix(fp8): switch nn.Module FP8 wrapper to hooks so CustomLinear dispatch survives apply_custom_layers_to_model Previous fix was wrong. `apply_custom_layers_to_model` does not do `module.__class__ = CustomLinear` — `wrap_custom_layer` constructs a NEW CustomLinear via __new__ and shares the original Linear's __dict__, then setattr installs the new object on the parent. The new object has type() == CustomLinear, but our wrapped forward closed over the original Linear instance, so `type(module).forward(module, ...)` resolved to Linear.forward on the captured old object and silently bypassed CustomLinear.forward — breaking LoRA/ControlLoRA patch dispatch for FP8 checkpoint models. Reproduced on a fresh worktree. Replace the instance-forward override with register_forward_pre_hook + register_forward_hook(always_call=True). Hooks are dispatched by nn.Module._call_impl with the actual called instance, so they fire on the new CustomLinear and self.forward resolves normally via class lookup — reaching CustomLinear.forward and its patch-aware branch. always_call=True keeps the exception-safety guarantee (post-hook fires even when forward raises). Replace the simulated __class__-swap test with one that runs real apply_custom_layers_to_model, attaches a sentinel _patches_and_weights, and asserts the patch-aware branch in CustomLinear.forward is reached. Verified the test fails under the old instance-forward implementation with the reviewer-described symptom and passes under the hook fix. * Add docs for fp8 --------- Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com> |
||
|
|
f99858b89f |
Add OKLab and Oklch image utilities and nodes, refactor color space nodes (#8999)
* Add OKLab and Oklch image utilities and nodes * refactor: unify oklab color conversions * refactor: unify shared color conversions * chore: typegen * chore: typegen --------- Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> |
||
|
|
aa865f6e08 |
feat: add image subfolder strategy setting UI (#9133)
* feat: add image subfolder strategy setting UI * fix: address image subfolder strategy review |
||
|
|
25bbf32a65 |
feat(model): Add ER SDE / DPM++ 2M Scheduler Support For Anima (#9125)
* refactor(anima): reshape ANIMA_SCHEDULER_MAP to (class, kwargs) tuples Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(anima): address Task 1 review feedback Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(anima): add dpmpp_2m and dpmpp_2m_sde schedulers * refactor(anima): unify ANIMA_SHIFT in schedulers.py and add Literal-coverage test * fix(anima): seed generator into scheduler.step for SDE reproducibility * feat(anima): add pure ancestral-Euler step helper Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(anima): fix _anima_euler_ancestral_step docstring formula to match code Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * refactor(anima): address Task 4 review feedback * feat(anima): add euler_a (rectified-flow ancestral Euler) scheduler * fix(anima): sample euler_a noise in float32 to avoid bfloat16 quantization * chore(anima): bump anima_denoise to v1.3.0 and regen schema * fix(frontend): revert Windows path-separator drift in schema regen * fix(anima): gate step_generator construction to schedulers that need it Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(anima): apply ruff lint and format fixes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(frontend): expose new Anima schedulers in dropdown and metadata recall * chore(frontend): apply prettier wrap to setAnimaScheduler PayloadAction * fix(anima): correct euler_a math — variance-preserving noise mix, not biased Euler * revert(anima): remove euler_a scheduler — quality not worth the complexity * chore(anima): apply ruff format (trim trailing blank lines) * feat(rectified-flow): add order-1 ER-SDE stepper for rectified flow Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(rectified-flow): document lambda_next>0 precondition; tighten terminal-step test Address code review feedback on order-1 ER-SDE stepper: - Add docstring preconditions to integral helpers noting the logarithmic singularity at lam=0 (callers must guard sigma_next>0). - Tighten terminal-step test from atol=1e-5 to torch.equal — the algebra is exact when sigma_next=0, not approximate. * feat(rectified-flow): add 2nd-order Taylor extension to ER-SDE stepper * test(rectified-flow): tighten Task 2 state-mutation test with value assertion Address code review feedback on the 2nd-order Taylor extension tests: - Assert state.old_d_x0 equals the analytically-computed d_x0 = 0.2v / (1.5 - 4.0) rather than just checking it's non-None. - Document that x_t is intentionally re-used across calls (state threading test, not trajectory correctness). - Document the order-2 correction coefficient magnitude that justifies the atol=1e-3 threshold in the engagement test. * feat(rectified-flow): add 3rd-order Taylor extension to ER-SDE stepper * docs(rectified-flow): document have_two_back invariant + order-3 test margin Address code review feedback on Task 3: - Comment why have_two_back checks both old_d_x0 and sigma_prev_prev (the sigma~=1 boundary path can break the joint invariant). - Document the analytically verified ~0.0004 per-element correction magnitude that justifies the atol=1e-3 threshold in the order-3 test. * feat(anima): register er_sde scheduler choice * docs(anima): document custom-code-path scheduler convention; tighten test Address code review feedback on Task 4: - Add an in-file comment above ANIMA_SCHEDULER_MAP explaining the convention: schedulers with custom code paths (er_sde) live in the Literal+labels only, not the map. - Hoist `import typing` to module-level in test_anima_schedulers.py (was inline-imported in two test functions). - Pin the er_sde label value (== "ER-SDE"), not just key existence. * feat(anima): wire er_sde scheduler into denoise loop * docs(anima): document float32 noise dtype and sigma_next/sigma_prev naming Address code review feedback on Task 5: - Comment explaining why fresh_noise is float32 (matches er_sde_rf_step's dtype contract with x_t.to(float32)). - Bridging comment at the inpaint extension call clarifying that sigma_next here means the same thing as sigma_prev in the Euler branch and the AnimaInpaintExtension API. * chore(anima): bump anima_denoise to v1.4.0 and regen schema * feat(frontend): expose er_sde scheduler in dropdown and metadata recall Address code review on Task 6 — er_sde was registered in the OpenAPI schema but missing from the frontend's own Zod enums and Redux PayloadAction types, so: - The combobox dropdown didn't list it. - setAnimaScheduler('er_sde') would fail TypeScript at the call site. - Metadata recall for er_sde-generated images would silently no-op (the scheduler value couldn't pass zParameterScheduler validation). Changes: - Add er_sde to zAnimaSchedulerField (the per-Anima Zod enum). - Add er_sde to the animaScheduler state-shape Zod enum. - Widen setAnimaScheduler's PayloadAction union. - Add ER-SDE option to the ParamAnimaScheduler combobox. - Make the metadata Scheduler handler accept ParameterAnimaScheduler too, with a fallback parse and a narrowing guard before the SD/SDXL dispatch. * fix(rectified-flow): guard 2nd-order branch against sigma_prev_curr=1.0 When step 0 goes through the sigma_curr=1 closed-form limit branch it writes state.sigma_prev_curr=1.0. On step 1, have_one_back was True and the 2nd-order path called _lambda(1.0) = 1.0/(1.0-1.0), crashing with ZeroDivisionError in every real denoise run. Fix: extend the have_one_back guard to require that sigma_prev_curr is more than _SIGMA_ONE_TOLERANCE below 1.0. The finite-difference derivative across the limit step is not meaningful, so skipping the 2nd-order term on that transition is correct. Order-3 is already gated behind old_d_x0 being set, which this path never sets, so no additional guard is needed there. Adds a regression test that runs the full sigma=1.0->0.9->0.7->0.0 sequence and asserts no ZeroDivisionError and all-finite output. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(scheduler): add ERSDEScheduler available to SD/SDXL ER-SDE solver (Cui et al., arXiv:2309.06169) usable across SD/SDXL (VP-SDE) and rectified-flow models. Anima migration follows in subsequent commits. - ERSDEScheduler(SchedulerMixin, ConfigMixin) with prediction_type (epsilon | v_prediction | flow_prediction), use_flow_sigmas, solver_order (1/2/3 with auto-warmup), and stochastic toggle - set_timesteps(sigmas=) for pre-shifted Anima/FLUX/Z-Image schedules - Closed-form limit at sigma=1 in flow mode - Unit tests + VP smoke + 5/5 Anima parity vs er_sde_rf_step (worst delta 5.137e-07) - Frontend wiring: zSchedulerField, SCHEDULER_OPTIONS, OpenAPI regen - parsing.tsx cleanup: removes the AnyScheduler widening since er_sde is now a first-class general scheduler Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(anima): wire ERSDEScheduler into ANIMA_SCHEDULER_MAP Adds er_sde to the standard scheduler dispatch map with rectified-flow kwargs (flow_prediction, use_flow_sigmas=True, flow_shift=3.0, solver_order=3, stochastic=True). Anima still routes through the legacy elif is_er_sde: branch — that's removed in a follow-up commit. This is the additive prerequisite that lets the cutover happen without a window where Anima can't use ER-SDE. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * test(anima): add ER-SDE dispatch integration tests Verifies the ANIMA_SCHEDULER_MAP['er_sde'] entry instantiates correctly, accepts pre-shifted sigmas via set_timesteps(sigmas=...), and resets multistep state. Catches wiring regressions that the algorithm-level parity test cannot. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * refactor(anima): remove elif is_er_sde branch, dispatch through ANIMA_SCHEDULER_MAP Anima ER-SDE now flows through the same standard scheduler path as dpmpp_2m_sde — pre-shifted sigmas via scheduler.set_timesteps(sigmas=...), inpaint extension via inpaint_extension.merge_intermediate_latents_with_init_latents, step_callback per-step. The custom code path was the only thing keeping ER-SDE off the universal pipeline. Bumps invocation version to 1.5.0. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(er_sde): mark module as internal reference and parity oracle ERSDEScheduler is now the production code path. er_sde_rf_step is kept as the comparison oracle for the scheduler's parity test, and as a self-contained mathematical reference for the rectified-flow algebra. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore(rectified-flow): remove er_sde.py reference helper ERSDEScheduler is the production code path. The pure-function helper was retained as a parity oracle but YAGNI — keeping ~200 lines of code purely as a regression net for hypothetical future drift isn't worth the maintenance signal it generates. Removes: - invokeai/backend/rectified_flow/er_sde.py - tests/backend/rectified_flow/test_er_sde.py - tests/backend/rectified_flow/test_er_sde_scheduler_anima_parity.py ERSDEScheduler's own tests (test_er_sde_scheduler.py) remain — they exercise both VP-SDE and rectified-flow paths directly. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(schema): restore forward slashes in @default cache dir paths Windows-side typegen run flipped these to backslashes. Restore the canonical forward-slash form to match upstream. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * style: apply ruff lint and format to ER-SDE files Sort imports + format per project ruff config (line-length 120). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * refactor(state): use zParameterAnimaScheduler in state shape The animaScheduler field inlined its enum (originally to add er_sde when the shared schema didn't have it yet). Now that zAnimaSchedulerField already includes er_sde, reference the shared zParameterAnimaScheduler to match the pattern used by scheduler/fluxScheduler/zImageScheduler. Drops the redundant .default('euler') — initial value comes from getInitialParamsState. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * style(types): sort imports per simple-import-sort Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(anima): honour clipped sigma schedule for DPM++ img2img/inpaint DPMSolverMultistepScheduler doesn't accept sigmas= in diffusers 0.35.1, so the fallback previously called set_timesteps(num_inference_steps=total_steps) which regenerated a full schedule from sigma_max, ignoring denoising_start/end. When the scheduler supports set_begin_index, call set_timesteps with the full step count and offset into it, so the internal flow_shift applies correctly and denoising starts at the right sigma. Also fixes the inpaint sigma_prev lookup and the timestep loop to use the same offset, and corrects the false parity-test reference in the ER-SDE dispatch test docstring. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * style: apply ruff format to anima_denoise dispatch block Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(anima): extract scheduler driver and fix Heun progress/inpaint bugs Encapsulate per-scheduler dispatch quirks (sigmas= vs num_inference_steps=, Heun's doubled-array index, set_begin_index path) in AnimaSchedulerDriver and tighten two latent bugs in the Heun path of anima_denoise: * Heun's terminal first-order step never reported a user-step completion, so progress capped at N-1 of N. The driver now flags it via sigma_prev==0, and the <= total_steps clamp that papered over the off-by-one is gone. * The inpaint mix ran after every Heun half-step, corrupting the second-order corrector's input (RectifiedFlowInpaintExtension's docstring says it should be called after each denoising step — i.e. once per user step). Mix is now gated on completes_user_step, which is unconditionally True for non-Heun. Also: Heun shift kwarg switched to ANIMA_SHIFT (its set_timesteps doesn't accept sigmas=, so it builds its own internal schedule); narrative comments in scheduler_driver and er_sde_scheduler trimmed; new tests covering driver iteration counts, terminal sigma_prev, seed determinism, and the begin_index fallback for clipped DPM++ schedules. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * style: apply ruff lint and format to anima scheduler driver Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * ci: re-run after flaky token-expiration test The 1-second JWT token-expiration test in test_token_service.py is timing sensitive — passes locally on retry. Empty commit to retrigger CI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Your Name <you@example.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com> |
||
|
|
fcc0881811 |
fix(mm): support ComfyUI bundled checkpoint format for Anima model identification (#9113)
Anima finetunes packaged in ComfyUI format use `model.diffusion_model.*` prefixed keys instead of bare or `net.*` prefixed keys. Update the probe and loader to recognize and handle this format. Co-authored-by: Your Name <you@example.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
51f528c819 |
Feat:(model) qwen image vae checkpoint (#9108)
* feat(qwen-image): standalone VAE checkpoint and Qwen2.5-VL encoder support Add standalone model types so Qwen Image can be run without downloading the full ~40 GB Diffusers pipeline. The VAE and Qwen2.5-VL encoder can now each come from their own model, with the Component Source (Diffusers) acting as a fallback for any submodel not provided separately. * feat(qwen-image): support ComfyUI single-file Qwen2.5-VL encoder Add a checkpoint loader for ComfyUI-style consolidated Qwen2.5-VL encoder files (e.g. qwen_2.5_vl_7b_fp8_scaled.safetensors), which bundle the language model and visual tower into one safetensors with FP8 + per-tensor weight_scale quantization. This drops the standalone encoder footprint from ~16 GB (Diffusers folder, FP16) to ~7 GB. * feat(qwen-image): register standalone components as starter models Add three new starter models so users can install a complete GGUF Qwen Image setup in one click without ever touching the full ~40 GB Diffusers pipeline: - "Qwen Image VAE" — single-file VAE checkpoint pulled from the Qwen-Image repo (~250 MB). - "Qwen2.5-VL Encoder (fp8 scaled)" — ComfyUI single-file FP8 encoder (~7 GB). - "Qwen2.5-VL Encoder (Diffusers)" — full-precision encoder via multi-folder HF download (text_encoder+tokenizer+processor, ~16 GB). The 8 GGUF main starters (Q2_K / Q4_K_M / Q6_K / Q8_0 for both Edit and txt2img) now declare the VAE + fp8 encoder as dependencies, so installing any of them automatically pulls in everything needed to generate. The fp8 encoder is preferred as the default dependency since it's smaller and the on-the-fly dequantization is essentially free at runtime. The Qwen Image starter bundle gets the VAE and fp8 encoder prepended so the bundled Lightning LoRA variants also benefit. * Chore Ruff Format * fix(qwen-image): backfill VAE/encoder fields on persisted state, recall in metadata, optimize scan - bump params slice persisted state to v3 with a v2→v3 migration that backfills qwenImageVaeModel and qwenImageQwenVLEncoderModel to null, preventing existing users from losing all persisted params on upgrade - emit qwen_image_vae and qwen_image_qwen_vl_encoder into graph metadata and add recall handlers so generations using standalone components are reproducible - clear the two new fields in the modelSelected listener when switching away from qwen-image, matching the existing cleanup pattern - identify single-file Qwen VL encoder checkpoints by reading only the safetensors key index via safe_open, instead of loading the full ~7GB state dict into RAM during model scan - log a clear info message and raise an actionable RuntimeError when the first-time HuggingFace tokenizer/config download is needed but offline, pointing users to the diffusers folder layout as an offline alternative - add unit tests for the migration, metadata recall, and identification * fix(qwen-image): auto-select VAE/encoder, clarify GGUF tip, fix fp8 single-file encoder crash - Auto-select first available standalone VAE and Qwen2.5-VL encoder when switching to a Qwen Image model, so GGUF users are ready-to-go without digging into Advanced. Prefers the diffusers-folder encoder over the single-file checkpoint. - Update the "Required for GGUF models" placeholder to clarify that the diffusers source is only required when a standalone VAE & encoder is not installed. - Fix QwenVLEncoderCheckpointLoader crash on ComfyUI fp8_scaled single-file encoders. Two issues: (1) handle the `.scale_weight` / `.scale_input` quantization key scheme alongside `.weight_scale`, and (2) apply Qwen2_5_VLForConditionalGeneration's _checkpoint_conversion_mapping before load_state_dict so legacy `visual.*` / `model.*` keys map onto the new `model.visual.*` / `model.language_model.*` layout expected by transformers ≥4.50. --------- Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com> |
||
|
|
8c17fbe9b4 |
feat: add configurable image subfolder strategies (#8969)
* feat: add configurable image subfolder strategies Add support for organizing output images into subfolders instead of a single flat directory. Four strategies are available via the image_subfolder_strategy config setting: flat (default, current behavior), date (YYYY/MM/DD), type (by image category), and hash (UUID prefix for filesystem performance). The strategy can be changed at any time - existing images keep their paths, only new images use the new strategy. * Chore ruff check * Chore typegen * Chore fix ts types * make subfolder optional * Add image_subfolder_strategy to InvokeAIAppConfig * Chore typegen again * Add test coverage for image subfolder feature Cover the new subfolder path surface introduced in PR #8969: subfolder validation and security checks, ImageService subfolder forwarding for all strategies, delete_images_on_board silent-failure contract, migration 28, config 4.0.2→4.0.3 upgrade, and recall_parameters subfolder resolution regression. * Uses a real in-memory SQLite database (same pattern as test_model_records_sql.py) to verify image_subfolder round-trips correctly through: TestImageSubfolderRoundTrip (3 tests) — save() -> get() for default empty, custom, and deeply nested subfolders TestGetManySubfolder (1 test) — get_many() deserializes image_subfolder on every row TestDeleteIntermediatesSubfolder (2 tests) — delete_intermediates() returns correct (name, subfolder) pairs and actually removes intermediate rows * Chore Docs * test(recall_parameters): merge duplicate test files into single module Two test files shared the basename test_recall_parameters.py (tests/app/api/routers/ and tests/app/routers/), which broke pytest collection due to module name conflict. Merge the load_image_file unit tests into the main router test file and remove the duplicate. --------- Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com> |
||
|
|
18b98e7ac9 |
feat(apionly): seedream provider (#9054)
* feat: initial external model support * feat: support reference images for external models * fix: sorting lint error * feat: add Seedream provider and capability-driven settings visibility Add BytePlus Seedream as external image generation provider with four models (seedream-4.5, seedream-4.0, seedream-3.0-t2i) including debug dump support and batch generation. Hide irrelevant canvas settings for external models by using ExternalModelCapabilities as the source of truth for UI rendering. Scheduler, LoRA, CFG Scale, and all Advanced settings (VAE, CLIP Skip, Seamless, etc.) are now hidden for external models. Steps, Guidance, and Seed controls are only shown when the model declares support via its capability flags. Adds supports_steps capability field and gates the graph builder accordingly. * feat: initial external model support * feat: support reference images for external models * fix: sorting lint error * chore: hide Reidentify button for external models * review: enable auto-install/remove fro external models * feat: show external mode name during install * review: model descriptions * review: implemented review comments * review: added optional seed control for external models * chore: fix linter warning * review: save api keys to a seperate file * docs: updated external model docs * chore: fix linter errors * fix: sync configured external starter models on startup * feat(ui): add provider-specific external generation nodes * feat: expose external panel schemas in model configs * feat(ui): drive external panels from panel schema * docs: sync app config docstring order * feat: add gemini 3.1 flash image preview starter model * feat: update gemini image model limits * fix: resolve TypeScript errors and move external provider config to api_keys.yaml Add 'external', 'external_image_generator', and 'external_api' to Zod enum schemas (zBaseModelType, zModelType, zModelFormat) to match the generated OpenAPI types. Remove redundant union workarounds from component prop types and Record definitions. Fix type errors in ModelEdit (react-hook-form Control invariance), parsing.tsx (model identifier narrowing), buildExternalGraph (edge typing), and ModelSettings import/export buttons. Move external_gemini_base_url and external_openai_base_url into api_keys.yaml alongside the API keys so all external provider config lives in one dedicated file, separate from invokeai.yaml. * feat: add resolution presets and imageConfig support for Gemini 3 models Add combined resolution preset selector for external models that maps aspect ratio + image size to fixed dimensions. Gemini 3 Pro and 3.1 Flash now send imageConfig (aspectRatio + imageSize) via generationConfig instead of text-based aspect ratio hints used by Gemini 2.5 Flash. Backend: ExternalResolutionPreset model, resolution_presets capability field, image_size on ExternalGenerationRequest, and Gemini provider imageConfig logic. Frontend: ExternalSettingsAccordion with combo resolution select, dimension slider disabling for fixed-size models, and panel schema constraint wiring for Steps/Guidance/Seed controls. * Remove unused external model fields and add provider-specific parameters - Remove negative_prompt, steps, guidance, reference_image_weights, reference_image_modes from external model nodes (unused by any provider) - Remove supports_negative_prompt, supports_steps, supports_guidance from ExternalModelCapabilities - Add provider_options dict to ExternalGenerationRequest for provider-specific parameters - Add OpenAI-specific fields: quality, background, input_fidelity - Add Gemini-specific fields: temperature, thinking_level - Add new OpenAI starter models: GPT Image 1.5, GPT Image 1 Mini, DALL-E 3, DALL-E 2 - Fix OpenAI provider to use output_format (GPT Image) vs response_format (DALL-E) and send model ID in requests - Add fixed aspect ratio sizes for OpenAI models (bucketing) - Add ExternalProviderRateLimitError with retry logic for 429 responses - Add provider-specific UI components in ExternalSettingsAccordion - Simplify ParamSteps/ParamGuidance by removing dead external overrides - Update all backend and frontend tests * feat: initial external model support * feat: add Seedream provider and capability-driven settings visibility Add BytePlus Seedream as external image generation provider with four models (seedream-4.5, seedream-4.0, seedream-3.0-t2i) including debug dump support and batch generation. Hide irrelevant canvas settings for external models by using ExternalModelCapabilities as the source of truth for UI rendering. Scheduler, LoRA, CFG Scale, and all Advanced settings (VAE, CLIP Skip, Seamless, etc.) are now hidden for external models. Steps, Guidance, and Seed controls are only shown when the model declares support via its capability flags. Adds supports_steps capability field and gates the graph builder accordingly. * Add Seedream provider, starter models, and provider-specific UI options - Add SeedreamProvider with support for 5.0 Lite, 4.5, 4.0, and 3.0 models - Add Seedream starter models with correct 2K/1K resolution tables - Add SeedreamImageGenerationInvocation with watermark and optimize_prompt fields - Register seedream node type in frontend graph builder - Add SeedreamProviderOptions UI component (watermark, optimize prompt checkboxes) - Add Seedream state/reducers/selectors to paramsSlice - Fix Seedream provider to use provider_options for guidance_scale and watermark - Add 429 rate limit handling with retry_after support - Update Seedream tests for new ExternalGenerationRequest interface * Chore Ruff check & format * Chore typegen * feat: full canvas workflow integration for external models - Add missing aspect ratios (4:5, 5:4, 8:1, 4:1, 1:4, 1:8) to type system for external model support - Sync canvas bbox when external model resolution preset is selected - Use params preset dimensions in buildExternalGraph to prevent "unsupported aspect ratio" errors - Lock all bbox controls (resize handles, aspect ratio select, width/height sliders, swap/optimal buttons) for external models with fixed dimension presets - Disable denoise strength slider for external models (not applicable) - Sync bbox aspect ratio changes back to paramsSlice for external models - Initialize bbox dimensions when switching to an external model * Chore typegen Linux seperator * feat: full canvas workflow integration for external models - Update buildExternalGraph test to include dimensions in mock params * Merge remote-tracking branch 'upstream/main' into external-models * Chore pnpm fix * add missing parameter * docs: add External Models guide with Gemini and OpenAI provider pages * docs: add Seedream provider page to External Models guide * chore: ruff format seedream provider and starter_models * chore(frontend): regenerate schema.ts to include Seedream config fields * fix: remove reserved Windows device name "nul" from repo * Chore windows path * fix: update InvokeAIAppConfig docstring with Seedream config fields * chore(frontend): regenerate schema.ts after docstring update * fix(external-models): address PR review feedback - Gemini recall: write temperature, thinking_level, image_size to image metadata; wire external graph as metadata receiver; add recall handlers. - Canvas: gate regional guidance, inpaint mask, and control layer for external models. - Canvas: throw a clear error on outpainting for external models (was falling back to inpaint and hitting an API-side mask/image size mismatch). - Workflow editor: add ui_model_provider_id filter so OpenAI and Gemini nodes only list their own provider's models. - Workflow editor: silently drop seed when the selected model does not support it instead of raising a capability error. - Remove the legacy external_image_generation invocation and the graph-builder fallback; providers must register a dedicated node. - Regenerate schema.ts. - remove Gemini debug dumps to outputs/external_debug * fix(seedream): TSC errors + seedream provider follow-ups - Export imageSizeChanged from paramsSlice so the metadata recall handler can import it. - Build the external graph's metadata model entry via zModelIdentifierField (ExternalApiModelConfig is not in the AnyModelConfig union). - Strip Seedream debug payload/image dumps. - Regenerate schema.ts. * chore pnpm fix * Chore Docs * Fix move the seedream to api_keys.yaml * fix(seedream): consolidate API key storage, update model IDs, fix metadata recall and node fields - Load external_seedream_api_key/base_url from api_keys.yaml like the other providers - Update Seedream 5.0 Lite ID to seedream-5-0-lite-260128 and add Seedream 5.0 (seedream-5-0-260128) - Remove deprecated Seedream 3.0 T2I (replaced by Seedream 4.0 per BytePlus) - Add metadata recall handlers for watermark and optimize_prompt so Remix restores them - Hide non-functional mode and mask_image fields on the Seedream node (Seedream API has no inpaint and infers mode from inputs); bump node to 1.1.0 * docs(mm): move external provider docs into location needed for astro * fix(linear): respect iterations for models without a seed node Linear UI dropped the iterations count when the graph builder returned no seed node (external API models without seed support like Seedream), so iterations > 1 produced only one image. Use batch.runs to repeat the graph in that case. * Fix Docs * Fix Docs 2 --------- Co-authored-by: CypherNaught-0x <9931495+CypherNaught-0x@users.noreply.github.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> |
||
|
|
73d46338af |
feat(apionly): add Alibaba Cloud Models (#9055)
* feat: initial external model support * feat: support reference images for external models * fix: sorting lint error * chore: hide Reidentify button for external models * review: enable auto-install/remove fro external models * feat: show external mode name during install * review: model descriptions * review: implemented review comments * review: added optional seed control for external models * chore: fix linter warning * review: save api keys to a seperate file * docs: updated external model docs * chore: fix linter errors * fix: sync configured external starter models on startup * feat(ui): add provider-specific external generation nodes * feat: expose external panel schemas in model configs * feat(ui): drive external panels from panel schema * docs: sync app config docstring order * feat: add gemini 3.1 flash image preview starter model * feat: update gemini image model limits * fix: resolve TypeScript errors and move external provider config to api_keys.yaml Add 'external', 'external_image_generator', and 'external_api' to Zod enum schemas (zBaseModelType, zModelType, zModelFormat) to match the generated OpenAPI types. Remove redundant union workarounds from component prop types and Record definitions. Fix type errors in ModelEdit (react-hook-form Control invariance), parsing.tsx (model identifier narrowing), buildExternalGraph (edge typing), and ModelSettings import/export buttons. Move external_gemini_base_url and external_openai_base_url into api_keys.yaml alongside the API keys so all external provider config lives in one dedicated file, separate from invokeai.yaml. * feat: add resolution presets and imageConfig support for Gemini 3 models Add combined resolution preset selector for external models that maps aspect ratio + image size to fixed dimensions. Gemini 3 Pro and 3.1 Flash now send imageConfig (aspectRatio + imageSize) via generationConfig instead of text-based aspect ratio hints used by Gemini 2.5 Flash. Backend: ExternalResolutionPreset model, resolution_presets capability field, image_size on ExternalGenerationRequest, and Gemini provider imageConfig logic. Frontend: ExternalSettingsAccordion with combo resolution select, dimension slider disabling for fixed-size models, and panel schema constraint wiring for Steps/Guidance/Seed controls. * Remove unused external model fields and add provider-specific parameters - Remove negative_prompt, steps, guidance, reference_image_weights, reference_image_modes from external model nodes (unused by any provider) - Remove supports_negative_prompt, supports_steps, supports_guidance from ExternalModelCapabilities - Add provider_options dict to ExternalGenerationRequest for provider-specific parameters - Add OpenAI-specific fields: quality, background, input_fidelity - Add Gemini-specific fields: temperature, thinking_level - Add new OpenAI starter models: GPT Image 1.5, GPT Image 1 Mini, DALL-E 3, DALL-E 2 - Fix OpenAI provider to use output_format (GPT Image) vs response_format (DALL-E) and send model ID in requests - Add fixed aspect ratio sizes for OpenAI models (bucketing) - Add ExternalProviderRateLimitError with retry logic for 429 responses - Add provider-specific UI components in ExternalSettingsAccordion - Simplify ParamSteps/ParamGuidance by removing dead external overrides - Update all backend and frontend tests * feat: add Alibaba Cloud DashScope external image generation provider Add AlibabaCloudProvider supporting Qwen Image and Wan model families via the DashScope API. Includes sync (multimodal-generation) and async (image-generation with task polling) request modes, five starter models (Qwen Image 2.0 Pro, 2.0, Max, Wan 2.6 T2I, Qwen Image Edit Max), config fields for API key and base URL, and frontend registration. * Chore Ruff check & format * Chore typegen * feat: full canvas workflow integration for external models - Add missing aspect ratios (4:5, 5:4, 8:1, 4:1, 1:4, 1:8) to type system for external model support - Sync canvas bbox when external model resolution preset is selected - Use params preset dimensions in buildExternalGraph to prevent "unsupported aspect ratio" errors - Lock all bbox controls (resize handles, aspect ratio select, width/height sliders, swap/optimal buttons) for external models with fixed dimension presets - Disable denoise strength slider for external models (not applicable) - Sync bbox aspect ratio changes back to paramsSlice for external models - Initialize bbox dimensions when switching to an external model * Chore typegen Linux seperator * feat: full canvas workflow integration for external models - Update buildExternalGraph test to include dimensions in mock params * Merge remote-tracking branch 'upstream/main' into external-models * Chore pnpm fix * add missing parameter * docs: add External Models guide with Gemini and OpenAI provider pages * docs: add Alibaba Cloud DashScope provider page to External Models guide * chore: ruff format alibabacloud provider * chore(frontend): regenerate schema.ts to include Alibaba Cloud DashScope config fields * fix: update InvokeAIAppConfig docstring with Alibaba Cloud DashScope config fields * chore(frontend): regenerate schema.ts after docstring update * fix(external-models): address PR review feedback - Gemini recall: write temperature, thinking_level, image_size to image metadata; wire external graph as metadata receiver; add recall handlers. - Canvas: gate regional guidance, inpaint mask, and control layer for external models. - Canvas: throw a clear error on outpainting for external models (was falling back to inpaint and hitting an API-side mask/image size mismatch). - Workflow editor: add ui_model_provider_id filter so OpenAI and Gemini nodes only list their own provider's models. - Workflow editor: silently drop seed when the selected model does not support it instead of raising a capability error. - Remove the legacy external_image_generation invocation and the graph-builder fallback; providers must register a dedicated node. - Regenerate schema.ts. - remove Gemini debug dumps to outputs/external_debug * feat: add AlibabaCloudImageGenerationInvocation node for DashScope provider * fix(external-models): resolve TSC errors in metadata parsing and external graph - Export imageSizeChanged from paramsSlice (required by the new ImageSize recall handler). - Emit the external graph's metadata model entry via zModelIdentifierField since ExternalApiModelConfig is not part of the AnyModelConfig union. * chore: prettier format ModelIdentifierFieldInputComponent * Chore Fix typegen * Chore Docs * fix(alibabacloud): remove references to non-existent negative_prompt field * fix(alibabacloud): address PR review — explicit routing, retries, fix double-counting, Qwen Edit Max as ref-image model - Explicit sync/async lookup, raise on unknown model_id - Move poll sleep to end of loop, info-log on first poll - if/elif in async parser to prevent url+b64_image double-count - 429/5xx retry with Retry-After, wrap RequestException into ExternalProviderRequestError - 32 MiB streaming cap on image downloads - Drop dead routing-table entries and the init_image edit path - Disable supports_negative_prompt on all Alibaba starter models (request schema has no negative_prompt field) - Switch Qwen Image Edit Max to txt2img + reference_images panel (up to 3 inputs) - Update docs - Add 8 unit tests covering parser, routing, retries, polling, and download cap * Chore Ruff * docs: fix info text on storage location of external model api keys --------- Co-authored-by: CypherNaught-0x <9931495+CypherNaught-0x@users.noreply.github.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> |
||
|
|
d50c898a7c |
fix(mm): identify Qwen2.5/Qwen3 causal LMs as Text LLM, not Qwen3 encoder (#9097)
* fix(mm): identify Qwen2.5/Qwen3 causal LMs as Text LLM, not Qwen3 encoder `Qwen3Encoder_Qwen3Encoder_Config` matches any directory with `config.json` at the root and a Qwen* class name, which also describes a complete causal LM like `Qwen2.5-1.5B-Instruct`. With both configs matching and equal sort keys, the encoder won the tie-break, blocking the model from being used as a prompt expander. A standalone text_encoder download has no tokenizer files; a complete causal LM does. Use that to reject the encoder match when tokenizer files are present alongside `config.json` at the root. Also fixes the secondary failure when manually switching the type from `Qwen3Encoder` to `Text LLM`: the existing record's `format=qwen3_encoder` and `variant` were carried over and produced no matching discriminator under `text_llm`. On `ValidationError` after a type change, retry with the stale fields stripped so the new class can apply its defaults. Closes #9090 * Chore Ruff * feat(prompt-tools): show install hint when no LLM/vision model is present The Expand Prompt (sparkle) and Image-to-Prompt buttons used to disappear entirely when no Text LLM or LLaVA model was installed, leaving users no way to discover the feature exists. Both buttons now stay visible at all times. Clicking them with no suitable model installed opens a popover that: - explains what kind of model the feature needs - recommends a default (Qwen2.5-1.5B-Instruct for prompt expansion, LLaVA Onevision 0.5B for image-to-prompt) - offers an "Open Model Manager" button that jumps straight to the Starter Models sub-tab (mirrors the useStarterModelsToast flow, but skips the Launchpad detour since we already know which models the user needs). Tooltip labels also reflect the missing-model state. Adds four starter models so the recommended setups are one click away: - Qwen2.5-1.5B-Instruct (~3 GB) — recommended Text LLM default - Qwen2.5-3B-Instruct (~6 GB) — higher quality Text LLM - SmolLM2-1.7B-Instruct (~3 GB) — Apache-2.0 Text LLM alternative - LLaVA Onevision Qwen2 7B (~16 GB) — larger LLaVA option alongside the existing 0.5B starter |
||
|
|
47d0952aab |
fix(multiuser): redact other users' current-item identifiers from queue status (#9087)
* fix(multiuser): redact other users' current-item identifiers from queue status events
QueueItemStatusChangedEvent embeds the SessionQueueStatus, which includes the
currently-running item's item_id, session_id, and batch_id. The event ships to
user:{owner} and admin rooms. When user A's item changed status while user B's
item was the one in progress, owner A's frontend received the event with B's
identifiers exposed.
In _set_queue_item_status, scrub item_id/session_id/batch_id from the embedded
queue_status when the in-progress item belongs to a different user than the
changed item. Aggregate counts remain global (not user-sensitive).
Identified out-of-scope in the security audit of #127.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(session_queue): close race condition in session queue user_id redaction
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com>
|
||
|
|
6190bca6e9 |
feat: add Custom Node Manager (#9047)
* feat: add Custom Node Manager for installing and managing node packs from the UI
Adds a new "Nodes" tab (circuit icon) to the sidebar with a two-panel layout:
- Left: list of installed custom node packs with reload and uninstall
- Right: tabbed install UI (Git URL / Scan Folder) with install log
Backend API endpoints (POST install, DELETE uninstall, POST reload, GET list)
handle git clone, pip dependency install, runtime node loading/unloading,
and automatic workflow import from node pack repositories. Workflows are
tagged with node-pack:<name> and removed on uninstall.
Includes user and developer documentation, plus 31 tests (21 backend, 10 frontend).
* Chore typegen
* Chore Typegen without Node
* feat(custom-nodes): detect deps instead of auto-installing
Auto-running pip on requirements.txt could pull incompatible
packages into the running InvokeAI env and break the app. The
installer now detects requirements.txt or pyproject.toml,
returns requires_dependencies + dependency_file, and the UI
shows a persistent warning toast pointing the user to the
node pack's documentation.
* Chore ruff
* custom nodes: require admin auth, share imported workflows, and localize UI
- Gate install/uninstall/reload routes on AdminUserOrDefault so they respect multiuser auth
- Import pack workflows under the installing admin with is_public=True so all users see them
- Replace hardcoded English strings in CustomNodesList and CustomNodesInstallLog with translations
- Reuse existing common/queue keys for clear/status, drop duplicates in en.json
* test(custom_nodes): update _import_workflows_from_pack tests for owner_user_id
Pass owner_user_id="admin" in all call sites and assert that user_id and
is_public=True are forwarded to workflow_records.create().
* custom nodes: track imported workflows via manifest and harden pack listing
- Record imported workflow IDs in .invokeai_pack_manifest.json inside the pack
directory; uninstall reads the manifest before rmtree and deletes only those
IDs, so user-authored workflows sharing the pack tag are preserved
- Gate GET /v2/custom_nodes/ with AdminUserOrDefault to match install/uninstall
/reload and prevent unauthenticated disclosure of absolute node pack paths
- Extract getParentDirectory() helper that handles both POSIX and Windows
separators so the nodes-directory label renders on all platforms
- Add regression tests for manifest roundtrip, colliding-tag preservation, and
parent-directory extraction across separator styles
* Chore typegen
* ui: hide Custom Nodes tab for non-admin users in multiuser mode
Add useIsCustomNodesEnabled hook (mirrors useIsModelManagerEnabled) and
conditionally render the tab in VerticalNavBar. Backend routes already
reject non-admin callers; this prevents the UI from advertising controls
that would 403.
* ui: guard Custom Nodes tab content for non-admin persisted state and add auth regression tests
- Suppress CustomNodesTabAutoLayout render and redirect to generate via
navigationApi.switchToTab when a non-admin user lands on a persisted
customNodes tab
- Add TestCustomNodesAuthorization with 10 route-level tests verifying
unauthenticated (401), non-admin (403), and admin (200) for list,
install, uninstall, and reload endpoints
- Add decision-matrix test for useIsCustomNodesEnabled covering
single-user, multiuser admin, multiuser non-admin, and unloaded user
* test: add shared helper for custom-nodes gate + admin happy-path tests
Extract getIsCustomNodesEnabled so test imports the real logic
instead of a local reimplementation. Add install/uninstall
admin-success tests with mocked filesystem/subprocess.
* fix(custom-nodes): return optimistic default while setup status loads
Prevents redirect away from persisted customNodes tab on startup
in single-user mode when RTK Query hasn't resolved yet.
* ui: split custom nodes permission into isKnown/isAllowed to close loading window
useIsCustomNodesEnabled now returns { isKnown, isAllowed } so the navbar
hides the tab conservatively (isAllowed=false while loading) while the
redirect only fires once the decision is definitive (isKnown && !isAllowed),
preventing both the non-admin flash and the single-user kickout.
* refactor(custom-nodes): extract permission derivation into shared helper
Tests now import deriveCustomNodesPermission directly instead
of mirroring the hook logic in a local simulateHook, so hook
and tests can never drift.
* Chore Knit fix
* fix(custom-nodes): purge full module subtree on uninstall
Only removing sys.modules[pack_name] left submodules cached, so
reinstall reused them and the @invocation decorators never re-
registered the nodes — the pack loaded with 0 nodes until a
full process restart. Now _purge_pack_modules strips the root
and every pack_name.* key.
* fix(custom-nodes): purge full module subtree on uninstall
Only removing sys.modules[pack_name] left submodules cached, so
reinstall reused them and the @invocation decorators never re-
registered the nodes — the pack loaded with 0 nodes until a
full process restart. Now _purge_pack_modules strips the root
and every pack_name.* key.
---------
Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com>
Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com>
|
||
|
|
eb15a4e8c5 |
feat(recall): support direct model reference images in recall API (#9045)
* feat(recall): support model-free reference images in recall API The recall parameters API previously exposed only `loras`, `control_layers`, and `ip_adapters`. This meant reference images used by architectures that feed images directly into the main model — FLUX.2 Klein, FLUX Kontext, and Qwen Image Edit — could not be sent through the recall endpoint at all: they have no adapter model to resolve, so they could not ride in the `ip_adapters` list. This change adds a new `reference_images` field on RecallParameter that carries only an `image_name`. The backend validates the file exists in outputs/images and forwards the resolved metadata (width/height) in the broadcast event. The frontend's recall handler picks the right config type (`flux2_reference_image` / `flux_kontext_reference_image` / `ip_adapter` fallback) via getDefaultRefImageConfig() based on the currently-selected main model, matching the behavior of a manual drag-and-drop, and dispatches `refImagesRecalled` with replace:false so these append rather than clobber any adapters already applied in the same event. Also consolidates the two existing docs under docs/contributing/RECALL_PARAMETERS/ (RECALL_PARAMETERS_API.md and RECALL_API_LORAS_CONTROLNETS_IMAGES.md) into a single RECALL_PARAMETERS_API.md that documents the full request schema including the new field. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test(recall): cover loras, control layers, and ip_adapters paths The original recall_parameters router (PR #8758) shipped without any unit tests for its three collection fields. This commit backfills that coverage alongside the reference_images tests added in the previous commit. The resolver helpers (resolve_model_name_to_key, load_image_file, process_controlnet_image) are monkey-patched via module-level attribute replacement so each test can pin down a specific resolution outcome without spinning up the model manager or an image-files service. Two small factory helpers (make_name_to_key_stub / make_load_image_file_stub) make that ergonomic. New coverage: * LoRAs — multi-entry resolution + weight/is_enabled pass-through, silent drop on unresolvable names, is_enabled default of True. * Control layers — ControlNet resolution precedence, fall-through to T2I Adapter and Control LoRA in order, missing image gracefully warned-and-continued, processed_image attached when the processor returns data, unresolvable entries dropped. * IP Adapters — IPAdapter-before-FluxRedux lookup order, method / image_influence pass-through, missing image gracefully warned-and- continued, unresolvable entries dropped. * Combined happy path — full request with prompts + model + all four collection fields, verifying every resolved value reaches the broadcast payload. * Main-model drop — an unresolvable main model is scrubbed from the broadcast so the frontend never receives a stale model name. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(frontend): typegen * chore: fix lint errors and typegen * fix(test): patch ApiDependencies in auth_dependencies to fix recall tests The patched_dependencies fixture only monkeypatched ApiDependencies in the recall_parameters module, but the endpoint also resolves CurrentUserOrDefault via auth_dependencies, which accesses ApiDependencies.invoker independently. Patch both import sites. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(frontend): typegen * feat(recall): add strict mode to clear unset parameters on recall Add a `strict` query parameter (default false) to POST recall endpoint. When true, parameters not in the request body are reset: list fields (loras, control_layers, ip_adapters, reference_images) become [] and scalar fields become null, so the frontend clears stale state. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(frontend): eliminate ref image doubling from race between Promise.all chains IP adapters and model-free reference images were dispatched via two independent Promise.all chains — one with replace:true, the other with replace:false. When a previous recall's promises were still in-flight they could resolve after the clear and re-append stale entries, doubling the list. Combine both into a single Promise.all with one replace:true dispatch so the race is impossible. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Alexander Eichhorn <alex@eichhorn.dev> |
||
|
|
0a09452fa3 |
feat(ui): add canvas snapshot save/restore functionality (#8978)
* feat(ui): add canvas snapshot save/restore functionality Add ability to save and restore canvas state snapshots, allowing users to preserve their canvas layout at any point and restore it later. This is useful when the canvas freezes or resets unexpectedly. Backend: - Add get_keys_by_prefix and delete_by_key to client_state persistence - Add corresponding API endpoints Frontend: - Add canvasSnapshotRestored reducer to canvasSlice - Add useCanvasSnapshots hook for snapshot CRUD operations - Add CanvasToolbarSnapshotMenuButton with save/restore UI - Add i18n keys for snapshot feature - Regenerate API schema types Tests: - Add tests for new client_state endpoints (prefix search, key deletion) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(ui): address review feedback for canvas snapshot feature - Preserve current modelBase on snapshot restore to prevent bbox desync with the active model (mirrors resetState pattern) - Exclude snapshot restore from undo history so it cannot be accidentally undone - Migrate manual fetch calls to RTKQ endpoints (clientState.ts) so snapshots go through the shared API transport layer with proper auth, session-expiry handling and sliding-window token refresh - Validate referenced images on restore and warn when some are missing - Detect incompatible (schema-changed) snapshots and show a specific error message instead of a generic failure toast - Disable snapshot restore while the canvas is staging to prevent entity ID conflicts with in-progress generations - Sort snapshot list by updated_at instead of rowid so re-saved snapshots appear at the top - Add pre-flight backend reachability check before image validation to avoid false "missing images" warnings when offline Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor(ui): consolidate collectImageNames to shared canvasProjectFile utility Remove the local collectImageNames from useCanvasSnapshots and reuse the shared, more comprehensive version from canvasProjectFile.ts that was introduced by the canvas project save/load feature (#8917). Snapshots don't include global ref images, so an empty array is passed for that parameter. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(canvas-snapshots): escape LIKE wildcards, warn on overwrite, fix default name chars - Escape %, _, \ in client_state prefix query to prevent accidental wildcard matching - Confirm before overwriting an existing snapshot instead of silently replacing it - Use - instead of / and : in the default snapshot name to avoid key separator clashes * fix(canvas): align canvasProjectRecalled with snapshot restore pattern Preserve modelBase, call syncScaledSize, and exclude from undo history to avoid bbox/model desync on project load — same pattern already used by canvasSnapshotRestored. --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Alexander Eichhorn <alex@eichhorn.dev> |
||
|
|
29741ddb06 |
Fix lazy If branch pruning and skipped-parent handling in graph runtime (#9079)
* Fix lazy If branch pruning and skipped-parent handling in graph runtime * Tighten lazy If runtime edge-case handling * Polish lazy If runtime diagnostics and idempotency --------- Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> |
||
|
|
3bde35be10 | Align DyPE with paper (#8980) | ||
|
|
f9f2a32e96 |
Feat(UI): Add LLM-powered prompt expansion and image-to-prompt features (#8899)
* Add LLM-powered prompt expansion and image-to-prompt features Adds two new buttons to the positive prompt area: - "Expand Prompt" uses a local TextLLM model (AutoModelForCausalLM) to expand brief prompts into detailed image generation prompts - "Image to Prompt" uses an existing LLaVA OneVision model to generate descriptive prompts from uploaded images Backend: new TextLLM model type with config, loader, pipeline wrapper, workflow node, and two new API endpoints (expand-prompt, image-to-prompt). Also fixes HuggingFace metadata fetch assertion error when file size is None. Frontend: ExpandPromptButton and ImageToPromptButton components with model picker popovers, RTK Query mutations, and model type hooks. Buttons only appear when compatible models are installed. * chore fix windows paths * Fix device mismatch for LLM inference and add CPU-only toggle for Text LLM models Derive the execution device from the loaded model parameters instead of the global TorchDevice chooser so that cpu_only models no longer receive GPU-bound inputs. Also expose the existing cpu_only setting in the frontend Model Manager for Text LLM models. * Harden LLM endpoints and add tests - Bound max_tokens to 1-2048 on ExpandPromptRequest to prevent OOM - Replace asserts with explicit type checks and proper HTTP status codes (404 for unknown models, 422 for wrong model type, 500 for unexpected) - Use float32 dtype for cpu_only TextLLM models instead of global fp16 - Add 16 tests for TextLLMPipeline and API request validation * Add Ctrl+Z undo for LLM prompt changes Saves the previous prompt before LLM overwrites it (Expand Prompt and Image to Prompt). Pressing Ctrl+Z in the prompt textarea restores the original prompt. Undo state auto-expires after 30 seconds and is cleared when the user types manually. * Add documentation and What's New entry for LLM prompt tools - Add docs/features/prompt-tools.md covering Expand Prompt, Image to Prompt, compatible models, Ctrl+Z undo, and the workflow node - Register new doc page in mkdocs.yml under Features - Add What's New item in en.json for the LLM Prompt Tools feature * fix: resolve merge conflict in mkdocs.yml nav * feat(ui): allow dragging gallery images onto prompt box for Image to Prompt Add drop target on the positive prompt textarea so users can drag images from the gallery directly into the prompt area. When dropped, the Image to Prompt popover opens automatically with the image pre-loaded, ready for description generation. * chore typegen * Fix typo in Z-Image Turbo diversity description * Fix three bugs in LLM/VLM utility endpoints Move torch.no_grad() from async endpoint into worker functions where inference actually runs, since the context manager does not carry across the thread boundary used by asyncio.to_thread(). Add threading.Lock around load_model() calls to serialize access to the thread-unsafe model loader, preventing race conditions from concurrent HTTP requests. Catch ImageFileNotFoundException in image_to_prompt and return 404 instead of letting it fall through to the blanket 500 handler. * Fix tokenizer validation, drag-drop dead end, and i18n for LLM prompt tools Validate tokenizer files at model probe time instead of deferring to runtime. Guard image drag-drop on the prompt textarea behind LLaVA model availability. Add missing modelManager.textLLM i18n key and replace all hardcoded strings in ImageToPromptButton and ExpandPromptButton with translation calls. * Add unit tests for promptUndo module * Fix typo in Z-Image Turbo diversity description * Chore fix typegen --------- Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com> |
||
|
|
dd5758b53d |
fix: SDXL DoRA LoRA fails with enable_partial_loading=true (#9063)
* fix: SDXL DoRA LoRA fails with enable_partial_loading=true cast_to_device returns plain torch.Tensor instead of torch.nn.Parameter, causing _aggregate_patch_parameters to replace valid weights with meta device dummies, falsely triggering DoRA's quantization guard. Fixes invoke-ai/InvokeAI#8624 * test: regression coverage for DoRA + partial-loading + CPU→device autocast Adds targeted coverage for the bug fixed in a0a87212 (#8624, PR #9063): - test_aggregate_patch_parameters_preserves_plain_tensor_with_dora: CPU-only unit test that feeds a plain torch.Tensor (as handed in by _cast_weight_bias_for_input) into _aggregate_patch_parameters with a DoRA patch. Pre-fix, the tensor was replaced by a meta-device dummy, tripping DoRA's quantization guard. - "single_dora" variant in the patch_under_test fixture: exercises the full CUDA/MPS autocast hot path via test_linear_sidecar_patches_with_autocast_from_cpu_to_device. --------- Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com> |
||
|
|
0531108f32 |
Fix graph execution state resume after JSON round-trip (#9042)
* Fix graph execution state resume after JSON round-trip * tightened tests, refactored * chore: ruff --------- Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> |
||
|
|
5a0818ab36 |
Prevent stale queue snapshots from regressing workflow completion state (#9043)
* fix queue item ordering across events and snapshots * clean up queue item status sequencing * trim white-box queue sequencing tests * format sqlite migrator tests * clarify queue status sequencing intent --------- Co-authored-by: Alexander Eichhorn <alex@eichhorn.dev> |
||
|
|
b2d79dc86c |
feat:(model-manager) add sorting capabilities for models (#9024)
* feat(model-manager): add comprehensive sorting capabilities for models dded the ability to sort models in the Model Manager by various attributes including Name, Base, Type, Format, Size, Date Added, and Date Modified. Supports both ascending and descending order. - Backend: Added `order_by` and `direction` query parameters to the ``/api/v1/models`/` listing endpoint. Implemented case-insensitive sorting in the SQLite model records service. - Frontend: Introduced `<ModelSortControl />` UI, updated Redux slices to manage sort state, removed client-side entity adapter sorting to respect server-side ordering, and added i18n localization keys. - Tests: Added test coverage for SQL-based sorting on size and name. * feat(model-manager): add comprehensive sorting capabilities for models dded the ability to sort models in the Model Manager by various attributes including Name, Base, Type, Format, Size, Date Added, and Date Modified. Supports both ascending and descending order. - Backend: Added `order_by` and `direction` query parameters to the ``/api/v1/models`/` listing endpoint. Implemented case-insensitive sorting in the SQLite model records service. - Frontend: Introduced `<ModelSortControl />` UI, updated Redux slices to manage sort state, removed client-side entity adapter sorting to respect server-side ordering, and added i18n localization keys. - Tests: Added test coverage for SQL-based sorting on size and name. * ruff fix * typegen fix * typegen fix - this time without my custom nodes. * another typegen fix * refactor(ui): consolidate model filter and sort controls into a unified menu - Replaced separate `ModelSortControl` and `ModelTypeFilter` components with a single, unified "Filtering" dropdown menu. - Organised filtering options into categorised submenus in the following order: Direction, Sort By, and Model Type. - Enhanced submenu labels to display the currently active selection inline for quick reference. - Improved visual alignment within menus by using hidden checkmarks on unselected items, ensuring consistent indentation across all options. - Resolved styling and linting issues (unused variables, JSX bind warnings) within the new component. * Lint fix * Addresses PR feedback to use translation strings directly within `ORDER_BY_OPTIONS`. Previously, sort keys and their translated labels were maintained in separate constructs (`ORDER_BY_OPTIONS` array and `ORDER_BY_LABELS` map). This refactor converts `ORDER_BY_OPTIONS` into an array of objects containing both the `key` and its corresponding `i18nKey`, creating a single source of truth. This change: - Simplifies the `SortBySubMenu` component by removing the redundant `ORDER_BY_LABELS` lookup map. - Improves maintainability by ensuring developers only need to update one place when adding or modifying sort options. - Reduces the risk of mismatched keys and labels. --------- Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com> Co-authored-by: Alexander Eichhorn <alex@eichhorn.dev> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> |
||
|
|
0d7205ff79 |
Handle mixed-dtype mismatches in autocast linear and conv wrappers (#9006)
* Handle CustomConv2d bias dtype mismatches * Fix mixed-dtype autocast regressions * Format custom_conv2d with ruff |
||
|
|
9deb545cc1 |
External models (Gemini Nano Banana & OpenAI GPT Image) (#8633) (#8884)
* feat: initial external model support * feat: support reference images for external models * fix: sorting lint error * chore: hide Reidentify button for external models * review: enable auto-install/remove fro external models * feat: show external mode name during install * review: model descriptions * review: implemented review comments * review: added optional seed control for external models * chore: fix linter warning * review: save api keys to a seperate file * docs: updated external model docs * chore: fix linter errors * fix: sync configured external starter models on startup * feat(ui): add provider-specific external generation nodes * feat: expose external panel schemas in model configs * feat(ui): drive external panels from panel schema * docs: sync app config docstring order * feat: add gemini 3.1 flash image preview starter model * feat: update gemini image model limits * fix: resolve TypeScript errors and move external provider config to api_keys.yaml Add 'external', 'external_image_generator', and 'external_api' to Zod enum schemas (zBaseModelType, zModelType, zModelFormat) to match the generated OpenAPI types. Remove redundant union workarounds from component prop types and Record definitions. Fix type errors in ModelEdit (react-hook-form Control invariance), parsing.tsx (model identifier narrowing), buildExternalGraph (edge typing), and ModelSettings import/export buttons. Move external_gemini_base_url and external_openai_base_url into api_keys.yaml alongside the API keys so all external provider config lives in one dedicated file, separate from invokeai.yaml. * feat: add resolution presets and imageConfig support for Gemini 3 models Add combined resolution preset selector for external models that maps aspect ratio + image size to fixed dimensions. Gemini 3 Pro and 3.1 Flash now send imageConfig (aspectRatio + imageSize) via generationConfig instead of text-based aspect ratio hints used by Gemini 2.5 Flash. Backend: ExternalResolutionPreset model, resolution_presets capability field, image_size on ExternalGenerationRequest, and Gemini provider imageConfig logic. Frontend: ExternalSettingsAccordion with combo resolution select, dimension slider disabling for fixed-size models, and panel schema constraint wiring for Steps/Guidance/Seed controls. * Remove unused external model fields and add provider-specific parameters - Remove negative_prompt, steps, guidance, reference_image_weights, reference_image_modes from external model nodes (unused by any provider) - Remove supports_negative_prompt, supports_steps, supports_guidance from ExternalModelCapabilities - Add provider_options dict to ExternalGenerationRequest for provider-specific parameters - Add OpenAI-specific fields: quality, background, input_fidelity - Add Gemini-specific fields: temperature, thinking_level - Add new OpenAI starter models: GPT Image 1.5, GPT Image 1 Mini, DALL-E 3, DALL-E 2 - Fix OpenAI provider to use output_format (GPT Image) vs response_format (DALL-E) and send model ID in requests - Add fixed aspect ratio sizes for OpenAI models (bucketing) - Add ExternalProviderRateLimitError with retry logic for 429 responses - Add provider-specific UI components in ExternalSettingsAccordion - Simplify ParamSteps/ParamGuidance by removing dead external overrides - Update all backend and frontend tests * Chore Ruff check & format * Chore typegen * feat: full canvas workflow integration for external models - Add missing aspect ratios (4:5, 5:4, 8:1, 4:1, 1:4, 1:8) to type system for external model support - Sync canvas bbox when external model resolution preset is selected - Use params preset dimensions in buildExternalGraph to prevent "unsupported aspect ratio" errors - Lock all bbox controls (resize handles, aspect ratio select, width/height sliders, swap/optimal buttons) for external models with fixed dimension presets - Disable denoise strength slider for external models (not applicable) - Sync bbox aspect ratio changes back to paramsSlice for external models - Initialize bbox dimensions when switching to an external model * Chore typegen Linux seperator * feat: full canvas workflow integration for external models - Update buildExternalGraph test to include dimensions in mock params * Merge remote-tracking branch 'upstream/main' into external-models * Chore pnpm fix * add missing parameter * docs: add External Models guide with Gemini and OpenAI provider pages * fix(external-models): address PR review feedback - Gemini recall: write temperature, thinking_level, image_size to image metadata; wire external graph as metadata receiver; add recall handlers. - Canvas: gate regional guidance, inpaint mask, and control layer for external models. - Canvas: throw a clear error on outpainting for external models (was falling back to inpaint and hitting an API-side mask/image size mismatch). - Workflow editor: add ui_model_provider_id filter so OpenAI and Gemini nodes only list their own provider's models. - Workflow editor: silently drop seed when the selected model does not support it instead of raising a capability error. - Remove the legacy external_image_generation invocation and the graph-builder fallback; providers must register a dedicated node. - Regenerate schema.ts. - remove Gemini debug dumps to outputs/external_debug * fix(external-models): resolve TSC errors in metadata parsing and external graph - Export imageSizeChanged from paramsSlice (required by the new ImageSize recall handler). - Emit the external graph's metadata model entry via zModelIdentifierField since ExternalApiModelConfig is not part of the AnyModelConfig union. * chore: prettier format ModelIdentifierFieldInputComponent * fix: remove unsupported thinkingConfig from Gemini image models and restrict GPT Image models to txt2img * chore typegen * chore(docs): regenerate settings.json for external provider fields * fix(external): fix mask handling and mode support for external providers - Remove img2img and inpaint modes from Gemini models (Gemini has no bitmap mask or dedicated edit API; image editing works via reference images in the UI) - Fix DALL-E 2 inpainting: convert grayscale mask to RGBA with alpha channel transparency (OpenAI expects transparent=edit area) and convert init image to RGBA when mask is present * fix(external): update mode support and UI for external providers - Remove DALL-E 2 from starter models (deprecated, shutdown May 12 2026) - Enable img2img for GPT Image 1/1.5/1-mini (supports edits endpoint) - Set Gemini models to txt2img only (no mask/edit API; editing via ref images) - Hide mode/init_image/mask_image fields on Gemini node (not usable) - Hide mask_image field on OpenAI node (no model supports inpaint) * Chore typegen * fix(external): improve OpenAI node UX and disable cache by default - Hide OpenAI node's mode and init_image fields: OpenAI's API has no img2img/inpaint distinction (the edits endpoint is invoked automatically when reference images are provided). init_image is functionally identical to a reference image and was misleading users. - Default use_cache to False for external image generation nodes: external API calls are non-deterministic and incur usage costs. Cache hits returned stale image references that did not produce new gallery entries on repeat invokes. * fix(external): duplicate cached images on cache hit instead of skipping External image generation nodes use the standard invocation cache, but returning the cached output (with stale image_name references) on cache hits resulted in no new gallery entries — the Invoke button would spin indefinitely on repeat invokes with identical parameters. Override invoke_internal so that on cache hit, the cached images are loaded and re-saved as new gallery entries. The expensive API call is still skipped (cost saving), but the user sees a new image as expected. * Chore typegen + ruff * CHore ruff format * fix(external): restore OpenAI advanced settings on Remix recall Remix recall iterates through ImageMetadataHandlers but only Gemini's temperature handler was wired up — OpenAI's quality, background, and input_fidelity were stored in image metadata but never parsed back into the params slice. Add the three missing handlers so Remix restores these settings as expected. --------- Co-authored-by: Alexander Eichhorn <alex@eichhorn.dev> Co-authored-by: Alexander Eichhorn <alex@code-with.us> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> |
||
|
|
9643b1385f |
Docs Overhaul (#8896)
* feat(docs): new docs scaffold * feat(docs): update alternate launchers section * feat(docs): add contributor section * fix(docs): update description of lynxhub launcher mention * feat(docs): add more docs * feat(docs): setup index page * feat(docs): add more docs, rewrote a few pages * feat(docs): add todo * feat(docs): set up internationalization * fix(docs): admonition typo * feat(docs): add invoke styles * feat(docs): add more invoke styling, revamp splash page, remove theme switcher * fix(docs): expressive code sh styles without title * chore(docs): cleanup readme * chore(docs): add new github pages workflow * fix(docs): remove base path * chore(docs): add initial translations CI, powered by Crowdin * feat(docs): upgrade astro * feat(docs): enhance new contributor guide * feat(docs): various enhancements - improve homepage; - enhance some docs pages; - override some layout components; - enhance interactivity and qol styling; - create new download page + component; - add llms.txt; - remove unused logo component; * feat(docs): isolate new docs * style(docs): use md reference links over utility links * chore(docs): specify package manager * feat(docs): releases page * feat(docs): add page context menus * feat(docs): sort workflows sidebar items * fix(docs): relative links on homepage * feat(docs): add text tool and recall params api guides * feat(docs): fix faq links, create models concept page * chore(docs): set CI to new dir, update deployment url * feat(docs): generate settings and api json for pages - update deploy script - add api and settings component to render generated json - increase page content width * style(docs): remove relative path for component import * fix(docs): resolve tests by regenerating json * fix(docs): fixing the test for real this time - sorts openapi output map required field - missing `__name__` attributes - resolved components name keyerror * feat(docs): finish 'adding nodes' page * feat(docs): upgrade astro + starlight, add link tester * chore(docs): upgrade astro * feat(docs): add prompting guides * fix(docs): generated openapi * fix(docs): ci node version * fix(docs): invalid links * fix(docs): md aside formatting * feat(docs): reorder 'configuration' category * feat(docs): change contributor checklist to steps list * chore(docs): upgrade deps * feat(docs): splash page image styling * feat(docs): add gallery marquee to homepage * feat(docs): add splash page marquee gallery * feat(docs): remove openapi generation * fix(docs): regenerate settings json * fix(docs): json generation test --------- Co-authored-by: joshistoast <me@joshcorbett.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> |
||
|
|
e252a5bb47 | fix(multiuser): make preexisting workflows visible after migration (#9049) | ||
|
|
33ec16deb4 |
Feature: Shared/private workflows and image boards in multiuser mode (#9018)
* feat: Per-user workflow libraries in multiuser mode (#114) * Add per-user workflow isolation: migration 28, service updates, router ownership checks, is_public endpoint, schema regeneration, frontend UI Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * feat: add shared workflow checkbox to Details panel, auto-tag, gate edit/delete, fix tests Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Restrict model sync to admin users only (#118) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * feat: distinct splash screens for admin/non-admin users in multiuser mode (#116) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Disable Save when editing another user's shared workflow in multiuser mode (#120) * Disable Save when editing another user's shared workflow in multiuser mode Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore(app): ruff * Add board visibility (private/shared/public) feature with tests and UI Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Enforce read-only access for non-owners of shared/public boards in UI Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix remaining board access enforcement: invoke icon, drag-out, change-board filter, archive Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * fix: allow drag from shared boards to non-board targets (viewer, ref image, etc.) Previously, images in shared boards owned by another user could not be dragged at all — the draggable setup was completely skipped in GalleryImage.tsx when canWriteImages was false. This blocked ALL drop targets including the viewer, reference image pane, and canvas. Now images are always draggable. The board-move restriction is enforced in the dnd target isValid functions instead: - addImageToBoardDndTarget: rejects moves from shared boards the user doesn't own (unless admin or board is public) - removeImageFromBoardDndTarget: same check Other drop targets (viewer, reference images, canvas, comparison, etc.) remain fully functional for shared board images. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(security): add auth requirement to all sensitive routes in multimodal mode * chore(backend): ruff * fix (backend): improve user isolation for session queue and recall parameters - Sanitize session queue information of all cross-user fields except for the timestamps and status. - Recall parameters are now user-scoped. - Queue status endpoints now report user-scoped activity rather than global activity - Tests added: TestSessionQueueSanitization (4 tests): 1. test_owner_sees_all_fields - Owner sees complete queue item data 2. test_admin_sees_all_fields - Admin sees complete queue item data 3. test_non_owner_sees_only_status_timestamps_errors - Non-owner sees only item_id, queue_id, status, and timestamps; everything else is redacted 4. test_sanitization_does_not_mutate_original - Sanitization doesn't modify the original object TestRecallParametersIsolation (2 tests): 5. test_user1_write_does_not_leak_to_user2 - User1's recall params are not visible in user2's client state 6. test_two_users_independent_state - Both users can write recall params independently without overwriting each other fix(backend): queue status endpoints report user-scoped stats rather than global stats * fix(workflow): do not filter default workflows in multiuser mode Problem: When categories=['user', 'default'] (or no category filter) and user_id was set for multiuser scoping, the SQL query became WHERE category IN ('user', 'default') AND user_id = ?, which excluded default workflows (owned by "system"). Fix: Changed user_id = ? to (user_id = ? OR category = 'default') in all 6 occurrences across workflow_records_sqlite.py — in get_many, counts_by_category, counts_by_tag, and get_all_tags. Default workflows are now always visible regardless of user scoping. Tests added (2): - test_default_workflows_visible_when_listing_user_and_default — categories=['user','default'] includes both - test_default_workflows_visible_when_no_category_filter — no filter still shows defaults * fix(multiuser): scope queue/recall/intermediates endpoints to current user Several read-only and event-emitting endpoints were leaking aggregate cross-user activity in multiuser mode: - recall_parameters_updated event was broadcast to every queue subscriber. Added user_id to the event and routed it to the owner + admin rooms only. - get_queue_status, get_batch_status, counts_by_destination and get_intermediates_count now scope counts to the calling user (admins still see global state). Removed the now-redundant user_pending/user_in_progress fields and simplified QueueCountBadge. - get_queue_status hides current item_id/session_id/batch_id when the current item belongs to another user. Also fixes test_session_queue_sanitization assertions that lagged behind the recently expanded redaction set. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(backend): ruff * fix(multiuser): reject anonymous websockets and scope queue item events Close three cross-user leaks in the websocket layer: - _handle_connect() now rejects connections without a valid JWT in multiuser mode (previously fell through to user_id="system"), so anonymous clients can no longer subscribe to queue rooms and observe other users' activity. In single-user mode it still accepts as system admin. - _handle_sub_queue() no longer silently falls back to the system user for an unknown sid in multiuser mode; it refuses the subscription. - QueueItemStatusChangedEvent and BatchEnqueuedEvent are now routed to user:{user_id} + admin rooms instead of the full queue room. Both events carry unsanitized user_id, batch_id, origin, destination, session_id, and error metadata and must not be broadcast. - BatchEnqueuedEvent gains a user_id field; emit_batch_enqueued and enqueue_batch thread it through. New TestWebSocketAuth suite covers connect accept/reject for both modes, sub_queue refusal, and private routing of the queue item and batch events (plus a QueueClearedEvent sanity check). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(multiuser): verify user record on websocket connect A deleted or deactivated user with an unexpired JWT could still open a websocket and subscribe to queue rooms. Now _handle_connect() checks the backing user record (exists + is_active) in multiuser mode, mirroring the REST auth path in auth_dependencies.py. Fails closed if the user service is unavailable. Tests: added deleted-user and inactive-user rejection tests; updated valid-token test to create the user in the database first. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(multiuser): close bulk download cross-user exfiltration path Backend: - POST /download now validates image read access (per-image) and board read access (per-board) before queuing the download. - GET /download/{name} is intentionally unauthenticated because the browser triggers it via <a download> which cannot carry Authorization headers. Access control relies on POST-time checks, UUID filename unguessability, private socket event routing, and single-fetch deletion. - Added _assert_board_read_access() helper to images router. - Threaded user_id through bulk download handler, base class, event emission, and BulkDownloadEventBase so events carry the initiator. - Bulk download service now tracks download ownership via _download_owners dict (cleaned up on delete). - Socket bulk_download room subscription restricted to authenticated sockets in multiuser mode. - Added error-catching in FastAPIEventService._dispatch_from_queue to prevent silent event dispatch failures. Frontend: - Fixed pre-existing race condition where the "Preparing Download" toast from the POST response overwrote the "Ready to Download" toast from the socket event (background task completes in ~17ms, so the socket event can arrive before Redux processes the HTTP response). Toast IDs are now distinct: "preparing:{name}" vs "{name}". - bulk_download_complete/error handlers now dismiss the preparing toast. Tests (8 new): - Bulk download by image names rejected for non-owner (403) - Bulk download by image names allowed for owner (202) - Bulk download from private board rejected (403) - Bulk download from shared board allowed (202) - Admin can bulk download any images (202) - Bulk download events carry user_id - Bulk download event emitted to download room - GET /download unauthenticated returns 404 for unknown files Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(multiuser): enforce board visibility on image listing endpoints GET /api/v1/images?board_id=... and GET /api/v1/images/names?board_id=... passed board_id directly to the SQL layer without checking board visibility. The SQL only applied user_id filtering for board_id="none" (uncategorized images), so any authenticated user who knew a private board ID could enumerate its images. Both endpoints now call _assert_board_read_access() before querying, returning 403 unless the caller is the board owner, an admin, or the board is Shared/Public. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(backend): ruff * fix(multiuser): require image ownership when adding images to boards add_image_to_board and add_images_to_board only checked write access to the destination board, never verifying that the caller owned the source image. An attacker could add a victim's image to their own board, then exploit the board-ownership fallback in _assert_image_owner to gain delete/patch/star/unstar rights on the image. Both endpoints now call _assert_image_direct_owner which requires direct image ownership (image_records.user_id) or admin — board ownership is intentionally not sufficient, preventing the escalation chain. Also fixed a pre-existing bug where HTTPException from the inner loop in add_images_to_board was caught by the outer except-Exception and returned as 500 instead of propagating the correct status code. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(backend): ruff * fix(multiuser): validate image access in recall parameter resolution The recall endpoint loaded image files and ran ControlNet preprocessors on any image_name supplied in control_layers or ip_adapters without checking that the caller could read the image. An attacker who knew another user's image UUID could extract dimensions and, for supported preprocessors, mint a derived processed image they could then fetch. Added _assert_recall_image_access() which validates read access for every image referenced in the request before any resolution or processing occurs. Access is granted to the image owner, admins, or when the image sits on a Shared/Public board. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(multiuser): require admin auth on model install job endpoints list_model_installs, get_model_install_job, pause, resume, restart_failed, and restart_file were unauthenticated — any caller who could reach the API could view sensitive install job fields (source, local_path, error_traceback) and interfere with installation state. All six endpoints now require AdminUserOrDefault, consistent with the neighboring cancel and prune routes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(multiuser): close bulk download exfiltration and additional review findings Bulk download capability token exfiltration: - Socket events now route to user:{user_id} + admin rooms instead of the shared 'default' room (the earlier toast race that blocked this approach was fixed in a prior commit). - GET /download/{name} re-requires CurrentUserOrDefault and enforces ownership via get_owner(). - Frontend download handler replaced <a download> (which cannot carry auth headers) with fetch() + Authorization header + programmatic blob download. Additional fixes from reviewer tests: - Public boards now grant write access in _assert_board_write_access and mutation rights in _assert_image_owner (BoardVisibility.Public). - Uncategorized image listing (GET /boards/none/image_names) now filters to the caller's images only, preventing cross-user enumeration. - board_images router uses board_image_records.get_board_for_image() instead of images.get_dto() to avoid dependency on image_files service. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(multiuser): add user_id scoping to workflow SQL mutations Defense-in-depth: the route layer already checks ownership before calling update/delete/update_is_public/update_opened_at, but the SQL statements did not include AND user_id = ?, so a bypass of the route check would allow cross-user mutations. All four methods now accept an optional user_id parameter. When provided, the SQL WHERE clause is scoped to that user. The route layer passes current_user.user_id for non-admin callers and None for admins. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(multiuser): allow non-owner uploads to public boards upload_image() blocked non-owner uploads even to public boards. The board write check now allows uploads when board_visibility is Public, consistent with the public-board semantics in _assert_board_write_access and _assert_image_owner. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com> |
||
|
|
b42274a57e | Feat[model support]: Qwen Image — full pipeline with edit, generate LoRA, GGUF, quantization, and UI (#9000) | ||
|
|
d4104be0b8 |
graph.py refactoring and If node optimization (#9030)
* test: add if-node execution coverage * feat: short-circuit if-node branch execution * test: cover iterated if-node pruning * style: apply ruff fixes for if-node work * refactor: track prepared exec node metadata * fix: defer iterated if branches until resolution * refactor: extract prepared exec registry * refactor: extract if branch scheduler * refactor: extract execution materializer * refactor: extract execution scheduler * refactor: extract execution runtime * refactor: clarify if branch resolution * refactor: clarify execution materialization * docs: describe graph execution helpers * refactor: clarify execution runtime * refactor: clarify execution scheduling * refactor: clarify iteration node selection * docs: describe execution materializer flow * refactor: clarify collector validation * refactor: clarify iterator validation * refactor: clarify graph validation flow * docs: update shared graph design overview * chore: typegen * fix: harden if-node scheduler edge cases |
||
|
|
ee600973ed | Broaden text encoder partial-load recovery (#9034) | ||
|
|
f0d09c34a8 |
feat: add Anima model support (#8961)
* feat: add Anima model support * schema * image to image * regional guidance * loras * last fixes * tests * fix attributions * fix attributions * refactor to use diffusers reference * fix an additional lora type * some adjustments to follow flux 2 paper implementation * use t5 from model manager instead of downloading * make lora identification more reliable * fix: resolve lint errors in anima module Remove unused variable, fix import ordering, inline dict() call, and address minor lint issues across anima-related files. * Chore Ruff format again * fix regional guidance error * fix(anima): validate unexpected keys after strict=False checkpoint loading Capture the load_state_dict result and raise RuntimeError on unexpected keys (indicating a corrupted or incompatible checkpoint), while logging a warning for missing keys (expected for inv_freq buffers regenerated at runtime). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(anima): make model loader submodel fields required instead of Optional Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(anima): add Classification.Prototype to LoRA loaders, fix exception types Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(anima): fix replace-all in key conversion, warn on DoRA+LoKR, unify grouping functions - Use key.replace(old, new, 1) in _convert_kohya_unet_key and _convert_kohya_te_key to avoid replacing multiple occurrences - Upgrade DoRA+LoKR dora_scale strip from logger.debug to logger.warning since it represents data loss - Replace _group_kohya_keys and _group_by_layer with a single _group_keys_by_layer function parameterized by extra_suffixes, with _KOHYA_KNOWN_SUFFIXES and _PEFT_EXTRA_SUFFIXES constants - Add test_empty_state_dict_returns_empty_model to verify empty input produces a model with no layers Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(anima): add safety cap for Qwen3 sequence length to prevent OOM Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(anima): add denoising range validation, fix closure capture, add edge case tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(anima): add T5 to metadata, fix dead code, decouple scheduler type guard Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(anima): update VAE field description for required field Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: regenerate frontend types after upstream merge Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: ruff format anima_denoise.py Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(anima): add T5 encoder metadata recall handler The T5 encoder was added to generation metadata but had no recall handler, so it wasn't restored when recalling from metadata. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore(frontend): add regression test for buildAnimaGraph Add tests for CFG gating (negative conditioning omitted when cfgScale <= 1) and basic graph structure (model loader, text encoder, denoise nodes). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * only show 0.6b for anima * dont show 0.6b for other models * schema * Anima preview 3 * fix ci --------- Co-authored-by: Your Name <you@example.com> Co-authored-by: kappacommit <samwolfe40@gmail.com> Co-authored-by: Alexander Eichhorn <alex@eichhorn.dev> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> |
||
|
|
e6f2980d7c |
Added If node and ability to link an Any output to a node input if cardinality matches (#8869)
* Added If node * Added stricter type checking on inputs * feat(nodes): make if-node type checks cardinality-aware without loosening global AnyField * chore: typegen |
||
|
|
01c67c5468 |
Fix (multiuser): Ask user to log back in when security token has expired (#9017)
* Initial plan * Warn user when credentials have expired in multiuser mode Agent-Logs-Url: https://github.com/lstein/InvokeAI/sessions/f0947cda-b15c-475d-b7f4-2d553bdf2cd6 Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Address code review: avoid multiple localStorage reads in base query Agent-Logs-Url: https://github.com/lstein/InvokeAI/sessions/f0947cda-b15c-475d-b7f4-2d553bdf2cd6 Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * bugfix(multiuser): ask user to log back in when authentication token expires * feat: sliding window session expiry with token refresh Backend: - SlidingWindowTokenMiddleware refreshes JWT on each mutating request (POST/PUT/PATCH/DELETE), returning a new token in X-Refreshed-Token response header. GET requests don't refresh (they're often background fetches that shouldn't reset the inactivity timer). - CORS expose_headers updated to allow X-Refreshed-Token. Frontend: - dynamicBaseQuery picks up X-Refreshed-Token from responses and updates localStorage so subsequent requests use the fresh expiry. - 401 handler only triggers sessionExpiredLogout when a token was actually sent (not for unauthenticated background requests). - ProtectedRoute polls localStorage every 5s and listens for storage events to detect token removal (e.g. manual deletion, other tabs). Result: session expires after TOKEN_EXPIRATION_NORMAL (1 day) of inactivity, not a fixed time after login. Any user-initiated action resets the clock. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(backend): ruff * fix: address review feedback on auth token handling Bug fixes: - ProtectedRoute: only treat 401 errors as session expiry, not transient 500/network errors that should not force logout - Token refresh: use explicit remember_me claim in JWT instead of inferring from remaining lifetime, preventing silent downgrade of 7-day tokens to 1-day when <24h remains - TokenData: add remember_me field, set during login Tests (6 new): - Mutating requests (POST/PUT/DELETE) return X-Refreshed-Token - GET requests do not return X-Refreshed-Token - Unauthenticated requests do not return X-Refreshed-Token - Remember-me token refreshes to 7-day duration even near expiry - Normal token refreshes to 1-day duration - remember_me claim preserved through refresh cycle Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(backend): ruff --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com> |
||
|
|
6963cd97ba | Fix SIGINT shutdown during active inference (#8993) | ||
|
|
f7aa5fcbbf |
Add chaining to Collect node (#8933)
* Add chained collect node * test(frontend): align parseSchema fixtures with collect v1.1 and normalize undefined fields in assertions * fix(nodes): block collect-to-collect links when inferred item types differ --------- Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> |
||
|
|
dc5007fe95 |
Fix/model cache Qwen/CogView4 cancel repair (#8959)
* Repair partially loaded Qwen models after cancel to avoid device mismatches * ruff * Repair CogView4 text encoder after canceled partial loads * Avoid MPS CI crash in repair regression test * Fix MPS device assertion in repair test |
||
|
|
cd47b3baf7 |
Feature: Make strict password checking optional (#8957)
* feat: add strict_password_checking config option to relax password requirements - Add `strict_password_checking: bool = Field(default=False)` to InvokeAIAppConfig - Add `get_password_strength()` function to password_utils.py (returns weak/moderate/strong) - Add `strict_password_checking` field to SetupStatusResponse API endpoint - Update users_base.py and users_default.py to accept `strict_password_checking` param - Update auth.py router to pass config.strict_password_checking to all user service calls - Create shared frontend utility passwordUtils.ts for password strength validation - Update AdministratorSetup, UserProfile, UserManagement components to: - Fetch strict_password_checking from setup status endpoint - Show colored strength indicators (red/yellow/blue) in non-strict mode - Allow any non-empty password in non-strict mode - Maintain strict validation behavior when strict_password_checking=True - Update SetupStatusResponse type in auth.ts endpoint - Add passwordStrength and passwordHelperRelaxed translation keys to en.json - Add tests for new get_password_strength() function Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Changes before error encountered Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore(backend): docstrings * chore(frontend): typegen --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com> |
||
|
|
62b7c7a6e8 |
Added SQL injection tests (#8873)
* Added SQL injection tests * Updated tests after multi-user merge * ruff:format --------- Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> |
||
|
|
c7bdaf93b2 |
Fix: Shut down the server with one keyboard interrupt (#94) (#8936)
* Fix: Kill the server with one keyboard interrupt (#94) * Initial plan * Handle KeyboardInterrupt in run_app to allow single Ctrl+C shutdown Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Force os._exit(0) on KeyboardInterrupt to avoid hanging on background threads Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Fix graceful shutdown to wait for download/install worker threads (#102) * Initial plan * Replace os._exit(0) with ApiDependencies.shutdown() on KeyboardInterrupt Instead of immediately force-exiting the process on CTRL+C, call ApiDependencies.shutdown() to gracefully stop the download and install manager services, allowing active work to complete or cancel cleanly before the process exits. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Make stop() idempotent in download and model install services When CTRL+C is pressed, uvicorn's graceful shutdown triggers the FastAPI lifespan which calls ApiDependencies.shutdown(), then a KeyboardInterrupt propagates from run_until_complete() hitting the except block which tries to call ApiDependencies.shutdown() a second time. Change both stop() methods to return silently (instead of raising) when the service is not running. This handles: - Double-shutdown: lifespan already stopped the services - Early interrupt: services were never fully started Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Fix shutdown hang on session processor thread lock (#108) * Initial plan * Fix shutdown hang: wake session processor thread on stop() and mark daemon Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix: shut down asyncio executor on KeyboardInterrupt to prevent post-generation hang (#112) Fix: cancel pending asyncio tasks before loop.close() to suppress destroyed-task warnings Fix: suppress stack trace when dispatching events after event loop is closed on shutdown Fix: cancel in-progress generation on stop() to prevent core dump during mid-flight Ctrl+C Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> |
||
|
|
6fe7910a90 |
fix(model-install): persist remote access_token for resume after restart (#8932)
Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> |
||
|
|
146b936844 |
feat(multiuser mode): Support multiple isolated users on same backend (#8822)
* Add comprehensive multi-user support specification and implementation plan Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Clarify Python tooling transition state Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Add executive summary for multi-user support specification Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Reorganize multiuser docs into subfolder and update with approved design decisions Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * docs: fix mkdocs syntax issues * Fix Z-Image VAE operations not reserving working memory for OOM prevention (#8) * Initial plan * Fix Z-Image VAE encode/decode to request working memory Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Add test for Z-Image working memory estimation Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix unit test: only set config attribute for AutoencoderKL, not FluxAutoEncoder Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * style: fix ruff errors * Fix test: use model_construct to bypass Pydantic validation for mock fields Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore(ruff): fix ruff errors --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> * Phase 1: Add multi-user database schema and authentication foundation (#6) * Initial plan * Add Phase 1: Database schema, authentication utilities, and user service - Added dependencies: passlib[bcrypt], python-jose[cryptography], email-validator - Created migration_25 for multi-user support database schema - users table with authentication fields - user_sessions, user_invitations, shared_boards tables - Added user_id columns to boards, images, workflows, session_queue, style_presets - Created system user for backward compatibility - Implemented authentication utilities - Password hashing and validation (password_utils.py) - JWT token generation and verification (token_service.py) - Implemented user service - Abstract base class (users_base.py) - SQLite implementation (users_default.py) - Full CRUD operations for users - Authentication and admin management - Added comprehensive tests for all components - All code passes ruff linting and mypy type checking Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Refactor user service to use transaction pattern and improve security documentation - Changed all database operations to use self._db.transaction() context manager - Follows the same pattern as other services like board_records - Improves thread safety and transaction management - Added detailed security warnings for the hardcoded JWT secret key - Documented that it must be moved to config before production - Fixed whitespace linting issues - All tests still pass with the refactored code Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix system user email to use valid domain - Changed system user email from system@invokeai.local to system@system.invokeai - .local domains are rejected by email-validator as special-use/reserved - All end-to-end tests now pass successfully Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix test failures: password length, migration chain, and table existence checks - Fixed bcrypt 72-byte password limit by truncating long passwords in hash_password and verify_password - Fixed test_migration_25 to use callback directly instead of migrator to avoid fragmented chain error - Updated system user email assertion in test from @invokeai.local to @system.invokeai - Added table existence checks for boards, images, workflows, and session_queue before altering them - This prevents "no such table" errors when migration runs in environments without all tables Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * (chore) fix ruff errors * (chore) fix ruff errors (2) * Fix test failures: use _conn instead of conn and improve password truncation - Fixed test_user_service.py to use db._conn instead of db.conn (SqliteDatabase uses private _conn) - Simplified password truncation logic in password_utils.py for better clarity - Ensured UTF-8 decoding handles truncated bytes properly with errors="ignore" Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore(uv): updated uv lockfile * Fix bcrypt password length errors by configuring passlib properly - Added bcrypt__relax_truncate_checks=True to CryptContext to prevent errors on long passwords - Removed min_length=8 constraint from pydantic models to allow service-level validation - Service-level validation provides better error messages and more control - Manual truncation code kept as safety net for passwords >72 bytes Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix bcrypt parameter name: use truncate_error instead of relax_truncate_checks - Changed bcrypt__relax_truncate_checks=True to bcrypt__truncate_error=False - The correct passlib parameter is truncate_error (not relax_truncate_checks) - Setting it to False allows passwords >72 bytes without raising an error Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * fix(passwords) downgrade bcrypt to work with current passlib * chore(uv): update locks file --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> * Implement Phase 2: Authentication Service with JWT and FastAPI Integration (#11) * Initial plan * Add Phase 2 authentication service - auth dependencies, router, and service integration Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Address code review feedback - add token expiration constants and improve documentation Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix email validation to allow special-use domains like .local for testing Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix system user to not be admin - allows /auth/setup to work on fresh database Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore: typegen --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> * Add Phase 3 integration tests and documentation for authentication middleware (#15) * Initial plan * Add Phase 3 integration tests for auth router endpoints Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Add Phase 3 completion documentation and testing guide Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore: ruff --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> * chore: fix unresolved merged conflict markers * Phase 4: Add multi-tenancy to boards and session queue services (#17) * Initial plan * Update boards service for multi-user support - Add user_id parameter to board creation and filtering - Update board_records base and SQLite implementation to filter by user - Include shared boards and public boards in user queries - Update boards router to require authentication - Update invocation context to pass user_id from queue item - Add user_id field to SessionQueueItem model Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Update session_queue service for multi-user support - Add user_id parameter to enqueue_batch method - Update ValueToInsertTuple to include user_id - Update prepare_values_to_insert to accept and use user_id - Update SQL INSERT statements to include user_id column - Update session_queue router to require authentication - Update retry_items_by_id to preserve user_id when retrying Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Add authentication imports to images, workflows, and style_presets routers - Import CurrentUser dependency in all three routers - Add CurrentUser parameter to upload_image endpoint - Prepare for further authentication requirements in these services Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Add multiuser tests and Phase 4 documentation - Create test_boards_multiuser.py with authentication tests - Verify board operations require authentication - Test board creation and listing with auth tokens - Add comprehensive Phase 4 implementation summary - Document all changes, data flows, and security considerations Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Add authentication to remaining board endpoints - Add CurrentUser to get_board endpoint - Add CurrentUser to update_board endpoint - Add CurrentUser to delete_board endpoint - Ensures all board operations require authentication - Addresses code review feedback Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Feature(image boards): Implement per-user board isolation - Complete verification report with all checks passed - Document code quality, security, and testing results - List all achievements and sign-off criteria - Mark phase as READY FOR MERGE Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore: ruff * chore: resolve conflicts in z_image_working_memory test * chore: ruff --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> * feat: Implement Phase 5 of multiuser plan - Frontend authentication (#19) * Phase 5: Implement frontend authentication infrastructure - Created auth slice with Redux state management for authentication - Created auth API endpoints (login, logout, setup, me) - Created LoginPage component for user authentication - Created AdministratorSetup component for initial admin setup - Created ProtectedRoute wrapper for route authentication checking - Updated API configuration to include Authorization headers - Installed and configured react-router-dom for routing - Updated App component with authentication routes - All TypeScript checks passing Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore(style): prettier, typegen and add convenience targets to makefile --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> * feat: Implement Phase 6 frontend UI updates - UserMenu and admin restrictions Co-authored-by: lstein <111189+lstein@users.noreply.github.com> docs: Add comprehensive testing and verification documentation for Phase 6 Co-authored-by: lstein <111189+lstein@users.noreply.github.com> docs: Add Phase 6 summary document Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * feat: Add user management script for testing multiuser features Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * feat: Implement read-only model manager access for non-admin users Co-authored-by: lstein <111189+lstein@users.noreply.github.com> feat: Add admin authorization to model management API endpoints Co-authored-by: lstein <111189+lstein@users.noreply.github.com> docs: Update specification and implementation plan for read-only model manager Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Phase 7: Comprehensive testing and security validation for multiuser authentication (#23) * Initial plan * Phase 7: Complete test suite with 88 comprehensive tests - Add password utils tests (31 tests): hashing, verification, validation - Add token service tests (20 tests): JWT creation, verification, security - Add security tests (13 tests): SQL injection, XSS, auth bypass prevention - Add data isolation tests (11 tests): multi-user data separation - Add performance tests (13 tests): benchmarks and scalability - Add comprehensive testing documentation - Add phase 7 verification report Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * bugfix(backend): Fix issues with authentication token expiration handling - Remove time.sleep from token uniqueness test (use different expiration instead) - Increase token expiration test time from 1 microsecond to 10 milliseconds - More reliable test timing to prevent flakiness Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Add Phase 7 summary documentation Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Fix test_performance.py missing logger fixture Add missing logger fixture to test_performance.py that was causing test failures. The fixture creates a Logger instance needed by the user_service fixture. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Add board isolation issue specification document Document the three board isolation issues that need to be addressed: 1. Board list not updating when switching users 2. "Uncategorized" board shared among users 3. Admin cannot access all users' boards Includes technical details, implementation plan, and acceptance criteria. This document will be used to create a separate GitHub issue and PR. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Fix test failures in Phase 7 tests - Fix board service API calls to use enum values (BoardRecordOrderBy, SQLiteDirection) instead of strings - Fix board deletion test to use get_dto() instead of non-existent get() method - Add exception handling to verify_password() for invalid hash formats - Update SQL injection test to accept both 401 and 422 status codes (Pydantic validation) All fixes ensure tests match actual API signatures and handle edge cases properly. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Fix token forgery test to properly decode and modify JWT payload The test was attempting to modify the JWT payload by string replacement on the base64-encoded data, which doesn't work since "false" doesn't appear literally in the base64 encoding. Fixed to: - Properly decode the base64 payload - Parse the JSON - Modify the is_admin field - Re-encode the payload - Create a forged token with the modified payload and original signature - Verify it's rejected with 401 status This properly tests that JWT signature verification prevents token forgery. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Fix test_verify_expired_token timing issue Increased token expiration from 10ms to 100ms and wait time from 20ms to 200ms to make the test more reliable. The previous timing was too tight and could cause race conditions where the token hadn't actually expired yet when verified. This ensures the test reliably validates that expired tokens are properly rejected. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Fix token verification to properly validate signatures and expiration The verify_token() function was not explicitly enabling JWT verification options, causing it to accept expired tokens and tokens with modified signatures/payloads. Fixed by explicitly setting verification options: - verify_signature: True (reject modified tokens) - verify_exp: True (reject expired tokens) - verify_nbf: True (verify "not before" claim) - verify_iat: True (verify "issued at" claim) - verify_aud: False (we don't use audience claims) Also added catch-all exception handler for other validation errors. This ensures all token security tests pass properly. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Revert to default python-jose verification behavior Removed explicit options parameter from jwt.decode() call since python-jose verifies signatures and expiration by default. The explicit options may have been causing issues or conflicts with the library's default behavior. Added comments clarifying that python-jose defaults are secure and handle verification properly. Need user to test and provide debugging output if issues persist. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Fix JWT expiration verification for python-jose 3.5.0 python-jose 3.5.0 has a bug where expiration verification doesn't work properly by default. The jwt.decode() function is not rejecting expired tokens even when they should be rejected. Workaround implemented: 1. First, get unverified claims to extract the 'exp' timestamp 2. Manually check if current time >= exp time (token is expired) 3. Return None immediately if expired 4. Then verify signature with jwt.decode() for tokens that aren't expired This ensures: - Expired tokens are properly rejected - Signature verification still happens for non-expired tokens - Modified tokens are rejected due to signature mismatch All three failing tests should now pass: - test_verify_expired_token - test_verify_token_with_modified_payload - test_token_signature_verification Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix race condition in token verification - verify signature before expiration Changed the order of verification in verify_token(): 1. First verify signature with jwt.decode() - rejects modified/forged tokens 2. Then manually check expiration timestamp Previous implementation checked expiration first using get_unverified_claims(), which could cause a race condition where: - Token with valid payload but INVALID signature would pass expiration check - If expiration check happened to return None due to timing, signature was never verified - Modified tokens could be accepted intermittently New implementation ensures signature is ALWAYS verified first, preventing any modified tokens from being accepted, while still working around the python-jose 3.5.0 expiration bug by manually checking expiration after signature verification. This eliminates the non-deterministic test failures in test_verify_token_with_modified_payload. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore(app): ruff --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> * Backend: Add admin board filtering and uncategorized board isolation Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix intermittent token service test failures caused by Base64 padding (#32) * Initial plan * Fix intermittent token service test failures due to Base64 padding Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Address code review: add constants for magic numbers in tests Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore(tests): ruff --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> * Implement user isolation for session queue and socket events (WIP - debugging queue visibility) (#30) * Add user isolation for queue events and field values filtering Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Add user column to queue list UI Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Add field values privacy indicator and implementation documentation Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Allow all users to see queue item status events while keeping invocation events private Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore(backend): ruff --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> * Fix Queue tab not updating for other users in real-time (#34) * Initial plan * Add SessionQueueItemIdList invalidation to queue socket events This ensures the queue item list updates in real-time for all users when queue events occur (status changes, batch enqueued, queue cleared). Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Add SessionQueueItemIdList invalidation to queue_items_retried event Ensures queue list updates when items are retried. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Improve queue_items_retried event and mutation invalidation - Add individual item invalidation to queue_items_retried event handler - Add SessionQueueStatus and BatchStatus tags to retryItemsById mutation - Ensure consistency between event handler and mutation invalidation patterns Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Add privacy check for batch field values in Queue tab Displays "Hidden for privacy" message for non-admin users viewing queue items they don't own, instead of showing the actual field values. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * i18n(frontend): change wording of queue values suppressed message * Add SessionQueueItemIdList cache invalidation to queue events Ensures real-time queue updates for all users by invalidating the SessionQueueItemIdList cache tag when queue events occur. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> * Fix multiuser information leakage in Queue panel detail view (#38) * Initial plan * Implement multiuser queue information leakage fix - Backend: Update sanitize_queue_item_for_user to clear session graph and workflow - Frontend: Add permission check to disable detail view for unauthorized users - Add test for sanitization logic - Add translation key for permission denied message Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix prettier formatting for QueueItemComponent Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Address code review feedback - Move Graph and GraphExecutionState imports to top of file - Remove dependency on test_nodes in sanitization test - Create minimal test invocation directly in test file Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Address additional code review feedback - Create shallow copy to avoid mutating original queue_item - Extract 'system' user_id to constant (SYSTEM_USER_ID) - Add constant to both backend and frontend for consistency Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix pydantic validation error in test fixture Add required timestamp fields (created_at, updated_at, started_at, completed_at) to SessionQueueItem in test fixture Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * fix(queue): Enforce user permissions for queue operations in multiuser mode (#36) * Initial plan * Add backend authorization checks for queue operations Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix linting issues in authorization changes Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Add frontend authorization checks for queue operations Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Add access denied messages for cancel and clear operations Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix access denied messages for all cancel/delete operations Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix merge conflict duplicates in QueueItemComponent Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore(frontend): typegen --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> * fix(multiuser): Isolate client state per user to prevent data leakage (#40) * Implement per-user client state storage to fix multiuser leakage Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix: Make authentication optional for client_state endpoints to support single-user mode Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Clear params state on logout/login to prevent user data leakage Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * feat(queue): show user/total pending jobs in multiuser mode badge (#43) * Initial plan * Add multiuser queue badge support - show X/Y format in multiuser mode Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Format openapi.json with Prettier Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Address code review feedback - optimize DB queries and improve code clarity Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * translationBot(ui): update translation files (#8767) Updated by "Cleanup translation files" hook in Weblate. Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/ Translation: InvokeAI/Web UI * Limit automated issue closure to bug issues only (#8776) * Initial plan * Add only-labels parameter to limit automated issue closure to bugs only Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * fix(multiuser): Isolate client state per user to prevent data leakage (#40) * Implement per-user client state storage to fix multiuser leakage Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix: Make authentication optional for client_state endpoints to support single-user mode Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Clear params state on logout/login to prevent user data leakage Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Initial plan * chore(backend) ruff & typegen * Fix real-time badge updates by invalidating SessionQueueStatus on queue events Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Weblate (bot) <hosted@weblate.org> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> * Convert session queue isolation logs from info to debug level Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Add JWT secret storage in database and app_settings service Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Add multiuser configuration option with default false Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Update token service tests to initialize JWT secret Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix app_settings_service to use proper database transaction pattern Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore(backend): typegen and ruff * chore(docs): update docstrings * Fix frontend to bypass authentication in single-user mode Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix auth tests to enable multiuser mode Auth tests were failing because the login and setup endpoints now return 403 when multiuser mode is disabled (the default). Updated test fixtures to enable multiuser mode for all auth-related tests. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix model manager UI visibility in single-user mode Model manager UI for adding, deleting and modifying models is now: - Visible in single-user mode (multiuser: false, the default) - Hidden in multiuser mode for non-admin users - Visible in multiuser mode for admin users Created useIsModelManagerEnabled hook that checks multiuser_enabled status and returns true when multiuser is disabled OR when user is admin. Updated all model manager components to use this hook instead of direct is_admin checks. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore(backend): ruff * chore(frontend): typegen * Fix TypeScript lint errors - Added multiuser_enabled field to SetupStatusResponse type in auth.ts - Removed unused user variable reference in MainModelDefaultSettings.tsx Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix test_data_isolation to enable multiuser mode Added fixture to enable multiuser mode for data isolation tests, similar to other auth tests. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Redirect login and setup pages to app in single-user mode When multiuser mode is disabled, the LoginPage and AdministratorSetup components now redirect to /app instead of showing the login/setup forms. This prevents users from being stuck on the login page after browser refresh in single-user mode. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix test_auth.py to initialize JWT secret Added setup_jwt_secret fixture to test_auth.py to initialize the JWT secret before running auth tests. This fixture was missing, causing token creation/verification to fail in auth router tests. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Prevent login form flash in single-user mode Show loading spinner instead of login/setup forms when multiuser mode is disabled or when redirecting is about to happen. This prevents the unattractive flash of the login dialog when refreshing the page in single-user mode. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix board and queue operations in single-user mode Changed boards, session_queue, and images routers to use CurrentUserOrDefault instead of CurrentUser. This allows these endpoints to work without authentication when multiuser mode is disabled (default), fixing the issue where users couldn't create boards or add jobs to the queue in single-user mode. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Add user management utilities and rename add_user.py Created three user management scripts in the scripts/ directory: - useradd.py (renamed from add_user.py) - add users with admin privileges - userdel.py - delete users by email address with confirmation - usermod.py - modify user details (name, password, admin status) All scripts support both CLI and interactive modes for flexibility. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix ESLint errors in frontend code - Fixed brace-style issue in App.tsx (else-if on same line) - Removed unused useAppSelector imports from model manager components - Fixed import sorting in ControlAdapterModelDefaultSettings.tsx Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Add userlist.py script for viewing database users Created scripts/userlist.py to display all users in the database. Supports: - Table format (default): Shows ID, email, display name, admin status, and active status - JSON format (--json flag): Outputs user data as JSON for scripting/automation Example usage: python scripts/userlist.py # Table view python scripts/userlist.py --json # JSON output Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix test_boards_multiuser.py test failures Fixed test failures caused by ApiDependencies.invoker not being set properly: - Added setup_jwt_secret fixture to initialize JWT secret for token generation - Added enable_multiuser_for_tests fixture that sets ApiDependencies.invoker as a class attribute - Updated tests to use enable_multiuser_for_tests fixture to ensure ApiDependencies is properly configured - Removed MockApiDependencies class approach in favor of directly setting the class attribute This fixes the AttributeError and ensures all tests have the proper setup. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore(backend): ruff * Fix userlist.py SqliteDatabase initialization Fixed AttributeError in userlist.py where SqliteDatabase was being passed the config object instead of config.db_path. The constructor expects a Path object (db_path) as the first argument, not the entire config object. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix test_boards_multiuser.py by adding app_settings service to mock Added AppSettingsService initialization to the mock_services fixture in tests/conftest.py. The test was failing because setup_jwt_secret fixture expected mock_invoker.services.app_settings to exist, but it wasn't being initialized in the mock services. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * bugfix(scripts): fix crash in userlist.py script * Fix test_boards_multiuser.py JWT secret initialization Fixed setup_jwt_secret fixture to call set_jwt_secret() directly instead of trying to access non-existent app_settings service. Removed incorrect app_settings parameter from InvocationServices initialization in tests/conftest.py since app_settings is not an attribute of InvocationServices. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix CurrentUserOrDefault to require auth in multiuser mode Changed get_current_user_or_default to raise HTTP 401 when multiuser mode is enabled and credentials are missing, invalid, or the user is inactive. This ensures that board/queue/image operations require authentication in multiuser mode while still working without authentication in single-user mode (default). Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore(front & backend): ruff and lint * Add AdminUserOrDefault and fix model settings in single-user mode Created AdminUserOrDefault dependency that allows admin operations to work without authentication in single-user mode while requiring admin privileges in multiuser mode. Updated model_manager router to use AdminUserOrDefault for update_model_record, update_model_image, and reidentify_model endpoints. This fixes the "Missing authentication credentials" error when saving model default settings in single-user mode. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix model manager operations in single-user mode Changed all model manager endpoints from AdminUser to AdminUserOrDefault to allow model installation, deletion, conversion, and cache management operations to work without authentication in single-user mode. This fixes the issue where users couldn't add or delete models in single-user mode. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix syntax error in model_manager.py Added Depends(AdminUserOrDefault) to all AdminUserOrDefault dependency parameters to fix Python syntax error where parameters without defaults were following parameters with defaults. Imported Depends from fastapi. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix FastAPI dependency injection syntax error Removed type annotations from AdminUserOrDefault dependency parameters. FastAPI doesn't allow both Annotated type hints and = Depends() default values together. Changed from `_: AdminUserOrDefault = Depends(AdminUserOrDefault)` to `_ = Depends(AdminUserOrDefault)` throughout model_manager.py. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix delete_model endpoint parameter annotation Changed delete_model endpoint to use Annotated[str, Path(...)] instead of str = Path(...) to match FastAPI's preferred syntax and fix the 422 Unprocessable Entity error when deleting models in single-user mode. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix parameter annotations for all AdminUserOrDefault endpoints Changed all endpoints using AdminUserOrDefault from old syntax (key: str = Path(...)) to FastAPI's preferred Annotated syntax (key: Annotated[str, Path(...)]). This fixes 422 Unprocessable Entity errors when updating model settings and deleting models in single-user mode. Updated endpoints: delete_model_image, install_model, install_hugging_face_model, and convert_model. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Revert to correct AdminUserOrDefault usage pattern Reverted model_manager.py to state before commit c47af8f and reapplied AdminUserOrDefault correctly. Changed from `_: AdminUser` to `current_admin: AdminUserOrDefault` using the same pattern as boards.py (`current_user: CurrentUserOrDefault`). This fixes all 422 errors in single-user mode while maintaining proper admin authentication in multiuser mode. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix parameter order for AdminUserOrDefault in model manager Moved current_admin: AdminUserOrDefault parameter before all parameters with default values in model_manager.py endpoints. Python requires parameters without defaults to come before parameters with defaults. Fixed 8 endpoints: delete_model, bulk_delete_models, delete_model_image, install_model, install_hugging_face_model, cancel_model_install_job, convert_model, and do_hf_login. Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore(frontend): typegen * chore(frontend): typegen again * Docs(app): Comprehensive Documentation of Multiuser Features (#50) * Implement Phase 8: Complete multiuser documentation (user, admin, and API guides) Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Update multiuser documentation for single-user mode and CLI scripts - Document multiuser config option (true/false/absent) - Explain single-user mode behavior (no login required) - Document mode switching and legacy "system" user - Update user management to reference CLI scripts (useradd, userdel, usermod, userlist) - Note that web UI for user management is coming in future release - Add adaptive API client example for both modes Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * docs(multiuser): bring user guide documentation up to date --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * docs(app): update multiuser documentation * bugfix(app): fix misaligned database migration calls * chore(tests): update migration test to accommodate resequencing of migrations * fix(frontend): prevent caching of static pages * chore(backend): ruff * fix(backend): fix incorrect migration import * Fix: Admin users can see image previews from other users' generations (#61) * Initial plan * Fix: strip image preview from InvocationProgressEvent sent to admin room Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore: ruff * fix(backend): add migration_29 file * chore(tests): fix migration_29 test --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> * fix(queue): System user queue items show blank instead of `<hidden>` for non-admin users (#63) * Initial plan * fix(queue): System user queue items show blank instead of `<hidden>` for non-admin users Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore(backend): ruff --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> * Hide "Use Cache" checkbox in node editor for non-admin users in multiuser mode (#65) * Initial plan * Hide use cache checkbox for non-admin users in multiuser mode Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix node loading hang when invoke URL ends with /app (#67) * Initial plan * Fix node loading hang when URL ends with /app Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Move user management scripts to installable module with CLI entry points (#69) * Initial plan * Add user management module with invoke-useradd/userdel/userlist/usermod entry points Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore(util): remove superceded user administration scripts --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> * chore(backend): reorganized migrations, but something still broken * Fix migration 28 crash when `client_state.data` column is absent (#70) * Initial plan * Fix migration 28 to handle missing data column in client_state table Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Consolidate multiuser DB migrations 27–29 into a single migration step (#71) * Initial plan * Consolidate migrations 27, 28, and 29 into a single migration step Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Add `--root` option to user management CLI utilities (#81) * Initial plan * Add --root option to user management CLI utilities Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix queue clear() endpoint to respect user_id for multi-tenancy (#75) Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Add tests for session queue clear() user_id scoping Co-authored-by: lstein <111189+lstein@users.noreply.github.com> chore(frontend): rebuild typegen Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> * fix: use AdminUserOrDefault for pause and resume queue endpoints (#77) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * fix: queue pause/resume buttons disabled in single-user mode (#83) In single-user mode, currentUser is never populated (no auth), so `currentUser?.is_admin ?? false` always returns false, disabling the buttons. Follow the same pattern as useIsModelManagerEnabled: treat as admin when multiuser mode is disabled, and check is_admin flag when enabled. Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * fix: enforce board ownership checks in multiuser mode (#84) - get_board: verify current user owns the board (or is admin), return 403 otherwise - update_board: verify ownership before updating, 404 if not found, 403 if unauthorized - delete_board: verify ownership before deleting, 404 if not found, 403 if unauthorized - list_all_board_image_names: add CurrentUserOrDefault auth and ownership check for non-'none' board IDs test: add ownership enforcement tests for board endpoints in multiuser mode - Auth requirement tests for get, update, delete, and list_image_names - Cross-user 403 forbidden tests (non-owner cannot access/modify/delete) - Admin bypass tests (admin can access/update/delete any user's board) - Board listing isolation test (users only see their own boards) - Refactored fixtures to use monkeypatch (consistent with other test files) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix: Clear auth state when switching from multiuser to single-user mode (#86) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix race conditions in download queue and model install service (#98) * Initial plan * Fix race conditions in download queue and model install service Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Weblate (bot) <hosted@weblate.org> Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com> |
||
|
|
dfc66b7142 |
Feature: Add FLUX.2 LOKR model support (detection and loading) (#8909)
* Add FLUX.2 LOKR model support (detection and loading) (#88) Fix BFL LOKR models being misidentified as AIToolkit format Fix alpha key warning in LOKR QKV split layers Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * Fix BFL→diffusers key mapping for non-block layers in FLUX.2 LoRA/LoKR BFL's FLUX.2 model uses different names than diffusers' Flux2Transformer2DModel for top-level modules (embedders, modulations, output layers). The existing conversion only handled block-level renames (double_blocks→transformer_blocks), causing "Failed to find module" warnings for non-block LoRA keys like img_in, txt_in, modulation.lin, time_in, and final_layer. --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Alexander Eichhorn <alex@eichhorn.dev> |
||
|
|
ddaa12b0fd |
Fix bare except clauses and mutable default arguments (#8871)
* Fix bare except clauses and mutable default arguments Replace bare `except:` with `except Exception:` in sqlite_database.py and mlsd/utils.py to avoid catching KeyboardInterrupt and SystemExit, which can prevent graceful shutdowns and mask critical errors (PEP 8 E722). Replace mutable default arguments (lists) with None in imwatermark/vendor.py to prevent shared state between calls, which is a known Python gotcha that can cause subtle bugs when default mutable objects are modified in place. * add tests for mutable defaults and bare except fixes * Simplify exception propagation tests * Remove unused db initialization in error propagation tests Removed unused database initialization in tests for KeyboardInterrupt and SystemExit. --------- Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com> |