- Shift+click "Send to ComfyUI" sends mode=replace, but mergeLoras keeps
the saved active flag of entries already in the list, so a listed but
disabled LoRA stayed off after the textarea was replaced.
- Call the shared enableListedLoras() after the merge, as the append path
does, so replace turns the target on and keeps its saved strength.
- Cover the path with the real mergeLoras in the send-to-comfy tests.
Based on the replace-mode coverage in willmiao/ComfyUI-Lora-Manager#1096.
Co-authored-by: Alexandre Zia <11000327+alexandrezia@users.noreply.github.com>
In legacy canvas rendering the search box and the LoRAs list sat flush on a
fresh node, and their gap grew while the node was resized. The canvas branch
of applyAutocompleteTextLayoutFix tried to clear the custom sizing with
`delete`, but computeLayoutSize() lives on DOMWidgetImpl.prototype, so the
delete was a no-op. The text widget stayed growable (60-100px) and shared the
node's free space with the LoRAs widget, while its 60px min-height overflowed
the DOM widget's 10px bottom margin: the visible gap was
min(20, allocation - 60).
Shadow computeLayoutSize with an own undefined property and give the widget a
fixed computeSize. Adjacent ComfyUI DOM widgets normally keep a 2 * margin
(20px) gap, which is too wide for the search box + LoRA list pair, so
allocate elementHeight + 8px instead: the search box stays 60px and the gap
stays constant at any node height, matching Vue node mode.
Also document the overlay margin math and the prototype-shadowing constraint
in the dual-mode widget guide.
The "already added" cue was a single check, so a listed-but-disabled
LoRA looked identical to an enabled one, and picking either inserted a
duplicate tag that left the disabled entry off.
Show two states — a green "Added" pill and an amber "Off" pill — and
make the pick act on them: an added LoRA is enabled in place (reusing
the shared add-or-enable helper), an active one is left alone, and the
typed query is removed either way so no duplicate tag or stray search
text is left in the prompt.
Co-authored-by: smhc <6404304+smhc@users.noreply.github.com>
Node rows can show library titles (Settings > LoRA Manager > Node LoRA
Name Display), but the textarea autocomplete only ever searched file
names. In "Model Name" mode a title fragment that does not appear in the
file name therefore returned nothing, even though the LoRA was visible
on the node.
Title matching follows the existing label setting instead of adding a
new toggle: File Name mode (the default) sends the unchanged request and
gets the same results and ordering as before. Only Model Name mode asks
the endpoint for title matches, which are appended after every filename
match so a path search is never reordered or hidden. The dropdown then
shows the title as the primary row label with the file name as secondary
text, matching what the node rows display.
Also cue results that are already on the node. The set is read from the
node's LoRA list (falling back to the textarea tags), normalized like the
backend resolves names, so legacy bare-name entries are recognized too.
Co-authored-by: smhc <6404304+smhc@users.noreply.github.com>
"Send to ComfyUI" appended a tag for a LoRA the node already listed,
which left a disabled entry disabled and made the button look broken.
Route the append path through shared add-or-enable helpers: listed LoRAs
are switched on in place (strengths kept), unlisted ones still append.
Reused from willmiao/ComfyUI-Lora-Manager#1181.
Co-authored-by: smhc <6404304+smhc@users.noreply.github.com>
- Send version_name only for titles shared by several files and guard
non-dict civitai values, so the cycler payload stays small.
- Keep cached labels after the availability TTL expires instead of
flashing file names while a refresh is in flight.
- List every covered node in the setting tooltip.
- Cover the payload rules and the stale-cache labels with tests.
The Always Randomize / Generate Fixed / Reuse Last buttons replace the
displayed loras without touching the seed chain, so the next queue's
beforeQueued shifted the stale seeds and the backend regenerated the
previous seeded roll, silently discarding what the widget displayed.
Reset the seed chain on manual rolls so the next execution takes the
first-execution path and runs the displayed loras.
ComfyUI creates every node before configuring any of them, so while a Lora
Loader restores its `loras` widget the upstream cycler/randomizer already
exists but still holds its factory-default config. The resulting sync
resolved an empty LoRA set, cleared the connected TriggerWord Toggle, and the
upstream node's own configure repopulated it a moment later. A draft or
change-tracker snapshot taken in that window keeps the cleared state as the
baseline, so the repopulated - and correct - graph compares dirty.
Coalesce syncs per source node and send only the last computed set. The
pending timer is stored on the node because utils.js is loaded twice (directly
by lora_loader.js and inlined into the Vue widget bundle), so both call sites
have to share it.
Reproduced on Lora_Cycler: the tracker baseline held
`toggle_trigger_words: []` / `orinalMessage: ""` while the live graph matched
the saved file byte for byte.
The pool and cycler widgets recompute derived state shortly after a workflow
loads (preview count, current cycle index/name). Writing that back made the
serialized node differ from the saved JSON, so ComfyUI's ChangeTracker marked
the untouched workflow modified on the next mouseup - the comparison only runs
on canvas interaction, which is why it looked like clicking dirtied it.
- Lora Pool: serialize `preview` only when the filter selection changed; the
live preview (match count) still refreshes on mount and on filter edits.
- Lora Cycler: the mount refresh and the first pool-config resolution (the
link only becomes resolvable once the graph is configured) update the UI
without rewriting the saved config. User edits and queue time still sync it.
Covered by the useLoraPoolState, useLoraCyclerState and LoraCyclerWidget
load-time tests.
Preview URLs now carry a cache-busting `&v=<mtime_ns>` suffix, so the media
type could no longer be read from the end of the string. Model cards,
duplicates, recipe cards and modals, the showcase thumbnail and the ComfyUI
preview tooltip all fell into the image branch and rendered `<img>` for video
previews, which browsers cannot decode.
Move the query-aware video detection that already lived in the versions tab
into a shared mediaTypes helper and use it everywhere a server-provided
preview URL is inspected. The web UI and the ComfyUI widget bundle each keep a
copy because they are served from different mounts. Video previews that turn
out to be webm now also get the right `<source type>`.
Add regression coverage for versioned mp4/webm/image URLs.
Fixes#1168
The chips marked as coming from the selected LoRA were outlined with
--lm-warning-border, an amber at 55% alpha. Composited over the Light
palette's #C9C9C9 that lands at 1.09:1, so the highlight practically vanished,
and amber already means "warning" elsewhere (out-of-range strength, locked
LoRA). The translucent ring also sat on the chip border with the black shadow
behind it, reading as a fuzzy third edge.
Replace it with an offset ring: a 1px gap in --lm-surface, then a 2px ring
mixed from --lm-accent and --lm-fg. Both tokens follow the palette, so the
ring stays at 5.6:1 on Light and 9.0:1 on Dark, over both an active (accent)
and an inactive chip, and the gap matches the container background in the
canvas and Vue node renderers. The ring extends only 3px, so the existing 6px
gap and 1px margins already leave room; no layout or JS changes.
Re-declare the ring on hover: .comfy-tag:hover has the same specificity and
comes later, so hovering used to replace the whole box-shadow and drop the
highlight.
Since frontend 1.16 the loader rebuilds a node's inputs from the node
definition - which now inserts `seed` - and then repairs every link target by
slot name. The prompt extension renamed `trigger_words` and appended a slot
during that same configure pass, so `filtered_trigger_words` could no longer be
matched by name and kept its saved target slot, which by then addressed the
`text` widget input (the textarea disappeared and the link was drawn into it).
Dynamic slots also drifted out of order and numbering.
Skip every slot mutation while the graph configures, keep `localized_name` in
sync when renumbering (the label prefers it over `name`), and normalize legacy
layouts once the graph has loaded: connected slots first, exactly one trailing
empty slot, numbered 1..n. Nodes already in the canonical layout are left
untouched, so loading does not mark workflows dirty.
The backend now accepts the bare `trigger_words` name used by workflows saved
before the current definition. The Lora_Randomizer and Lora_Cycler templates
are migrated to the canonical layout.
TriggerWord Toggle serialized the transient `highlighted` UI state into
widgets_values, but highlight is recomputed after load from the current
selection/library, so an untouched workflow always compared dirty against
the saved JSON and ComfyUI prompted to save on close. Strip `highlighted`
from serialized tag values (backend never reads it).
Also restore saved widget values by widget name instead of positional
index (position drift corrupted unrelated widget slots on load), and
preserve `locked` in mergeLoras so load-time merging no longer drops it.
Workflows saved with `highlighted` keys will show as modified once after
upgrading; saving them once writes the clean format.
Fixes#893
ComfyUI exposes commands and menuCommands for the menu bar, but the
workflow tab context menu is built inside WorkflowTab.vue and has no
extension hook. Reuse the registered create/update actions and inject
the entries into the reka-ui portal, the same fallback the Graph menu
already uses.
The entries sit above the tab-close group. Clicking one activates the
right-clicked tab through app.extensionManager.workflow.openWorkflow
(the switch the native Save/Export entries use), so the action targets
that tab's graph instead of whichever tab was active. Update is enabled
from that tab's own lm_source marker and link-status check, and a menu
instance is only enhanced once.
- Replace the multi-root folder_paths.workflows workflow library with a
scalar workflow_path setting (Settings > Library); remove the
extra_folder_paths.workflows path and the standalone Model Paths editor.
- Migrate pre-release settings.json files that still keep
folder_paths.workflows / extra_folder_paths.workflows on startup, so an
upgrade keeps the configured folder instead of silently losing it.
- Add "Create LM-managed workflow" to the ComfyUI Graph menu and the File
menu/command palette: it writes the serialized graph into the configured
folder, stamps extra.lm_source and registers the entry in the scanner
cache without forcing a rescan.
- Attach the decode image of the client's last executed prompt as the
workflow preview. The prompt id is sent with the create request and the
backend only honors it while it is still the registry's current prompt,
so a tab never borrows another tab's output; otherwise the card keeps the
placeholder preview.
- Detect library entries deleted/renamed while a graph still carries the
marker: a link-status endpoint clears the stale extra.lm_source (on graph
load, menu open and before create/update), and the write-back route
returns 404 instead of recreating the document.
- Collapse the workflows.noPaths standalone/ComfyUI split into a single
description/hint; the folder is edited in Settings > Library in both
modes, so the manual settings.json guidance and the standalone
open-settings-folder fallback are gone.
- Add the preview tensor conversion as a shared utility (reused by the
recipe widget save path) and cover create, preview gating, link status,
migration and menu injection with tests.
LM widgets were painted with a fixed dark palette: translucent slate fills
plus light text. On the dark palettes those values happened to blend into the
node, but on the Light palette the translucency composited into grey slabs and
light text landed on light surfaces. The prompt textarea was the clearest
case: it used the fixed --color-charcoal-400 scale token, which never flips
with the theme, so it stayed charcoal inside a white node.
Add web/comfyui/lm_theme.css as the single colour layer. Every value aliases the
active ComfyUI palette (--comfy-input-bg, --component-node-*, --comfy-menu-bg,
...) and derives raised/hover/selected surfaces with color-mix, so built-in and
user-imported palettes are covered without per-theme rules. Contexts select the
token family the neighbouring built-in widget uses: lm-widget-root for canvas
DOM widgets, lm-vue-node for the Vue node renderer, lm-popover for menus
appended to <body>. Only status colours, shadows and scrims keep a light/dark
variant. Whole-node containers no longer paint a background, so the node
surface shows through and only inputs, cards and buttons are filled.
lm_styles.css, the canvas widget JS (autocomplete dropdown, tag chips, group
editor) and all Vue SFC styles now consume these tokens; tag category badges
derive their hue from oklch tokens so the tint and text contrast flip with the
theme. Empty states get an explicit 12px size: the canvas DOM overlay inherits
the 16px body size while Vue nodes render at text-xs, which made the
placeholders oversized and heavy in canvas mode.
A regression test rejects new colour literals outside the preview-image
overlays, and the DOM widget guide documents the token map and the
blend-don't-overlay rule. Rebuilt the committed vue-widgets bundle.
Add an Update from ComfyUI entry to the workflow card context menu,
enabled only when the workflow is the active graph in a connected
ComfyUI tab and carries unsaved edits.
ComfyUI side (workflow_writeback.js): the first graphChanged after a
load/write-back flips a dirty flag inside the extra.lm_source marker
(ChangeTracker only dispatches on real state changes); the active
graph's link state (file_path, sha256, dirty) is reported to
POST /api/lm/workflows/comfyui-state on load, tab switch, dirty flip
and write-back. A new lm_collect_workflow WS handler answers LM-page
write-back requests: it reuses the regular PUT content flow and posts
the outcome to /api/lm/workflows/collect-result.
Backend: an in-memory WorkflowLinkRegistry holds per-client link states
(pruned against live websocket sids) and pending collect futures;
POST /api/lm/workflows/update-from-comfy targets the tab holding the
requested file (dirty holders win) and awaits the collect result,
mapping no_changes/cancelled to 200, timeout to 504.
Open in ComfyUI now stamps an extra.lm_source provenance marker
(file_path + document sha256) onto the loaded graph, which rides the
workflow draft serialization across tabs and reloads. A new
LoraManager.UpdateManagedWorkflow command (palette, menubar File group,
and an item injected into the workflow actions dropdown; disabled unless
the active graph carries the marker) serializes the current graph and
PUTs it to /api/lm/workflows/content.
The write targets the workflow document: bare .json artifacts are
rewritten in place, while zip/image containers keep their original bytes
(the SHA256 is their CivitAI identity) and receive the edited graph in
the derived .workflow.json sidecar. Optimistic concurrency via
base_sha256 rejects writes with 409 when the library copy changed since
open (force retries after user confirmation). Post-write, analysis
fields and (for .json artifacts) hash/size/modified are refreshed in the
metadata sidecar and caches.
Anima 2.9B/3.8B insert blocks between the original 28, so old LoRA keys land on the wrong layers and ComfyUI emits no missing-key warning. Add a model-family adapter that rewrites block indices in memory before the generic LoRA loader runs.
- 28->40, 40->52 and composed 28->52 mappings, with anchored kohya/generic key patterns
- Anima detection from image_model/llm_adapter and block count from blocks/num_blocks
- skip text encoder, llm_adapter and semantic connector keys; collision and newer-LoRA errors
- ComfyUI setting (default on) synced to the LM settings API; no base-model-specific node toggle
- docs, unit and loader integration tests
Reuses the manifest data from PR #1104; supersedes its node-level toggle design.
Add a Workflows page that manages ComfyUI workflow JSON files as a
first-class library alongside loras/checkpoints/embeddings:
- opt-in via the new 'Workflow Management' settings toggle (default off)
- dedicated workflow folder roots with sidecar/preview support, separate
from ComfyUI's own workflow storage; 'Send to ComfyUI' loads a workflow
straight into the graph
- workflow scanner parses the graph document (UI/API format sniffing,
node classes, model/civitai refs) and persists the analysis in the
SQLite model cache
- settings UI: workflow folder paths editor in the Library tab and the
standalone Model Paths page
Fixes from sandbox E2E verification:
- include the workflow scanner in startup initialization so the page no
longer hangs on 'initializing' when enabled without folders
- add the missing workflows entry to the frontend page-state map (page
init crashed and the sidebar fell back to the loras tree without it)
- project workflow analysis fields through the scanner cache entry and
persist them in the model cache (new columns with auto-migration)
- keep symlinked paths intact in the directory picker (abspath instead
of resolve), so stored library paths match what the user sees on disk
Also rebuilds the vue-widgets bundle to sync it with web/comfyui/utils.js.
Promoted combo widgets on a subgraph boundary hold their own store-backed
copy of the interior widget's value, seeded from the workflow's serialized
widgets_values, so migrating the interior loader widget never reached them:
the boundary combo kept the old backslash spelling, the frontend flagged it
as a missing model on load, and the error entry (keyed to the host node)
survived the interior node's onWidgetChanged.
- migrateWidgetValue generalizes the separator migration to any widget.
- applyToAllNodes now also migrates the projected boundary widgets of every
subgraph node; their value setter writes through to the frontend's widget
store, and firing the host node's onWidgetChanged clears the host-keyed
error entries. Fixing the values before the post-load missing-model scan
means the flags are never raised at all.
- The per-node onConfigure hook schedules a boundary sweep via
queueMicrotask so pasted subgraph nodes (which bypass the graph-level
configure hook) get covered once the paste settles.
The frontend serializeValue hook resolved %date:...% at queue time, baking
the queue timestamp into the serialized prompt. Prompts queued within the
same second (or re-run from history) shared one filename and silently
overwrote each other when add_counter_to_filename was off. %date% now
passes through to the backend, which formats it with datetime.now() at
save time; the date: check also runs before the '.' split so formats with
dots (e.g. %date:yyyy.M.d%) are not mistaken for %Node.Widget% patterns.
As a safety net, counter-less saves now fall back to an incrementing
suffix when the target file already exists instead of overwriting it.
- Global exclusion lists (node classes + title patterns) in settings,
applied at the shared filterRegistryNodes choke point; settings UI
section is hidden in standalone mode
- Per-node "Exclude from Send Targets" context-menu toggle persisted
in the workflow JSON (lm_exclude_send)
- Quick-exclude button on node selector items writes the comfy class
to the exclusion list
- Precedence: per-node exclusion > explicit marker > global lists
- interceptModeChange now supports multiple listeners; registry hooks
mode changes so mute/bypass refreshes candidates immediately
The follow-up report found three gaps in the value migration:
* applyToAllNodes only walked the root graph, so loader nodes inside
subgraphs kept their backslash values. It now recurses through
node.subgraph (Subgraph extends LGraph, so .nodes works at every level).
Promoted combo widgets share the interior widget's store-backed value,
so migrating the interior widget fixes the subgraph boundary too.
* Pasted nodes never hit the graph-level configure hook. A per-node
onConfigure wrapper now runs the same sanitize + migrate pass after
widget values restore.
* The corrected value kept its stale "value not in list" flag. The
migration now fires the node's onWidgetChanged hook, which the
frontend's error-clearing chain uses to drop value_not_in_list errors.
The forward-slash paths fix changed the checkpoint/unet combo lists on
Windows from "dir\model.safetensors" to "dir/model.safetensors", so
workflows saved before it loaded with a value no option matches: the
front-end extension reset the widget to the first model, or ComfyUI
flagged it "value not in list" when the widget was wired.
Two layers:
* random_loader_control.js migrates the widget value to its
separator-normalized form when that form is a known model, before the
reset-to-first fallback and before the wired early return.
* The loader nodes declare VALIDATE_INPUTS for the model name input,
lifting ComfyUI's strict list check for it; the shared helper resolves
separator-normalized names against the cache, so API-submitted or
programmatic values validate too. get_checkpoint_info_absolute now
normalizes backslashes explicitly instead of via os.sep, which was a
no-op on Linux.
The frontend's right-side Properties Panel falls back to WidgetLegacy for
unregistered widget types, and WidgetLegacy.draw() writes widget.width
(≈panel width) onto the real widget object. The canvas DOM overlay honors
widget.width ?? node.width, so clicking a node with the panel open squashes
the widget content to the left until undo/recreate (ComfyUI_frontend #11574).
Setting hideInPanel: true on all addDOMWidget options keeps LM widgets out
of the panel entirely. Older frontends without the option ignore it safely.
Refs #979
Add a "Save Recipe with Workflow" action next to "Save Recipe" in the LoRA
widget context menu. It posts the current UI-format graph alongside the save
request so the stored preview embeds it and the recipe can send the graph back
to ComfyUI. Embedding stays opt-in rather than folded into "Save Recipe": the
workflow is by far the largest metadata field and its widget values may carry
sensitive data.
- web/comfyui: new menu entry; saveRecipeDirectly({ embedWorkflow }) posts the
UI graph and reports the outcome (embedded / skipped) via toasts.
- save_recipe_from_widget handler: reads an optional JSON workflow field so the
long-standing body-less POST keeps working, including from cached clients.
- RecipePersistenceService.save_recipe_from_widget: embeds the graph through
the existing optimize_image workflow path, derives has_workflow by detection,
and skips graphs above MAX_WORKFLOW_EMBED_BYTES with workflow_skipped.
ComfyUI frontend 1.53 turned LGraphNode.mode into a prototype accessor
backed by node._state, and serialize() now reads that state directly.
Redefining mode on the instance shadowed the setter, so bypass/mute
never reached the serialized workflow and silently reverted to Always
on save/reload or workflow tab switch.
Add interceptModeChange() in web/comfyui/utils.js: it delegates to the
prototype accessor when one exists (observing changes only), and falls
back to the legacy closure accessor on older frontends. Use it in
lora_loader.js and in the Vue widgets' setupModeChangeHandler, which
covers the LoRA provider/aggregator nodes with the same latent bug.
The cycler-list payload now carries usage_tips, and the LORAS widget
parses strength_min/strength_max/strength_range into a cached lookup.
Strength inputs (model and clip) turn amber with an explanatory tooltip
when dragged, typed, or stepped outside the recommended range.
Related: https://github.com/willmiao/ComfyUI-Lora-Manager/issues/1090
Whitespace cleanup in cleanupLoraSyntax() and the autocomplete blur
formatter collapsed all whitespace runs, including inside <lora:...>
tags. A file named 'test - 0021.safetensors' was rewritten to
'test - 0021' in the node text, so runtime file resolution failed.
Protect lora tags with placeholders (or segment splitting) so only
whitespace between entries is normalized; names inside tags are kept
byte-for-byte.
Rebuilt from the preceding three commits' sources:
- active-filters chip and its dead settings-toggled broadcast removed
(the built bundle also no longer embeds the scripts/app.js test shim
that the chip's settings.js import used to pull in)
- scrollbar inset re-measured on programmatic value changes
- app/api bindings canonicalized to "../../../scripts/*" externals and
settings.js no longer inlined (bound at runtime via "../settings.js"
to the vanilla module instance), per the new build guard
The loramanager.lora_active_filters_autocomplete tooltip only mentioned
the /activefilters and /noactivefilters commands, while the prompt-node
tag-autocomplete tooltip cross-links every toggle entry point (typing in
the node and the node's right-click menu). 6ba64ebb added the right-click
menu entry without extending the tooltip to match; align the wording with
the established pattern.
The indicator chip added for /activefilters discoverability was broken by
design of its import path: AutocompleteTextWidget.vue imported
web/comfyui/settings.js into the vue-widgets bundle, and settings.js's
"../../scripts/app.js" import resolved at build time to the repo-root test
shim (scripts/app.js, an in-memory settings store). The chip therefore read
and wrote an orphaned in-memory Map: clicking it flipped only its own
visual state and never touched the real ComfyUI setting that
autocomplete.js consults (use_active_filters query param).
Beyond the defect, a persistent per-node control for a global persisted
setting misleads users and needs cross-instance sync machinery, which the
footer hint, slash commands, right-click menu entry and settings dialog
already cover.
- AutocompleteTextWidget.vue: remove the chip button, its state/handlers,
the settings.js import (the shim-inlining pathway) and all chip styles
- AutocompleteTextWidget.test.ts: drop the chip indicator describe block
and the settings.js module mock; beforeEach import no longer needed
- settings.js: drop the lora-manager:setting-toggled window broadcast and
its export — the chip was its only consumer, so every
setLoraManagerSettingValue write no longer dispatches a dead event
- autocomplete.activeFilters.test.js: drop the broadcast assertion test
- loraLoader.activeFiltersMenu.test.js: drop SETTING_TOGGLED_EVENT_NAME
from the settings.js mock
Discoverability of /activefilters // /noactivefilters is unchanged:
command-list footer, first-run hint, node context menu, settings dialog.
The absolutely-positioned clear (x) and active-filters filter buttons sit at
the textarea's right edge, so when content overflows and a classic
(non-overlay) vertical scrollbar appears the buttons overlap it. Measure the
scrollbar gutter (offsetWidth - clientWidth) when content overflows and
expose it as --lm-vscrollbar-width on .input-wrapper; the buttons' right is
now calc(base + var) so they shift left of the scrollbar only while one is
present (0 otherwise, incl. overlay-scrollbar platforms).
Refreshed on input, mount, canvas/Vue-DOM mode change and via a ResizeObserver
on the textarea (widget resize). Rebuilt the vue-widgets bundle.
Mirror the /noautocomplete discoverability pattern for the loras\nactive-filters search toggle:\n\n- autocomplete.js: extend the slash-command-list footer and the\n one-time first-run hint to loras nodes, advertising\n /activefilters and /noactivefilters\n- lora_loader.js: add an 'Active Filters Search: ON/OFF' entry to the\n right-click menu of all loras-autocomplete node classes\n- settings.js: broadcast a 'lora-manager:setting-toggled' window event\n on every setLoraManagerSettingValue write\n- AutocompleteTextWidget.vue: add a persistent filter indicator chip\n (loras mode only) that reflects and toggles the setting and stays in\n sync via the setting-toggled event\n- tests: footer/hint/event coverage, context-menu tests for all four\n node classes, widget indicator tests; rebuild vue-widgets bundle
The hidden __lm_autocomplete_meta_* widget persisted lastAccepted
(insertedText/textSnapshot) into exported workflow JSON, leaking old
prompt text even after the user deleted it.
Patch app.graphToPrompt (shared by workflow export, Export API and
queueing) to strip lastAccepted from the serialized result's
widgets_values / widgets_values_named / output inputs. Only the
exported artifact is touched; live node state, undo snapshots,
copy/paste and local saves keep the boundary intact.
Autocomplete suggestions were ranked purely by relevance across the whole
library, so same-named loras from different subfolders interleaved and were
hard to tell apart. Results are now bucketed by folder (root first, then
alphabetically, with nested paths sorting naturally) while keeping the
existing relevance ordering within each folder group.
The LoRA Manager page kept its active filters in localStorage, which the
ComfyUI-side autocomplete read directly. When the two run in different
browsers, origins, or the ComfyUI Desktop Electron shell, localStorage is
not shared and the active-filters search silently did nothing.
The manager page now mirrors its filter state to a server-side in-memory
store (PUT /api/lm/{prefix}/active-filters), pushed on every change via a
storage-listener hook and once on page load. The autocomplete widget sends
only use_active_filters=true, and the relative-paths endpoint injects the
stored filters into the search, with explicit query params taking
precedence.
Old workflows (saved before the control_after_generate feature) carry a
shorter widgets_values array. The frontend's index-based widget restore
then shifts the old weight_dtype value into the hidden control widget
(leaving an invalid value like 'default') and silently resets
weight_dtype to its default. On graph load, hand the shifted value back
to weight_dtype when it still sits at its default, then reset the
control mode to 'fixed' so old workflows keep loading deterministically.
- Add Tag Autocomplete ON/OFF entry to the Prompt (LoraManager) node
right-click menu, cross-referencing the slash commands
- Show the current autocomplete state (/autocomplete or /noautocomplete
hint) below the slash command list
- Show a one-time dismissible tip in the suggestion dropdown on first use
- Clarify toggle command labels (Turn autocomplete ON/OFF) and cross-link
all three entry points in the settings tooltip
- Share the setting write path via setLoraManagerSettingValue()