Skip to content

forge-again v1.7.9

Choose a tag to compare

@logan71f100 logan71f100 released this 16 Aug 05:53
· 40 commits to main since this release

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 requestAnimationFrame when a tab is hidden — they pause it entirely (measured: native rAF never fired in 4000 ms). Svelte 5's tick(), which gradio's client awaits on the submit path, races an rAF against a setTimeout; 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/join is 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/ping now 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.Tabs were 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 a gr.render on 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 its onload could 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.