74 Commits
Author SHA1 Message Date
Gero Doll 721dacd654 Merge pull request #13 from Limbicnation/fix/ollama-vram-autounload
Free Ollama VRAM after node execution
2026-06-23 05:02:47 +02:00
limbicnation 719ec0cb9c chore: bump version to 1.4.2 2026-06-23 04:55:02 +02:00
limbicnation 37df810313 style: apply ruff format to ollama_client.py 2026-06-23 04:54:01 +02:00
limbicnation 77b2c48fde fix: address review feedback on VRAM autounload
- PromptRefiner unload_model toggle now actually controls eviction:
  keep_alive is "0s" when on, None (server default) when off, so the
  UI no longer unloads against the user's choice.
- Cleanup always runs; unload fires only when unload_model is on AND the
  subprocess fallback left a model loaded, instead of skipping cleanup
  entirely when the toggle is off.
- release_vram() clears empty_cache() on every CUDA device, not just
  device 0, for multi-GPU rigs.
- Add docstrings to INPUT_TYPES methods and language ids to plan doc
  code fences.
2026-06-23 04:52:43 +02:00
limbicnation 3bfc4f7db7 perf: unload Ollama model only on subprocess fallback
The post-execution cleanup unconditionally called unload_model(), which
sends a generate request to evict the model. On the streaming-success
path keep_alive="0s" has already evicted it, so that request forced
Ollama to reload the model just to unload it again — a cold load+unload
cycle with a VRAM spike after every node run.

Track whether the subprocess fallback ran and pass unload=used_subprocess
to cleanup. The streaming path relies on keep_alive="0s"; only the
subprocess path (which carries the 5m default) still needs an explicit
unload. CUDA cache release continues to run on every path.
2026-06-23 04:43:40 +02:00
limbicnation f0aaf1314a Free Ollama VRAM after node execution
Pass keep_alive="0s" on every Ollama generate call so models are
evicted from GPU VRAM immediately instead of lingering 5 minutes,
which caused CUDA OOM when downstream diffusion models loaded.

Each node now runs async VRAM cleanup in a try/finally block. The
cleanup uses unload=True so it also evicts a model loaded via the
subprocess fallback path (which carries the default keep_alive).

Add unload_model(), release_vram(), cleanup() and cleanup_async()
to OllamaClient, plus a per-node unload toggle on PromptRefiner.
2026-06-23 04:21:47 +02:00
limbicnation 48127fc6c9 docs: update CLAUDE.md current version to 1.4.1 2026-06-10 23:06:33 +02:00
limbicnation 4ef84cce2d chore: bump version to 1.4.1
Republish containing the Python 3.10 StrEnum compatibility fix; the
1.4.0 registry artifact was published before that fix landed.
v1.4.1
2026-06-10 23:02:09 +02:00
limbicnation cca9fecba6 fix: make PromptCombiner StrEnum import compatible with Python 3.10
requires-python is >=3.10 but enum.StrEnum was added in 3.11, so the
combiner node (and thus the whole package) failed to import on 3.10 —
which is also why the Test CI job was red. Back-port StrEnum on <3.11
with matching str() semantics.
v1.4.0
2026-06-10 22:40:38 +02:00
limbicnation ae87f0b06f chore: bump version to 1.4.0 2026-06-10 22:35:38 +02:00
Gero Doll 8a56ed45a6 Merge pull request #12 from Limbicnation/feature/dual-stream-prompt-refiner
Add dual-stream prompt refiner node
2026-06-10 22:32:08 +02:00
limbicnation eab2efc461 Fix dual-stream parser false split on 'negative-space'
Require a colon separator and anchor the Negative label to a line
start so the word 'negative' in the positive prompt body (e.g. the
art term 'negative space') is no longer mistaken for a stream label.
Add regression tests.
2026-06-10 22:16:42 +02:00
limbicnation ebbb25a2a3 Add dual-stream prompt refiner node
Add PromptDualStreamRefinerNode that produces a positive and negative
prompt pair in a single pass via Ollama, intended for the shipped Q8
GGUF of qwen2-5-7b-dual-stream-prompt-lora. Reuses OllamaClient for
streaming, timeouts, progress, and llama-runner crash handling, and
parses Positive/Negative output defensively across label variants.

