Skip to content

Slice 3a: image_edit Modality + Qwen-Image-Edit 2511 (1/2/3 images) (closes part of #5)#19

Open
jmpijll wants to merge 1 commit into
v3.0from
slice/5-qwen-edit
Open

Slice 3a: image_edit Modality + Qwen-Image-Edit 2511 (1/2/3 images) (closes part of #5)#19
jmpijll wants to merge 1 commit into
v3.0from
slice/5-qwen-edit

Conversation

@jmpijll

@jmpijll jmpijll commented Jun 1, 2026

Copy link
Copy Markdown
Owner

Summary

Slice 3a covers the Qwen-Image-Edit 2511 half of issue #5. The
FLUX Kontext on Klein half is deferred to a follow-up issue / PR
because it is gated on Slice 2 fixing the FLUX 2 Klein workflow first.
Issue #5 stays open after this PR merges; the follow-up PR will close
it.

Closes part of #5.

  • New image_edit Modality with one shared Plugin
    (core/modalities/image_edit/plugin.py) - slot-value validation,
    stepped progress mapper, Discord renderer that surfaces the edit
    instruction + every source-image slot + seed + output, default
    post-actions echoing the Manifest's declared Actions (upscale +
    animate are valid follow-ups for an edit Run).
  • Three Qwen-Image-Edit 2511 manifests for 1 / 2 / 3 input images.
    All three share the same loader + sampler graph and differ only in
    the number of LoadImage nodes wired into the
    TextEncodeQwenImageEditPlus conditioning's image2 / image3
    inputs. Lightning 4-step LoRA is baked at node 4; a user-stack LoRA
    at node 5 defaults to strength 0.0.
  • All workflow JSONs were built by introspecting /object_info on
    the live ComfyUI; the only loader filenames in any of them are the
    exact strings that /object_info advertises, and the manifest
    requires blocks declare those exact strings.
  • No new Role values were needed: source_image,
    source_image_2, and source_image_3 already existed in
    core/manifest/roles.py. Modality.IMAGE_EDIT was already present
    too (anticipated by ADR-0002).

Models used (from live /object_info)

  • UNET: qwen_image_edit_2511_fp8mixed.safetensors
  • CLIP: qwen_2.5_vl_7b_fp8_scaled.safetensors (type: qwen_image)
  • VAE: qwen_image_vae.safetensors
  • Lightning LoRA: Qwen-Image-Edit-2511-Lightning-4steps-V1.0-bf16.safetensors
  • User LoRA default: QWEN_EDIT_ACTION_V1.safetensors (strength 0.0)

Acceptance criteria

  • Modality.IMAGE_EDIT = "image_edit" present (it already was).
  • Reuses existing Roles (source_image, source_image_2,
    source_image_3); no new Role added. (See
    core/manifest/roles.py.)
  • ImageEditPlugin validates slot values, exposes a progress
    mapper that sums sampler steps across nodes, renders Outputs
    into a Discord embed, returns Manifest-declared default
    Actions.
  • Plugin registered in core.modalities.default_registry
    (verified by tests/test_image_edit_plugin.py::test_registered_in_default_registry).
  • Three workflow JSONs grounded in /object_info, not copied
    from v2 (workflows/qwen_image_edit_2511_{1image,2images,3images}.json).
  • Three manifests with exact requires filenames + slots for
    prompt, negative_prompt, image_1[/image_2/image_3],
    seed, lora, lora_strength
    (workflows/manifests/qwen_image_edit_2511_*.yaml).
  • Unit tests: tests/test_image_edit_plugin.py +
    tests/test_qwen_edit_manifest_loading.py (44 new tests).
  • Full pytest (excluding tests/integration) green:
    368 passed.
  • Live smoke against http://172.27.1.165:8188 PASSED for all
    three variants
    .

Live smoke evidence

Source images were generated via the existing qwen_image_2512
manifest first, then fed into each edit variant. Full details +
reproduction commands in docs/v3/smoke/SLICE_3_RUNS.md.

variant prompt_id latency output bytes
qwen_image_edit_2511_1image f46e87b3-19a8-41f6-8a97-d5aa5cf9aaf2 21.77 s 2,333,633
qwen_image_edit_2511_2images 8f1e061c-2526-408a-aa81-77ce8b4865da 17.14 s 1,896,280
qwen_image_edit_2511_3images eeb3bf7a-1747-4750-8f87-5a1c0e2d5d14 20.47 s 2,139,755

ComfyUI: RTX 5090, fp8 mixed UNET, 4-step Lightning sampling.

Anchors

  • PRD: docs/v3/PRD.md -- "image edit (1-3 inputs)" item in the
    v3 ship list.
  • ADR-0001: workflow-manifest format (every slot is data, not
    code; requires validated against /object_info).
  • ADR-0002: Plugin Protocol contract (one Plugin per Modality).

Deferred work (NOT in this PR)

Worktree note

This branch was implemented from the worktree at
/Users/jamievanderpijll/discomfy-slice-3-qwen (Slice 4 surfaced a
clobber risk when working directly in the main checkout). The
worktree's venv is a symlink to the main repo's venv, so no
duplicate environment was created.

Test plan

  • pytest -q --ignore=tests/integration -> 368 passed.
  • pytest tests/test_image_edit_plugin.py tests/test_qwen_edit_manifest_loading.py -x -q -> 44 passed.
  • python scripts/v3_smoke.py --manifest qwen_image_edit_2511_1image --slot prompt="..." --slot image_1=... -> OK.
  • python scripts/v3_smoke.py --manifest qwen_image_edit_2511_2images --slot prompt="..." --slot image_1=... --slot image_2=... -> OK.
  • python scripts/v3_smoke.py --manifest qwen_image_edit_2511_3images --slot prompt="..." --slot image_1=... --slot image_2=... --slot image_3=... -> OK.

Made with Cursor

Slice 3a adds the image_edit Modality and three Qwen-Image-Edit 2511
manifests (1, 2, and 3 input images) sharing one Plugin. Workflow JSONs
were built from live /object_info introspection, not by copying the v2
workflows. The user-LoRA at node 5 defaults to strength 0.0 so the
manifest stays safe to register on any server with the declared LoRA
file installed.

Closes part of #5. The FLUX Kontext on Klein half of #5 is deferred to
a follow-up issue / PR because the Klein workflow is gated on Slice 2
fixing FLUX 2 Klein first. Issue #5 stays open.

- core/modalities/image_edit/{__init__,plugin.py}: new ImageEditPlugin
  (modality IMAGE_EDIT, output image/png) with a stepped progress
  mapper, slot-value validator that reuses the manifest-driven
  coercion helpers, a Discord renderer that surfaces the edit
  instruction + every source-image slot + seed + output, and
  default_post_actions that echoes the Manifest's declared Actions.
- core/modalities/{__init__,registry}.py: register ImageEditPlugin in
  the default registry alongside the existing Plugins.
- workflows/qwen_image_edit_2511_{1image,2images,3images}.json: three
  variants of the same graph (UNETLoader -> Lightning LoRA -> user
  LoRA stack -> ModelSamplingAuraFlow -> CFGNorm -> KSampler /
  euler / simple / 4 steps; LoadImage -> ImageScaleToTotalPixels ->
  VAEEncode for the first source; positive + negative
  TextEncodeQwenImageEditPlus conditioning; VAEDecode -> SaveImage).
  Variants differ only in extra LoadImage nodes (16, 17) wired into
  image2 / image3 of the conditioning nodes.
- workflows/manifests/qwen_image_edit_2511_{1image,2images,3images}.yaml:
  manifests with exact /object_info filenames in requires (UNET, VAE,
  CLIP, Lightning LoRA, QWEN_EDIT_ACTION_V1) and 6/7/8 Slots: prompt,
  negative_prompt, image_1[/image_2/image_3], seed, lora, lora_strength.
  Actions declare upscale + animate follow-ups; no model branching.
- tests/test_image_edit_plugin.py: Plugin contract, slot-value
  coercion (incl. multi-image cases), progress monotonicity, render
  output surface + multi-source ordering, default_post_actions
  echoing.
- tests/test_qwen_edit_manifest_loading.py: directory load, requires
  validation (positive + UNET/Lightning-LoRA negative paths), every
  slot target resolves to an existing (node, field) in the workflow
  JSON, slot counts match the variant, attachment positions are
  1-indexed and unique, apply_slots writes through correctly, and
  every loader filename in the workflow appears in the manifest's
  requires list.
- docs/v3/smoke/SLICE_3_RUNS.md: live-smoke evidence (prompt_ids,
  latencies, output bytes) for all three variants against the live
  ComfyUI at 172.27.1.165:8188.

Live smoke evidence (Tuesday, 2026-06-02, all PASSED):
  1image  prompt_id f46e87b3-19a8-41f6-8a97-d5aa5cf9aaf2  21.77s  2,333,633 B
  2images prompt_id 8f1e061c-2526-408a-aa81-77ce8b4865da  17.14s  1,896,280 B
  3images prompt_id eeb3bf7a-1747-4750-8f87-5a1c0e2d5d14  20.47s  2,139,755 B

Tests: 368 passed (full suite, ignoring tests/integration).
Worktree: /Users/jamievanderpijll/discomfy-slice-3-qwen (slice/5-qwen-edit).
Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant