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>
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>
* feat: add configurable shift parameter for Z-Image sigma schedule
Add a shift (mu) override to the Z-Image denoise invocation and expose
it in the UI. When left blank, shift is auto-calculated from image
dimensions (existing behavior). Users can override to fine-tune the
timestep schedule, with an inline X button to reset back to auto.
* refactor: switch Z-Image sigma schedule from exponential to linear time shift
Use shift directly as a linear multiplier instead of exp(mu), giving
more predictable and uniform control over the timestep schedule.
Auto-calculated values are converted via exp(mu) to preserve identical
default behavior.
* feat: recall Z-Image shift parameter from metadata
Write z_image_shift into graph metadata and add a ZImageShift recall
handler so the shift override can be restored from previously generated
images. Auto-mode (null) is omitted from metadata to avoid persisting a
stale value.
---------
Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com>
openapi-typescript computes enum types from `const` usage in
discriminated unions rather than from the enum definition itself,
dropping values that only appear in some union members (e.g. "anima"
from BaseModelType). Add a post-processing step that patches generated
string enum types to match the actual OpenAPI schema definitions.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Alexander Eichhorn <alex@eichhorn.dev>
* fix(ui): replace all hardcoded frontend strings with i18n translation keys
Remove fallback/defaultValue strings from t() calls, replace hardcoded
English text in labels, tooltips, aria-labels, placeholders and JSX content
with proper t() calls, and add ~50 missing keys to en.json. Fix incorrect
i18n key paths in CanvasObjectImage.ts and a Zoom button aria-label bug
in CanvasToolbarScale.tsx.
* chore pnpm run fix
---------
Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com>
* feat(frontend): suppress tooltips on touch devices
* fix(frontend): change selector to role="tooltip" because .chakra-tooltip does not match
* chore(frontend): lint:prettier
* feat: add Anima model support
* schema
* image to image
* regional guidance
* loras
* last fixes
* tests
* fix attributions
* fix attributions
* refactor to use diffusers reference
* fix an additional lora type
* some adjustments to follow flux 2 paper implementation
* use t5 from model manager instead of downloading
* make lora identification more reliable
* fix: resolve lint errors in anima module
Remove unused variable, fix import ordering, inline dict() call,
and address minor lint issues across anima-related files.
* Chore Ruff format again
* fix regional guidance error
* fix(anima): validate unexpected keys after strict=False checkpoint loading
Capture the load_state_dict result and raise RuntimeError on unexpected
keys (indicating a corrupted or incompatible checkpoint), while logging
a warning for missing keys (expected for inv_freq buffers regenerated
at runtime).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(anima): make model loader submodel fields required instead of Optional
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(anima): add Classification.Prototype to LoRA loaders, fix exception types
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(anima): fix replace-all in key conversion, warn on DoRA+LoKR, unify grouping functions
- Use key.replace(old, new, 1) in _convert_kohya_unet_key and _convert_kohya_te_key to avoid replacing multiple occurrences
- Upgrade DoRA+LoKR dora_scale strip from logger.debug to logger.warning since it represents data loss
- Replace _group_kohya_keys and _group_by_layer with a single _group_keys_by_layer function parameterized by extra_suffixes, with _KOHYA_KNOWN_SUFFIXES and _PEFT_EXTRA_SUFFIXES constants
- Add test_empty_state_dict_returns_empty_model to verify empty input produces a model with no layers
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(anima): add safety cap for Qwen3 sequence length to prevent OOM
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(anima): add denoising range validation, fix closure capture, add edge case tests
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(anima): add T5 to metadata, fix dead code, decouple scheduler type guard
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(anima): update VAE field description for required field
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: regenerate frontend types after upstream merge
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: ruff format anima_denoise.py
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(anima): add T5 encoder metadata recall handler
The T5 encoder was added to generation metadata but had no recall
handler, so it wasn't restored when recalling from metadata.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore(frontend): add regression test for buildAnimaGraph
Add tests for CFG gating (negative conditioning omitted when cfgScale <= 1)
and basic graph structure (model loader, text encoder, denoise nodes).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* only show 0.6b for anima
* dont show 0.6b for other models
* schema
* Anima preview 3
* fix ci
---------
Co-authored-by: Your Name <you@example.com>
Co-authored-by: kappacommit <samwolfe40@gmail.com>
Co-authored-by: Alexander Eichhorn <alex@eichhorn.dev>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com>
* feat: Add canvas-workflow integration feature
This commit implements a new feature that allows users to run workflows
directly from the unified canvas. Users can now:
- Access a "Run Workflow" option from the canvas layer context menu
- Select a workflow with image parameters from a modal dialog
- Customize workflow parameters (non-image fields)
- Execute the workflow with the current canvas layer as input
- Have the result automatically added back to the canvas
Key changes:
- Added canvasWorkflowIntegrationSlice for state management
- Created CanvasWorkflowIntegrationModal and related UI components
- Added context menu item to raster layers
- Integrated workflow execution with canvas image extraction
- Added modal to global modal isolator
This integration enhances the canvas by allowing users to leverage
custom workflows for advanced image processing directly within the
canvas workspace.
Implements feature request for deeper workflow-canvas integration.
* refactor(ui): simplify canvas workflow integration field rendering
- Extract WorkflowFieldRenderer component for individual field rendering
- Add WorkflowFormPreview component to handle workflow parameter display
- Remove workflow compatibility filtering - allow all workflows
- Simplify workflow selector to use flattened workflow list
- Add comprehensive field type support (String, Integer, Float, Boolean, Enum, Scheduler, Board, Model, Image, Color)
- Implement image field selection UI with radio
* feat(ui): add canvas-workflow-integration logging namespace
* feat(ui): add workflow filtering for canvas-workflow integration
- Add useFilteredWorkflows hook to filter workflows with ImageField inputs
- Add workflowHasImageField utility to check for ImageField in Form Builder
- Only show workflows that have Form Builder with at least one ImageField
- Add loading state while filtering workflows
- Improve error messages to clarify Form Builder requirement
- Update modal description to mention Form Builder and parameter adjustment
- Add fallback error message for workflows without Form Builder
* feat(ui): add persistence and migration for canvas workflow integration state
- Add _version field (v1) to canvasWorkflowIntegrationState for future migrations
- Add persistConfig with migration function to handle version upgrades
- Add persistDenylist to exclude transient state (isOpen, isProcessing, sourceEntityIdentifier)
- Use es-toolkit isPlainObject and tsafe assert for type-safe migration
- Persist selectedWorkflowId and fieldValues across sessions
* pnpm fix imports
* fix(ui): handle workflow errors in canvas staging area and improve form UX
- Clear processing state when workflow execution fails at enqueue time
or during invocation, so the modal doesn't get stuck
- Optimistically update listAllQueueItems cache on queue item status
changes so the staging area immediately exits on failure
- Clear processing state on invocation_error for canvas workflow origin
- Auto-select the only unfilled ImageField in workflow form
- Fix image field overflow and thumbnail sizing in workflow form
* feat(ui): add canvas_output node and entry-based staging area
Add a dedicated `canvas_output` backend invocation node that explicitly
marks which images go to the canvas staging area, replacing the fragile
board-based heuristic. Each `canvas_output` node produces a separate
navigable entry in the staging area, allowing workflows with multiple
outputs to be individually previewed and accepted.
Key changes:
- New `CanvasOutputInvocation` backend node (canvas.py)
- Entry-based staging area model where each output image is a separate
navigable entry with flat next/prev cycling across all items
- Frontend execute hook uses `canvas_output` type detection instead of
board field heuristic, with proper board field value translation
- Workflow filtering requires both Form Builder and canvas_output node
- Updated QueueItemPreviewMini and StagingAreaItemsList for entries
- Tests for entry-based navigation, multi-output, and race conditions
* Chore pnp run fix
* Chore eslint fix
* Remove unused useOutputImageDTO export to fix knip lint
* Update invokeai/frontend/web/src/features/controlLayers/components/CanvasWorkflowIntegration/useCanvasWorkflowIntegrationExecute.tsx
Co-authored-by: dunkeroni <dunkeroni@gmail.com>
* move UI text to en.json
* fix conflicts merge with main
* generate schema
* Chore typegen
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com>
Co-authored-by: dunkeroni <dunkeroni@gmail.com>
Klein 9B Base (undistilled) and Klein 9B (distilled) have identical
architectures and cannot be distinguished from the state dict alone.
Use a filename heuristic ("base" in the name) to detect the Base
variant for checkpoint, GGUF, and diffusers format models.
Also fixes the incorrect guidance_embeds-based detection for diffusers
format, since both variants have guidance_embeds=False.
* feat: add support for OneTrainer BFL Flux LoRA format
Newer versions of OneTrainer export Flux LoRAs using BFL internal key
names (double_blocks, single_blocks, img_attn, etc.) with a
'transformer.' prefix and split QKV projections (qkv.0/1/2, linear1.0/1/2/3).
This format was not recognized by any existing detector.
Add detection and conversion for this format, merging split QKV and
linear1 layers into MergedLayerPatch instances for the fused BFL model.
* chore ruff
OneTrainer exports Z-Image LoRAs with 'transformer.layers.' key prefix
instead of 'diffusion_model.layers.'. Add this prefix (and the
PEFT-wrapped 'base_model.model.transformer.layers.' variant) to the
Z-Image LoRA probe so these models are correctly identified and loaded.
* Added If node
* Added stricter type checking on inputs
* feat(nodes): make if-node type checks cardinality-aware without loosening global AnyField
* chore: typegen
* Initial plan
* Warn user when credentials have expired in multiuser mode
Agent-Logs-Url: https://github.com/lstein/InvokeAI/sessions/f0947cda-b15c-475d-b7f4-2d553bdf2cd6
Co-authored-by: lstein <111189+lstein@users.noreply.github.com>
* Address code review: avoid multiple localStorage reads in base query
Agent-Logs-Url: https://github.com/lstein/InvokeAI/sessions/f0947cda-b15c-475d-b7f4-2d553bdf2cd6
Co-authored-by: lstein <111189+lstein@users.noreply.github.com>
* bugfix(multiuser): ask user to log back in when authentication token expires
* feat: sliding window session expiry with token refresh
Backend:
- SlidingWindowTokenMiddleware refreshes JWT on each mutating request
(POST/PUT/PATCH/DELETE), returning a new token in X-Refreshed-Token
response header. GET requests don't refresh (they're often background
fetches that shouldn't reset the inactivity timer).
- CORS expose_headers updated to allow X-Refreshed-Token.
Frontend:
- dynamicBaseQuery picks up X-Refreshed-Token from responses and
updates localStorage so subsequent requests use the fresh expiry.
- 401 handler only triggers sessionExpiredLogout when a token was
actually sent (not for unauthenticated background requests).
- ProtectedRoute polls localStorage every 5s and listens for storage
events to detect token removal (e.g. manual deletion, other tabs).
Result: session expires after TOKEN_EXPIRATION_NORMAL (1 day) of
inactivity, not a fixed time after login. Any user-initiated action
resets the clock.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore(backend): ruff
* fix: address review feedback on auth token handling
Bug fixes:
- ProtectedRoute: only treat 401 errors as session expiry, not
transient 500/network errors that should not force logout
- Token refresh: use explicit remember_me claim in JWT instead of
inferring from remaining lifetime, preventing silent downgrade of
7-day tokens to 1-day when <24h remains
- TokenData: add remember_me field, set during login
Tests (6 new):
- Mutating requests (POST/PUT/DELETE) return X-Refreshed-Token
- GET requests do not return X-Refreshed-Token
- Unauthenticated requests do not return X-Refreshed-Token
- Remember-me token refreshes to 7-day duration even near expiry
- Normal token refreshes to 1-day duration
- remember_me claim preserved through refresh cycle
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore(backend): ruff
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: lstein <111189+lstein@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com>
* feat: add bulk reidentify action for models (#8951)
Add a "Reidentify Models" bulk action to the model manager, allowing
users to re-probe multiple models at once instead of one by one.
- Backend: POST /api/v2/models/i/bulk_reidentify endpoint with partial
failure handling (returns succeeded/failed lists)
- Frontend: bulk reidentify mutation, confirmation modal with warning
about custom settings reset, toast notifications for all outcomes
- i18n: new translation keys for bulk reidentify UI strings
* fix typgen
* Fix bulk reidentify failing for models without trigger_phrases
The bulk reidentify endpoint was directly assigning trigger_phrases
without checking if the config type supports it, causing an
AttributeError for ControlNet models. Added the same hasattr guard
used by the individual reidentify endpoint. Also restored the
missing path preservation that the individual endpoint has.
* Repair partially loaded Qwen models after cancel to avoid device mismatches
* ruff
* Repair CogView4 text encoder after canceled partial loads
* Avoid MPS CI crash in repair regression test
* Fix MPS device assertion in repair test
* fix(ui): resolve models by name+base+type when recalling metadata for reinstalled models
When a model (IP Adapter, ControlNet, etc.) is deleted and reinstalled,
it gets a new UUID key. Previously, metadata recall would fail because
it only looked up models by their stored UUID key. Now the recall falls
back to searching by name+base+type, allowing reinstalled models with
the same name to be correctly resolved.
https://claude.ai/code/session_01XYubzMK363BXGTvfJJqFnX
* Add hash-based model recall fallback for reinstalled models
When a model is deleted and reinstalled, it gets a new UUID key but
retains the same BLAKE3 content hash. This adds hash as a middle
fallback stage in model resolution (key → hash → name+base+type),
making recall more robust.
Changes:
- Add /api/v2/models/get_by_hash backend endpoint (uses existing
search_by_hash from model records store)
- Add getModelConfigByHash RTK Query endpoint in frontend
- Add hash fallback to both resolveModel and parseModelIdentifier
https://claude.ai/code/session_01XYubzMK363BXGTvfJJqFnX
* Chore pnpm fix
* Chore typegen
---------
Co-authored-by: Claude <noreply@anthropic.com>
When deleting a file-based model (e.g. LoRA), the previous logic used
rmtree on the parent directory, which would delete all files in that
folder — even unrelated ones. Now only the specific model file is
removed, and the parent directory is cleaned up only if empty afterward.
* feat: add strict_password_checking config option to relax password requirements
- Add `strict_password_checking: bool = Field(default=False)` to InvokeAIAppConfig
- Add `get_password_strength()` function to password_utils.py (returns weak/moderate/strong)
- Add `strict_password_checking` field to SetupStatusResponse API endpoint
- Update users_base.py and users_default.py to accept `strict_password_checking` param
- Update auth.py router to pass config.strict_password_checking to all user service calls
- Create shared frontend utility passwordUtils.ts for password strength validation
- Update AdministratorSetup, UserProfile, UserManagement components to:
- Fetch strict_password_checking from setup status endpoint
- Show colored strength indicators (red/yellow/blue) in non-strict mode
- Allow any non-empty password in non-strict mode
- Maintain strict validation behavior when strict_password_checking=True
- Update SetupStatusResponse type in auth.ts endpoint
- Add passwordStrength and passwordHelperRelaxed translation keys to en.json
- Add tests for new get_password_strength() function
Co-authored-by: lstein <111189+lstein@users.noreply.github.com>
* Changes before error encountered
Co-authored-by: lstein <111189+lstein@users.noreply.github.com>
* chore(backend): docstrings
* chore(frontend): typegen
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: lstein <111189+lstein@users.noreply.github.com>
Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com>
* fix(gallery): restore arrow-key browsing and extract shared prev/next navigation
* Added same behavior to Upscale mode and autofocus to gallery after using hotkeys Ctrl+Enter and Ctrl+Shift+Enter
* restore arrow navigation focus flow across viewer states
* fix(gallery): stabilize arrow-key browsing, remove viewer UI flicker, and optimize code
---------
Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com>
LoRAs trained with musubi-tuner (and potentially other trainers) that
only target transformer blocks (double_blocks/single_blocks) without
embedding layers (txt_in/vector_in/context_embedder) were incorrectly
classified as Flux 1. Add fallback detection using attention projection
hidden_size and MLP ratio from transformer block tensors
Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com>
* perf(flux2): optimize model loading order to prevent cache eviction (fixes#7513)
* Update flux2_klein_text_encoder.py
* Update flux2_klein_text_encoder.py version
---------
Co-authored-by: Alexander Eichhorn <alex@eichhorn.dev>
Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com>