- Rename nodes to 'Checkpoint Loader (LoraManager)' and 'Unet Loader (LoraManager)'\n- Use os.sep for relative path formatting in model COMBO inputs\n- Update path matching to be robust across OS separators\n- Update docstrings and comments
Refactor _prepare_checkpoint_paths() to return a tuple instead of having
side effects on instance variables. This prevents extra unet paths from
being incorrectly classified as checkpoints when processing extra paths.
- Changed return type from List[str] to Tuple[List[str], List[str], List[str]]
(all_paths, checkpoint_roots, unet_roots)
- Updated _init_checkpoint_paths() and _apply_library_paths() callers
- Fixed extra paths processing to properly isolate main and extra roots
- Updated test_checkpoint_path_overlap.py tests for new API
This ensures models in extra unet paths are correctly identified as
diffusion_model type and don't appear in checkpoints list.
lora_stack stores relative paths (e.g., 'Illustrious/style/file.safetensors'),
but comfy.utils.load_torch_file requires absolute paths. Previously, when
loading LoRAs from lora_stack, the relative path was passed directly to the
low-level API, causing FileNotFoundError on Windows.
This fix extracts the lora name from the relative path and uses
get_lora_info_absolute() to resolve the full absolute path before passing
it to load_torch_file(). This maintains compatibility with the lora_stack
format while ensuring correct file loading across all platforms.
Fixes: FileNotFoundError for relative paths in LoraLoaderLM and LoraTextLoaderLM
when processing lora_stack input.
- Add get_lora_info_absolute() function to return absolute file paths
- Replace LoraLoader().load_lora() with comfy.utils.load_torch_file() +
comfy.sd.load_lora_for_models() to enable loading LoRAs from any path
- This allows LoRA Manager to load LoRAs from non-standard paths (multi-library support)
- Fixes#805
Introduce a new private method `_normalize_trigger_words` to handle consistent splitting and cleaning of trigger word strings. This method splits input by both single and double commas, strips whitespace, and filters out empty strings, returning a set of normalized words. It is now used in `process_trigger_words` to compare trigger word overrides, ensuring accurate detection of changes by comparing normalized sets instead of raw strings.
- Update package.json test script to run both JS and Vue tests
- Simplify LoraCyclerLM output by removing redundant lora name fallback
- Extend Vitest config to include TypeScript test files
- Add Vue testing dependencies and setup for component testing
- Implement comprehensive test suite for BatchQueueSimulator component
- Add test setup file with global mocks for ComfyUI modules
Use union type "AUTOCOMPLETE_TEXT_PROMPT,STRING" to enable input mode
compatibility with STRING outputs while preserving autocomplete widget
functionality via widgetType option.
Fixes issue where text inputs could not receive connections from
STRING-type outputs after changing from built-in STRING to custom
AUTOCOMPLETE_TEXT_PROMPT type.
Affected nodes:
- Prompt (LoraManager)
- Text (LoraManager)
Introduce a new TextLM node to the Lora Manager extension, providing a simple text input with autocomplete functionality for tags and styles. The node is integrated into the module's import system and node class mappings, enabling users to utilize autocomplete features for efficient prompt creation.
Update the placeholder text in the PromptLM class to include guidance for quick tag search functionality. The new placeholder now reads "Enter prompt... /char, /artist for quick tag search", providing users with immediate cues on how to utilize tag search features directly within the input field. This improves usability by making advanced functionality more discoverable.
Adds custom words autocomplete functionality similar to comfyui-custom-scripts,
with the following features:
Backend (Python):
- Create CustomWordsService for CSV parsing and priority-based search
- Add API endpoints: GET/POST /api/lm/custom-words and
GET /api/lm/custom-words/search
- Share storage with pysssss plugin (checks for their user/autocomplete.txt first)
- Fallback to Lora Manager's user directory for storage
Frontend (JavaScript/Vue):
- Add 'custom_words' and 'prompt' model types to autocomplete system
- Prompt node now supports dual-mode autocomplete:
* Type 'emb:' prefix → search embeddings
* Type normally → search custom words (no prefix required)
- Add AUTOCOMPLETE_TEXT_PROMPT widget type
- Update Vue component and composable types
Key Features:
- CSV format: word[,priority] compatible with danbooru-tags.txt
- Priority-based sorting: 20% top priority + prefix + include matches
- Preview tooltip for embeddings (not for custom words)
- Dynamic endpoint switching based on prefix detection
Breaking Changes:
- Prompt (LoraManager) node widget type changed from
AUTOCOMPLETE_TEXT_EMBEDDINGS to AUTOCOMPLETE_TEXT_PROMPT
- Removed standalone web/comfyui/prompt.js (integrated into main widgets)
Fixes comfy_dir path calculation by prioritizing folder_paths.base_path
from ComfyUI when available, with fallback to computed path.
- Change `STRING` input type to `AUTOCOMPLETE_TEXT_LORAS` in LoraManagerLoader, LoraStacker, and WanVideoLoraSelectLM nodes for LoRA syntax input
- Change `STRING` input type to `AUTOCOMPLETE_TEXT_EMBEDDINGS` in PromptLoraManager node for prompt input
- Remove manual multiline, autocomplete, and dynamicPrompts configurations in favor of built-in autocomplete types
- Update placeholder text for consistency across nodes
- Remove unused `setupInputWidgetWithAutocomplete` mock from frontend tests
- Add Vue app cleanup logic to prevent memory leaks in widget management
- Add execution_index and next_index fields to CyclerConfig interface
- Introduce beforeQueued hook in widget to handle index shifting for batch executions
- Use execution_index when provided, fall back to current_index for single executions
- Track execution state with Symbol to differentiate first vs subsequent executions
- Update state management to handle dual-index logic for proper LoRA cycling in batch queues
Removed the sort by selection UI from the Lora Cycler widget and
hardcoded the sorting to always use filename. This simplifies the
interface while maintaining all sorting functionality.
Changes:
- Removed sort_by prop/emit from LoraCyclerSettingsView
- Removed sort tabs UI and associated styles
- Hardcoded sort_by = "filename" in backend node
- Removed sort by handling logic from LoraCyclerWidget
- Updated widget height to accommodate removal
Add Lora Cycler node that cycles through LoRAs sequentially from a filtered pool. Supports configurable sort order, strength settings, and persists cycle progress across workflow save/load.
Backend:
- New LoraCyclerNode with cycle() method
- New /api/lm/loras/cycler-list endpoint
- LoraService.get_cycler_list() for filtered/sorted list
Frontend:
- LoraCyclerWidget with Vue.js component
- useLoraCyclerState composable
- LoraCyclerSettingsView for UI display
- Add execution_seed and next_seed parameters to support deterministic randomization across batch executions
- Separate UI display generation from execution stack generation to maintain consistency in batch queues
- Update LoraService to accept optional seed parameter for reproducible randomization
- Ensure each execution with a different seed produces unique results without affecting global random state
- Update DebugMetadata node to return metadata via ComfyUI's UI system instead of websocket
- Add new JsonDisplayWidget Vue component for displaying metadata in the UI
- Remove dependency on PromptServer and websocket communication
- Improve error handling with proper UI feedback
- Maintain backward compatibility with existing metadata collection system
Add support for respecting recommended strength values from LoRA usage_tips
when randomizing LoRA selection.
Features:
- New toggle setting to enable/disable recommended strength respect (default off)
- Scale range slider (0-2, default 0.5-1.0) to adjust recommended values
- Uses recommended strength × random(scale) when feature enabled
- Fallbacks to original Model/Clip Strength range when no recommendation exists
- Clip strength recommendations only apply when using Custom Range mode
Backend changes:
- Parse usage_tips JSON string to extract strength/clipStrength
- Apply scale factor to recommended values during randomization
- Pass new parameters through API route and node
Frontend changes:
- Update RandomizerConfig type with new properties
- Add new UI section with toggle and dual-range slider
- Wire up state management and event handlers
- No layout shift (removed description text)
Tests:
- Add tests for enabled/disabled recommended strength in API routes
- Add test verifying config passed to service
- All existing tests pass
Build: Include compiled Vue widgets
- Add `_preprocess_loras_input` method to handle different widget input formats
- Move core randomization logic to `LoraService` for better separation of concerns
- Update `_select_loras` method to use new service-based approach
- Add comprehensive test fixtures for license filtering scenarios
- Include debug print statement for pool config inspection during development
This refactor improves code organization by centralizing business logic in the service layer while maintaining backward compatibility with existing widget inputs.
- Document dual UI systems: standalone web UI and ComfyUI custom node widgets
- Add ComfyUI widget development guidelines including styling and constraints
- Update terminology in LoraRandomizerNode from 'frontend/backend' to 'fixed/always' for clarity
- Include UI constraints for ComfyUI widgets: minimize vertical space, avoid dynamic height changes, keep UI simple
- Implement LoRA locking to prevent specific LoRAs from being changed during randomization
- Add visual styling for locked state with amber accents and distinct backgrounds
- Introduce `roll_mode` configuration with 'backend' (execute current selection while generating new) and 'frontend' (execute newly generated selection) behaviors
- Move LoraPoolNode to 'Lora Manager/randomizer' category and remove standalone class mappings
- Standardize RETURN_NAMES in LoraRandomizerNode for consistency
- Import and register two new nodes: LoraDemoNode and LoraRandomizerNode
- Update import exception handling for better readability with multi-line formatting
- Add comprehensive documentation file `docs/custom-node-ui-output.md` for UI output usage in custom nodes
- Ensure proper node registration in NODE_CLASS_MAPPINGS for ComfyUI integration
- Maintain backward compatibility with existing node structure and import fallbacks
- Update documentation to reflect new widget filename `lora-manager-widgets.js`
- Remove `LoraManagerDemoNode` import and registration from `__init__.py`
- Translate development guide from Chinese to English for broader accessibility
- Clean up obsolete demo references to align with actual widget implementation
The SaveImage class has been renamed to SaveImageLM to better reflect its purpose within the Lora Manager module. This change ensures consistent naming across import statements, class mappings, and the actual class definition, improving code readability and maintainability.
- Simplify and consolidate the logic for processing trigger words and groups
- Remove redundant code paths and improve maintainability
- Ensure consistent behavior between list and string trigger data inputs
- Preserve existing functionality for strength adjustment and group mode
- Add CheckpointLoaderKJ to NODE_EXTRACTORS mapping for KJNodes support
- Enhance model filename generation in SaveImage to handle different data types
- Add proper type checking and fallback for model metadata values
- Improve robustness when processing checkpoint paths for filename generation
Add `allow_strength_adjustment` parameter to enable mouse wheel adjustment of trigger word strengths. When enabled, strength values are preserved and can be modified interactively. Also improves trigger word parsing by handling whitespace more consistently and adding debug logging for trigger data inspection.
- Extract and preserve strength values from trigger words in format "(word:strength)"
- Maintain strength formatting when filtering active trigger words in both group and individual modes
- Update active state tracking to handle strength-modified words correctly
- Ensure backward compatibility with existing trigger word formats
Remove direct imports of IO type constants from comfy.comfy_types and replace them with string literals "STRING" in input type definitions and return types. This improves code portability and reduces dependency on external type definitions.
Changes made across multiple files:
- Remove `from comfy.comfy_types import IO` imports
- Replace `IO.STRING` with "STRING" in INPUT_TYPES and RETURN_TYPES
- Move CLIPTextEncode import to function scope in prompt.py for better dependency management
This refactor maintains the same functionality while making the code more self-contained and reducing external dependencies.