smart_image_gen v0.7.3: edit_image inherits style from prior tool call

User reported edit_image picking 'juggernaut' (photoreal) for an edit
on a furry image — the LLM didn't carry context, and the tool's
fallback _route_style only sees the edit instruction text, which for
neutral edits ('bigger', 'glowing eyes') has no furry keywords.

Fix in two places:

  1. Tool: _inherited_style scans __messages__ in reverse for prior
     generate_image / edit_image tool calls and returns the style arg
     they used. edit_image now resolves: explicit style → inherited →
     keyword fallback. Deterministic, no LLM cooperation needed for
     follow-up edits on previously-generated images.

  2. System prompt: explicit three-step style resolution for
     edit_image. Generated by you → omit style and auto-inherit.
     Uploaded by user → INSPECT visually and pick a matching style
     (the LLM is the only thing with vision; the tool can't see
     pixels). Then keep that style for subsequent edits.

Both paths matter — the tool fix handles the common case
deterministically, the prompt fix handles the upload case where
there's nothing to inherit from.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-19 15:31:57 -05:00
co-authored by Claude Opus 4.7
parent def27087c1
commit 6700f6ce33
3 changed files with 68 additions and 4 deletions
@@ -1,7 +1,7 @@
"""
title: Smart Image Generator & Editor (ComfyUI)
author: ai-stack
version: 0.7.2
version: 0.7.3
description: Generate or edit images via ComfyUI with automatic SDXL
checkpoint routing. Two methods — generate_image (txt2img) and
edit_image (img2img on the user's most recently attached image). The
@@ -20,6 +20,7 @@ import asyncio
import base64
import inspect
import io
import json
import re
import time
import uuid
@@ -222,6 +223,42 @@ def _route_style(prompt: str) -> str:
return DEFAULT_STYLE
def _inherited_style(messages: Optional[list]) -> Optional[str]:
"""
Return the `style` arg from the most recent generate_image /
edit_image tool call in the conversation. Used so edit_image can
auto-inherit the style of the image being edited when the LLM
didn't pass one explicitly — without this, an edit on a furry
image with a neutral edit prompt ("make the eyes glow") falls
through to the keyword router and picks a wrong style.
"""
if not messages:
return None
for msg in reversed(messages):
if not isinstance(msg, dict):
continue
for tc in (msg.get("tool_calls") or []):
if not isinstance(tc, dict):
continue
fn = tc.get("function") or {}
if fn.get("name") not in ("generate_image", "edit_image"):
continue
raw_args = fn.get("arguments")
if isinstance(raw_args, str):
try:
args = json.loads(raw_args)
except (TypeError, ValueError):
args = {}
elif isinstance(raw_args, dict):
args = raw_args
else:
args = {}
style = args.get("style")
if isinstance(style, str) and style in STYLES:
return style
return None
def _seed_value(seed: int) -> int:
return seed if seed > 0 else int(time.time() * 1000) % (2**31)
@@ -799,9 +836,18 @@ class Tools:
Pick `style` for the DESIRED OUTPUT, not the input image.
Style resolution order: explicit `style` arg → inherited from the
most recent prior generate_image / edit_image call in this
conversation → keyword detection on `prompt`. Omit `style` to
let the tool inherit from the previous call automatically — it
usually picks the right thing for follow-up edits on an image
the LLM just generated.
:param prompt: What the changed area should look like.
Tool auto-prepends quality tags — don't include those.
:param style: One of the StyleName values. Omit to auto-detect.
:param style: One of the StyleName values. Omit to auto-inherit
from the previous tool call (recommended for edits on
images you generated earlier in this chat).
:param mask_text: Noun phrase describing the region to edit. Set
for LOCAL changes; omit for GLOBAL.
:param denoise: 0.0 = no change, 1.0 = ignore source. Defaults to
@@ -810,7 +856,12 @@ class Tools:
:param seed: 0 to randomize, otherwise specific.
:return: Markdown image of the result, or an error if no image is attached.
"""
chosen = style or _route_style(prompt)
# Resolve style with explicit > inherited-from-prior-call > keyword.
# Inheritance covers the common case where the LLM is editing an
# image it already generated and forgets to set style — without it,
# neutral edit prompts ("bigger", "glowing eyes") fall through to
# the keyword router and get the wrong checkpoint.
chosen = style or _inherited_style(__messages__) or _route_style(prompt)
settings = STYLES.get(chosen)
if not settings:
return f"Unknown style '{chosen}'. Available: {', '.join(STYLES.keys())}"