Skip to content

v2.16.1#1665

Merged
mohnjiles merged 37 commits into
mainfrom
main
Jun 16, 2026
Merged

v2.16.1#1665
mohnjiles merged 37 commits into
mainfrom
main

Conversation

@mohnjiles

Copy link
Copy Markdown
Contributor

Added

  • Added automatic text encoder and VAE selection to the Inference Model card. Selecting a model now fills any empty encoder slots and the default VAE with the matching local files for the detected workflow, so you don't need to know which files pair with which architecture (e.g. qwen_3_4b or qwen_3_8b + Flux.2 VAE for Flux.2 Klein, clip_l + t5xxl for Flux, qwen_3_06b + qwen_image_vae for Anima). Anything you pick manually is never overridden
  • Added a misplaced-model warning to the Inference Model card with a one-click Move button. If a model sits in a folder that can't work with the selected workflow (like a Z-Image or Anima file in the StableDiffusion folder), a compact warning explains the problem instead of letting generation fail with a cryptic ComfyUI error. The Move button relocates the file and its metadata to the right folder, then re-selects it. Dismissible per model
  • Added a native macOS menu bar with the standard application menu — About Stability Matrix, Settings… (⌘,), and the usual Services / Hide / Quit (⌘Q) items

Changed

  • The Inference Workflow selector now switches the model loader to match the chosen profile, showing or hiding the separate encoder and VAE fields as appropriate. It will never switch to a loader that can't load the selected file; you get the warning above instead
  • Renamed the "Anima / SD" workflow profile to "Anima". Anima has no all-in-one version, so it's now handled like Z-Image: standalone model in DiffusionModels with a separate text encoder and VAE
  • Image Lab's Flux.2 Klein model checks now match the text encoder to your selected UNET variant (4B vs 9B), and switching variants updates the status banner immediately
  • Image Lab's Flux Kontext and Qwen Image Edit providers now show ComfyUI's actual workflow rejection message instead of a generic "Generation failed" (Flux.2 Klein already did this)
  • Image Lab now opens the same ComfyUI error detail dialog that Inference uses when a workflow is rejected or a node fails mid-generation, showing the full error JSON instead of a truncated toast
  • Keyboard shortcuts now use ⌘ (Command) instead of Ctrl on macOS — save/open, Generate, undo/redo, copy/paste/cut, tab navigation, and the mask editor all follow the platform convention, and context menus show the ⌘ glyph

Fixed

  • Fixed #1659 - Z-Image and Anima workflows hiding the Text Encoder selectors and passing an invalid None CLIP input to ComfyUI; standalone workflows now expose and automatically fill compatible text encoders and VAEs
  • Fixed #1654 and #1658 - Inference Image-to-Image masks could disappear in Linux AppImage builds, fail to appear in the image-card preview, or crash the app when saving an enabled clipping mask because Avalonia retained pixels owned by a disposed Skia image; converted mask bitmaps now own their pixel data and previews refresh after editing, restoring a project, or loading image dimensions
  • Fixed #1660 - CivArchive downloads always saving to the model folder root; the primary Download button now offers the inferred folder, existing subdirectories, and a custom folder picker, while filename patterns containing path separators create missing nested subfolders and keep downloads inside the selected models directory
  • Fixed #1661 - Custom UNet workflows missing current ComfyUI encoder types such as sdxl; the selector now includes current CLIP loader values while retaining single-encoder compatibility and migrating legacy HiDream casing
  • Fixed #1664 - Gemini failures with a saved key being misreported as "API key not configured"; Image Lab now shows the actual invalid-key, billing, quota, or permission error and explains that Nano Banana image generation requires a paid-tier API key from a Google AI project with billing enabled
  • Fixed "No text encoders configured" errors when generating with an all-in-one checkpoint after a UNet model had been selected in the same tab
  • Fixed Qwen Image Edit in Image Lab failing mid-generation when a wrong-size Qwen2.5-VL text encoder was installed. The 7B encoder is now required, and the correct download is offered when it's missing
  • Fixed Image Lab reporting "all models present" for Flux.2 Klein 9B setups that only had the 4B text encoder (and vice versa). The matching encoder download is now offered
  • Fixed Image Lab model and LoRA dropdowns hiding files whose CivitAI base model tag is unrecognized (commonly "Other"), even when the filename clearly matches the provider
  • Fixed Animagine XL and other SDXL models with "anima" in the name being misdetected as the Anima architecture
  • Fixed the running-package exit confirmation not appearing when quitting via ⌘Q, the macOS app menu, or the Dock — it previously only showed when closing the window directly, so those paths could tear down running packages without warning. All quit paths now prompt
  • Fixed an empty strip of space appearing below the native window title bar on macOS and Linux; the Windows-only caption area (icon, title, and min/max/close buttons) is now collapsed on those platforms so content sits directly under the system title bar