Includes config/Modelfile.dualstream, unit tests, node registration,
and a corrected implementation plan replacing the invalid local
transformers/PEFT approach.
2026-06-10 22:10:16 +02:00
Gero Doll 70ba1bf8b7 Merge pull request #11 from Limbicnation/fix/ollama-runner-crash-handling
fix: handle Ollama llama-runner crashes with structured error categor…
2026-05-08 04:02:35 +02:00
limbicnation bf54b54ca9 fix: handle Ollama llama-runner crashes with structured error categorization
Replace the catch-all RuntimeError wrapper in OllamaClient.generate_streaming
with a StreamResult dataclass that categorises failures (ok, timeout, transient,
model_crash, server_error, unavailable). Llama-runner crashes (HTTP 500 with
"runner terminated" / "exit status" / "load failed") are detected and surfaced
as user-actionable messages in the ComfyUI prompt output instead of bubbling
up as Python stacktraces.

PromptGenerator, NegativePrompt, and PromptRefiner nodes now branch on
result.kind: model_crash / server_error / unavailable surface the message
directly (subprocess fallback would also fail), while timeout / transient
fall through to the existing subprocess fallback path.

Adds 6 unit tests covering each error class plus the success path. Updates
the existing PromptRefiner seed tests to return StreamResult from mocks.
2026-05-08 03:43:58 +02:00
limbicnationandClaude Opus 4.7 b5e1731ff7 chore: bump version to 1.3.5
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.3.5
2026-05-01 04:19:28 +02:00
limbicnationandClaude Opus 4.7 2fea087592 fix: use relative import for style_presets in StyleApplier
The absolute `from style_presets import StylePreset` failed at INPUT_TYPES()
evaluation because ComfyUI's loader does not reliably place the custom-node
directory on sys.path. Switch to `from ..style_presets import StylePreset`
with an absolute fallback for test/script-execution contexts, matching the
dual-mode try/except pattern already used in __init__.py.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 04:19:16 +02:00
limbicnation 50807f2d1a Bump version v1.3.4 v1.3.4 2026-05-01 04:03:26 +02:00
limbicnation 242c3f0edc chore: bump version to 1.3.3 2026-05-01 03:02:04 +02:00
limbicnation ff26170a59 style: fix ruff formatting in test_prompt_refiner.py 2026-05-01 02:42:32 +02:00
limbicnation 662afb4286 chore: bump version to 1.3.2 2026-05-01 02:35:30 +02:00
limbicnation 718ace85a6 chore: remove incorrectly nested custom_nodes/ directory
The previous commit added files under custom_nodes/comfyui-prompt-generator/
which is the wrong structure for this standalone repo. The correct flat structure
(__init__.py and nodes/ at repo root) already existed. This removes the duplicate
nested copy.
2026-05-01 02:31:05 +02:00
limbicnation aac7906b29 feat: add PromptCombiner, PromptRefiner, NegativePrompt nodes
- Fix StyleApplier relative imports (from ..style_presets)
- Add PromptCombiner: blend/concat/weighted_average modes with emphasis markers
- Add PromptRefiner: iterative LLM refinement (1-3 passes) via Ollama
- Add NegativePrompt: auto (LLM) and preset (category-based) negative generation
- Update __init__.py to register all 5 nodes
2026-05-01 02:26:19 +02:00
Gero Doll 3c2408ed20 Merge pull request #10 from Limbicnation/pr-9
Pr 9
2026-04-30 08:11:35 +02:00
limbicnation ed5b681f06 fix: address PR #9 review issues
- fix(scripts): tomllib fallback for Python 3.10 compat
- fix(ci): remove verify-tag-exists from test.yml (publish.yml already guards)
- fix(tests): ensure local nodes/ import in test_node_registration.py
- fix(adapter): shared module-level model cache across OllamaClient instances
- fix(adapter): exact model tag match in check_health() to avoid prefix conflation
- fix(refiner): per-pass seed increment so multi-pass refinement varies
- fix(combiner): validate mode before single-prompt fast path
- feat(generator): strip DeepSeek <think> and markdown <details> blocks
- test: add prompt_refiner seed tests, cache sharing tests, exact match tests
- chore(deps): add dev extras with tomli fallback
2026-04-30 08:05:17 +02:00
limbicnationandClaude Opus 4.7 fc5d02362f chore: bump version to 1.3.1
Hardening release. No public API changes — same 5 NODE_CLASS_MAPPINGS
keys as v1.3.0. The bump exists so the registry can serve a build that
includes the version-tag guard, the registration contract tests, the
mapping drift self-check, the modernized typing, and the CI fixes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 06:15:58 +02:00
limbicnationandClaude Opus 4.7 604639e8b3 ci: prevent silent version drift with pre-commit and GH Actions guards
Direct response to the v1.1.x → v1.3.0 silent-skip pattern, where
pyproject.toml was bumped four times without ever pushing the matching
git tag, so .github/workflows/publish.yml never fired and the registry
stayed on v1.1.6.

- scripts/check_version_tag.py: stdlib-only (tomllib) script that fails
  if pyproject.toml's version has no matching git tag locally.
