25bbf32a65
* refactor(anima): reshape ANIMA_SCHEDULER_MAP to (class, kwargs) tuples Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(anima): address Task 1 review feedback Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(anima): add dpmpp_2m and dpmpp_2m_sde schedulers * refactor(anima): unify ANIMA_SHIFT in schedulers.py and add Literal-coverage test * fix(anima): seed generator into scheduler.step for SDE reproducibility * feat(anima): add pure ancestral-Euler step helper Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(anima): fix _anima_euler_ancestral_step docstring formula to match code Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * refactor(anima): address Task 4 review feedback * feat(anima): add euler_a (rectified-flow ancestral Euler) scheduler * fix(anima): sample euler_a noise in float32 to avoid bfloat16 quantization * chore(anima): bump anima_denoise to v1.3.0 and regen schema * fix(frontend): revert Windows path-separator drift in schema regen * fix(anima): gate step_generator construction to schedulers that need it Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(anima): apply ruff lint and format fixes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(frontend): expose new Anima schedulers in dropdown and metadata recall * chore(frontend): apply prettier wrap to setAnimaScheduler PayloadAction * fix(anima): correct euler_a math — variance-preserving noise mix, not biased Euler * revert(anima): remove euler_a scheduler — quality not worth the complexity * chore(anima): apply ruff format (trim trailing blank lines) * feat(rectified-flow): add order-1 ER-SDE stepper for rectified flow Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(rectified-flow): document lambda_next>0 precondition; tighten terminal-step test Address code review feedback on order-1 ER-SDE stepper: - Add docstring preconditions to integral helpers noting the logarithmic singularity at lam=0 (callers must guard sigma_next>0). - Tighten terminal-step test from atol=1e-5 to torch.equal — the algebra is exact when sigma_next=0, not approximate. * feat(rectified-flow): add 2nd-order Taylor extension to ER-SDE stepper * test(rectified-flow): tighten Task 2 state-mutation test with value assertion Address code review feedback on the 2nd-order Taylor extension tests: - Assert state.old_d_x0 equals the analytically-computed d_x0 = 0.2v / (1.5 - 4.0) rather than just checking it's non-None. - Document that x_t is intentionally re-used across calls (state threading test, not trajectory correctness). - Document the order-2 correction coefficient magnitude that justifies the atol=1e-3 threshold in the engagement test. * feat(rectified-flow): add 3rd-order Taylor extension to ER-SDE stepper * docs(rectified-flow): document have_two_back invariant + order-3 test margin Address code review feedback on Task 3: - Comment why have_two_back checks both old_d_x0 and sigma_prev_prev (the sigma~=1 boundary path can break the joint invariant). - Document the analytically verified ~0.0004 per-element correction magnitude that justifies the atol=1e-3 threshold in the order-3 test. * feat(anima): register er_sde scheduler choice * docs(anima): document custom-code-path scheduler convention; tighten test Address code review feedback on Task 4: - Add an in-file comment above ANIMA_SCHEDULER_MAP explaining the convention: schedulers with custom code paths (er_sde) live in the Literal+labels only, not the map. - Hoist `import typing` to module-level in test_anima_schedulers.py (was inline-imported in two test functions). - Pin the er_sde label value (== "ER-SDE"), not just key existence. * feat(anima): wire er_sde scheduler into denoise loop * docs(anima): document float32 noise dtype and sigma_next/sigma_prev naming Address code review feedback on Task 5: - Comment explaining why fresh_noise is float32 (matches er_sde_rf_step's dtype contract with x_t.to(float32)). - Bridging comment at the inpaint extension call clarifying that sigma_next here means the same thing as sigma_prev in the Euler branch and the AnimaInpaintExtension API. * chore(anima): bump anima_denoise to v1.4.0 and regen schema * feat(frontend): expose er_sde scheduler in dropdown and metadata recall Address code review on Task 6 — er_sde was registered in the OpenAPI schema but missing from the frontend's own Zod enums and Redux PayloadAction types, so: - The combobox dropdown didn't list it. - setAnimaScheduler('er_sde') would fail TypeScript at the call site. - Metadata recall for er_sde-generated images would silently no-op (the scheduler value couldn't pass zParameterScheduler validation). Changes: - Add er_sde to zAnimaSchedulerField (the per-Anima Zod enum). - Add er_sde to the animaScheduler state-shape Zod enum. - Widen setAnimaScheduler's PayloadAction union. - Add ER-SDE option to the ParamAnimaScheduler combobox. - Make the metadata Scheduler handler accept ParameterAnimaScheduler too, with a fallback parse and a narrowing guard before the SD/SDXL dispatch. * fix(rectified-flow): guard 2nd-order branch against sigma_prev_curr=1.0 When step 0 goes through the sigma_curr=1 closed-form limit branch it writes state.sigma_prev_curr=1.0. On step 1, have_one_back was True and the 2nd-order path called _lambda(1.0) = 1.0/(1.0-1.0), crashing with ZeroDivisionError in every real denoise run. Fix: extend the have_one_back guard to require that sigma_prev_curr is more than _SIGMA_ONE_TOLERANCE below 1.0. The finite-difference derivative across the limit step is not meaningful, so skipping the 2nd-order term on that transition is correct. Order-3 is already gated behind old_d_x0 being set, which this path never sets, so no additional guard is needed there. Adds a regression test that runs the full sigma=1.0->0.9->0.7->0.0 sequence and asserts no ZeroDivisionError and all-finite output. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(scheduler): add ERSDEScheduler available to SD/SDXL ER-SDE solver (Cui et al., arXiv:2309.06169) usable across SD/SDXL (VP-SDE) and rectified-flow models. Anima migration follows in subsequent commits. - ERSDEScheduler(SchedulerMixin, ConfigMixin) with prediction_type (epsilon | v_prediction | flow_prediction), use_flow_sigmas, solver_order (1/2/3 with auto-warmup), and stochastic toggle - set_timesteps(sigmas=) for pre-shifted Anima/FLUX/Z-Image schedules - Closed-form limit at sigma=1 in flow mode - Unit tests + VP smoke + 5/5 Anima parity vs er_sde_rf_step (worst delta 5.137e-07) - Frontend wiring: zSchedulerField, SCHEDULER_OPTIONS, OpenAPI regen - parsing.tsx cleanup: removes the AnyScheduler widening since er_sde is now a first-class general scheduler Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(anima): wire ERSDEScheduler into ANIMA_SCHEDULER_MAP Adds er_sde to the standard scheduler dispatch map with rectified-flow kwargs (flow_prediction, use_flow_sigmas=True, flow_shift=3.0, solver_order=3, stochastic=True). Anima still routes through the legacy elif is_er_sde: branch — that's removed in a follow-up commit. This is the additive prerequisite that lets the cutover happen without a window where Anima can't use ER-SDE. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * test(anima): add ER-SDE dispatch integration tests Verifies the ANIMA_SCHEDULER_MAP['er_sde'] entry instantiates correctly, accepts pre-shifted sigmas via set_timesteps(sigmas=...), and resets multistep state. Catches wiring regressions that the algorithm-level parity test cannot. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * refactor(anima): remove elif is_er_sde branch, dispatch through ANIMA_SCHEDULER_MAP Anima ER-SDE now flows through the same standard scheduler path as dpmpp_2m_sde — pre-shifted sigmas via scheduler.set_timesteps(sigmas=...), inpaint extension via inpaint_extension.merge_intermediate_latents_with_init_latents, step_callback per-step. The custom code path was the only thing keeping ER-SDE off the universal pipeline. Bumps invocation version to 1.5.0. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(er_sde): mark module as internal reference and parity oracle ERSDEScheduler is now the production code path. er_sde_rf_step is kept as the comparison oracle for the scheduler's parity test, and as a self-contained mathematical reference for the rectified-flow algebra. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore(rectified-flow): remove er_sde.py reference helper ERSDEScheduler is the production code path. The pure-function helper was retained as a parity oracle but YAGNI — keeping ~200 lines of code purely as a regression net for hypothetical future drift isn't worth the maintenance signal it generates. Removes: - invokeai/backend/rectified_flow/er_sde.py - tests/backend/rectified_flow/test_er_sde.py - tests/backend/rectified_flow/test_er_sde_scheduler_anima_parity.py ERSDEScheduler's own tests (test_er_sde_scheduler.py) remain — they exercise both VP-SDE and rectified-flow paths directly. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(schema): restore forward slashes in @default cache dir paths Windows-side typegen run flipped these to backslashes. Restore the canonical forward-slash form to match upstream. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * style: apply ruff lint and format to ER-SDE files Sort imports + format per project ruff config (line-length 120). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * refactor(state): use zParameterAnimaScheduler in state shape The animaScheduler field inlined its enum (originally to add er_sde when the shared schema didn't have it yet). Now that zAnimaSchedulerField already includes er_sde, reference the shared zParameterAnimaScheduler to match the pattern used by scheduler/fluxScheduler/zImageScheduler. Drops the redundant .default('euler') — initial value comes from getInitialParamsState. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * style(types): sort imports per simple-import-sort Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(anima): honour clipped sigma schedule for DPM++ img2img/inpaint DPMSolverMultistepScheduler doesn't accept sigmas= in diffusers 0.35.1, so the fallback previously called set_timesteps(num_inference_steps=total_steps) which regenerated a full schedule from sigma_max, ignoring denoising_start/end. When the scheduler supports set_begin_index, call set_timesteps with the full step count and offset into it, so the internal flow_shift applies correctly and denoising starts at the right sigma. Also fixes the inpaint sigma_prev lookup and the timestep loop to use the same offset, and corrects the false parity-test reference in the ER-SDE dispatch test docstring. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * style: apply ruff format to anima_denoise dispatch block Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(anima): extract scheduler driver and fix Heun progress/inpaint bugs Encapsulate per-scheduler dispatch quirks (sigmas= vs num_inference_steps=, Heun's doubled-array index, set_begin_index path) in AnimaSchedulerDriver and tighten two latent bugs in the Heun path of anima_denoise: * Heun's terminal first-order step never reported a user-step completion, so progress capped at N-1 of N. The driver now flags it via sigma_prev==0, and the <= total_steps clamp that papered over the off-by-one is gone. * The inpaint mix ran after every Heun half-step, corrupting the second-order corrector's input (RectifiedFlowInpaintExtension's docstring says it should be called after each denoising step — i.e. once per user step). Mix is now gated on completes_user_step, which is unconditionally True for non-Heun. Also: Heun shift kwarg switched to ANIMA_SHIFT (its set_timesteps doesn't accept sigmas=, so it builds its own internal schedule); narrative comments in scheduler_driver and er_sde_scheduler trimmed; new tests covering driver iteration counts, terminal sigma_prev, seed determinism, and the begin_index fallback for clipped DPM++ schedules. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * style: apply ruff lint and format to anima scheduler driver Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * ci: re-run after flaky token-expiration test The 1-second JWT token-expiration test in test_token_service.py is timing sensitive — passes locally on retry. Empty commit to retrigger CI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Your Name <you@example.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Jonathan <34005131+JPPhoto@users.noreply.github.com>