Performance

  • Optimized SKBitmap-to-WriteableBitmap conversion used throughout Inference and Image Lab; pixel data is now copied directly native-to-native (single bulk copy when strides match, per-row otherwise) instead of round-tripping every scanline through a temporary managed buffer, reducing allocations and GC pressure on full-resolution images

Supporters

🌟 Visionaries

A massive thank you to our brilliant Visionaries: Waterclouds, bluepopsicle, Ibixat, Droolguy, snotty, LG, whudunit, MrMxyzptlk12836, Psilocyfer18731, KalAbaddon, and moon_milky2843! There's a little of your support behind every fix and refinement in this update, and we're grateful for all of it. A warm welcome to our newest Visionary, cusalapapen1481; it's wonderful to have you with us! 💛

🚀 Pioneers

And an equally big thank you to our fantastic Pioneer crew, all familiar faces this time around: Szir777, [USA]TechDude, SinthCore, Jisuren, Tigon, jweg79, rwx14662, Hurbie53, ahnhj.al, drew.lukas, Tuskaruho, Cjloha, Alligator1907, Bitti, Ghislain G, CommissarGiygas16050, qob97515211, bastardofbethlehem, and Zombop! You keep showing up for us, and that steadiness is a big part of how this project keeps moving forward. Thank you, truly, every one of you. 💛

mohnjiles and others added 30 commits June 9, 2026 22:36
Only Flux2KleinProvider caught Refit ApiException and showed ComfyUI's
node-validation message; Flux Kontext and Qwen Image Edit collapsed the
same failures into a generic "Generation failed", hiding the actual
problem (wrong encoder, missing file, etc.) from the user. Bring both
providers up to parity with the Klein handler.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The three Image Lab local providers (Flux Kontext, Qwen Image Edit,
Flux.2 Klein) and their workflow builders carried heavily duplicated
ComfyUI plumbing — identical in all three copies. Extract the genuinely
shared logic into three helpers in StabilityMatrix.Avalonia/Helpers,
removing ~480 lines of duplication while leaving provider-specific logic
(model detection, node graphs, per-provider settings) untouched.

- ComfyProgressReporter: a disposable that reports the initial "Queued"
  stage, subscribes to the ComfyTask progress events, dedups updates by
  (percent, running node), and unsubscribes on dispose. Replaces the
  per-provider local-function block.
- ComfyGenerationHelper: SelectOutputImages (prefer "SaveImage", else
  first non-empty output), GetMimeTypeForFileName, and Truncate (the
  three copied provider helpers now share one home).
- ComfyWorkflowHelper: GetReferenceImageNames parameterized over the only
  things that differed (max image count + filename prefix), and ApplyLoras
  for the LoRA-chaining loop.

Also remove the vestigial IsFluxKontextAvailable observable property in
BananaVisionPageViewModel — it was set seven times in UpdateProviderStatus
but never read (no binding, no consumer). And log a warning when the
fire-and-forget InterruptPromptAsync faults instead of swallowing it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add ArgumentNullException.ThrowIfNull for the required task/providerId
constructor args of the reusable ComfyProgressReporter, matching the
existing pattern used elsewhere in the codebase. The other review
suggestions (null checks in SelectOutputImages/GetMimeTypeForFileName/
Truncate) were declined: their inputs are statically non-null under
nullable reference types at the only call sites (ComfyImage.FileName is
`required`, GetImagesForExecutedPromptAsync returns a non-null dictionary,
Exception.Message is never null), so the guards would be redundant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Image Lab failures only surfaced a truncated toast/bubble message while
Inference opened a JSON detail dialog for the same errors. Carry the raw
ComfyUI error body (queue-time ApiException content or execution-time
ComfyNodeException JSON) through ImageGenerationResponse and
ImageGenerationException so the chat page can open the same
DialogHelper.CreateJsonDialog Inference uses. Node-execution errors were
previously caught by the generic handler and lost their details
entirely; they now also get a short node-name summary in the chat.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Move the user-facing strings added for the Inference folder-mismatch
warning, the one-click model move, and the Image Lab Comfy error dialog
out of code and into Languages/Resources.resx so they can be translated
like the rest of the UI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Keeps the folder-mismatch warning text consistent with every other
SharedFolderType display in this file and with the canonical folder
naming used by RelativePathFromSharedFolder.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…orkflow-fixes

