Releases: logan71f100/forge-again
Release list
forge-again v1.7.13
Restoring a session no longer hands the model a blank image, and the AI assistant edits the prompt you are actually looking at.
Fixes
- Restore could make a generation come back solid white or solid black. The session was capturing the canvas transport binds — the hidden textareas that carry whole images between the inpaint canvas and the server. Their contents point at one particular upload, so restoring a stale marker was not a no-op: it is not a loadable URL, the canvas's image never loads, and an empty frame is uploaded instead. Server-side that flattens to the img2img background colour, white by default, so the model was handed a blank init image and returned white outside the mask and black inside it. Decoding a saved grid settles it — the final image is exactly 255 minus the mask everywhere, and the masked edge is smooth in pixel space rather than blocky at the latent grid. It only bit sometimes because a 100 ms poller watches those textareas for outside changes, and the verify pass writes the marker a second time. They are no longer captured, no longer applied, and are stripped from stored sessions.
- Restore could silently switch a feature on. A linked input accordion ties its open state to its enable checkbox, so opening one enables that script server-side. The safe expand helper is attached late and gradio 6 mounts accordions later still, so an unlucky restore fell through to a plain click — enabling the Refiner with a foreign checkpoint and swapping the UNet partway through sampling. If it cannot be expanded safely it now stays shut: a value we fail to restore is recoverable, a feature we silently enable is not.
- The assistant typed your prompt into Replacer. Control lookup fell back to any label containing the requested text, in page order, so a bare "prompt" matched Replacer's, SUPIR's and the detection prompt equally. A bare prompt request now resolves to the tab's own box by its stable element id.
- A prompt edit did not count as a prompt edit. The follow-through check required the label "positive prompt", but the control is called "Prompt" — which is what the assistant correctly used. Every genuine edit was scored as "described a change but did not make one", nudged, and restarted before it could generate: five turns, five rewrites, no generation between any of them.
- A rewritten prompt could silently unload a LoRA. Tags present before an edit and missing after it are now carried over. Dropping one changes the output completely, and a rewrite is prose work, not a decision to unload a model.
- Inpaint area went missing from saved sessions. An unlabelled radio is captured under its first option's text, and the rule treating that as "still on its default" is wrong wherever a control's default is not its first option — as img2img's Inpaint area is. That silently lost a real setting.
- Replacer's quick-add LoRA chips ignored the mode you were in. The list and its heading were read once, when the server built its UI, so a server started in xl offered xl LoRAs for the rest of its life however often you switched. Every mode's chips now carry their own tag and the browser shows those matching the live mode radio.
Features
- The assistant can see your inpaint selection. It reads the mask straight off the canvas: no settings to enable, nothing extra added to the gallery, and it works before you generate, so a bad selection is catchable without spending a run. It is also told each turn whether it has actually looked, and forbidden from claiming otherwise — it had been asserting "the mask appears to cover the area correctly" without ever having fetched one.
- Restore says what it could not put back. Unmatched values previously went only to the browser console, so a setting that failed to apply looked identical to one that was never saved.
Reliability
- A generation no longer starts while the LLM still holds the VRAM. The assistant asks it to hibernate and used to trust the acknowledgement, but llama.cpp will not hibernate mid-completion, so a long reply kept the memory for tens of seconds while a run began on a card that was already full. It now waits for the real state and kills the LLM if it will not park — a run stalled at 0% recovered the instant it was killed, and another had died mid-sampling with weights split across CPU and GPU under the same pressure.
- The saved session cannot claim "nothing was edited" before it has read the stored one, which would otherwise strip every other tab from the file.
Upgrading
Pull and restart. JavaScript and Python changes both need a real server restart rather than a browser reload. No configuration or model changes are required.
Two things stated plainly rather than left implied. The VAE decode work in v1.7.12 shipped a measurement, not a fix — three plausible causes were each tested against real numbers and all three were wrong. And the intermittent sampling stall remains unattributed; the console log added in v1.7.12 is what will settle it.
forge-again v1.7.12
macOS installs work again, clearing a saved session actually clears it, and the server now keeps its own console log — so the next time something misbehaves, the evidence is already on disk.
Fixes
- macOS could not launch at all.
requirements_versions.txtpinstorch==2.13.0+cu126, a CUDA build that has no Apple-silicon wheel, so pip could only answer "No matching distribution found". The launcher already knew this and filtered the torch pins into a temporary requirements file — butlaunch.pyrunsprepare_environment()itself moments later and installed from the unfiltered file, undoing the filtering before the UI ever came up. The filtered copy is now kept and handed tolaunch.pythroughREQS_FILE. Thanks to @jasonmello114 for the report and the complete log (#15). - Clearing a saved session now clears it. There was previously no way to make one go away while a page was open, which is exactly when you would want to: the page seeds its snapshot at boot and never re-syncs, saves merge per tab, and the unload beacon writes the stale copy back on the way out — so anything removed server-side reappeared within a minute. A new 🗑 button beside Restore empties the page's own copy first, then deletes the file. Nothing on screen changes; it forgets what was recorded, not what is set.
- An emptied edited-tab list meant "unknown" instead of "empty". Which made that reset useless — the very next capture wrote back the untouched tab it had just removed. Absent now means "this page is too old to say"; empty means "nothing has been edited", and only the active tab survives.
- A name shared with a script kept settings alive forever. Defaults are indexed by the last two path segments, so a tab's own control and every script reusing the name landed together — img2img's Width (1024) with Ultimate SD Upscale's tile Width (64), Sampling steps 20 with 25, Mask blur 4 with 8 — and the rule that every recorded default must agree could never be satisfied. A bare label now resolves to the tab's own control. This was most of what survived pruning in a tab nobody had configured.
- Values that name no control, and values that are not choices. A double-ended slider with no label of its own is captured as a bare "(start)"/"(end)", which no default list can judge and which restore would apply to whichever unit it found first — a coin toss between three ControlNet units. An empty string, meanwhile, is a dropdown whose options have not loaded yet, not a deliberate setting. Both are now dropped when captured and when saved, so existing sessions heal themselves.
Reliability
- The server keeps its own console log.
server-console.login the Forge root, written by the server rather than depending on how it was launched: model loads and unloads, memory decisions, per-run peak VRAM, step rates, tracebacks. Launching normally sent all of that to a window that closes, and redirecting it block-buffered — so during a stall, which is precisely when the process will not exit to flush, the log ran thousands of characters behind the truth. Flushed on every write, rotated at 8 MB, and enabled by the existing forensics setting. start.bat > run.logis no longer thousands of characters behind. The script recommends that redirect for bug reports; Python only line-buffers to a console, so it now setsPYTHONUNBUFFERED=1.- VAE decode reports itself when it matters. One line when a decode is slow or asked for more memory than was free, giving what it needed, what was already resident and what was actually available. Measurement first: the marginal cost is 0.1563 MB per latent pixel at fp16, holding across five resolutions, and exceeding free VRAM degrades gracefully rather than falling off a cliff — 4.3 GB over budget still decoded in 7.7 s, because the memory manager evicts the diffusion model to make room. Three plausible fixes were tried against those numbers and all three were wrong, so this ships the measurement and not a guess.
- The test suite can no longer write into your saved session. It isolated
config.jsonbut not the session file, and the browser tier opens img2img, clicks around inside it and generates at 128×128 — all of which was captured into the real session, so a later restore opened and rebuilt a tab that had never been configured.
Documentation
- docs/first-models.md — a step-by-step walkthrough for a first working model set. Chroma is transformer-only and needs three sidecar downloads nothing in the UI asks for; missing them fails with "You do not have CLIP state dict!", which does not tell you what to fetch. Every link was checked rather than recalled, with sizes and a running total. It also flags that the obvious VAE link is gated and answers HTTP 401 in a way that reads as a broken install, and states plainly that GGUF runs on Metal and ROCm as well as CUDA.
Upgrading
Pull and restart. JavaScript and Python changes both need a real server restart rather than a browser reload. No configuration or model changes are required. If a saved session has been picking up tabs you never configured, press 🗑 once after restarting — the earlier fixes stop new ones being recorded, but only the reset clears what is already there.
forge-again v1.7.11
The progress bar now names the stage a run is really in, a run can stop at its first preview so a bad composition is caught in seconds, and the test suite can no longer write into your saved session.
Features
- Pause after the first preview. A checkbox under the seed row stops a run as soon as there is something to look at, and the generate box becomes
✕ Cancel | ▶ Resume— catching a composition that is going wrong in the first few steps rather than after a full sampling pass. The pause runs on the sampler thread, deliberately: the other route to a preview runs on the HTTP thread, and blocking there would freeze the progress endpoint and take the Resume button down with it. It is armed per run from the UI rather than as a setting, so it travels with the request and arming it in one tab cannot stop a run started from another. Interrupt, Skip and Stop all break it, so a paused run stays cancellable. Verified end to end: a real generation paused at its first preview and resumed to completion. - The progress bar says which stage the run is in. "Queuing" used to be the answer to several different questions — the words came from whatever the API happened to put in
textinfo, so a task the server had never heard of read asWaiting...(as though the server were waiting) and the model load read asQueued...(as though nothing had started). It now walksSending…→Waiting for the server…→Accepted — 1 of 3 in queue→Loading <checkpoint>…→Encoding prompt…→ the percentage. The distinction matters with more than one person on a server, where a queue is a normal state rather than a symptom: the server marks a task accepted the instant it enters the handler, and the wait after that is somebody else's run. - The load stages are reported, not guessed. Freeing VRAM, loading the checkpoint, hashing it on first sight, applying LoRAs and encoding the prompt each say so. Everything between the click and the first sampling step used to be invisible from the browser, and on a large GGUF that is the longest silent stretch of a run.
Fixes
- The test suite no longer writes into your saved session. The harness copied
config.jsonto a temp file so a run could never touch personal settings, but the session file sat at a fixed path — and the UI tier opens img2img, clicks around inside it and uploads a 128×128 image. All of that was faithfully captured into the real session, so a later restore opened and rebuilt an img2img tab that had never been configured. The session path is now redirected for test runs, and the check that watches it looks at the harness's own copy. - A legacy session no longer claims every tab was edited. Restoring only tabs you configured relies on knowing where edits happened, and a session written before that was recorded had no such record. Treating every tab in it as edited re-admitted precisely the tabs the rule exists to drop — permanently, since restoring re-marked them. It no longer guesses: a tab re-earns its place the moment it is actually touched.
- A paused run reads as one sentence. The paused bar was three fragments run together — the client's label, the server's status text saying the same thing in other words, and the percentage left standing from the last step before the pause, which made a stopped run look like a moving one.
Upgrading
Pull and restart. JavaScript changes need a real server restart rather than a browser reload — the cache-buster is baked into the page at UI-creation time. No configuration or model changes are required, and the new pause checkbox is off by default, so nothing about an ordinary generation changes until you tick it.
forge-again v1.7.10
Restoring a session now puts back what you actually had, and saves only what you actually changed.
Fixes
- Restore no longer overwrites itself. The UI-mode radio is not an ordinary setting: switching sd/xl/flux runs
set_mode, which rewrites the checkpoint, the VAE/text-encoder list, GPU weights and the whole resolution/CFG/steps/sampler block — in a response that lands hundreds of milliseconds after the click returns. Restoring it in label order meant the mode went in, the saved checkpoint and resolution went in next, and then the preset's answer landed on top of both, finishing "successfully" with the wrong model loaded. The mode is now applied alone and first, is never replayed when the UI already matches it (a redundant switch costs a full model reload), and everything else waits for the checkpoint, VAE, GPU weights and resolution block to stop changing. - Values overwritten mid-restore are put back. Every write goes into a UI that answers asynchronously, so a checkpoint reload or a late refresh could still clobber a value set several tabs earlier. Restore now ends with a verify pass that re-reads everything it wrote and re-applies whatever drifted, quicksettings first and allowed to settle.
- A saved session holds what you changed, not a copy of the page. Values were compared against
ui-config.jsonas text, so the"1"a slider reports never matched the1.0it was built with — 160 of 216 surviving entries were untouched ControlNet, FreeU, PAG and LatentModifier sliders. Comparison is now numeric, with half a step of tolerance for sliders that quantize, plus rules for empty multiselects, for radios still on their first option, and for label matches whose type disagrees (the "Hires. fix" accordion toggle was matching a same-named dropdown). - Restore stops opening tabs you never configured. Value pruning alone cannot empty a tab like Checkpoint Merger, whose model dropdowns legitimately read back whatever is loaded, so opening it once kept it in the session — and every later restore re-opened it, which in Gradio 6 means rebuilding it. A tab is now kept only if something in it was actually changed. End to end on a real session: 413 entries across 5 tabs became 45 across the 3 that were used.
- A restart no longer costs you your settings. When the connection watchdog reloads the page after the server comes back, the full session is restored automatically instead of the prompts alone.
- The GPU Weights slider and the VRAM reserve stay in step. Switching modes moved the reserve without moving the slider that displays it, so the number on screen disagreed with the number in use.
Reliability
- Debug instrumentation is off unless you ask for it. The client forensics added while chasing connection faults are now behind a setting, default off; with it off the logging endpoint does no work at all.
- VRAM is sized correctly on AMD and Apple silicon. The reserve calculation reads AMD's sysfs
mem_info_vram_total, and macOS reportstorch.mps.recommended_max_memory()instead of claiming all system RAM as VRAM. - The session rules are covered by the test suite. A new static check asserts that a default is dropped, an unconfigured tab is dropped, and a value you actually changed is never dropped or altered — verified by mutation: disabling either pruning rule makes it fail.
- Connection forensics record the two facts that were missing. Tab visibility changes are stamped on both edges, and every queue join records how long it took to leave the browser — which separates "the request sat in a throttled background tab" from "the submit was fine and delivery failed" without guesswork.
- Session backups can't wander into git.
last_session.jsonwas ignored but the.prevrotation and.tmpwritten beside it were not, leaving a full copy of a session onegit add .away from being published.
Upgrading
Pull and restart. JavaScript changes need a real server restart rather than a browser reload — the cache-buster is baked into the page at UI-creation time. No configuration or model changes are required. Existing last_session.json files are read as-is and shrink to just your changes on the next save; if you want the instrumentation from the forensics entry above, enable Log connection forensics for debugging in Settings.
forge-again v1.7.9
This release is about the UI keeping its promises: generations that start when you are not looking at the tab, a gallery that shows the result instead of a preview, and a Restore that actually restores.
Reliability
- Generations now start in a background tab. Browsers do not merely throttle
requestAnimationFramewhen a tab is hidden — they pause it entirely (measured: native rAF never fired in 4000 ms). Svelte 5'stick(), which gradio's client awaits on the submit path, races an rAF against asetTimeout; with the rAF half dead every await fell through to a throttled timer, so a submit stalled until you looked at the tab again. While hidden, frame callbacks are now serviced from a Worker clock, which browsers do not throttle; visible tabs keep native rAF untouched. Verified hidden-tab: queue join 0.43 s → started 0.48 s → completed, image delivered. - Switching away mid-submit no longer parks the run. The first shim decided at scheduling time, so clicking Generate while visible and then switching away left the callback waiting on a frame that never came. Callbacks scheduled while visible are now tracked and re-dispatched onto the Worker clock when the tab goes hidden.
- A generation that never starts now says so. A trusted Generate click arms a 15 s check (paced off the Worker clock, since a plain timer would be throttled by the very condition it is watching). If nothing starts, you get a warning with a Retry button, and the forensics record which stage stalled —
/queue/joinis instrumented separately, so "never reached the server" is now distinguishable from "joined but never ran." The warning clears itself the moment any job starts. - The page re-attaches to a run it stopped tracking. Interrupting tore down the progress UI while the run continued to the next step boundary, leaving the finished image with nowhere to arrive.
/internal/pingnow reports the running task id, and the watchdog adopts an unattached job — progress bar, live previews, completion handling and the finished image, once per task and only onto the tab you are actually looking at.
Fixes
- Restore Session brings back every setting, not just the visible ones. Four separate holes on the capture side: only the active tab was scanned (gradio 6 keeps opened tabs mounted, so a change in Img2img was dropped when a save fired from Txt2img); mounted-but-hidden controls were skipped, and because snapshots merge, a stale value survived forever — this is the Distilled CFG that kept returning as 0.2; nested
gr.Tabswere not a control kind at all, so "Resize to / Resize by" was unsaveable and the img2img mode was never recorded, which is why inpaint settings never came back; and the autosave debounce ran on a main-thread timer, throttled in exactly the background tab where a save matters most. Saves are also cumulative now — the client seeds from the stored session and the server merges per tab, instead of a payload carrying only the mounted tabs overwriting all the others. Covered by an end-to-end test. - img2img finally honours ui-config defaults.
create_ui()applies saved defaults while building the page, but the img2img body is constructed inside agr.renderon first open — long after that — so Inpaint area, Masked content, Mask blur, padding, Resize by, denoise and CFG had silently ignored the file since the lazy-tab work, which also made the v1.7.5 per-mode inpaint defaults dead on arrival. The render now diffs the component registry around the build and applies saved values to whatever it created. - The gallery no longer pins a stale live preview in front of the result. The preview
<img>decodes asynchronously, so itsonloadcould run after completion and insert a brand-new preview node at the front of the gallery with nothing left to clean it up — which the next run then selected, the "stuck gallery." The handler re-checks for teardown before inserting, cleanup sweeps every preview node rather than the one its closure holds, and each run sweeps at start so an already-stuck gallery self-heals.
Performance
- The VRAM reserve can no longer push the model into CPU swap. The reserve exists to stop activations evicting weights, but its 60%-of-VRAM cap could do precisely what it was meant to prevent: on an 11 GB card it reserved 6758 MB, leaving 4.5 GB for a 7.3 GB model — 1775 MB resident against 5520 MB swapped, 44.8 s/it, a two-hour ETA, and an allocator assert during VAE decode. The cap is now also bounded by what remains after the weights. A tighter activation budget is strictly better than swapping: at worst it falls into the existing tiled-VAE path, which costs seconds rather than hours. When a run genuinely cannot fit, it now says so through the hints framework instead of thrashing silently.
Upgrading
Pull and restart — no config or model changes. Settings saved by an older build still load; values that were never captured before (the img2img mode and the Resize to/by choice) start being recorded the first time you use those tabs.
forge-again v1.7.8
A connection-stability release, driven by a full client + server audit and by forensic data from real sessions. Full test suite green (50 passed, including the GPU tier).
Baseline first, because it reframes the work: across 15,782 logged client events, 190 real generation streams completed with zero drops, and per-stream heartbeat gaps sat at a healthy 15.1s median. The generation stream itself is reliable and the GPU is not blocking the event loop -- the faults were in the polling, recovery and background-load layers around it.
Fixes
- Missed generation results are recovered, and the recovery actually works. A completion lost to a throttled background tab or a dead stream now gets pulled back: the watchdog detects the tell-tale state (server idle, task still undelivered) and re-requests the recorded result over a fresh connection. Three bugs stood between that idea and it working: the restore-progress button was created
visible=False, which gradio 6 unmounts, so the entire restore feature had been dead since the port; the server only remembered the last 2 results by task id, so a couple of later runs evicted the one you were trying to recover (now 16); and the recovery cleared the task id synchronously after clicking, winning a race against gradio's own async handler that reads it, which made every attempt silently no-op. Recovery now reports honestly either way -- a checkmark when it delivers, or a clear "the image is in your output folder" when the result is genuinely gone. - Progress polling survives blips. Both poll chains used "tear everything down" as their error handler, and that fires on any failed request -- so a single transient blip mid-generation removed the progress bar, restored the Generate button, and cleared the task id, leaving a still-running job looking finished and unrecoverable. Up to 5 consecutive failures are now tolerated, and a failed live-preview poll (purely cosmetic) can no longer tear down the run's tracking at all.
- Background tabs keep working. Progress, live previews and completion detection were all paced by main-thread timers, which browsers throttle to roughly once a minute in a hidden tab. They now run on a Web Worker clock (new
javascript/forgeTimer.js, reusable for any correctness-bearing loop). queue(64)mis-port. That call's first positional argument isstatus_update_rate, notmax_size-- so the inherited setting was broadcasting queue estimations every 64 seconds while leaving the size cap unset. Spelled out explicitly; UI events also get a dedicated thread-capacity limiter instead of sharing the process-wide pool with every sync API route.- Stuck Generate button. The 12-second self-recovery for a submit that never reached the backend could never restore the button, because a required argument was never passed at its only call site.
- Less background load. The assistant's watchdog polled roughly once a second forever -- even with the panel never opened -- and its readiness probe could park a server thread when llama-server was down. The cadence is now adaptive (3s in use, 20s idle; measured 12 requests per 12s down to 2) and the probe short-circuits and caches. Separately,
/internal/client-logno longer does blocking disk I/O inside the request,restore_progressno longer busy-waits unbounded while holding a worker, and an extra-networks handler no longer re-attached a listener on every UI update. - Two hot handlers off the generation path. The gallery info round-trip fired on every gallery click -- including the automatic one 250ms after each result lands -- and opened a full event stream each time; it reads no shared state, so it is now unqueued (measured: 0 streams per gallery click, was 1). Token counters read the loaded model's tokenizer and therefore ran under the same lock a generation holds, so a keystroke mid-run parked a server thread for the entire run; they now skip while a job is running and refresh on your next edit.
Upgrading
Pull and restart -- and hard-refresh the browser tab (Ctrl+F5), since several of these fixes live in the page's JavaScript.
forge-again v1.7.7
An infrastructure release: the UI's warnings and errors now run through two small, documented frameworks instead of ad-hoc code, and both are covered by the test harness. Full suite green (50 passed, including the GPU tier).
Features
- Unified frontend notifications (
forgeNotify). One stacked, consistently styled system for every banner, toast, and choice dialog:forgeNotify.info/success/warn/error(msg, opts)with per-level colors and timeouts, id-based replacement (state banners like connection lost/reconnected swap in place instead of stacking), sticky notifications with a close button, choice-dialog buttons, and built-in once-per-server-launch suppression. The connection watchdog's four banners and the flash-LoRA guard now run through it; any future warning is a one-liner. - Generation hints under the result (
generation_hints). The info area beneath a generation is now fed by a documented framework:generation_hints.add(p, text)for one-off notices from any backend code, and@generation_hints.rulefor rules evaluated on every run (a broken rule logs and never breaks a generation). Ships with two real hints: a notice when the inference reserve is raised for a large run (previously console-only), and a flash-LoRA settings rule that also covers API and assistant-driven runs that bypass the client-side guard.error_tipsgainsregister_tip(pattern, tip, field)so extensions can add plain-language error explanations too. - Hints reach the API. The result payload's info JSON now exports
comments, so API callers — including the built-in AI assistant — see the same hints the UI shows.
Tests
- New static-tier
hintscheck (rule firing/quiet cases, broken-rule isolation,register_tipround-trips) and a GPU-tier end-to-end check asserting hints land in the API response. Suite grows from 48 to 50 checks.
Upgrading
Pull and restart. No config or model changes needed.
forge-again v1.7.6
A performance and workflow release: the canvas image transport is rebuilt, two long-standing slowdowns are gone, and the Lora tab finally understands modes. Full test suite green (48 passed, including the GPU tier).
Performance
- File-based canvas image transport. ForgeCanvas historically moved whole images as base64 text through hidden textboxes, in both directions - a 24 MP phone photo became a ~34 MB string riding inside every img2img submit and every send-to-inpaint push, measured as the correlate of queue-stream stalls and lost generations. The canvas now uploads images as real multipart files (submit payload: 34,303,350 bytes -> 133 bytes) and receives server-set images as file URLs (send-to-inpaint push: megabytes -> 86 bytes). Base64 remains the automatic fallback, marker paths only resolve inside gradio's temp dirs, and phone-photo EXIF rotation is handled.
- Back-to-back generations stay warm. The VAE's worst-case decode estimate (~9 GB for a 1 MP fp32 decode) was passed wholesale to the memory manager, which evicted the ENTIRE diffusion model at the end of every run to decode one image - the next run then paid a full weight reload, or worse, sampled partially CPU-swapped at ~10 s/it. The decode now requests only real headroom (the tiled-decode fallback covers genuine shortfalls). Measured: warm back-to-back 768x768 XL runs went from paying a reload every run to 4.0 s flat with zero evictions.
Features
- Lora tab filters by mode. The tab now opens showing the current mode's loras (by your models/Lora/sd|xl|flux directory layout - metadata version detection is 'Unknown' for most modern files and never filtered anything), re-filters live on mode switches, and searching another mode's folder still reaches everything. The
lora_filter_disabledsetting now defaults to off. - Lora tab loads during generations. The pages' content was delivered through the generation queue, so opening the UI mid-run left the tab spinning until the run finished. Content and refresh now bypass the queue (they are disk reads).
- Session restore brings the checkpoint back. The quicksettings row (Checkpoint, VAE, Clip skip, mode radio) lives outside every tab and was never captured. It is now saved with each session/profile and restored FIRST, so cross-mode restores flip the mode, wait for the list, then select the saved model. (Sessions/profiles saved before this release predate the data - re-save once.)
- Flash LoRA guard. Generating with a flash/distill LoRA at CFG > 1 or > 16 steps multiplies the work several-fold for no quality gain. The first offending Generate per server launch is held behind a choice - "Apply flash settings & run" (CFG 1.0, 16 steps) or "Run as is" - then the guard stays out of the way until the next server boot.
Upgrading
Pull and restart. No config or model changes needed. If you keep saved sessions/UI profiles, re-save them once so they include the checkpoint.
forge-again v1.7.5
A quality-of-life and stability wave: a mask eraser, sensible inpaint defaults, the white-image root cause fixed, and a self-healing, fully-instrumented connection layer. Full test suite green (48 passed, including the GPU tier).
Features
- Eraser brush for mask/sketch canvases. New toolbar toggle on the inpaint/sketch canvases: paint the mask, hit the eraser, and drawing removes mask instead of adding it. Reuses the canvas's existing erase branch under the hood, resets the drawing tool state correctly on toggle-off, and survives gradio 6's pane rebuilds. Undo/redo work on erase strokes.
- Sensible per-mode inpaint defaults. Mode switch / launch now also seeds the img2img inpaint controls: masked content
original, inpaint areaOnly masked(full-resolution crop — the big quality win for small-region fixes), padding 64 (sd) / 96 (xl, flux), and mask blur scaled to the mode's resolution.
Fixes
- The white/blank inpaint output bug. Flux's VAE + text encoders could leak into sd/xl mode: a stale VAE-dropdown event replayed after an in-place mode switch re-wrote the flux modules over the switch's correct list, and flux's 16-channel VAE then loaded into the SD/XL model — white or uniform-gray decodes at best, a hard
size mismatch for IntegratedAutoencoderKLat worst.modules_changenow drops flux-only modules outside flux mode and refuses a stale empty-clear inside flux mode. - "Resize by" said "no image selected" on the Inpaint tab. The source-resolution helper matched sub-tab panes by inline style; a never-visited pane (no inline style at all) shadowed the real image with its empty placeholder canvas. Visibility now comes from
offsetParent, and ≤1px placeholders are skipped. - Replacer: "Distilled CFG Scale (Flux only)" now hides outside flux mode, live — its visibility used to be decided once at page build, so it stuck around after an in-place switch to sd/xl.
- Replacer: quick-add LoRA chips single-fire. On a long-lived page one click could append every LoRA tag at once (gradio 6 re-binding per-button event deps across remounts). The chips are now plain HTML with one delegated listener — structurally single-fire.
- XL/SD generations stay warm. The adaptive VRAM reserve's real-CFG doubling (added for Chroma) double-counted on xl/sd, whose constants were already sized for CFG>1 — XL at 1024×1024 reserved ~3.7 GB and evicted weights that fit fine, paying a model reload on every run. Doubling is now flux-only.
Reliability
- Orphaned generations self-heal. If gradio's completion stream dies mid-job, the server finishes but the page shows "generating" forever.
/internal/pingnow reports real server busyness; when the UI disagrees with an idle server for ~16 s, the watchdog resets the generate controls in place (no reload) and points at the output folder. - Never-started queue tasks are reaped. A queue join whose session died before starting used to be lost silently and wedged the busy signal permanently; pending entries that never start are now dropped after 10 minutes.
- Connection forensics. The page now logs the full queue-event stream (decoded), gallery image-load failures (with an HTTP probe of the failing URL), and a snapshot of the img2img source at every Generate click — all shipped server-side to a rotating
client-debug.log, so any "the image never showed up" report is diagnosable from the machine without browser console spelunking.
Upgrading
Pull and restart. No config or model changes needed — the new inpaint defaults apply on your next mode switch or launch.
forge-again v1.7.4
Patch release on top of v1.7.3 — a performance fix and a UI fix. Full test suite green (48 passed, including the GPU tier).
Performance
- Forge stays warm between generations. The AI assistant's pre-generation VRAM guard armed its auto-restore worker whenever the llama-server had a model — but that check deliberately survives hibernate, so an LLM that was already parked asleep got woken ~6 seconds after every generation, refilling ~10 GB of VRAM and evicting the Forge weights. Every back-to-back run then paid a full model re-upload, even with the assistant completely unused. An already-sleeping LLM is now left parked (Forge keeps the VRAM; consecutive runs start immediately); auto-restore only arms when a generation actually interrupted an awake, in-use server, and the first chat message still auto-wakes the LLM either way.
Fixes
- "Bad image index: -1" on the gallery hires-fix button.
all_gallery_buttons()filtered thumbnails through gradio 4's inline[style="display: block;"].tabitempane style; gradio 6 unmounts inactive panes instead, so the selector matched nothing andselected_gallery_index()always returned -1 (breaking the hires-fix/upscale button and losing the selection for every other consumer). Dropped the dead pane filter — gradio 6 still renders the same.thumbnail-item/.selectedclasses, and the existing visibility check already scopes to the active gallery. A single-image gallery with a lost selection now also falls back to image 0 server-side, matching the Replacer's own guard.
Upgrading
Pull and restart. No config or model changes needed.