- workflow_registry.js: add force param to refreshRegistry(), bypass fingerprint
dedup when responding to lora_registry_refresh WS message. Without this, the
backend's wait_for_all() times out after 0.5s because the frontend skips the
register-nodes POST when the workflow fingerprint hasn't changed (common after
ComfyUI restart with an empty or unchanged workflow).
- misc_handlers.py: demote 'No nodes registered after refresh' from WARNING to
DEBUG — empty workflows are a normal operational state, not a warning-worthy
condition.
- Handle compound node IDs (e.g. "252:0") from expanded group subgraphs
to fix 400 Bad Request on workflows with group nodes
- Frontend proactively pushes node data via afterConfigureGraph and
LiteGraph hooks (onNodeAdded/onNodeRemoved/graphChanged), eliminating
WebSocket round-trip latency for most "Send to Workflow" operations
- Add content-fingerprint dedup to skip duplicate register-nodes POSTs
- Fast-path cache returns immediately when tabs are registered (including
0-node registrations), avoiding unnecessary WS refresh cycles
- Distinguish "Empty Registry" from other errors in standalone UI toast
- Reduce WS refresh timeout 2s→0.5s, add cooldown and lock to prevent
concurrent refresh storms
- All [LM:Registry] logs at DEBUG level
Changes:
- Backend: _validate_folder_paths() now checks checkpoints↔unet overlap
within the same library using os.path.realpath() for symlink resolution
- Backend: set() calls _validate_folder_paths() for both folder_paths and
extra_folder_paths before writing
- Backend: extracted _normalize_path_set() helper to eliminate duplicated
normalization logic
- Frontend: inline error display with red border + error message below the
conflicting input, no save triggered
- Frontend: path normalization (strip trailing slash, lowercase) in pre-check
to reduce false negatives vs backend realpath
- Frontend: asymmetric error UX — message only on the user-edited side,
red border on the pre-existing conflict side
- CSS: has-error styles with hardcoded rgba fallback for older browsers
- i18n: checkpointUnetOverlap + checkpointUnetOverlapInline keys added to
all 10 locale files
Remove dynamic height calculation that auto-resized the node when
LoRAs are added or removed. The widget now stays at the size the user
sets via the node resize handle, scrolling when content overflows.
- Drop updateWidgetHeight() and hardcoded entry-count height math
- Set --comfy-widget-min-height once (200px) instead of recalculating
- In Vue mode: add contain:layout+size to break the ResizeObserver
feedback loop that forced node growth with content (CSS via
.lm-loras-container.lm-vue-node scoped to vueNodesMode only)
- Remove unused "Node 2.0: Maximum visible LoRA entries" setting
- Bulk refresh filter now excludes models with hf_url
- Individual refresh for HF models only checks CivitAI API
- CivArchive client validates model IDs before querying
- Add onerror handler on <img> previews to fallback to no-preview.png
- Fire async cache cleanup when preview file returns 404
- Add ModelCache.clear_preview_by_path() for safe stale-url removal
- Downgrade /api/lm/previews 404 log from warning to debug
- Merge Relink to Civitai and new Link to HuggingFace into a single
'Link Model' submenu with sub-options for each source
- Add POST /api/lm/set-hf-url endpoint to associate a model with a
HuggingFace repo URL, saving hf_url to .metadata.json
- Add link_hf_modal.html for URL input, following relink-civitai pattern
- Use update_single_model_cache instead of add_model_to_cache to
prevent duplicate cache entries after linking
- Remove os.path.realpath usage for consistency with relink-civitai
- Raise errors instead of silently falling back to LoRA scanner when
model root cannot be determined
- Scope .input-group CSS rules to modal IDs to fix style conflicts
with download-modal.css
- Add i18n keys across all 10 locales with translations for
zh-CN, zh-TW, ja, ko, de, es, fr, he, ru
When Civitai returns 429 (Too Many Requests) during example image
downloads, the previous behavior treated all failures identically and
permanently removed the corresponding images from model metadata —
making them impossible to retry.
This commit adds:
- 429 detection + Retry-After header parsing in download_to_memory
- Exponential backoff retry (up to 3 attempts) in
download_model_images_with_tracking
- Separate tracking of rate-limited vs permanently failed URLs
- rate_limited_models progress tracking persisted to disk
- Rate-limited models are NOT added to failed_models/processed_models
so they are automatically retried on subsequent download runs
- Force mode clears failed_models when rate-limited images exist
- Parse limit.output from model catalog alongside model IDs
for per-model max output token limits
- Use catalog lookup in chat_completion_json() to set max_tokens;
fall back to 4096 for unknown models (e.g. local Ollama)
- Remove the JSON retry (response_format → plain text fallback);
keep _try_salvage_json as last-resort for truncated responses
- Reduce Ollama num_ctx from 32768 to 8192 (sufficient for
metadata enrichment, saves VRAM)
- Fix stale test comment referencing removed retry
Remove tests/enrich_hf_validation/baselines/ from git tracking
(.gitignore entry + git rm --cached). These contain README snapshots
from community HF repos that may include NSFW/sensitive content.
Local files are preserved on disk for offline reference.
Commit 9a0d866b changed _strip_fenced_code_blocks to preserve bash/shell
code blocks (they carry CLI setup and trigger-word metadata signal).
Update the two affected tests to expect bash content in the output
instead of asserting it is stripped.
- Rename test_bash_code_block_stripped → test_bash_code_block_preserved
- Update assertions: expect 'pip install' in result
The bare call inside _build_prompt_context
would raise NameError because class methods don't close over class-level
scope. Use instead to trigger attribute lookup.
Update enrich_hf_metadata prompt.md clue locations for better LLM accuracy.
Update baseline report to v2 (mean 69.0, 46 models, +2.2pp vs baseline 71.1%).
Consolidate README snapshots into baselines/readmes/.
_Previous_ _find_scanner_for_model and identify_model_type contained ~25 lines
of identical scanner-iteration + path-matching logic. Factor it into
_find_model_entry() so a new scanner type or edge-case fix can't drift apart.
- Rename py/agent_cli/ -> py/metadata_ops/ (module was never agent-related)
- Rename tests/agent_cli/ -> tests/metadata_ops/
- Remove 9 low-value/debug INFO log points across agent_handlers.py,
agent_service.py, llm_service.py, and metadata_ops/__init__.py
- Keep LLM raw response at DEBUG level for diagnostics
- Consolidate per-model progress + LLM result into single concise
log line with basename instead of full path
- Update package/class/method docstrings to clarify this is a
pipeline infrastructure, not a true agent loop
Three-part fix for enrich_hf_metadata failing to extract correct preview_url
from HuggingFace collection repos where models share flat heading levels:
1. _strip_standalone_images() now converts <img> tags to markdown image
syntax  instead of stripping the URL entirely, so the LLM
can still extract preview URLs.
2. _extract_section() uses a line-count-based forward window (stopping at
<a id> anchors) for non-heading matches, instead of stopping at the
very next heading. This prevents same-level sub-headings (# Download,
# Trigger, # Sample prompt within a single model section) from
truncating the window before sample images are included.
3. Post-processor preview fallback now filters gallery images to the
model-specific README section before falling back to the repo-wide
first image.
Move the HF model list from ~/Documents/ into tests/enrich_hf_validation/test_data/
and commit the pipeline validation baseline artifacts (report.json,
preprocessing_audit.json, README snapshots) into baselines/.
Update config.py and run_validation.py defaults to use repo-relative paths
via os.path.dirname(__file__) instead of ~/Documents/ hardcode.
Originates from changes in 8fb00998 (validation pipeline audit).
- agent_service._format_base_models: output bullet list instead of
JSON array for cleaner LLM parsing
- prompt.md mapping section: replace 14-row HF→CivitAI table with
compact rule set covering 14 mapping paths including new entries
for HiDream-ai, OnomaAIResearch/Illustrious, ideogram-ai/ideogram,
Tongyi-MAI/Z-Image-Turbo, and Wan-AI/Wan2.*
- base_model extraction instruction: add guidance to infer from
model filename, YAML tags, and README body text when YAML
frontmatter has no explicit base_model:
- Rename md_to_html.py → readme_processor.py (file no longer just HTML conversion)
- _extract_section: include YAML frontmatter, use heading-level-aware forward
walk (sub-headings under # are included), increase walk limit past 30 lines
- _is_heading: exclude </hN> closing tags from boundary detection
- _heading_level: new helper for heading-level-aware section matching
- css: yield 0 for heading like closing tags, was unexpectedly caught by _is_heading
- extract_gallery_images: fix YAML block scalar (text: >-) prompt extraction;
use endswith instead of == to detect the block marker
- _strip_widget_section: add to clean_readme_for_llm (widget text is handled
by post-processor, not needed in LLM prompt)
- _strip_standalone_images: keep markdown image URLs intact for LLM preview
extraction (was stripping to alt text only)
- list_base_models: switch from scanner-cache aggregation to
CivitaiBaseModelService.get_base_models() - always returns full list
- Ollama: add num_ctx=32768 to payload options so thinking models have room
to both reason and produce output
- Add tests/agent_cli/test_readme_processor.py: 59 tests covering extraction,
cleaning, section matching, heading detection
- Update existing tests for behavioral changes