Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
d9dea78
feat(canvas): add raster layer blend modes and boolean operations sub…
dunkeroni Oct 29, 2025
7a4c87a
feat(canvas): boolean ops submenu and UI polish
dunkeroni Oct 29, 2025
de37f87
(chore): prettier lint
dunkeroni Oct 29, 2025
f3d9323
add icons to boolean submenu items
dunkeroni Oct 30, 2025
4adaa70
add delete button for color blend operations
dunkeroni Oct 30, 2025
0e535ff
move composite operation type and imports
dunkeroni Nov 1, 2025
47a6092
chore: pnpm eslint
dunkeroni Nov 2, 2025
4484346
update blend modes order
dunkeroni Nov 2, 2025
a006619
update default blend mode to 'color'
dunkeroni Nov 2, 2025
b6a89bd
add i18n for blend modes
dunkeroni Nov 3, 2025
5cd6183
actually use translations for blend modes now
dunkeroni Nov 3, 2025
edcf922
move composite options into types.ts
dunkeroni Nov 13, 2025
8a00690
cleanup and comments
dunkeroni Nov 14, 2025
03f7627
update names
dunkeroni Nov 14, 2025
7c4737f
move constant mapping out of function
dunkeroni Nov 15, 2025
31d7cfc
Merge branch 'main' into feature/raster-blend-boolean
dunkeroni Nov 15, 2025
456d578
WIP not working.
Pfannkuchensack Dec 3, 2025
8db8aa8
Add Z-Image ControlNet V2.0 support
Pfannkuchensack Dec 14, 2025
3ed0e55
fix: resolve linting errors in Z-Image ControlNet support
Pfannkuchensack Dec 21, 2025
1c13ca8
style: apply ruff formatting
Pfannkuchensack Dec 21, 2025
3668d5b
feat(z-image): add Extension-based Z-Image ControlNet support
Pfannkuchensack Dec 21, 2025
b08accd
feat(starter-models): add Z-Image Turbo starter models
Pfannkuchensack Dec 22, 2025
e1acb63
fix(ui): :bug: `HotkeysModal` and `SettingsModal` initial focus (#8687)
joshistoast Dec 22, 2025
f8b1f42
fix(z-image): Fix padding token shape mismatch for GGUF models
Pfannkuchensack Dec 22, 2025
5264b75
Merge branch 'main' into fix/z-image-gguf-padding-token-shape
Pfannkuchensack Dec 22, 2025
84f3e44
Merge branch 'main' into feat/z-image-starter-models
Pfannkuchensack Dec 22, 2025
7b9ce35
Merge branch 'main' into pr/8679
blessedcoolant Dec 22, 2025
874b547
chore: format code for ruff checks
blessedcoolant Dec 22, 2025
2be701c
Feature: Add Tag System for user made Workflows (#8673)
Pfannkuchensack Dec 22, 2025
259304b
Feature(UI): add extract masked area from raster layers (#8667)
DustyShoe Dec 22, 2025
73be5e5
Merge branch 'main' into feature/z-image-control
Pfannkuchensack Dec 22, 2025
14c0823
Merge branch 'main' into feature/raster-blend-boolean
dunkeroni Dec 22, 2025
aa764f8
Feature: z-image Turbo Control Net (#8679)
blessedcoolant Dec 23, 2025
7068cf9
Merge branch 'main' into pr/8690
blessedcoolant Dec 23, 2025
90e3400
fix(z-image): Fix padding token shape mismatch for GGUF models (#8690)
blessedcoolant Dec 23, 2025
a748519
feat(starter-models): add Z-Image Q8 quant and ControlNet Tile
Pfannkuchensack Dec 23, 2025
1b5d91d
Merge branch 'main' into feat/z-image-starter-models
blessedcoolant Dec 23, 2025
5a0b227
feat(starter-models): add Z-Image Turbo starter models (#8689)
blessedcoolant Dec 23, 2025
f82bcd4
fix: CFG Scale min value reset to zero (#8691)
blessedcoolant Dec 24, 2025
73c6b31
feat(model manager): 💄 refactor model manager bulk actions UI (#8684)
joshistoast Dec 24, 2025
3fe5f62
feat(hotkeys): :sparkles: Overhaul hotkeys modal UI (#8682)
joshistoast Dec 24, 2025
39114b0
Feature (UI): add model path update for external models (#8675)
Pfannkuchensack Dec 24, 2025
21138e5
fix support multi-subfolder downloads for Z-Image Qwen3 encoder (#8692)
Pfannkuchensack Dec 24, 2025
4cb9b8d
Feature: add prompt template node (#8680)
Pfannkuchensack Dec 24, 2025
8731414
feat(hotkeys modal): ⚡ loading state + performance improvements (#8694)
joshistoast Dec 24, 2025
5be1e03
Feature/user workflow tags (#8698)
Pfannkuchensack Dec 24, 2025
ac245cb
feat(backend): add support for xlabs Flux LoRA format (#8686)
Pfannkuchensack Dec 24, 2025
ddb85ca
fix(prompts): :bug: prompt attention behaviors, add tests (#8683)
joshistoast Dec 24, 2025
b9493dd
Workaround for Windows being unable to remove tmp directories when in…
lstein Dec 26, 2025
de1aa55
chore: bump version to v6.10.0rc1 (#8695)
lstein Dec 26, 2025
65efc3d
Feature: Add Z-Image-Turbo regional guidance (#8672)
Pfannkuchensack Dec 26, 2025
0b1befa
(chore) Prep for v6.10.0rc2 (#8701)
lstein Dec 26, 2025
4174214
fix(model-manager): add Z-Image LoRA/DoRA detection support
Pfannkuchensack Dec 27, 2025
355c985
fix(model-manager): add Z-Image LoRA/DoRA detection and loading support
Pfannkuchensack Dec 27, 2025
d403587
Merge branch 'fix/z-image-lora-dora-detection' of https://github.com/…
Pfannkuchensack Dec 27, 2025
d42bf9c
fix(model-manager): add Z-Image LoRA/DoRA detection support (#8709)
blessedcoolant Dec 27, 2025
8deafab
feat(prompts): :lipstick: increase prompt font size (#8712)
joshistoast Dec 28, 2025
63ff383
Merge branch 'main' into feature/raster-blend-boolean
lstein Dec 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions docs/RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ The launcher uses GitHub as the source of truth for available releases.

## General Prep

Make a developer call-out for PRs to merge. Merge and test things out. Bump the version by editing `invokeai/version/invokeai_version.py`.
Make a developer call-out for PRs to merge. Merge and test things
out. Create a branch with a name like user/chore/vX.X.X-prep and bump the version by editing
`invokeai/version/invokeai_version.py` and commit locally.

## Release Workflow

Expand All @@ -26,14 +28,14 @@ It is triggered on **tag push**, when the tag matches `v*`.

### Triggering the Workflow

Ensure all commits that should be in the release are merged, and you have pulled them locally.

Double-check that you have checked out the commit that will represent the release (typically the latest commit on `main`).
Ensure all commits that should be in the release are merged into this branch, and that you have pulled them locally.

Run `make tag-release` to tag the current commit and kick off the workflow. You will be prompted to provide a message - use the version specifier.

If this version's tag already exists for some reason (maybe you had to make a last minute change), the script will overwrite it.

Push the commit to trigger the workflow.

> In case you cannot use the Make target, the release may also be dispatched [manually] via GH.

### Workflow Jobs and Process
Expand Down Expand Up @@ -89,7 +91,7 @@ The publish jobs will not run if any of the previous jobs fail.

They use [GitHub environments], which are configured as [trusted publishers] on PyPI.

Both jobs require a @hipsterusername or @psychedelicious to approve them from the workflow's **Summary** tab.
Both jobs require a @lstein or @blessedcoolant to approve them from the workflow's **Summary** tab.

- Click the **Review deployments** button
- Select the environment (either `testpypi` or `pypi` - typically you select both)
Expand All @@ -101,7 +103,7 @@ Both jobs require a @hipsterusername or @psychedelicious to approve them from th

Check the [python infrastructure status page] for incidents.

If there are no incidents, contact @hipsterusername or @lstein, who have owner access to GH and PyPI, to see if access has expired or something like that.
If there are no incidents, contact @lstein or @blessedcoolant, who have owner access to GH and PyPI, to see if access has expired or something like that.

#### `publish-testpypi` Job

Expand Down
9 changes: 9 additions & 0 deletions invokeai/app/api/routers/workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,15 @@ async def get_workflow_thumbnail(
raise HTTPException(status_code=404)


@workflows_router.get("/tags", operation_id="get_all_tags")
async def get_all_tags(
categories: Optional[list[WorkflowCategory]] = Query(default=None, description="The categories to include"),
) -> list[str]:
"""Gets all unique tags from workflows"""

return ApiDependencies.invoker.services.workflow_records.get_all_tags(categories=categories)


@workflows_router.get("/counts_by_tag", operation_id="get_counts_by_tag")
async def get_counts_by_tag(
tags: list[str] = Query(description="The tags to get counts for"),
Expand Down
11 changes: 11 additions & 0 deletions invokeai/app/invocations/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,12 @@ class BoardField(BaseModel):
board_id: str = Field(description="The id of the board")


class StylePresetField(BaseModel):
"""A style preset primitive field"""

style_preset_id: str = Field(description="The id of the style preset")


class DenoiseMaskField(BaseModel):
"""An inpaint mask field"""

Expand Down Expand Up @@ -327,6 +333,11 @@ class ZImageConditioningField(BaseModel):
"""A Z-Image conditioning tensor primitive value"""

conditioning_name: str = Field(description="The name of conditioning tensor")
mask: Optional[TensorField] = Field(
default=None,
description="The mask associated with this conditioning tensor for regional prompting. "
"Excluded regions should be set to False, included regions should be set to True.",
)


class ConditioningField(BaseModel):
Expand Down
57 changes: 57 additions & 0 deletions invokeai/app/invocations/prompt_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from invokeai.app.invocations.baseinvocation import BaseInvocation, BaseInvocationOutput, invocation, invocation_output
from invokeai.app.invocations.fields import InputField, OutputField, StylePresetField, UIComponent
from invokeai.app.services.shared.invocation_context import InvocationContext


@invocation_output("prompt_template_output")
class PromptTemplateOutput(BaseInvocationOutput):
"""Output for the Prompt Template node"""

positive_prompt: str = OutputField(description="The positive prompt with the template applied")
negative_prompt: str = OutputField(description="The negative prompt with the template applied")


@invocation(
"prompt_template",
title="Prompt Template",
tags=["prompt", "template", "style", "preset"],
category="prompt",
version="1.0.0",
)
class PromptTemplateInvocation(BaseInvocation):
"""Applies a Style Preset template to positive and negative prompts.

Select a Style Preset and provide positive/negative prompts. The node replaces
{prompt} placeholders in the template with your input prompts.
"""

style_preset: StylePresetField = InputField(
description="The Style Preset to use as a template",
)
positive_prompt: str = InputField(
default="",
description="The positive prompt to insert into the template's {prompt} placeholder",
ui_component=UIComponent.Textarea,
)
negative_prompt: str = InputField(
default="",
description="The negative prompt to insert into the template's {prompt} placeholder",
ui_component=UIComponent.Textarea,
)

def invoke(self, context: InvocationContext) -> PromptTemplateOutput:
# Fetch the style preset from the database
style_preset = context._services.style_preset_records.get(self.style_preset.style_preset_id)

# Get the template prompts
positive_template = style_preset.preset_data.positive_prompt
negative_template = style_preset.preset_data.negative_prompt

# Replace {prompt} placeholder with the input prompts
rendered_positive = positive_template.replace("{prompt}", self.positive_prompt)
rendered_negative = negative_template.replace("{prompt}", self.negative_prompt)

return PromptTemplateOutput(
positive_prompt=rendered_positive,
negative_prompt=rendered_negative,
)
112 changes: 112 additions & 0 deletions invokeai/app/invocations/z_image_control.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Copyright (c) 2024, Lincoln D. Stein and the InvokeAI Development Team
"""Z-Image Control invocation for spatial conditioning."""

from pydantic import BaseModel, Field

from invokeai.app.invocations.baseinvocation import (
BaseInvocation,
BaseInvocationOutput,
Classification,
invocation,
invocation_output,
)
from invokeai.app.invocations.fields import (
FieldDescriptions,
ImageField,
InputField,
OutputField,
)
from invokeai.app.invocations.model import ModelIdentifierField
from invokeai.app.services.shared.invocation_context import InvocationContext
from invokeai.backend.model_manager.taxonomy import BaseModelType, ModelType


class ZImageControlField(BaseModel):
"""A Z-Image control conditioning field for spatial control (Canny, HED, Depth, Pose, MLSD)."""

image_name: str = Field(description="The name of the preprocessed control image")
control_model: ModelIdentifierField = Field(description="The Z-Image ControlNet adapter model")
control_context_scale: float = Field(
default=0.75,
ge=0.0,
le=2.0,
description="The strength of the control signal. Recommended range: 0.65-0.80.",
)
begin_step_percent: float = Field(
default=0.0,
ge=0.0,
le=1.0,
description="When the control is first applied (% of total steps)",
)
end_step_percent: float = Field(
default=1.0,
ge=0.0,
le=1.0,
description="When the control is last applied (% of total steps)",
)


@invocation_output("z_image_control_output")
class ZImageControlOutput(BaseInvocationOutput):
"""Z-Image Control output containing control configuration."""

control: ZImageControlField = OutputField(description="Z-Image control conditioning")


@invocation(
"z_image_control",
title="Z-Image ControlNet",
tags=["image", "z-image", "control", "controlnet"],
category="control",
version="1.1.0",
classification=Classification.Prototype,
)
class ZImageControlInvocation(BaseInvocation):
"""Configure Z-Image ControlNet for spatial conditioning.

Takes a preprocessed control image (e.g., Canny edges, depth map, pose)
and a Z-Image ControlNet adapter model to enable spatial control.

Supports 5 control modes: Canny, HED, Depth, Pose, MLSD.
Recommended control_context_scale: 0.65-0.80.
"""

image: ImageField = InputField(
description="The preprocessed control image (Canny, HED, Depth, Pose, or MLSD)",
)
control_model: ModelIdentifierField = InputField(
description=FieldDescriptions.controlnet_model,
title="Control Model",
ui_model_base=BaseModelType.ZImage,
ui_model_type=ModelType.ControlNet,
)
control_context_scale: float = InputField(
default=0.75,
ge=0.0,
le=2.0,
description="Strength of the control signal. Recommended range: 0.65-0.80.",
title="Control Scale",
)
begin_step_percent: float = InputField(
default=0.0,
ge=0.0,
le=1.0,
description="When the control is first applied (% of total steps)",
)
end_step_percent: float = InputField(
default=1.0,
ge=0.0,
le=1.0,
description="When the control is last applied (% of total steps)",
)

def invoke(self, context: InvocationContext) -> ZImageControlOutput:
return ZImageControlOutput(
control=ZImageControlField(
image_name=self.image.image_name,
control_model=self.control_model,
control_context_scale=self.control_context_scale,
begin_step_percent=self.begin_step_percent,
end_step_percent=self.end_step_percent,
)
)
Loading