[codex] Improve inference model workflow handling
…ders

Addresses review feedback that the three Image Lab providers still shared a
near-identical GenerateAsync skeleton after the helper extraction — the
connection check, prompt queue, cancellation/interrupt registration, output
download loop, and four catch arms were copy-pasted in all three.

Pull that whole flow into an abstract ComfyImageGenerationProviderBase
(template method), mirroring the existing InferenceGenerationViewModel base
pattern. Subclasses now supply only:
  - ProviderId / ProviderName / LogName / MaxInputImages / ProviderPrefix
  - GetMissingModels(request)  — provider model requirements
  - BuildWorkflow(request)     — option parsing + node graph

Shared provider-option parsing (custom UNET, LoRAs, dimensions) moves to
protected base helpers used by all three. Each provider drops from ~190 lines
to ~45-95; net -250 lines.

Provider-specific logic stays in the subclasses: Flux.2 Klein keeps its
variant-aware model check and Steps/Cfg/ExplicitDimensions options. Because the
providers are DI singletons the base stays stateless per request, so Klein
re-resolves its UNET in both GetMissingModels and BuildWorkflow; a
logSelection:false flag avoids logging the same selection twice.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…omfy-helpers

Consolidate duplicated ComfyUI plumbing across Image Lab providers
…ialog

Comfy error detail dialog for Image Lab + localize new strings
…encoders

Addresses several Inference / Image Lab / CivArchive issues:

- Masks (LykosAI#1654, LykosAI#1658): Skia->Avalonia bitmap conversion now copies pixels into
  a WriteableBitmap instead of wrapping a pointer owned by a disposed SKImage, so
  enabled clipping masks no longer disappear, fail to preview, or crash on save.
  MaskEditor disposes both cached render images; SelectImageCard exposes a
  MaskOverlayImage that refreshes after editing, restore, or size load.

- CivArchive downloads (LykosAI#1660): the primary Download button is now a SplitButton
  offering the inferred folder, existing subdirectories, and a custom folder
  picker. Install locations are modelled as a typed InstallLocationOption (no more
  stringly-typed "Models\" round-trip or "Custom..." equality), and the directory
  scan runs off the UI thread. ModelImportService sanitizes each pattern path
  segment and drops rooted/traversal input so downloads stay inside the models dir.

- Custom UNet encoders (LykosAI#1661): ClipTypes now lists ComfyUI's current DualCLIPLoader
  values while keeping single-encoder compatibility and migrating legacy "HiDream"
  casing to "hidream".

- Gemini errors (LykosAI#1664): providers return a machine-readable ImageGenerationErrorCode
  instead of a baked English string, so Image Lab shows the actual invalid-key,
  billing, quota, or permission error (localized) and explains that Nano Banana
  needs a paid-tier key with billing enabled. Account/key dialogs are localized,
  and the add-key dialog now gives step-by-step setup instructions with the AI
  Studio and Cloud billing links.

Adds a debug-only "Gemini error dialogs" panel in Settings to preview each error
through the real handlers, plus unit/UI tests for the path sanitization, encoder
list, and pixel-ownership conversion.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- ToAvaloniaBitmap(SKImage) now peeks pixels directly and only falls back to
  SKBitmap.FromImage for GPU-backed images, removing a redundant full-image copy.
- CivArchive install-location enumeration is wrapped so an inaccessible
  subdirectory no longer fails the whole scan, keeping the default and custom
  options available.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The TitleBarHost row hosts the window icon, title, and caption buttons on
Windows, but those are all native (and hidden) on macOS/Linux, leaving an
empty ~32px band under the system title bar. Collapse the row height to 0 on
non-Windows platforms so content sits directly below the native title bar.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
On-screen rendering leases a GPU Skia surface, so the persistent layer
surfaces are GPU-backed and owned by the render thread. Off-screen export
(e.g. saving an Image Lab annotation) composites onto a CPU surface from the
UI thread; reusing those GPU surfaces there produced a fully blank image.
RenderToSurface now recreates a layer surface when its GPU/CPU backing doesn't
match the current target, so exports composite correctly and the next
on-screen render simply recreates the GPU surface.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Keyboard shortcuts were hardcoded to Ctrl everywhere, which is wrong on macOS
where the command key is ⌘ (Meta).

- Add a PlatformGesture markup extension that swaps the Ctrl token for Cmd on
  macOS, and convert all XAML KeyBinding/HotKey/InputGesture definitions
  (save/open, generate, undo/redo, copy/paste/cut, tab nav, mask ops) to use it
  so both the binding and the displayed glyph follow the platform.
- Add PlatformKeyModifiers.CommandModifier (Meta on macOS, Control elsewhere)
  and apply it to code-behind modifier checks: image paste, search focus,
  paint undo/redo, mask-editor layer ops, and wheel-resize/zoom (which also
  avoids clashing with the macOS Ctrl+scroll screen-zoom gesture).

Completion trigger (Ctrl+Space) and drag-to-copy are intentionally left on
Ctrl, matching macOS conventions for those actions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
macOS apps are expected to have a native menu bar with a proper app menu.
Avalonia's native backend builds the app menu from NativeMenu.GetMenu(Application)
during AppBuilder's AfterSetup phase, then auto-appends the standard
Services/Hide/Quit (⌘Q) items. Set our menu in Application.Initialize() — which
runs just before that phase — so About Stability Matrix and Settings… (⌘,)
appear in the app menu instead of Avalonia's default "About Avalonia" menu.
Setting it later (or on the window) is too late and yields the default or a
duplicate menu. Text-editing shortcuts (⌘C/V/X/Z/A) are handled natively.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The running-package confirmation only fired on the window close button
(MainWindow.OnClosing, WindowClosing reason). ⌘Q, the native app menu Quit, and
dock Quit route through lifetime shutdown and skipped it, tearing down running
packages without warning.

Move the confirmation into App.OnShutdownRequested so every quit path is covered,
and route the window close button through App.Shutdown() so there is a single
confirmation flow. A guard flag prevents a second prompt on the follow-up
shutdown after the user confirms.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Cancel re-entrant shutdown requests while async dispose is in progress until it
  completes, so we don't Environment.Exit before settings/database flushes finish.
- Guard the exit confirmation with an isConfirmingExit flag so rapid repeated quit
  requests don't stack multiple dialogs.
- Resolve RunningPackageService from the already-non-null serviceProvider instead
  of the nullable static Services property.

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

Fix Image Lab Gemini errors, I2I masks, CivArchive downloads, custom encoders
macOS UX: ⌘ shortcuts, native app menu, and exit confirmation
Add the Visionaries and Pioneers sections for the 2.16.1 release,
sourced from the hall-of-fame roster and cross-checked against the
v2.16.0 section plus the annual-carryover and name-mapping notes:

- Carry over annual patrons absent from the monthly export (Ghislain G,
  SinthCore, whudunit) so nobody is dropped prematurely.
- Use established clean display names for long-standing supporters
  (Waterclouds, Tigon, [USA]TechDude) and raw handles otherwise.
- cusalapapen1481 is the only genuinely new supporter this release;
  every Pioneer is a returning face, so no new-Pioneer welcome.
- Avoid em dashes per house style.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
mohnjiles and others added 7 commits June 15, 2026 14:02
CopyPixelRows allocated a managed byte[] and did a double copy
(native -> managed -> native) for every scanline, adding GC pressure
on full-resolution images. Switch to unsafe Buffer.MemoryCopy for a
direct native-to-native copy with no per-row allocation.

Also cast the row offset to long to avoid int overflow on very large
images, and drop the now-unused System.Runtime.InteropServices import.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When sourceRowBytes == destinationRowBytes the pixel buffer is
contiguous, so copy the whole thing in a single Buffer.MemoryCopy
instead of looping per scanline. Falls back to the per-row copy when
strides differ (alignment padding).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Optimize SkiaExtensions pixel copy with zero-alloc MemoryCopy

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors local image generation providers into a shared base class, introduces automatic text encoder and VAE selection, adds a misplaced-model warning with a one-click move feature, and improves macOS platform integration with native menus and Command-key shortcuts. It also optimizes bitmap conversions and enhances CivArchive download folder selection. The code review identified several improvement opportunities, including ensuring DirectoryPath.FullPath is used in path calculations, initializing the mask editor's canvas size if the bitmap size is already populated, refactoring prompt interruption to guarantee CancellationTokenSource disposal, using null-safe string comparisons for enum values, and adding defensive null checks for LoRA models.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread StabilityMatrix.Avalonia/ViewModels/Inference/ModelCardViewModel.cs
Comment thread StabilityMatrix.Avalonia/Helpers/ComfyWorkflowHelper.cs
@mohnjiles mohnjiles merged commit d97f6cc into LykosAI:main Jun 16, 2026
3 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 16, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

2 participants