- .pre-commit-config.yaml: wires ruff (check + format) and the local
  version-tag-guard hook. The guard fires only on pyproject.toml edits.
- test.yml: new verify-tag-exists job that fails the main-branch build
  when pyproject.toml's version has no matching tag in the repo. Belt
  and suspenders for the pre-commit hook.
- test.yml validate job: same comfy-cli telemetry fix already applied
  to publish.yml; suppresses the interactive opt-in prompt in CI.
- pytest.ini + test.yml: lower coverage gate from 70 (never enforced;
  failed on every main push since chain nodes were added) to 50 (the
  actual current floor). Comment marks it as a starting point for
  future test growth.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 06:15:08 +02:00
limbicnationandClaude Opus 4.7 e8d781d737 feat: add registration safety guards (mapping self-check + contract tests)
Direct response to the v1.1.6 packaging gap, where the prompt-chain nodes
(combiner, refiner, negative) were authored under nodes/ but never wired
into NODE_CLASS_MAPPINGS, so they silently failed to ship.

- __init__.py now raises RuntimeError at import time if NODE_CLASS_MAPPINGS
  and NODE_DISPLAY_NAME_MAPPINGS drift apart. ComfyUI startup logs surface
  the mismatch instead of dropping the node from the menu silently.
- New tests/unit/test_node_registration.py contract suite (8 tests):
  * Expected 5 keys are registered.
  * Display names cover every class.
  * Each registered class satisfies the ComfyUI node interface
    (INPUT_TYPES classmethod, RETURN_TYPES, FUNCTION, CATEGORY,
    and the FUNCTION attribute resolves to a callable method).
  * Every nodes/*_node.py module on disk is reachable from the mapping —
    this is the regression guard that would have caught v1.1.6.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 06:14:55 +02:00
limbicnationandClaude Opus 4.7 839188382c feat: modernize typing to PEP 585, add ruff config, refactor combiner mode handling
Changes:
- Add [tool.ruff] config with target-version py310 and a curated rule set
  (E/F/W, I, UP, B, SIM, RUF) so future drift is caught in CI lint.
- PEP 585 sweep across all node modules: drop legacy typing.Dict / List /
  Tuple / Optional in favor of dict / list / tuple / `X | None`. Annotate
  class-level mutable defaults as ClassVar to satisfy RUF012.
- PromptCombinerNode: replace the magic-string mode chain with a CombineMode
  StrEnum + match statement. The dropdown choices in INPUT_TYPES are now
  derived from the same Literal alias used in the function signature, so the
  UI and the type contract can't drift apart.
- Smoke tests for PromptCombinerNode (14 tests) covering enum mapping, all
  three modes, edge cases, and the unknown-mode error path. Brings combiner
  coverage from 28% to 96%.
- Tidy preexisting issues surfaced by the new lint rules: B904 except chaining
  in style_presets, RUF013 implicit Optional, RUF059 unused unpack, SIM117
  nested-with consolidation in tests.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 06:14:44 +02:00
limbicnationandClaude Opus 4.7 8e19db8e72 ci: pass token explicitly and fail loudly when REGISTRY_ACCESS_TOKEN is unset
comfy-cli removed the implicit env-var lookup and the --confirm flag.
The new contract is: pass the token via --token, and gate publishing
on a clear preflight check so CI failures point straight at the
missing secret instead of a typer "No such option" message.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 04:59:24 +02:00
limbicnationandClaude Opus 4.7 e1090a9ccf ci: disable comfy-cli telemetry prompt to unblock publish workflow
The first invocation of comfy-cli in CI hit the interactive
"Do you agree to enable tracking?" prompt and aborted. Run
'comfy --skip-prompt tracking disable' before validate/publish
so the workflow runs unattended.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.3.0
2026-04-30 04:56:17 +02:00
limbicnation e82aa5adbb bump version to 1.3.0 2026-04-28 06:15:50 +02:00
Gero Doll 52d9b0d4f5 Merge pull request #8 from Limbicnation/pr-7
Pr 7
2026-04-28 05:27:45 +02:00
limbicnation 52dcfbcb17 fix: address PR #8 review issues
- Fix _weighted_average deduplication bug (now uses weight-ratio emphasis markers)
- Replace bare except Exception with specific exception handling in OllamaClient
- Propagate API contract mismatches (TypeError/AttributeError) as RuntimeError
- Replace print() with logging.getLogger(__name__) in all new nodes
- Expose top_p in PromptRefinerNode INPUT_TYPES for consistency
- Update PR-8-REVIEW.md with fix log and merge recommendation
2026-04-28 05:01:03 +02:00
limbicnation 8f2eca40d9 fix: address code review issues (#7)
- Remove dead imports from prompt_generator_node.py and ollama_client.py
- Switch optional imports to importlib.util.find_spec pattern
- Remove orphaned _cached_models/_cache_time from PromptGeneratorNode
- Remove unused seed param from PromptRefinerNode
- Add top_p input to NegativePromptNode with proper wiring
- Fix pytest.ini to not omit adapters from coverage
- Remove unused pytest imports from test files
- Run ruff check + format (all clean now)
- All 29 tests passing
2026-04-27 17:30:19 +02:00
limbicnation 89c8341612 feat: add prompt chain nodes + test infrastructure
Phase 1 — Foundation Hardening:
- Extract ollama_client.py adapter from PromptGeneratorNode
- Add pytest suite (29 tests, 70% coverage gate)
- Unify style sources into config/styles.yaml
- Extend CI with pytest + coverage

Phase 2 — Prompt Chain Nodes:
- PromptRefinerNode: iterative LLM refinement (1-3 passes)
- NegativePromptNode: style-aware negative prompt generation
- PromptCombinerNode: blend/concat/weighted_average modes

New graph target:
  PromptGenerator -> PromptRefiner -> PromptCombiner -> CLIP
                          ^
  NegativePrompt ---------+

Closes roadmap phases 1.1-2.3
2026-04-27 07:00:58 +02:00
Gero Doll 758411fdfc Merge pull request #6 from Limbicnation/fix/node-naming-conflict
fix: prefix node keys to resolve naming conflict
2026-03-09 03:25:18 +01:00
limbicnation 26eba3e38c fix: prefix node keys with Limbicnation_ to resolve naming conflict
NODE_CLASS_MAPPINGS keys PromptGenerator and StyleApplier conflicted
with 3 other packages. Prefixed with Limbicnation_ to match PublisherId.
Bumped version to 1.2.0.
2026-03-09 02:37:06 +01:00
Gero Doll 8af678564e Merge pull request #5 from Limbicnation/feature/style-system-consolidation
Feature/style system consolidation
2026-02-27 06:12:49 +01:00
limbicnation 0829dfd336 fix: address code review findings for style system consolidation 2026-02-27 06:10:03 +01:00
limbicnation 3f0ee9b3ee chore: remove unwanted files and update .gitignore 2026-02-27 05:50:50 +01:00
limbicnation 272eb01b6c feat: consolidate style system to 9 styles across both nodes 2026-02-27 05:33:48 +01:00
limbicnation 44ac55e950 docs: fix README icon reference and update heading layout
Point image src to icon.png, remove emoji from heading,
add clear float for proper badge alignment.
2026-02-16 06:32:38 +01:00
limbicnation 394f13c463 docs: update CLAUDE.md to reflect v1.1.6 project state
Sync version, document streaming API with per-chunk timeouts,
add model discovery section, restructure LoRA docs.
2026-02-16 06:13:21 +01:00
limbicnation 6845d8b95f Added .claude/ and AGENTS.md to .gitignore 2026-02-16 06:08:39 +01:00
Gero Doll 16dcc6526c Merge pull request #4 from Limbicnation/fix/streaming-timeout-v1.1.6
fix: replace blocking ollama.generate() with streaming to eliminate 1…
2026-02-16 06:05:02 +01:00
limbicnation 6e2688f5ba fix: replace blocking ollama.generate() with streaming to eliminate 120s timeout errors
Switch to streamed generation with per-chunk timeout enforcement and
ComfyUI ProgressBar integration. Add user-configurable timeout slider
(30-600s), cold-start detection via ollama.ps(), and graceful fallback
to subprocess. Bump version to 1.1.6.
2026-02-16 06:01:47 +01:00
limbicnation b171550164 fix: replace blocking ollama.generate() with streaming to eliminate 120s timeout errors
Switch to streamed generation with per-chunk timeout enforcement and
ComfyUI ProgressBar integration. Add user-configurable timeout slider
(30-600s), cold-start detection via ollama.ps(), and graceful fallback
to subprocess. Bump version to 1.1.6.
2026-02-16 05:49:15 +01:00
limbicnation 1ded90171a fix: add video_wan style and improve LoRA compatibility v1.1.5
- Add minimal 'video_wan' style template optimized for WanVideo LoRA
- Fix issue where LoRA would return empty results for verbose templates
- Improve extract_final_prompt to remove 'None' artifacts
- Bump version to 1.1.5
2026-02-02 05:27:27 +01:00
limbicnation 9ddae78e22 chore: bump version to 1.1.4 and update developer agent memory 2026-02-02 05:21:37 +01:00