CivArchive
    AGGA 2026: The Sampler & Scheduler Pack I made. - Forge & ReForge (2.1)
    NSFW
    Preview 117511532
    Preview 117511544
    Preview 117511610
    Preview 117511620

    šŸ‘‹ If you like what I do and want to support the development, feel free to buy me a coffee:

    Ko-Fi

    GitHub


    Hey!, you're probably wondering: "Are you still alive...?" No. Well... actually, I'm back with something juicy. The truth is, I'm in the red and I simply refuse to buy another external hard drive just to fill it with thousands of LoRAs.

    So, instead of more gigabytes, I brought you Intelligence. There are always new LoRAs, LyCORIS, and VAEs, but nobody looks at the "brain" of the checkpoint. We need to make it smarter, not just limit ourselves to the classics.

    This is not just a set of scripts; it is an Intelligent Rendering Engine designed for Stable Diffusion. While standard samplers traverse noise linearly, AGGA uses latent masks, dynamic momentum, and temporal anchors to ensure every pixel has a purpose.

    Compatibility Note: These samplers and schedulers are fully cross-compatible with the original A1111/Forge samplers. You can mix standard samplers with AGGA schedulers and vice versa.


    āš ļø Installation (The "Core Touch" Method)

    I had some issues wrapping this as a standard extension (too much overhead), so I went for the most efficient, "Power User" route: Direct Core Integration. It's faster, lighter, and works natively in A1111 and WebUI Forge.

    1. Step 1: Drop the .py files into your modules folder.

    2. Step 2: Open modules/sd_schedulers.py and add this line at the very end:

      import modules.sd_agga_schedulers
    3. Step 3: Open modules/sd_samplers_kdiffusion.py and add this line at the very end:

      import modules.sd_samplers_pseudo_hires_loader

    That's it. No complex installation, just pure python logic injection.


    • 100% Laziness MODE!

    # @title āš™ļø AGGA Engine: Auto-Injector (Run after uploading files)
    # INSTRUCTIONS:
    # 1. Upload 'sd_agga_schedulers.py', 'sd_samplers_pseudo_hires.py', and 'sd_samplers_pseudo_hires_loader.py' to the /content folder.
    # 2. Run this cell. It will auto-detect your WebUI (A1111/Forge) and install the engine.
    
    import shutil
    import os
    from pathlib import Path
    
    # 1. Configuración de Rutas / Path Configuration
    HOME = Path('/content')
    # Lista de posibles rutas de instalación / List of possible install paths
    base_paths = [
        Path('/content/stable-diffusion-webui'),
        Path('/content/webui_forge_cu121_torch231/stable-diffusion-webui'), # Common Forge path
        Path('/content/A1111'),
        Path('/content/gdrive/MyDrive/sd/stable-diffusion-webui')
    ]
    
    # Detectar ruta activa / Detect active path
    WEBUI_PATH = next((p for p in base_paths if p.exists()), Path('/content/stable-diffusion-webui'))
    TARGET_MOD = WEBUI_PATH / "modules"
    
    # 2. Archivos a procesar / Files to process
    agga_files = [
        'sd_agga_schedulers.py',
        'sd_samplers_pseudo_hires.py',
        'sd_samplers_pseudo_hires_loader.py'
    ]
    
    def handle_agga_files():
        missing = []
        if not TARGET_MOD.exists():
            print(f"āŒ Error: 'modules' folder not found in {WEBUI_PATH}")
            return agga_files
    
        print(f"🚚 Moving AGGA Engine to: {TARGET_MOD}")
        for f_name in agga_files:
            src = HOME / f_name
            dst = TARGET_MOD / f_name
    
            if src.exists():
                # Si ya existe en el destino, lo borramos para evitar errores / Overwrite safety
                if dst.exists():
                    os.remove(dst)
    
                shutil.move(str(src), str(dst))
                print(f"  āœ… {f_name} installed successfully.")
            elif not dst.exists():
                missing.append(f_name)
            else:
                print(f"  ā„¹ļø {f_name} was already installed.")
        return missing
    
    def patch_core_module(file_path, import_line):
        if not file_path.exists():
            print(f"  āŒ File not found: {file_path.name}")
            return
    
        content = file_path.read_text()
        if import_line not in content:
            with open(file_path, "a") as f:
                f.write(f"\n{import_line}\n")
            print(f"  šŸ’‰ Code injection applied to: {file_path.name}")
        else:
            print(f"  ✨ {file_path.name} is already patched.")
    
    # --- EXECUTION ---
    print(f"šŸ” WebUI detected at: {WEBUI_PATH}")
    missing_files = handle_agga_files()
    
    if not missing_files:
        print("\nšŸ› ļø Patching Core System...")
        patch_core_module(TARGET_MOD / "sd_schedulers.py", "import modules.sd_agga_schedulers")
        patch_core_module(TARGET_MOD / "sd_samplers_kdiffusion.py", "import modules.sd_samplers_pseudo_hires_loader")
        print(f"\nāœ… AGGA Engine Deployed successfully. Ready to generate.")
    else:
        print(f"\nāš ļø Warning: Source files not found in /content: {', '.join(missing_files)}")
        print("Please upload the .py files to the Colab root folder first.")

    🧠 The "Landing Phase" Concept

    The main difference between AGGA and standard tools lies in the Landing Phase and Noise Injection. Standard samplers often "wash out" details in the final 20% of steps to eliminate noise. AGGA does the opposite: it detects where the edges and textures are and reinforces detail just before finishing.


    šŸ› ļø Sampler Guide (Movement Engines)

    1. The "Pseudo-Hires" Series (General Purpose & Speed)

    • Pseudo-Hires Soft: The base engine. It uses a pure Euler trajectory with a custom noise ramp for a balanced composition without artifacts.

    • Pseudo-Hires Sharp: Introduces an energy reinforcement of 1.12x in the last third of generation (step > 65%), ideal for defining metallic edges and hard textures.

    • Pseudo-Hires Ultra: Our most aggressive configuration. It applies a progressive boost that scales up to 1.18 + progress * 0.10 to maximize detail in hair and skin.

    • DPM++ 2M Pseudo-Hires: A second-order version for those who prefer DPM stability, but with an extra "push" at the end to avoid that typical soft/washed-out look of standard DPM.

    🌟 NEW: AGGA Pseudo-HiRes Flash v9 (Universal Fusion)

    This major update transforms the Flash sampler into a "Universal 4-in-1 Engine". It is no longer just a fast sampler; it acts as a Smart Engine that adapts its mathematics based on your step count and prompt commands:

    • Auto-Rescue Mode (<15 Steps): The engine analyzes the image "energy" at step 0.

      • If the image is too flat/grey, it activates Euler Ancestral to inject life.

      • If the image is too chaotic, it activates DPM++ 2M to enforce structure.

      • If the image is balanced, it uses Native for maximum speed.

    • High-Res Mode (>15 Steps): Automatically activates the classic Flash V2 engine to achieve that sharp, high-contrast texture (latex, armor, mesh details).

    • Fusion Mode (New): You can now mix two samplers in a single generation using prompt tags (see Prompts section below).

    • Exact-Match Math: The internal engines for DPM++ 2M and Euler A have been rewritten to be 1:1 mathematical replicas of the official K-Diffusion library. You get official quality with AGGA's smart logic.

    2. The "Native" Series (Detail & Structure)

    • AGGA Detail-Native: An internal "Refiner" mode. In the last 40% of generation, it "tricks" the model with a lower sigma to force it to draw micro-details like pores and fine hairs without changing the composition.

    • AGGA Structural-Detail (Hybrid) [NEW]: The best of both worlds. The first 45% uses DPM++ 2M logic for perfect anatomical coherence, then seamlessly switches to the AGGA Detail engine to inject texture. Perfect for complex bodies.

    • AGGA Hyper-Detail Hybrid: Splits generation into two distinct phases: the first 66% is dedicated to clean structure (V2) and the rest to aggressive edge refinement (V4).

    3. The "Specialist" Series (Specific Use Cases)

    • AGGA DMD-Turbo Landing: Specifically for distilled models (Lightning/Turbo/4-8 steps). It replaces the last Euler step with a direct interpolation toward the clean image for a "crystalline" finish.

    • AGGA Herrscher-Native: Momentum-based engine (0.50). Includes a recovery system that "pushes" tensor energy if it drops below 1.0, keeping colors and contrast vibrant.

    • AGGA Style-Repair: Designed to rescue the essence of Checkpoints. It extracts a "Style-Delta" by perturbing noise every 3 steps to recover concepts diluted by the model.

    • AGGA Style-Repair Ultra: The definitive version for a "Studio Look". It includes an atmospheric mask that protects the background while repairing the 3D volume of the main subject.

    • AGGA Pixel-Master: A latent quantization engine. In the last step, it applies a spatial resize (Downscale area -> Upscale nearest) to force the model to work on a fixed pixel grid and limited color palette. Use this for authentic Latent Pixel Art (SNES/NES style).


    šŸŒ‰ AGGA Universal Bridge (The Model Translator)

    I decided to make Illustrious, NoobAI, SDXL, and PDXL more compatible with each other. This sampler is a mathematical bridge designed so that models that speak different "languages" (different energy and brightness structures) can understand each other without errors.

    Unlike other samplers that inject LoRA force linearly or abruptly, Universal Bridge uses a Quartic Stability Curve: f(p) = 1.0 - (2p - 1.0)^4. This formula creates a 'plateau' of compatibility in the intermediate steps, protecting the original anatomy at the beginning and preventing the texture from becoming 'pasty' or gray at the end.

    How does it work? When you press "Generate," the sampler performs three critical tasks in milliseconds:

    1. DNA Detection (Step 0): It measures the energy of the base model (checking if it's Velvette, Illustrious, etc.).

    2. Synchronization: If it detects a direction command (e.g., Hacia_Velvette), it adjusts the contrast and color so that the LoRA feels "at home."

    3. Aesthetic Refinement: Applies a Sharpening Injector and a safety floor to prevent the image from looking blurry or gray.

    Practical Example: Prompt: <lora:Pony_Style_V2:1> Hacia_Velvette, Modo_Neutral

    • The system loads a Pony LoRA (Expected Energy: 0.016593).

    • Hacia_Velvette: Translates that DNA towards the Velvette destination (Std: 0.019734). Prevents Pony's aggressive aesthetic from breaking the delicate model.

    • Modo_Neutral: Deactivates heavy color translation but keeps the Sharpening Injector active for perfect edges.


    šŸ“ Scheduler Guide (Noise Maps)

    The scheduler decides how much "strength" the noise has at each step. AGGA offers maps that standard schedulers cannot replicate.

    1. Intelligent & Adaptive (Smart V2)

    • AGGA Smart (Updated to v2): Intelligent logic with 5 time zones based on your step count:

      • 1-4 Steps: Lightning Curve (Instant convergence).

      • 5-8 Steps: Turbo/DMD Curve (Aggressive, optimized for Flash).

      • 9-19 Steps: AYS (Align Your Steps) Curve - The sweet spot for Fusion modes.

      • 20-49 Steps: Dynamic Rho (High fidelity).

      • 50+ Steps: Double Anchor (Deep repair/upscaling).

    • Dynamic Rho: The value of ρ evolves from 5.0 to 9.0. This provides a very stable structure at the beginning and ultra-fine refinement at the end.

    2. Anchors (Time Warping)

    • Style-Anchor: Creates a sinusoidal time "plateau" in the style sigmas. The sampler spends more real-time processing the middle steps where aesthetics are defined.

    • Ultra-Anchor: Reinforced version (factor 0.32). Creates a pseudo-plateau where time seems to stop to inject the maximum amount of style possible.

    • Double-Anchor (The Sniper): Our most advanced scheduler. It combines style anchoring with a "sniper" dip at 82% of the process to fix critical details like eyes and faces.

    • AGGA AYS-Anchor [NEW]: Combines NVIDIA's "Align Your Steps" optimized values with AGGA's anchor warping. Science + Art.

    3. Specialized

    • AGGA DMD: Extreme power curve (ρ = 7.0). Ideal for Lightning models.

    • Log-Linear: A perfect logarithmic distribution. The "gold standard" for the Detail-Native sampler.

    • Pixel-Staircase V1 & V2: A staircase of sigmas. It groups steps (e.g., 3 by 3) so the sampler has time to "settle" the pixel quantization before dropping to the next level. V2 adds "Edge Locking" for cleaner sprites.


    šŸŽ® Prompt Command Guide (Total Control)

    AGGA allows you to control the internal engine behavior directly from your prompt.

    Fusion Commands (For Flash v9 Sampler)

    Mix two engines to get the best of both worlds:

    • fsn_euler_dpm: Creativity + Precision. Euler creates rich colors, DPM cleans lines. (Ideal: Complex illustrations, backgrounds, abstract art).

    • fsn_native_flash: Stability + Texture. Native ensures perfect anatomy, Flash injects the "crunch". (Ideal: Latex, armor, 8k details).

    • fsn_dpm_euler: Structure + Softness. DPM builds a solid body, Euler softens skin at the end. (Ideal: Soft female portraits, oil painting).

    • fsn_native_dpm: The Tank. Maximum structural stability. Almost impossible to break. (Ideal: Difficult hands, complex poses).

    • Split Control: Decide when the switch happens (Default 50%). E.g., split_30 (switch at 30%), split_80.

    Universal Bridge Commands (LoRA Compatibility)

    Use these commands (in Spanish) to direct the DNA translation:

    • Destination (Hacia_): Indicates towards which "DNA" to translate the influence.

      • Hacia_Pony, Hacia_Noobai, Hacia_Illustrious_V2, Hacia_Velvette, Hacia_SDXL, etc.

    • Source (Desde_): To override automatic detection if using a heavily modified merge.

      • Desde_Pony, Desde_Noobai, etc.

    • Power Modes:

      • Modo_Safe: 1:1 Technical compatibility. Avoids errors without changing original colors.

      • Modo_Fuerte: Aggressive injection of color and blacks. Ideal for highlighting character designs.

      • Modo_Ultra: Brute power boost (1.50) for when a LoRA appears invisible.

      • Modo_Neutral: Deactivates color/energy bridge but keeps the Sharpening Injector active.

      • Puente_Inverso / Modo_Reverso: Swaps source and destination.

    Advanced Prompt Example (Combo):

    (masterpiece), 1girl, latex suit, detailed texture, <lora:StylePony:1>, 
    fsn_native_flash, split_70, Hacia_SDXL, Modo_Fuerte

    (This uses Native for 70% for anatomy, Flash at the end for texture, while translating a Pony LoRA to work strongly on an SDXL model).


    Thanks so much for your support! ♄

    Description

    null

    FAQ

    Comments (32)

    Herrscher_AGGA
    Author
    Jan 14, 2026
    CivitAI

    I forgot to mention it, but you don't need to delete your kdiffusion and sd_scheduler files if they're different from the ones I use. Just paste this into each one:

    (in sd_scheduler.py add this at the end: import modules.sd_agga_schedulers) and (in sd_samplers_kdiffusion.py add this at the end: import modules.sd_samplers_pseudo_hires_loader).

    You only need to do this once if they're different from mine.

    CaptainFurryTrashJan 14, 2026Ā· 3 reactions
    CivitAI

    Do these work with Comfy?

    Edit: Nevermind, I figured out that they don't. Do you have any plans to make ones that do?

    Herrscher_AGGA
    Author
    Jan 14, 2026Ā· 5 reactions

    Yes, I was thinking of making them for Reforge too, I'll probably upload them later or tomorrow.

    Herrscher_AGGA
    Author
    Jan 15, 2026Ā· 3 reactions

    :3 ya!

    aaUn17Jan 15, 2026Ā· 3 reactions
    CivitAI

    Any chance of a side by side comparison?

    DefprofJan 15, 2026Ā· 4 reactions
    CivitAI

    Looks like it works with sd-webui-forge-neo. Just make sure you put the import lines AFTER everything else in samplers and schedulers.

    antarekJan 15, 2026Ā· 3 reactions
    CivitAI

    Impressive, thanks for the hard work!
    For info i tested replacing both "sd_schedulers.py" and "sd_samplers_kdiffusion.py" using your versions from your "core" folder inside of the zip file and i couldn't start Forge anymore (error message). But by just manually adding "import modules.sd_agga_schedulers" to "sd_samplers_kdiffusion.py" and "import modules.sd_samplers_pseudo_hires_loader" to "sd_samplers_kdiffusion.py" as explained in your installation instructions everything works fine. So maybe that you should remove the "core" folder from your zip file so people won't face the same issue.

    Herrscher_AGGA
    Author
    Jan 15, 2026Ā· 1 reaction

    Yes, that's why I separated them, since we don't all use the same web UI. Take them as an example xd

    Herrscher_AGGA
    Author
    Jan 15, 2026
    CivitAI

    Hi, I fixed A1111 (I had forgotten to update a sampler and also improved the loader)

    PrometheaJan 15, 2026Ā· 2 reactions
    CivitAI

    ComfyUI nodes don't work. Either Sampler says the object has no attribute Sample, or that tensors are different devices.

    Herrscher_AGGA
    Author
    Jan 15, 2026Ā· 1 reaction

    I just updated the script (for download), but here it is:

    sampler_func = func_map.get(sampler_name, sample_pseudo_hires_soft)

    # ================================================================

    # (THE FIX)

    # ================================================================

    def sampler_wrapper(model, x, sigmas, args, *kwargs):

    # Forzar que los sigmas estƩn en el mismo dispositivo que los latents (GPU)

    if sigmas.device != x.device:

    sigmas = sigmas.to(x.device)

    return sampler_func(model, x, sigmas, args, *kwargs)

    return (sampler_wrapper,)

    PrometheaJan 15, 2026Ā· 1 reaction

    @Herrscher_AGGAĀ Still no luck.

    PrometheaJan 16, 2026

    Maybe I am doing something wrong? Just unzipping and copying it into the custom nodes folder?

    AmatiramisuJan 16, 2026Ā· 3 reactions

    @PrometheaĀ  Two issues:

    1. Syntax error: args, kwargs should be *args, **kwargs (missing asterisk and double asterisk - at least from the comment here it got removed due to formatting.)

    2. (edited for more clarity - sorry):

    at the top of the file:

    import torch

    import torch.nn.functional as F

    import math

    import comfy.samplers <- add this

    -

    then change line 711 from

    return (sampler_wrapper,) to

    return (comfy.samplers.KSAMPLER(sampler_wrapper),)

    PrometheaJan 16, 2026

    @AmatiramisuĀ SamplerCustomAdvanced

    KSAMPLER.sample.<locals>.<lambda>() takes 1 positional argument but 5 were given

    AmatiramisuJan 16, 2026Ā· 1 reaction

    @PrometheaĀ ? gimme a few and let me verify..

    AmatiramisuJan 16, 2026Ā· 1 reaction

    @PrometheaĀ Yeah, sorry my mistake, should've looked more closely. the ksampler wrapper is the right direction but only half the fix. The callback format inside the sampler functions are still written for a1111/forge, and I thought that the comfy-specific zip was actually already converted. Thats a bit more work than this.

    Herrscher_AGGA
    Author
    Jan 16, 2026Ā· 1 reaction

    Sorry, I didn't notice that the asterisk had been deleted from the comment, although it does appear in the file I uploaded yesterday. However, I can't use ComfyUI to test it; it's new to me. I'll try to fix it as soon as possible.

    PrometheaJan 17, 2026Ā· 2 reactions

    @Herrscher_AGGAĀ No pressure. NexorAI showed me some of his generations, and I am just hyped. This concept is much more promising as the 100th new detailer-Lora.

    Herrscher_AGGA
    Author
    Jan 17, 2026Ā· 1 reaction

    I haven't tried it, but it should be better (I'll try it tomorrow): import torch

    import torch.nn.functional as F

    import comfy.sample

    import comfy.samplers

    # =====================================================

    def finalize_sigmas(sigmas: torch.Tensor):

    if sigmas[-1].item() != 0.0:

    sigmas = torch.cat([sigmas, sigmas.new_zeros([1])])

    return sigmas

    # =====================================================

    # SCHEDULERS

    # =====================================================

    def pseudo_hires_sigmas(n, sigma_min, sigma_max, device):

    ramp = torch.linspace(0, 1, n, device=device)

    sigmas = sigma_max torch.exp(-ramp 4.5)

    p0 = int(n * 0.45)

    p1 = int(n * 0.80)

    sigmas[p0:p1] = sigmas[p0]

    sigmas[p1:] = torch.linspace(sigmas[p1], sigma_min, n - p1, device=device)

    # sigmas[-2] = sigmas[-1]

    return finalize_sigmas(sigmas)

    def get_sigmas_agga_dmd(n, sigma_min, sigma_max, device):

    rho = 7.0

    ramp = torch.linspace(0, 1, n, device=device)

    min_inv = sigma_min ** (1 / rho)

    max_inv = sigma_max ** (1 / rho)

    sigmas = (max_inv + ramp (min_inv - max_inv)) * rho

    return finalize_sigmas(sigmas)

    def get_sigmas_log_linear(n, sigma_min, sigma_max, device):

    steps = torch.linspace(0, 1, n, device=device)

    s_max = torch.as_tensor(sigma_max, device=device)

    s_min = torch.as_tensor(sigma_min, device=device)

    sigmas = torch.exp(

    torch.log(s_max) * (1 - steps) +

    torch.log(s_min) * steps

    )

    return finalize_sigmas(sigmas)

    def get_sigmas_dynamic_rho(

    n,

    sigma_min,

    sigma_max,

    device,

    rho_start=5.0,

    rho_end=9.0

    ):

    ramp = torch.linspace(0, 1, n, device=device)

    rhos = rho_start + (rho_end - rho_start) * ramp

    sigmas = torch.empty(n, device=device)

    for i in range(n):

    r = rhos[i]

    min_inv = sigma_min ** (1 / r)

    max_inv = sigma_max ** (1 / r)

    sigmas[i] = (max_inv + ramp[i] (min_inv - max_inv)) * r

    return finalize_sigmas(sigmas)

    def get_sigmas_style_anchor(n, sigma_min, sigma_max, device):

    ramp = torch.linspace(0, 1, n, device=device)

    ramp_anchored = ramp + 0.15 torch.sin(ramp torch.pi)

    sigmas = sigma_max ((sigma_min / sigma_max) * ramp_anchored)

    sigmas[-2] *= 0.9

    return finalize_sigmas(sigmas)

    def get_sigmas_ultra_anchor(n, sigma_min, sigma_max, device):

    ramp = torch.linspace(0, 1, n, device=device)

    ramp_hybrid = ramp + 0.32 torch.sin(ramp torch.pi)

    sigmas = sigma_max ((sigma_min / sigma_max) * ramp_hybrid)

    current_last = sigmas[-3]

    s_min_t = torch.as_tensor(sigma_min, device=device)

    sigmas[-3:] = torch.linspace(

    current_last,

    s_min_t,

    3,

    device=device

    )

    return finalize_sigmas(sigmas)

    def get_sigmas_agga_double_anchor(n, sigma_min, sigma_max, device):

    t = torch.linspace(0, 1, n, device=device)

    style_warp = 0.35 torch.sin(t torch.pi)

    eye_sniper = 0.15 torch.exp(-180 (t - 0.82) ** 2)

    dmd_tail = 0.10 (t * 4)

    t_warped = t + style_warp + eye_sniper + dmd_tail

    t_warped = t_warped / t_warped[-1]

    sigmas = sigma_max ((sigma_min / sigma_max) * (t_warped ** 1.1))

    s_start = torch.log10(sigmas[-4])

    s_end = torch.log10(torch.as_tensor(sigma_min, device=device))

    sigmas[-4:] = torch.logspace(

    s_start,

    s_end,

    4,

    device=device

    )

    return finalize_sigmas(sigmas)

    def get_sigmas_agga_pixel_staircase(n, sigma_min, sigma_max, device):

    t = torch.linspace(0, 1, n, device=device)

    s_max = torch.as_tensor(sigma_max, device=device)

    s_min = torch.as_tensor(sigma_min, device=device)

    sigmas = torch.exp(

    torch.log(s_max) * (1 - t) +

    torch.log(s_min) * t

    )

    for i in range(1, len(sigmas)):

    if i % 3 != 0:

    sigmas[i] = sigmas[i - 1] * 0.98

    return finalize_sigmas(sigmas)

    def get_sigmas_agga_pixel_staircase_v2(

    n,

    sigma_min,

    sigma_max,

    device,

    hold_steps=3,

    decay=0.985

    ):

    t = torch.linspace(0, 1, n, device=device)

    s_max = torch.as_tensor(sigma_max, device=device)

    s_min = torch.as_tensor(sigma_min, device=device)

    sigmas = torch.exp(

    torch.log(s_max) * (1 - t) +

    torch.log(s_min) * t

    )

    for i in range(1, len(sigmas)):

    if i % hold_steps != 0:

    sigmas[i] = sigmas[i - 1] * decay

    return finalize_sigmas(sigmas)

    def get_sigmas_agga_smart(n, sigma_min, sigma_max, device):

    if n <= 8:

    return get_sigmas_agga_dmd(n, sigma_min, sigma_max, device)

    return get_sigmas_dynamic_rho(n, sigma_min, sigma_max, device)

    def get_sigmas_agga_ays_anchor(n, sigma_min, sigma_max, device):

    ays_base = torch.tensor(

    [14.615, 6.315, 3.771, 2.181, 1.342,

    0.862, 0.555, 0.380, 0.234, 0.113, 0.029],

    device=device

    )

    t = torch.linspace(0, 1, n, device=device)

    t_warped = t + 0.15 torch.sin(t torch.pi)

    log_base = ays_base.log()

    indices = t_warped * (len(log_base) - 1)

    idx0 = indices.floor().long().clamp(0, len(log_base) - 2)

    idx1 = idx0 + 1

    alpha = indices - idx0

    log_sigmas = (

    log_base[idx0] * (1 - alpha) +

    log_base[idx1] * alpha

    )

    sigmas = torch.exp(log_sigmas)

    return finalize_sigmas(sigmas)

    # =====================================================

    # SAMPLERS

    # =====================================================

    @torch.no_grad()

    def sample_pseudo_hires_soft(model, x, sigmas, extra_args=None, callback=None, **kwargs):

    extra_args = {} if extra_args is None else extra_args

    s_in = x.new_ones([x.shape[0]])

    total_steps = len(sigmas) - 1

    for i in range(total_steps):

    sigma, sigma_next = sigmas[i], sigmas[i + 1]

    dt = sigma_next - sigma

    denoised = model(x, sigma s_in, *extra_args)

    d = (x - denoised) / sigma

    x = x + d * dt

    if callback:

    callback(i, x, denoised, total_steps, sigma)

    return x

    @torch.no_grad()

    def sample_pseudo_hires_sharp(model, x, sigmas, extra_args=None, callback=None, **kwargs):

    extra_args = {} if extra_args is None else extra_args

    s_in = x.new_ones([x.shape[0]])

    total_steps = len(sigmas) - 1

    for i in range(total_steps):

    sigma, sigma_next = sigmas[i], sigmas[i + 1]

    dt = sigma_next - sigma

    denoised = model(x, sigma s_in, *extra_args)

    d = (x - denoised) / sigma

    if i > total_steps * 0.65:

    x = x + d dt 1.12

    else:

    x = x + d * dt

    if callback:

    callback(i, x, denoised, total_steps, sigma)

    return x

    @torch.no_grad()

    def sample_pseudo_hires_ultra(model, x, sigmas, extra_args=None, callback=None, **kwargs):

    extra_args = {} if extra_args is None else extra_args

    s_in = x.new_ones([x.shape[0]])

    total_steps = len(sigmas) - 1

    for i in range(total_steps):

    sigma, sigma_next = sigmas[i], sigmas[i + 1]

    dt = sigma_next - sigma

    denoised = model(x, sigma s_in, *extra_args)

    d = (x - denoised) / sigma

    if i > total_steps * 0.55:

    boost = 1.18 + (i / total_steps) * 0.10

    x = x + d dt boost

    else:

    x = x + d * dt

    if callback:

    callback(i, x, denoised, total_steps, sigma)

    return x

    @torch.no_grad()

    def sample_dpmpp_2m_pseudo_hires(model, x, sigmas, extra_args=None, callback=None, **kwargs):

    extra_args = {} if extra_args is None else extra_args

    s_in = x.new_ones([x.shape[0]])

    total_steps = len(sigmas) - 1

    old_denoised = None

    for i in range(total_steps):

    sigma, sigma_next = sigmas[i], sigmas[i + 1]

    dt = sigma_next - sigma

    denoised = model(x, sigma s_in, *extra_args)

    if old_denoised is None:

    d = (x - denoised) / sigma

    x = x + d * dt

    else:

    d = (x - denoised) / sigma

    d_old = (x - old_denoised) / \

    sigmas[max(i-1, 0)] if old_denoised is not None else d

    correction = 0.5 (d + d_old) dt

    x = x + correction * 1.0

    if i > total_steps * 0.60:

    boost = 1.12 + (i / total_steps) * 0.08

    x = x + d dt boost

    old_denoised = denoised

    if callback:

    callback(i, x, denoised, total_steps, sigma)

    return x

    @torch.no_grad()

    def sample_pseudo_hires_flash_v2(model, x, sigmas, extra_args=None, callback=None, **kwargs):

    extra_args = extra_args or {}

    s_in = x.new_ones([x.shape[0]])

    total_steps = len(sigmas) - 1

    old_denoised = None

    for i in range(total_steps):

    sigma, sigma_next = sigmas[i], sigmas[i + 1]

    dt = sigma_next - sigma

    denoised = model(x, sigma s_in, *extra_args)

    if old_denoised is None:

    d = (x - denoised) / sigma

    x = x + d dt 1.05

    else:

    d = (x - denoised) / sigma

    d_old = (x - old_denoised) / sigmas[max(i-1, 0)]

    x = x + (0.6 d + 0.4 d_old) * dt

    if i > total_steps * 0.50:

    progress = (i - total_steps 0.50) / (total_steps 0.50)

    boost = 1.08 + progress * 0.18

    x = x + d dt boost

    if i == total_steps - 1:

    x = x + (denoised - x) * 0.15

    old_denoised = denoised

    if callback:

    callback(i, x, denoised, total_steps, sigma)

    return x

    @torch.no_grad()

    def sample_pseudo_hires_detail(model, x, sigmas, extra_args=None, callback=None, **kwargs):

    extra_args = extra_args or {}

    s_in = x.new_ones([x.shape[0]])

    total_steps = len(sigmas) - 1

    def get_detail_mask(latent):

    dy = torch.abs(latent[:, :, 1:, :] - latent[:, :, :-1, :])

    dx = torch.abs(latent[:, :, :, 1:] - latent[:, :, :, :-1])

    dy = F.pad(dy, (0, 0, 0, 1), mode='replicate')

    dx = F.pad(dx, (0, 1, 0, 0), mode='replicate')

    grad = torch.sqrt(dx**2 + dy**2).mean(dim=1, keepdim=True)

    grad = torch.clamp(grad * 2.0, 0.0, 1.0)

    return grad

    for i in range(total_steps):

    sigma, sigma_next = sigmas[i], sigmas[i + 1]

    dt = sigma_next - sigma

    denoised = model(x, sigma s_in, *extra_args)

    d = (x - denoised) / sigma

    progress = i / total_steps

    if progress < 0.4:

    multiplier = 1.05

    elif progress < 0.7:

    multiplier = 1.10 + (progress * 0.10)

    else:

    multiplier = 1.0

    x_next = x + d dt multiplier

    if progress >= 0.7:

    detail_mask = get_detail_mask(x)

    refine_strength = 0.05 * (1.0 - progress)

    x_next = x_next + (denoised - x_next) * \

    refine_strength * detail_mask

    sharpen_strength = 0.03 * detail_mask

    x_next = x_next + (x_next - x) * sharpen_strength

    x = x_next

    if callback:

    callback(i, x, denoised, total_steps, sigma)

    return torch.clamp(x, -5.0, 5.0)

    @torch.no_grad()

    def sample_agga_dmd_turbo(model, x, sigmas, extra_args=None, callback=None, **kwargs):

    extra_args = extra_args or {}

    s_in = x.new_ones([x.shape[0]])

    total_steps = len(sigmas) - 1

    for i in range(total_steps):

    sigma, sigma_next = sigmas[i], sigmas[i + 1]

    dt = sigma_next - sigma

    denoised = model(x, sigma s_in, *extra_args)

    d = (x - denoised) / sigma

    if i < total_steps - 1:

    x = x + d * dt

    else:

    x = x + (denoised - x) * 0.85

    blurred_x = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1)

    sharpen_map = x - blurred_x

    x = x + sharpen_map * 0.15

    if callback:

    callback(i, x, denoised, total_steps, sigma)

    return torch.clamp(x, -5.0, 5.0)

    @torch.no_grad()

    def sample_agga_herrscher_native(model, x, sigmas, extra_args=None, callback=None, **kwargs):

    extra_args = extra_args or {}

    s_in = x.new_ones([x.shape[0]])

    total_steps = len(sigmas) - 1

    momentum_beta = 0.50

    momentum = None

    for i in range(total_steps):

    sigma, sigma_next = sigmas[i], sigmas[i+1]

    dt = sigma_next - sigma

    denoised = model(x, sigma s_in, *extra_args)

    d = (x - denoised) / sigma

    if momentum is None:

    momentum = d

    else:

    momentum = momentum_beta momentum + (1 - momentum_beta) d

    x_next = x + momentum * dt

    progress = i / total_steps

    if 0.2 < progress < 0.9:

    mag = x_next.std()

    if mag < 1.0:

    scale_factor = (1.0 / (mag + 1e-6)) * 0.05

    x_next = x_next * (1.0 + scale_factor)

    x_next = x_next - (x_next.mean() * 0.02)

    x = x_next

    if callback:

    callback(i, x, denoised, total_steps, sigma)

    return torch.clamp(x, -5.0, 5.0)

    @torch.no_grad()

    def sample_agga_detail_native(model, x, sigmas, extra_args=None, callback=None, **kwargs):

    extra_args = extra_args or {}

    s_in = x.new_ones([x.shape[0]])

    total_steps = len(sigmas) - 1

    for i in range(total_steps):

    sigma, sigma_next = sigmas[i], sigmas[i + 1]

    progress = i / total_steps

    denoised = model(x, sigma s_in, *extra_args)

    if i > 0:

    dy = torch.abs(denoised[:, :, 1:, :] - denoised[:, :, :-1, :])

    dx = torch.abs(denoised[:, :, :, 1:] - denoised[:, :, :, :-1])

    dy = F.pad(dy, (0, 0, 0, 1), mode='replicate')

    dx = F.pad(dx, (0, 1, 0, 0), mode='replicate')

    detail_mask = torch.clamp(

    (dx + dy).mean(dim=1, keepdim=True) * 2.5, 0.0, 1.0)

    if progress > 0.60:

    sigma_refine = sigma * 0.95

    refine_denoised = model(x, sigma_refine s_in, *extra_args)

    denoised = denoised + \

    (refine_denoised - denoised) (0.4 detail_mask)

    else:

    blurred = F.avg_pool2d(denoised, 3, 1, 1)

    denoised = denoised + \

    (denoised - blurred) (0.12 detail_mask)

    if i < total_steps - 1:

    x = denoised + (x - denoised) * (sigma_next / sigma)

    else:

    x = denoised

    if callback:

    callback(i, x, denoised, total_steps, sigma)

    return torch.clamp(x, -5.0, 5.0)

    @torch.no_grad()

    def sample_agga_hyper_detail_hybrid(model, x, sigmas, extra_args=None, callback=None, **kwargs):

    extra_args = extra_args or {}

    s_in = x.new_ones([x.shape[0]])

    total_steps = len(sigmas) - 1

    split_step = int(total_steps * 0.66)

    for i in range(total_steps):

    sigma, sigma_next = sigmas[i], sigmas[i + 1]

    denoised = model(x, sigma s_in, *extra_args)

    dy = torch.abs(denoised[:, :, 1:, :] - denoised[:, :, :-1, :])

    dx = torch.abs(denoised[:, :, :, 1:] - denoised[:, :, :, :-1])

    dy = F.pad(dy, (0, 0, 0, 1), mode='replicate')

    dx = F.pad(dx, (0, 1, 0, 0), mode='replicate')

    detail_mask = torch.clamp(

    (dx + dy).mean(dim=1, keepdim=True) * 2.5, 0.0, 1.0)

    if i >= split_step:

    sigma_refine = sigma * 0.95

    refine_denoised = model(x, sigma_refine s_in, *extra_args)

    denoised = denoised + \

    (refine_denoised - denoised) (0.45 detail_mask)

    else:

    blurred = F.avg_pool2d(denoised, 3, 1, 1)

    denoised = denoised + (denoised - blurred) (0.12 detail_mask)

    if i < total_steps - 1:

    x = denoised + (x - denoised) * (sigma_next / sigma)

    x_std = x.std()

    if x_std < 1.0:

    x = x (1.0 + (1.0 - x_std) 0.05)

    else:

    x = denoised

    if callback:

    callback(i, x, denoised, total_steps, sigma)

    return torch.clamp(x, -5.0, 5.0)

    @torch.no_grad()

    def sample_agga_style_repair_prompt_aware(model, x, sigmas, extra_args=None, callback=None, **kwargs):

    extra_args = extra_args or {}

    s_in = x.new_ones([x.shape[0]])

    total_steps = len(sigmas) - 1

    BOCETADO_STEPS = int(total_steps * 0.40)

    prev_x = x.clone()

    for i in range(total_steps):

    sigma = sigmas[i]

    sigma_next = sigmas[i + 1]

    dt = sigma_next - sigma

    denoised = model(x, sigma s_in, *extra_args)

    style_force_vector = None

    last_noise_uncond = getattr(model, 'last_noise_uncond', None)

    if last_noise_uncond is not None and i > BOCETADO_STEPS:

    uncond_denoised = x - sigma * last_noise_uncond

    style_force_vector = denoised - uncond_denoised

    dy = torch.abs(denoised[:, :, 1:, :] - denoised[:, :, :-1, :])

    dx = torch.abs(denoised[:, :, :, 1:] - denoised[:, :, :, :-1])

    dy = F.pad(dy, (0, 0, 0, 1), mode='replicate')

    dx = F.pad(dx, (0, 1, 0, 0), mode='replicate')

    style_mask = torch.clamp(torch.sqrt(

    dx**2 + dy**2).mean(dim=1, keepdim=True) * 2.8, 0.0, 1.0)

    if i < BOCETADO_STEPS:

    boost = 1.20 + (i / BOCETADO_STEPS) * 0.20

    d = (x - denoised) / sigma

    x = x + d dt boost

    else:

    if style_force_vector is not None:

    prompt_guidance = style_force_vector style_mask 0.25

    x = x + prompt_guidance * torch.abs(dt)

    x = x + (x - prev_x) 0.035 style_mask

    d = (x - denoised) / sigma

    x = x + d * dt

    if i >= BOCETADO_STEPS:

    x_std = x.std()

    if x_std > 1.15:

    x = x * (1.15 / x_std)

    prev_x = x.clone()

    if callback:

    callback(i, x, denoised, total_steps, sigma)

    return torch.clamp(x, -5.0, 5.0)

    @torch.no_grad()

    def sample_agga_style_repair_pro(model, x, sigmas, extra_args=None, callback=None, **kwargs):

    extra_args = extra_args or {}

    s_in = x.new_ones([x.shape[0]])

    total_steps = len(sigmas) - 1

    BOCETADO_STEPS = int(total_steps * 0.40)

    prev_x = x.clone()

    for i in range(total_steps):

    sigma, sigma_next = sigmas[i], sigmas[i + 1]

    progress = i / total_steps

    denoised = model(x, sigma s_in, *extra_args)

    dy = torch.abs(denoised[:, :, 1:, :] - denoised[:, :, :-1, :])

    dx = torch.abs(denoised[:, :, :, 1:] - denoised[:, :, :, :-1])

    dy = F.pad(dy, (0, 0, 0, 1), mode='replicate')

    dx = F.pad(dx, (0, 1, 0, 0), mode='replicate')

    style_mask = torch.clamp(torch.sqrt(

    dx**2 + dy**2).mean(dim=1, keepdim=True) * 2.8, 0.0, 1.0)

    if i < BOCETADO_STEPS:

    boost = 1.20 + (i / BOCETADO_STEPS) * 0.25

    d = (x - denoised) / sigma

    x = x + d (sigma_next - sigma) boost

    else:

    strength = 0.05 + progress * 0.15

    x = x + (denoised - x) strength style_mask

    if i % 3 == 0 and i < total_steps - 1:

    sigma_style = sigma (1.12 + 0.05 (progress - 0.4))

    denoised_style = model(x, sigma_style s_in, *extra_args)

    style_delta = (denoised_style - denoised) 0.04 style_mask

    x = x + style_delta

    x = x + (x - prev_x) 0.035 style_mask

    if i < total_steps - 1 and i >= BOCETADO_STEPS:

    x = denoised + (x - denoised) * (sigma_next / sigma)

    x_std = x.std()

    if x_std < 1.08:

    x = x * (1.08 / (x_std + 1e-6))

    elif i == total_steps - 1:

    x = denoised + (x - denoised) * 0.07

    prev_x = x.clone()

    if callback:

    callback(i, x, denoised, total_steps, sigma)

    return torch.clamp(x, -5.0, 5.0)

    @torch.no_grad()

    def sample_agga_style_repair_ultra(model, x, sigmas, extra_args=None, callback=None, **kwargs):

    extra_args = extra_args or {}

    s_in = x.new_ones([x.shape[0]])

    total_steps = len(sigmas) - 1

    BOCETADO_STEPS = int(total_steps * 0.45)

    prev_x = x.clone()

    for i in range(total_steps):

    sigma, sigma_next = sigmas[i], sigmas[i + 1]

    dt = sigma_next - sigma

    progress = i / total_steps

    denoised = model(x, sigma s_in, *extra_args)

    d = (x - denoised) / sigma

    dy = torch.abs(denoised[:, :, 1:, :] - denoised[:, :, :-1, :])

    dx = torch.abs(denoised[:, :, :, 1:] - denoised[:, :, :, :-1])

    dy = F.pad(dy, (0, 0, 0, 1), mode='replicate')

    dx = F.pad(dx, (0, 1, 0, 0), mode='replicate')

    style_mask = torch.clamp(torch.sqrt(

    dx**2 + dy**2).mean(dim=1, keepdim=True) * 2.8, 0.0, 1.0)

    if i < BOCETADO_STEPS:

    x = x + d * dt

    else:

    speed_factor = torch.exp(-torch.abs(dt) * 2.5).item()

    u_boost = 1.18 + progress * 0.12

    if i % 2 == 0 or speed_factor > 0.6:

    sigma_style = sigma (1.15 + 0.05 (progress - 0.4))

    denoised_style = model(x, sigma_style s_in, *extra_args)

    atm_mask = torch.clamp(style_mask + 0.20, 0.0, 1.0)

    style_delta = (denoised_style - denoised) * \

    0.05 atm_mask (1.0 + speed_factor)

    x = x + style_delta * u_boost

    x = x + d dt u_boost

    sharpen = 0.038 + (speed_factor * 0.015)

    x = x + (x - prev_x) sharpen style_mask

    if i == total_steps - 1:

    x = denoised + (x - denoised) * 0.08

    prev_x = x.clone()

    if callback:

    callback(i, x, denoised, total_steps, sigma)

    return torch.clamp(x, -5.5, 5.5)

    @torch.no_grad()

    def sample_agga_pixel_master(model, x, sigmas, extra_args=None, callback=None, **kwargs):

    extra_args = extra_args or {}

    s_in = x.new_ones([x.shape[0]])

    total_steps = len(sigmas) - 1

    block_size = 1.88

    for i in range(total_steps):

    sigma = sigmas[i]

    sigma_next = sigmas[i + 1]

    dt = sigma_next - sigma

    denoised = model(x, sigma s_in, *extra_args)

    d = (x - denoised) / sigma

    x = x + d * dt

    if i == total_steps - 1:

    latents = denoised

    h, w = latents.shape[-2:]

    small_h, small_w = int(h / block_size), int(w / block_size)

    latents_pixelated = F.interpolate(

    latents, size=(small_h, small_w), mode='area')

    latents_pixelated = F.interpolate(

    latents_pixelated, size=(h, w), mode='nearest')

    x = latents_pixelated

    if callback:

    callback(i, x, denoised, total_steps, sigma)

    return x

    @torch.no_grad()

    def sample_agga_structural_detail(model, x, sigmas, extra_args=None, callback=None, **kwargs):

    extra_args = extra_args or {}

    s_in = x.new_ones([x.shape[0]])

    total_steps = len(sigmas) - 1

    old_d = None

    split_idx = int(total_steps * 0.45)

    for i in range(total_steps):

    sigma = sigmas[i]

    sigma_next = sigmas[i + 1]

    dt = sigma_next - sigma

    denoised = model(x, sigma s_in, *extra_args)

    d = (x - denoised) / sigma

    if i < split_idx:

    if old_d is None:

    x = x + d * dt

    else:

    x = x + 0.5 (d + old_d) dt

    else:

    dy = torch.abs(denoised[:, :, 1:, :] - denoised[:, :, :-1, :])

    dx = torch.abs(denoised[:, :, :, 1:] - denoised[:, :, :, :-1])

    dy = F.pad(dy, (0, 0, 0, 1), mode='replicate')

    dx = F.pad(dx, (0, 1, 0, 0), mode='replicate')

    detail_mask = torch.clamp(

    (dx + dy).mean(dim=1, keepdim=True) * 2.2, 0.0, 1.0)

    progress_phase2 = (i - split_idx) / (total_steps - split_idx)

    boost_amount = 1.0 + (progress_phase2 * 0.15)

    final_dt = dt (1.0 + (boost_amount - 1.0) detail_mask)

    x = x + d * final_dt

    if progress_phase2 > 0.6:

    x = x + (x - x.clone()) 0.04 detail_mask

    old_d = d

    if callback:

    callback(i, x, denoised, total_steps, sigma)

    return torch.clamp(x, -5.0, 5.0)

    # =====================================================

    class AGGA_KSampler_Pro:

    @classmethod

    def INPUT_TYPES(cls):

    return {

    "required": {

    "model": ("MODEL",),

    "seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),

    "steps": ("INT", {"default": 20, "min": 1, "max": 10000}),

    "cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0}),

    "sampler_name": ([

    "AGGA Pseudo-HiRes Soft",

    "AGGA Pseudo-HiRes Sharp",

    "AGGA Pseudo-HiRes Ultra",

    "AGGA DPM++ 2M Pseudo",

    "AGGA Flash v2",

    "AGGA Detail",

    "AGGA DMD Turbo",

    "AGGA Herrscher Native",

    "AGGA Detail Native",

    "AGGA Hyper Detail Hybrid",

    "AGGA Style Repair Prompt",

    "AGGA Style Repair Pro",

    "AGGA Style Repair Ultra",

    "AGGA Pixel Master",

    "AGGA Structural Detail",

    ],),

    "scheduler": ([

    "agga_log_linear",

    "agga_dmd",

    "agga_pseudo_hires",

    "agga_dynamic_rho",

    "agga_style_anchor",

    "agga_ultra_anchor",

    "agga_double_anchor",

    "agga_pixel_staircase",

    "agga_pixel_staircase_v2",

    "agga_smart",

    "agga_ays_anchor",

    ],),

    "positive": ("CONDITIONING",),

    "negative": ("CONDITIONING",),

    "latent_image": ("LATENT",),

    }

    }

    RETURN_TYPES = ("LATENT",)

    FUNCTION = "sample"

    CATEGORY = "sampling/custom_sampling"

    def sample(self, model, seed, steps, cfg, sampler_name, scheduler,

    positive, negative, latent_image):

    latent = latent_image["samples"]

    device = latent.device

    torch.manual_seed(seed)

    noise = torch.randn_like(latent)

    model_sampling = model.get_model_object("model_sampling")

    sigma_min, sigma_max = model_sampling.sigma_min, model_sampling.sigma_max

    scheduler_map = {

    "agga_log_linear": get_sigmas_log_linear,

    "agga_dmd": get_sigmas_agga_dmd,

    "agga_pseudo_hires": pseudo_hires_sigmas,

    "agga_dynamic_rho": get_sigmas_dynamic_rho,

    "agga_style_anchor": get_sigmas_style_anchor,

    "agga_ultra_anchor": get_sigmas_ultra_anchor,

    "agga_double_anchor": get_sigmas_agga_double_anchor,

    "agga_pixel_staircase": get_sigmas_agga_pixel_staircase,

    "agga_pixel_staircase_v2": get_sigmas_agga_pixel_staircase_v2,

    "agga_smart": get_sigmas_agga_smart,

    "agga_ays_anchor": get_sigmas_agga_ays_anchor,

    }

    sigmas_fn = scheduler_map.get(scheduler, get_sigmas_log_linear)

    sigmas = sigmas_fn(steps, sigma_min, sigma_max, device)

    sampler_map = {

    "AGGA Pseudo-HiRes Soft": sample_pseudo_hires_soft,

    "AGGA Pseudo-HiRes Sharp": sample_pseudo_hires_sharp,

    "AGGA Pseudo-HiRes Ultra": sample_pseudo_hires_ultra,

    "AGGA DPM++ 2M Pseudo": sample_dpmpp_2m_pseudo_hires,

    "AGGA Flash v2": sample_pseudo_hires_flash_v2,

    "AGGA Detail": sample_pseudo_hires_detail,

    "AGGA DMD Turbo": sample_agga_dmd_turbo,

    "AGGA Herrscher Native": sample_agga_herrscher_native,

    "AGGA Detail Native": sample_agga_detail_native,

    "AGGA Hyper Detail Hybrid": sample_agga_hyper_detail_hybrid,

    "AGGA Style Repair Prompt": sample_agga_style_repair_prompt_aware,

    "AGGA Style Repair Pro": sample_agga_style_repair_pro,

    "AGGA Style Repair Ultra": sample_agga_style_repair_ultra,

    "AGGA Pixel Master": sample_agga_pixel_master,

    "AGGA Structural Detail": sample_agga_structural_detail,

    }

    sampler_func = sampler_map[sampler_name]

    sampler = comfy.samplers.SamplerCustom(sampler_func)

    samples = comfy.sample.sample_custom(

    model=model,

    noise=noise,

    cfg=cfg,

    sampler=sampler,

    sigmas=sigmas,

    positive=positive,

    negative=negative,

    latent_image=latent_image,

    noise_mask=None,

    callback=None,

    disable_pbar=False,

    seed=seed,

    )

    return ({"samples": samples},)

    # =====================================================

    NODE_CLASS_MAPPINGS = {

    "AGGA KSampler Pro": AGGA_KSampler_Pro

    }

    NODE_DISPLAY_NAME_MAPPINGS = {

    "AGGA KSampler Pro": "AGGA KSampler (All-in-One)"

    }

    PrometheaJan 18, 2026Ā· 2 reactions

    Sadly, with the new code, the nodes don't show up at all. :/

    Herrscher_AGGA
    Author
    Jan 18, 2026Ā· 1 reaction

    I've managed to get it working and generating images, but they come out blurry. I'll see if I can finish it today; ComfyUI is very sensitive to samplers.

    Herrscher_AGGA
    Author
    Jan 19, 2026Ā· 1 reaction

    Sorry, but it’s not happening. This is all new territory for me, and despite all my research, I just can't get it right. It’s always something—either the nodes fail, or the image looks awful. NexorAI got it running in ComfyUI (apparently using Gemini), so you might want to look into that, but I haven't had any luck making it work myself:

    import torch import torch.nn.functional as F import math # --- SCHEDULER LOGIK MIT SICHERHEITS-FALLSCHIRM --- def get_sigmas_agga_double_anchor(n, sigma_min, sigma_max, device): try: # Sicherstellen, dass keine Null-Werte den Logarithmus killen s_min = torch.as_tensor(max(sigma_min, 0.0001), device=device) s_max = torch.as_tensor(max(sigma_max, 0.0001), device=device) t = torch.linspace(0, 1, n, device=device) # AGGA Kurve t_warped = (t + 0.35 torch.sin(t math.pi) + 0.15 torch.exp(-180 (t - 0.82)**2)) t_warped = t_warped / t_warped[-1] sigmas = s_max ((s_min / s_max) * (t_warped**1.1)) if n > 4: sigmas[-4:] = torch.logspace(torch.log10(sigmas[-4]), torch.log10(s_min), 4, device=device) return torch.cat([sigmas, sigmas.new_zeros([1])]) except Exception as e: print(f"AGGA ERROR: Fallback auf Standard-Sigmas wegen: {e}") steps = torch.linspace(0, 1, n, device=device) sig = torch.exp(torch.log(torch.as_tensor(sigma_max, device=device)) (1 - steps) + torch.log(torch.as_tensor(sigma_min, device=device)) steps) return torch.cat([sig, sig.new_zeros([1])])

    def get_sigmas_log_linear(n, sigma_min, sigma_max, device): steps = torch.linspace(0, 1, n, device=device) sigmas = torch.exp(torch.log(torch.as_tensor(sigma_max, device=device)) (1 - steps) + torch.log(torch.as_tensor(sigma_min, device=device)) steps) return torch.cat([sigmas, sigmas.new_zeros([1])]) # --- SAMPLER LOGIK --- @torch.no_grad() def sample_agga_structural_detail(model, x, sigmas, **kwargs): extra_args = kwargs.get('extra_args', {}) s_in = x.new_ones([x.shape[0]]) total_steps = len(sigmas) - 1 for i in range(total_steps): sigma, sigma_next = sigmas[i], sigmas[i + 1] denoised = model(x, sigma s_in, *extra_args) boost = (1.0 + (i/total_steps 0.2)) if i > (total_steps 0.45) else 1.0 x = x + ((x - denoised) / sigma) (sigma_next - sigma) boost return x # --- COMFYUI NODES --- class AGGASchedulerNode: @classmethod def INPUT_TYPES(s): return {"required": {"model": ("MODEL",), "steps": ("INT", {"default": 25, "min": 1, "max": 1000}), "denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0}), "scheduler": (["agga_double_anchor", "standard"],)}} RETURN_TYPES = ("SIGMAS",) FUNCTION = "get_sigmas" CATEGORY = "sampling/custom_sampling"

    def get_sigmas(self, model, steps, denoise, scheduler): device = torch.device("cuda" if torch.cuda.is_available() else "cpu") ms = model.get_model_object("model_sampling") # Sicherheits-Check für das Modell-Objekt s_min = ms.sigma_min if ms else 0.02 s_max = ms.sigma_max if ms else 14.6 s = int(steps / denoise) if denoise < 1.0 else steps if scheduler == "agga_double_anchor": sigmas = get_sigmas_agga_double_anchor(s, s_min, s_max, device) else: sigmas = get_sigmas_log_linear(s, s_min, s_max, device) if denoise < 1.0: sigmas = sigmas[-(steps + 1):] return (sigmas,) class AGGASamplerNode: @classmethod def INPUT_TYPES(s): return {"required": {"sampler_name": (["AGGA Structural-Detail (Hybrid)", "AGGA-Detail-Native", "AGGA Pseudo-HiRes Soft"],)}} RETURN_TYPES = ("SAMPLER",) FUNCTION = "get_sampler" CATEGORY = "sampling/custom_sampling" def get_sampler(self, sampler_name): f = sample_agga_structural_detail def w(*args, kwargs): if len(args) == 8: return f(args[0], args[1], args[6], extra_args=kwargs.get('extra_args'), callback=kwargs.get('callback')) elif len(args) == 4: # Fix für SamplerCustomAdvanced guider = args[0] model = guider.model if hasattr(guider, 'model') else guider return f(model, args[1], args[3], kwargs) elif len(args) >= 3: return f(args[0], args[1], args[2], **kwargs) return f(*args, **kwargs) w.sample = w w.sampler_function = f w.extra_options = {} return (w,) NODE_CLASS_MAPPINGS = {"AGGA Scheduler": AGGASchedulerNode, "AGGA Sampler": AGGASamplerNode} NODE_DISPLAY_NAME_MAPPINGS = {"AGGA Scheduler": "AGGA Custom Scheduler", "AGGA Sampler": "AGGA Custom Sampler"}

    Herrscher_AGGA
    Author
    Jan 19, 2026Ā· 8 reactions
    CivitAI

    Update: I managed to get it working in ComfyUI, but it's just not the same. While it generates sharp definition in A1111, in Comfy it’s simply blurry—the system is just too restrictive. I've spent days sitting here for hours trying to fix it, but I’m burnt out. In A1111, I can build, test, fix, and improve them, but here in Comfy, it’s so complicated that I’m exhausted. I’m giving up.

    I’m sorry about this, but there won't be any ComfyUI versions. I know there are people who can make it work there, and I’ve tried everything—with help from AI and my colleagues—but nothing worked. Regards!

    PrometheaJan 19, 2026

    Too bad, but thumbs up for the attempt and putting all the time and work into it.

    Herrscher_AGGA
    Author
    Jan 19, 2026Ā· 4 reactions

    @PrometheaĀ Yes, I will continue learning about nodes; I may be able to do it in the future since some people have managed to do it with the help of Gemini, although I will try not to use Python since ComfyUI is different and that was one of the problems.

    CaptainFurryTrashJan 20, 2026

    Thank you for trying!

    PrometheaMar 11, 2026Ā· 5 reactions

    @Herrscher_AGGAĀ  I got it to work with Claude's help! If you're interested, I can send you the files and a transcript of the chat so you can study them. As you said, you're interested in getting more into Nodes. By the way, this is one of the best, if not THE best, sampler/scheduler combos I have tried so far.

    Herrscher_AGGA
    Author
    Mar 12, 2026Ā· 1 reaction

    @PrometheaĀ Wow, that is amazing news! Yes, please absolutely send me the files and the chat transcript. Seeing how you and Claude managed to solve the node logic is exactly what I need to finally wrap my head around ComfyUI without burning out again.

    Also, thank you so much for that massive compliment! Hearing that it's one of the best combos you've tried really makes all those hours of testing and frustration totally worth it. You can send the files to me via direct message here on Civitai, or on Discord (my username is im_agga / ID: 312749266890129408). Thank you again for putting in the effort to make this work!

    CaptainFurryTrashMar 12, 2026

    @PrometheaĀ Would absolutely love that!

    CaptainFurryTrashApr 2, 2026Ā· 2 reactions

    @Herrscher_AGGAĀ Any update on this?

    Herrscher_AGGA
    Author
    Apr 5, 2026

    @CaptainFurryTrash @Promethea Hi everyone, sorry for the delay! I've been refining PGP so I can fully focus on the samplers next. Once version 4.5 is released (this Monday or Tuesday), I'll start working on ComfyUI. The examples you provided gave me some great ideas on how the nodes work, and I've been testing a ComfyUI version. I apologize for taking so long with this, but it's a bit complicated! You can try this file which includes the missing ones, though I haven't fully tested them yet and I think they can still be improved: https://drive.google.com/file/d/1e6GJPWMznV7bdnRZvLBsj542hnWXNsQ8/view?usp=sharing

    Other
    Illustrious

    Details

    Downloads
    160
    Platform
    CivitAI
    Platform Status
    Available
    Created
    1/15/2026
    Updated
    6/14/2026
    Deleted
    -

    Files

    agga2026TheSampler_forgeReforge.zip

    Mirrors

    agga2026TheSampler_forgeReforge.zip

    Mirrors

    agga2026TheSampler_forgeReforge21.zip

    Mirrors