Commit Graph

954 Commits

Author SHA1 Message Date
Alexander Eichhorn 5bd1f7e25f docs(fp8): refresh FP8 Storage page after hook-based loader change (#9241)
PR #9231 routed every nn.Module — including diffusers ModelMixin — through
InvokeAI's `register_forward_pre_hook` / `register_forward_hook` path, but
the FP8 Storage docs still described the old `enable_layerwise_casting`
implementation. Also corrects two unrelated inaccuracies the rewrite
surfaced: pre-Ampere CUDA cards are not a no-op (the FP8 path gates only
on `device.type == "cuda"`, and `float8_e4m3fn` is a pure storage dtype
that works on any CUDA device), and the UI does not grey out the toggle
based on hardware.

Tell users what to include when reporting an FP8 problem so triage isn't
blocked on follow-up questions: repro steps, exact model + variant,
LoRA stack, partner toggles (low-VRAM, cpu_only), GPU + VRAM, OS, and
the relevant log lines.
2026-05-28 22:52:28 -04:00
Josh Corbett e854ab402b fix(docs): encourage uv sync over uv pip install (#9238)
Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com>
2026-05-26 20:20:02 -04:00
Josh Corbett 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>
2026-05-26 20:45:51 +00:00
Alexander Eichhorn 9622900f7c docs: cover Canvas, Workflow, Gallery, and Model Manager features (#9196)
* docs: cover Canvas, Workflow, Gallery, and Model Manager features

- New: Canvas Workflow Integration (run workflow on raster layer)
- New: Canvas Projects (.invk save/load)
- New: Custom Node Manager (install/manage community node packs)
- New: Layer tips (canvas drag & drop targets + lock transparency)
- gallery: virtual boards (by date)
- editor-interface: workflow library tags (dynamic per-user tags)
- adding-nodes: point manual install at Custom Node Manager
- models: editable source URL, bulk delete/reidentify, missing-files filter, settings export/import
- fp8-storage: hardware support tiers (Ampere / Ada+Hopper / pre-Ampere)

* docs: address review feedback

- custom-node-manager: fix broken creating-nodes link (absolute path)
- adding-nodes: fix broken community-nodes links (absolute path),
  document Workflow Connectors (#9027) under Connecting Nodes
- concepts/models: note that HF Repo IDs can be pasted into URL field,
  remove obsolete v4.0.0 autoimport tip
- fp8-storage: surface "full precision only" warning at the top,
  remove redundant quantized-formats bullet near the bottom
2026-05-18 20:04:49 -04:00
Jonathan 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>
2026-05-18 23:35:43 +00:00
Alexander Eichhorn 993c68102f docs: load Plausible on invoke.ai (custom), not ghpages (#9161)
* docs: load Plausible on invoke.ai (custom), not ghpages

Plausible was being injected on the ghpages target, which redirects to
invoke.ai and therefore never serves analytics. Flip the conditional so
the script loads on the actual production custom-domain build.

* docs: gate Plausible on ENABLE_ANALYTICS env var

Only inject the tracking script when ENABLE_ANALYTICS=true, which the
deploy workflow sets exclusively on main-branch pushes. Keeps local
builds, PR builds, and manual workflow_dispatch runs analytics-free.

* Update .github/workflows/deploy-docs.yml

Co-authored-by: Josh Corbett <joshwcorbett@icloud.com>

---------

Co-authored-by: Josh Corbett <joshwcorbett@icloud.com>
2026-05-18 17:18:48 -04:00
Valeri Che 3fec11a144 docs: add lasso tool and gradient guides (#9175)
* docs: add lasso tool guide

* docs: document lasso panning behavior during drawing

* docs: move lasso and shapes guides into canvas category

* docs: add Gradient description
2026-05-16 16:14:04 +00:00
Lincoln Stein a79606a905 docs: Add multiuser documentation and reposition Workflows (#9099)
* docs: added multi-user mode and moved workflows under features

* docs: finish moving workflows under features/

* Update docs/src/content/docs/features/Canvas/text-tool.mdx

Co-authored-by: Josh Corbett <joshwcorbett@icloud.com>

* Update docs/src/content/docs/features/hotkeys.mdx

Co-authored-by: Josh Corbett <joshwcorbett@icloud.com>

* docs(multiuser): fix links, remove redundant sections

* Update docs/src/content/docs/features/Multi-User Mode/api-guide.mdx

Co-authored-by: Josh Corbett <joshwcorbett@icloud.com>

* docs(multiuser): address issues raised in 6 May review

* Update docs/src/content/docs/features/Multi-User Mode/api-guide.mdx

Co-authored-by: Josh Corbett <joshwcorbett@icloud.com>

* Update docs/src/content/docs/features/Multi-User Mode/api-guide.mdx

Co-authored-by: Josh Corbett <joshwcorbett@icloud.com>

* docs(multiuser): more doc fixes

* docs(multiuser): remove outdated jwt config entries and reword strong password requirement

* Apply suggestions from code review

Co-authored-by: Josh Corbett <joshwcorbett@icloud.com>

* docs(multiuser): fixed errors identified in review

* Update docs/src/content/docs/features/Multi-User Mode/admin-guide.mdx

Co-authored-by: Josh Corbett <joshwcorbett@icloud.com>

* docs(multiuser): correct API and UI inaccuracies flagged in review

Reviewer comments pointed out several places where the multi-user docs
described behavior the code does not implement. Each item was verified
against the source before updating the docs.

- api-guide: create-board examples use board_name as a query parameter
  (not a JSON body) to match the FastAPI Query() declaration in
  boards.py.
- api-guide: the "all endpoints require authentication" list now
  includes the three intentionally unauthenticated image/thumbnail
  endpoints, with the UUID-unguessability rationale used in the code
  comments.
- api-guide: /auth/status sample response now shows both the
  setup_required=true and setup_required=false states, with a note
  that admin_email is only populated during initial setup.
- admin-guide: delete-user warning no longer claims that all of a
  user's content is removed; it now lists what actually cascades
  (sessions, shared_boards, invitations sent, client_state) and what
  is left orphaned (boards, images, workflows, queue items, style
  presets, plus on-disk image files).
- admin-guide: removed the hallucinated "Admin -> Queue Overview"
  navigation and per-user filter; the actual admin queue experience is
  the regular queue panel showing all users' items, with no built-in
  user filter.
- admin-guide: fixed broken relative link to user-guide
  (../user-guide -> ./user-guide; same folder).
- user-guide: queue badge description corrected -- it is a single
  count of the user's own pending + in_progress items, not an X/Y
  ratio.
- user-guide: admin badge location corrected -- the user menu lives
  near the bottom of the left-hand nav bar, and the "Admin" badge
  appears inside the dropdown, not in the top-right corner.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Josh Corbett <joshwcorbett@icloud.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 02:32:08 +00:00
Valeri Che 2ea25968f0 fix(docs): clarify Shapes tool description (#9176) 2026-05-15 01:38:55 +00:00
Valeri Che 932eeedc33 Feat(canvas): Replace Rectangle tool with new Shapes tool (#9082)
* Feat(Canvas): Replace Rectangle tool with multifunctional Shapes tool.

* Fix: Tweaked icon size on top bar

* Fix: also tweaked SVGs for Gradient tool to align with unified 16px icon size

* Feat: added freehand shape

* fix(canvas): remove duplicate lasso payload export after rebase

* `fix(canvas): clear polygon preview stroke on commit`

* chore: remove temporary codex artifact

* chore: format with prettier

* fix(canvas): preserve shapes sessions across view switch

* chore: format with prettier

* add: constrain rectangles to squares with shift

* fix(canvas): refine shapes space and alt interactions

* fix(canvas): preserve polygon sessions across temporary tool switches

* refactor(i18n): reuse lasso labels for shapes polygon modes

* fix(i18n): merge shapes locale additions with modifier hints

* feat(canvas): add shape-specific modifier hints and docs

* fix(canvas): refine shape modifier hints and toolbar overflow

* fix(canvas): keep toolbar overflow clipped to the right

* fix: Escape while panning while drawing should exit shape tool

---------

Co-authored-by: Alexander Eichhorn <alex@eichhorn.dev>
Co-authored-by: dunkeroni <dunkeroni@gmail.com>
2026-05-14 08:41:29 -04:00
Josh Corbett acd1211128 feat(docs): upgrade deps, add translation page, fix bad links (#9160) 2026-05-11 23:36:33 -04:00
Josh Corbett 71b06e74e2 Revert "feat(docs): upgrade deps, add translation page, fix bad links (#9157)" (#9159)
This reverts commit 0f937ce7ee.

Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com>
2026-05-11 22:50:14 -04:00
Alexander Eichhorn 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>
2026-05-12 02:43:38 +00:00
Josh Corbett 0f937ce7ee feat(docs): upgrade deps, add translation page, fix bad links (#9157)
Co-authored-by: joshistoast <me@joshcorbett.com>
2026-05-11 22:29:23 -04:00
Alexander Eichhorn f9f2c658b1 docs: add Plausible analytics to invoke.ai site (#9140)
* docs: add Plausible analytics to invoke.ai site

* Only isGhPages and not anything else
2026-05-11 15:23:03 -04:00
Jonathan aa865f6e08 feat: add image subfolder strategy setting UI (#9133)
* feat: add image subfolder strategy setting UI

* fix: address image subfolder strategy review
2026-05-08 19:50:49 -04:00
Alexander Eichhorn 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>
2026-05-06 22:35:14 -04:00
Alexander Eichhorn 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>
2026-05-06 20:24:47 -04:00
Alexander Eichhorn fcf3aca5f7 feat(config): enable partial model loading by default (#9092)
Flips `enable_partial_loading` default from false to true so low-VRAM
mode is on out of the box. Updates the low-VRAM docs and generated
settings reference accordingly.

Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com>
2026-05-05 22:48:18 -04:00
Alexander Eichhorn 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>
2026-05-05 03:00:20 +00:00
Alexander Eichhorn 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>
2026-04-27 20:36:34 +00:00
Lincoln Stein 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>
2026-04-27 16:11:10 -04:00
Alexander Eichhorn 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>
2026-04-26 22:03:16 -04:00
CypherNaugh_0x 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>
2026-04-20 17:13:26 +00:00
Josh Corbett f621bc8fd2 fix(docs): anticipate more redirects and update more links (#9076)
Co-authored-by: joshistoast <me@joshcorbett.com>
2026-04-19 20:13:30 -04:00
Josh Corbett ec5f22b981 fix(docs): address bad links (#9074)
* fix(docs): add more yaml configuration docs

* feat(docs): add redirects for app links

* feat(docs): update readme links, add installation redirect

---------

Co-authored-by: joshistoast <me@joshcorbett.com>
2026-04-19 17:53:14 -04:00
Josh Corbett 5436cedc1d fix(docs): deploy targets (#9070) 2026-04-18 20:37:32 -04:00
Josh Corbett 8cdc8c87fe fix(docs): urls respect baseurl + better deployment scheduling (#9069)
* fix(docs): avoid relative link urls, fix homepage title

* fix(docs): better deployment run scheduling

* fix(docs): remove crowdin

---------

Co-authored-by: joshistoast <me@joshcorbett.com>
2026-04-18 19:51:55 -04:00
Josh Corbett 63a1fe5299 fix(docs): deployment paths mismatch (#9067)
also adds the favicon

Co-authored-by: joshistoast <me@joshcorbett.com>
Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com>
2026-04-18 16:46:54 -04:00
Lincoln Stein 3c17a569ce Revert "Revert "New Documentation Fixes (#9061)" (#9065)" (#9066)
This reverts commit b513a3d3c6.
2026-04-18 16:45:32 -04:00
Lincoln Stein b513a3d3c6 Revert "New Documentation Fixes (#9061)" (#9065)
This reverts commit 7eaf1d5bd0.
2026-04-17 17:32:23 -04:00
Josh Corbett 7eaf1d5bd0 New Documentation Fixes (#9061)
* fix(docs): swap `docs-new` to `docs`

also renames `docs` to `docs-old`, purely for preservation purposes.

* feat(docs): clarify compel syntax availability

---------

Co-authored-by: joshistoast <me@joshcorbett.com>
2026-04-17 08:10:10 -04:00
Josh Corbett 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>
2026-04-16 22:03:05 -04:00
Lincoln Stein e252a5bb47 fix(multiuser): make preexisting workflows visible after migration (#9049) 2026-04-14 12:27:14 -04:00
Alexander Eichhorn acd4157bdf feat(ui): add canvas project save/load (.invk format) (#8917)
* feat(ui): add canvas project save/load (.invk format)

Add ZIP-based .invk file format to save and restore the entire canvas
state including all layers, masks, reference images, generation
parameters, LoRAs, and embedded image files. Images are deduplicated
on load - only missing images are re-uploaded from the project file.
- Always clear LoRAs on project load, even when project has none
- Fix jszip dependency ordering in package.json
- Add useAssertSingleton to SaveCanvasProjectDialog for consistency
- Add concurrency limit (max 5) for image fetch/upload requests
- Remove redundant deep-clone in remapCroppableImage (mutate in-place)
- Default project name to "Canvas Project" instead of empty string

* Chore pnpm fix
2026-04-14 01:01:57 +00:00
Valeri Che 441821ca03 Feat(canvas): Add Lasso Tool with Freehand and Polygon modes (#8908)
* Feat(Canvas): Add Lasso tool with Freehand and Polygon modes

* Refine Lasso modes behavior and optimisation.

* Fix: Pettier

* added docs/features/Lasso_tool.md

* Fix: Removed restrictions mentioned in PR's conversation:
1. Disabled when there is no visible raster content
2. Lasso is blocked when all inpaint masks are globally hidden.

---------

Co-authored-by: dunkeroni <dunkeroni@gmail.com>
2026-04-14 00:22:34 +00:00
Sense_wang f01cbd35a8 docs: Fix typo in contributing guide - remove extra 'the' (#8949)
Co-authored-by: Contributor <contributor@example.com>
2026-03-09 18:03:32 +00:00
Lincoln Stein 863fa50551 Doc: update multiuser mode documentation (#8953)
* docs(multiuser): update multiuser mode documentation

* Update docs/multiuser/user_guide.md

Co-authored-by: dunkeroni <dunkeroni@gmail.com>

* Update docs/multiuser/user_guide.md

Co-authored-by: dunkeroni <dunkeroni@gmail.com>

* Update docs/multiuser/user_guide.md

Co-authored-by: dunkeroni <dunkeroni@gmail.com>

* slight wording change

* add info about the host interface binding option

---------

Co-authored-by: dunkeroni <dunkeroni@gmail.com>
2026-03-09 17:56:56 +00:00
Lincoln Stein 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>
2026-02-26 23:47:25 -05:00
DustyShoe e9246c1899 Feature(UI): Add text tool to canvas (#8723)
* Initial mashup of mentioned feature. Still need to resolve some quirks and kinks.

* Clean text tool integration

* Fixed text tool opions bar jumping and added more fonts

* Touch up for cursor styling

* Minor addition to doc file

* Appeasing frontend checks

* Prettier fix

* knip fixes

* Added safe zones to font selection and color picker to be clickable without commiting text.

* Removed color probing on cursor and added dynamic font display for fallback, minor tweaks

* Finally fixed the text shifting on commit

* Cursor now represent actual input field size. Tidy up options UI

* Some strikethrough and underline line tweaks

* Replaced the focus retry loop with a callback‑ref based approach in in CanvasTextOverlay.tsx
Renamed containerMetrics to textContainerData in CanvasTextOverlay.tsx
Fixed mouse cursor disapearing during typing.

* Added missing localistaion string

* Moved canvas-text-tool.md to docs/contributing/frontend

* ui: Improve functionality of the text toolbar

Few things done with this commit.

- The varying size of the font selector box has been fixed. The UI no longer shifts and moves with font change.
- We no longer format the font size input to add px each time. Instead now just have a permanent px indicator.
- The bug with the random text inputs on the slider value has also been fixed.
- The font size value is only committed on blur keeping it consistent with other editing apps.
- Fixed the spacing of the toolbar to make it look cleaner.
- Font size now permits increments of 1.

* Added autoselect text in font size on click allowing immediate imput

* Improvement: Added uncommited layer state with CTRL-move and options to select line spacing.

* Added rotation handle to rotate uncommiitted text layer.

* Fix: Redirect user facing labels to use localization file + Add tool discription to docs

* Fixed box padding. Disable tool swich when text input is active, added message on canvas for better UX.

* Updated  Text tool description

* Updated  Text tool description

* Typo

* Add draggable text-box border with improved cursor feedback and larger hit targets. Supress hotkeys on uncommitted text.

* Lint

* Fix(bug): text commit to link uploaded image assets instead of embedding full base64

---------

Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com>
Co-authored-by: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com>
2026-02-20 01:43:32 +00:00
Lincoln Stein 3ada1dc743 Feature(app): Add an endpoint to recall generation parameters (#8758)
* feature(app): Add an endpoint to recall generation parameters and transmit to frontend

-core generation parameters
-support for LoRAs and IP-adapters
-controlnets
-documentation in docs/contributing/RECALL_PARAMETERS

* chore(app): refactor controlnet image processing in recall_parameters route

* docs(app): updated recall endpoint documentation

* chore(app): ruff format

* chore(frontend): rerun typegen

---------

Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com>
2026-02-16 23:27:10 +00:00
Lincoln Stein b23f18734b feat(model_manager): Add scan and delete of orphaned models (#8826)
* Add script and UI to remove orphaned model files

- This commit adds command-line and Web GUI functionality for
  identifying and optionally removing models in the models directory
  that are not referenced in the database.

Co-authored-by: lstein <111189+lstein@users.noreply.github.com>

* Add backend service and API routes for orphaned models sync

Co-authored-by: lstein <111189+lstein@users.noreply.github.com>

Add expandable file list to orphaned models dialog

Co-authored-by: lstein <111189+lstein@users.noreply.github.com>

* Fix cache invalidation after deleting orphaned models

Co-authored-by: lstein <111189+lstein@users.noreply.github.com>

* (bugfix) improve status messages

* docs(backend): add info on the orphaned model detection/removal feature

* Update docs/features/orphaned_model_removal.md

---------

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: dunkeroni <dunkeroni@gmail.com>
2026-02-06 22:32:10 +00:00
Lincoln Stein 5801e59e2b Documentation: InvokeAI PR review and merge policy (#8795)
* docs: Add a PR review and merge policy

* doc(release): add policy on release candidates

* docs(CD/CI): add best practice for external components
2026-01-30 01:03:43 +00:00
Alexander Eichhorn cf07f8be14 Add new model type integration guide (#8779)
* Add new model type integration guide

Comprehensive documentation covering all steps required to integrate
a new model type into InvokeAI, including:

- Backend: Model manager, configs, loaders, invocations, sampling
- Frontend: Graph building, state management, parameter recall
- Metadata, starter models, and optional features (ControlNet, LoRA, IP-Adapter)

Uses FLUX.1, FLUX.2 Klein, SD3, SDXL, and Z-Image as reference implementations.

* docs: improve new model integration guide

- Move document to docs/contributing/ directory
- Fix broken TOC links by replacing '&' with 'and' in headings
- Add code example for text encoder config (section 2.4)
- Add text encoder loader example (new section 3.3)
- Expand text encoder invocation to show full conditioning flow (section 4.2)

---------

Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com>
2026-01-29 13:45:29 +00:00
Alexander Eichhorn b92c6ae633 feat(flux2): add FLUX.2 klein model support (#8768)
* WIP: feat(flux2): add FLUX 2 Kontext model support

- Add new invocation nodes for FLUX 2:
  - flux2_denoise: Denoising invocation for FLUX 2
  - flux2_klein_model_loader: Model loader for Klein architecture
  - flux2_klein_text_encoder: Text encoder for Qwen3-based encoding
  - flux2_vae_decode: VAE decoder for FLUX 2

- Add backend support:
  - New flux2 module with denoise and sampling utilities
  - Extended model manager configs for FLUX 2 models
  - Updated model loaders for Klein architecture

- Update frontend:
  - Extended graph builder for FLUX 2 support
  - Added FLUX 2 model types and configurations
  - Updated readiness checks and UI components

* fix(flux2): correct VAE decode with proper BN denormalization

FLUX.2 VAE uses Batch Normalization in the patchified latent space
(128 channels). The decode must:
1. Patchify latents from (B, 32, H, W) to (B, 128, H/2, W/2)
2. Apply BN denormalization using running_mean/running_var
3. Unpatchify back to (B, 32, H, W) for VAE decode

Also fixed image normalization from [-1, 1] to [0, 255].

This fixes washed-out colors in generated FLUX.2 Klein images.

* feat(flux2): add FLUX.2 Klein model support with ComfyUI checkpoint compatibility

- Add FLUX.2 transformer loader with BFL-to-diffusers weight conversion
- Fix AdaLayerNorm scale-shift swap for final_layer.adaLN_modulation weights
- Add VAE batch normalization handling for FLUX.2 latent normalization
- Add Qwen3 text encoder loader with ComfyUI FP8 quantization support
- Add frontend components for FLUX.2 Klein model selection
- Update configs and schema for FLUX.2 model types

* Chore Ruff

* Fix Flux1 vae probing

* Fix Windows Paths schema.ts

* Add 4B und 9B klein to Starter Models.

* feat(flux2): add non-commercial license indicator for FLUX.2 Klein 9B

- Add isFlux2Klein9BMainModelConfig and isNonCommercialMainModelConfig functions
- Update MainModelPicker and InitialStateMainModelPicker to show license icon
- Update license tooltip text to include FLUX.2 Klein 9B

* feat(flux2): add Klein/Qwen3 variant support and encoder filtering

Backend:
- Add klein_4b/klein_9b variants for FLUX.2 Klein models
- Add qwen3_4b/qwen3_8b variants for Qwen3 encoder models
- Validate encoder variant matches Klein model (4B↔4B, 9B↔8B)
- Auto-detect Qwen3 variant from hidden_size during probing

Frontend:
- Show variant field for all model types in ModelView
- Filter Qwen3 encoder dropdown to only show compatible variants
- Update variant type definitions (zFlux2VariantType, zQwen3VariantType)
- Remove unused exports (isFluxDevMainModelConfig, isFlux2Klein9BMainModelConfig)

* Chore Ruff

* feat(flux2): add Klein 9B Base (undistilled) variant support

Distinguish between FLUX.2 Klein 9B (distilled) and Klein 9B Base (undistilled)
models by checking guidance_embeds in diffusers config or guidance_in keys in
safetensors. Klein 9B Base requires more steps but offers higher quality.

* feat(flux2): improve diffusers compatibility and distilled model support

Backend changes:
- Update text encoder layers from [9,18,27] to (10,20,30) matching diffusers
- Use apply_chat_template with system message instead of manual formatting
- Change position IDs from ones to zeros to match diffusers implementation
- Add get_schedule_flux2() with empirical mu computation for proper schedule shifting
- Add txt_embed_scale parameter for Qwen3 embedding magnitude control
- Add shift_schedule toggle for base (28+ steps) vs distilled (4 steps) models
- Zero out guidance_embedder weights for Klein models without guidance_embeds

UI changes:
- Clear Klein VAE and Qwen3 encoder when switching away from flux2 base
- Clear Qwen3 encoder when switching between different Klein model variants
- Add toast notification informing user to select compatible encoder

* feat(flux2): fix distilled model scheduling with proper dynamic shifting

- Configure scheduler with FLUX.2 Klein parameters from scheduler_config.json
  (use_dynamic_shifting=True, shift=3.0, time_shift_type="exponential")
- Pass mu parameter to scheduler.set_timesteps() for resolution-aware shifting
- Remove manual shift_schedule parameter (scheduler handles this automatically)
- Simplify get_schedule_flux2() to return linear sigmas only
- Remove txt_embed_scale parameter (no longer needed)

This matches the diffusers Flux2KleinPipeline behavior where the
FlowMatchEulerDiscreteScheduler applies dynamic timestep shifting
based on image resolution via the mu parameter.

Fixes 4-step distilled Klein 9B model quality issues.

* fix(ui): fix FLUX.1 graph building with posCondCollect node lookup

The posCondCollect node was created with getPrefixedId() which generates
a random suffix (e.g., 'pos_cond_collect:abc123'), but g.getNode() was
called with the plain string 'pos_cond_collect', causing a node lookup
failure.

Fix by declaring posCondCollect as a module-scoped variable and
referencing it directly instead of using g.getNode().

* Remove Flux2 Klein Base from Starter Models

* Remove Logging

* Add Default Values for Flux2 Klein and add variant as additional info to from_base

* Add migrations for the z-image qwen3 encoder without a variant value

* Add img2img, inpainting and outpainting support for FLUX.2 Klein

- Add flux2_vae_encode invocation for encoding images to FLUX.2 latents
- Integrate inpaint_extension into FLUX.2 denoise loop for proper mask handling
- Apply BN normalization to init_latents and noise for consistency in inpainting
- Use manual Euler stepping for img2img/inpaint to preserve exact timestep schedule
- Add flux2_img2img, flux2_inpaint, flux2_outpaint generation modes
- Expand starter models with FP8 variants, standalone transformers, and separate VAE/encoders
- Fix outpainting to always use full denoising (0-1) since strength doesn't apply
- Improve error messages in model loader with clear guidance for standalone models

* Add GGUF quantized model support and Diffusers VAE loader for FLUX.2 Klein

- Add Main_GGUF_Flux2_Config for GGUF-quantized FLUX.2 transformer models
- Add VAE_Diffusers_Flux2_Config for FLUX.2 VAE in diffusers format
- Add Flux2GGUFCheckpointModel loader with BFL-to-diffusers conversion
- Add Flux2VAEDiffusersLoader for AutoencoderKLFlux2
- Add FLUX.2 Klein 4B/9B hardware requirements to documentation
- Update starter model descriptions to clarify dependencies install together
- Update frontend schema for new model configs

* Fix FLUX.2 model detection and add FP8 weight dequantization support

- Improve FLUX.2 variant detection for GGUF/checkpoint models (BFL format keys)
- Fix guidance_embeds logic: distilled=False, undistilled=True
- Add FP8 weight dequantization for ComfyUI-style quantized models
- Prevent FLUX.2 models from being misidentified as FLUX.1
- Preserve user-editable fields (name, description, etc.) on model reidentify
- Improve Qwen3Encoder detection by variant in starter models
- Add defensive checks for tensor operations

* Chore ruff format

* Chore Typegen

* Fix FLUX.2 Klein 9B model loading by detecting hidden_size from weights

Previously num_attention_heads was hardcoded to 24, which is correct for
Klein 4B but causes size mismatches when loading Klein 9B checkpoints.

Now dynamically calculates num_attention_heads from the hidden_size
dimension of context_embedder weights:
- Klein 4B: hidden_size=3072 → num_attention_heads=24
- Klein 9B: hidden_size=4096 → num_attention_heads=32

Fixes both Checkpoint and GGUF loaders for FLUX.2 models.

* Only clear Qwen3 encoder when FLUX.2 Klein variant changes

Previously the encoder was cleared whenever switching between any Klein
models, even if they had the same variant. Now compares the variant of
the old and new model and only clears the encoder when switching between
different variants (e.g., klein_4b to klein_9b).

This allows users to switch between different Klein 9B models without
having to re-select the Qwen3 encoder each time.

* Add metadata recall support for FLUX.2 Klein parameters

The scheduler, VAE model, and Qwen3 encoder model were not being
recalled correctly for FLUX.2 Klein images. This adds dedicated
metadata handlers for the Klein-specific parameters.

* Fix FLUX.2 Klein denoising scaling and Z-Image VAE compatibility

- Apply exponential denoising scaling (exponent 0.2) to FLUX.2 Klein,
  matching FLUX.1 behavior for more intuitive inpainting strength
- Add isFlux1VAEModelConfig type guard to filter FLUX 1.0 VAEs only
- Restrict Z-Image VAE selection to FLUX 1.0 VAEs, excluding FLUX.2
  Klein 32-channel VAEs which are incompatible

* chore pnpm fix

* Add FLUX.2 Klein to starter bundles and documentation

- Add FLUX.2 Klein hardware requirements to quick start guide
- Create flux2_klein_bundle with GGUF Q4 model, VAE, and Qwen3 encoder
- Add "What's New" entry announcing FLUX.2 Klein support

* Add FLUX.2 Klein built-in reference image editing support

FLUX.2 Klein has native multi-reference image editing without requiring
a separate model (unlike FLUX.1 which needs a Kontext model).

Backend changes:
- Add Flux2RefImageExtension for encoding reference images with FLUX.2 VAE
- Apply BN normalization to reference image latents for correct scaling
- Use T-coordinate offset scale=10 like diffusers (T=10, 20, 30...)
- Concatenate reference latents with generated image during denoising
- Extract only generated portion in step callback for correct preview

Frontend changes:
- Add flux2_reference_image config type without model field
- Hide model selector for FLUX.2 reference images (built-in support)
- Add type guards to handle configs without model property
- Update validators to skip model validation for FLUX.2
- Add 'flux2' to SUPPORTS_REF_IMAGES_BASE_MODELS

* Chore windows path fix

* Add reference image resizing for FLUX.2 Klein

Resize large reference images to match BFL FLUX.2 sampling.py limits:
- Single reference: max 2024² pixels (~4.1M)
- Multiple references: max 1024² pixels (~1M)

Uses same scaling approach as BFL's cap_pixels() function.
2026-01-26 23:21:37 -05:00
Lincoln Stein 56fd7bc7c4 docs(z-image) add Z-Image requirements and starter bundle (#8734)
* docs(z-image) add minimum requirements for Z-Image and create Z-Image starter bundle

* fix(model manager) add flux VAE to Z-Image bundle

* docs(model manager) remove out-of-date model info link

* chore: fix frontendchecks

* chore: lint:prettier

* docs(model manager): clarify minimum hardware for z-image turbo

* (fix) add flux VAE to ZIT starter dependencies & tweak UI docs
2026-01-04 10:17:26 -05:00
Lincoln Stein 0b1befa9ab (chore) Prep for v6.10.0rc2 (#8701) 2025-12-26 18:26:04 -05:00
Lincoln Stein de1aa557b8 chore: bump version to v6.10.0rc1 (#8695)
* chore: bump version to v6.10.0rc1

* docs: fix names of code owners in release doc
2025-12-26 02:08:14 +00:00
Alexander Eichhorn a2e109b3c2 feat(ui): improve hotkey customization UX with interactive controls and validation (#8649)
* feat: remove the ModelFooter in the ModelView and add the Delete Model Button from the Footer into the View

* forget to run pnpm fix

* chore(ui): reorder the model view buttons

* Initial plan

* Add customizable hotkeys infrastructure with UI

Co-authored-by: dunkeroni <3298737+dunkeroni@users.noreply.github.com>

* Fix ESLint issues in HotkeyEditor component

Co-authored-by: dunkeroni <3298737+dunkeroni@users.noreply.github.com>

* Fix knip unused export warning

Co-authored-by: dunkeroni <3298737+dunkeroni@users.noreply.github.com>

* Add tests for hotkeys slice

Co-authored-by: dunkeroni <3298737+dunkeroni@users.noreply.github.com>

* Fix tests to actually call reducer and add documentation

Co-authored-by: dunkeroni <3298737+dunkeroni@users.noreply.github.com>

* docs: add comprehensive hotkeys system documentation

- Created new HOTKEYS.md technical documentation for developers explaining architecture, data flow, and implementation details
- Added user-facing hotkeys.md guide with features overview and usage instructions
- Removed old CUSTOMIZABLE_HOTKEYS.md in favor of new split documentation
- Expanded documentation with detailed sections on:
  - State management and persistence
  - Component architecture and responsibilities
  - Developer integration

* Behavior changed to hotkey press instead of input + checking for allready used hotkeys

---------

Co-authored-by: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: dunkeroni <3298737+dunkeroni@users.noreply.github.com>
Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com>
2025-11-16 14:35:37 +00:00
Lincoln Stein 36e400dd5d (chore) Update requirements to python 3.11-12 (#8657)
* (chore) update requirements to python 3.11-12

* update uv.lock
2025-11-08 21:29:43 -05:00