fix(sampler): JoyAI-Echo overwrote the i2v anchor on H3
H3 keys keyframe pins by frame index and takes only first/last, so memory frame 0 evicted the anchor and the rest were refused. Forced off with a reason; hidden in Engine Settings. Tooltips now state the LoRA requirement.
This commit is contained in:
@@ -99,6 +99,16 @@
|
||||
looked exactly like one where the feature was switched off.
|
||||
|
||||
### Fixed
|
||||
- **JoyAI-Echo is switched off and hidden on MiniMax H3, where it was doing damage.** The
|
||||
memory bank places frame *i* at sequence position *i*, but H3's packed layout pins only the
|
||||
first or last frame — so every frame past the first was refused, and the one that landed
|
||||
*replaced the scene's i2v anchor*, because H3 keys pins by frame index. Not an inert toggle:
|
||||
a harmful one. The sampler now forces it off on H3 and says why, and Engine Settings stops
|
||||
offering the whole group.
|
||||
- **JoyAI-Echo's tooltips now say it requires the JoyAI-Echo LoRA.** Without it the injected
|
||||
memory frames change nothing on any model, because the base weights were never trained to
|
||||
read them as memory — the controls read as a working feature.
|
||||
|
||||
- **Closing Models & Pipeline mid-edit no longer leaves its edit buffer behind.** Escape, the
|
||||
✕, or switching to another section tore the section down without ending the edit, so the
|
||||
next visit inherited a dirty flag and a baseline belonging to a config that had already
|
||||
|
||||
@@ -128,8 +128,19 @@
|
||||
bounded_attention_enabled:
|
||||
"Bounded Attention masks text cross-attention; H3 puts text in the same self-attention "
|
||||
+ "stream as the video, where the mask would be far too large to hold.",
|
||||
joyai_memory:
|
||||
"JoyAI-Echo places memory frame i at sequence position i. H3's packed layout pins only "
|
||||
+ "the FIRST or LAST frame, so every frame past the first is refused — and the one that "
|
||||
+ "lands replaces the scene's i2v anchor, because pins are keyed by frame index. This "
|
||||
+ "one is not merely inert on H3, it is harmful, so the sampler forces it off.",
|
||||
};
|
||||
|
||||
// JoyAI's own sub-settings: they configure a bank that cannot be built here.
|
||||
const JOYAI_SUB_INPUTS = [
|
||||
"joyai_memory_size", "joyai_fix_frames", "joyai_frame_select", "joyai_memory_strength",
|
||||
"joyai_audio_memory",
|
||||
];
|
||||
|
||||
// Same idea for non-boolean knobs whose neutral value means "off".
|
||||
// The latent ops (second_pass_op, segmented detailing) are NOT listed here any more: what
|
||||
// they need is an upsampler whose latents are the same width as the model's, which depends
|
||||
@@ -171,7 +182,7 @@
|
||||
if (!usesChainSampler(st)) return new Set();
|
||||
if (!isH3(st)) return new Set(Object.keys(H3_ONLY_SAMPLER_INPUTS));
|
||||
return new Set([...Object.keys(H3_DEAD_SAMPLER_INPUTS), ...IDENTITY_SUB_INPUTS,
|
||||
...H3_DEAD_VALUE_INPUTS]);
|
||||
...JOYAI_SUB_INPUTS, ...H3_DEAD_VALUE_INPUTS]);
|
||||
}
|
||||
|
||||
// Returns [{short, detail}] for settings that are ON but cannot do anything on H3.
|
||||
|
||||
@@ -26,11 +26,13 @@ test("H3 hides identity transfer's sub-settings with it, not just the toggle", (
|
||||
}
|
||||
});
|
||||
|
||||
test("H3 hides v2a_grad_scale but keeps the feature it couples to", () => {
|
||||
test("H3 hides the whole JoyAI group, coupling knob included", () => {
|
||||
// This used to assert the opposite for joyai_audio_memory, on the reading that only the
|
||||
// LTXAV coupling knob was dead. That was wrong: the VIDEO half does not work on H3
|
||||
// either, and audio memory is gated on it, so nothing in the group can function.
|
||||
const inert = PC.familyInertInputs(h3);
|
||||
assert.ok(inert.has("v2a_grad_scale"));
|
||||
// JoyAI audio memory itself works on H3 — only the LTXAV coupling knob is dead.
|
||||
assert.ok(!inert.has("joyai_audio_memory"));
|
||||
assert.ok(inert.has("joyai_audio_memory"));
|
||||
});
|
||||
|
||||
test("LTX hides the H3-only audio clock", () => {
|
||||
@@ -70,3 +72,24 @@ test("the main-window chips no longer name a control that is now hidden", () =>
|
||||
assert.ok(!chips.some((c) => /can't run/.test(c.short)),
|
||||
"a hidden setting should not also be chipped");
|
||||
});
|
||||
|
||||
// ── JoyAI-Echo is hidden on H3 ────────────────────────────────────────────────
|
||||
// Not because it fails to fire, but because it fires and does the wrong thing: H3 keys
|
||||
// keyframe pins by frame index and accepts only the first or last, so the one memory frame
|
||||
// that lands REPLACES the scene's i2v anchor and the rest are refused.
|
||||
|
||||
test("every JoyAI control disappears on H3", () => {
|
||||
const inert = PC.familyInertInputs(h3);
|
||||
for (const k of ["joyai_memory", "joyai_memory_size", "joyai_fix_frames",
|
||||
"joyai_frame_select", "joyai_memory_strength", "joyai_audio_memory",
|
||||
"v2a_grad_scale"]) {
|
||||
assert.ok(inert.has(k), `${k} should be hidden on H3`);
|
||||
}
|
||||
});
|
||||
|
||||
test("JoyAI stays available on LTX", () => {
|
||||
const inert = PC.familyInertInputs(ltx);
|
||||
for (const k of ["joyai_memory", "joyai_memory_size", "joyai_audio_memory"]) {
|
||||
assert.ok(!inert.has(k), `${k} must remain reachable on LTX`);
|
||||
}
|
||||
});
|
||||
|
||||
+13
-2
@@ -2740,7 +2740,7 @@ class FunPackLTXAVSceneChainSampler:
|
||||
# mapping and lands a numeric on a combo (e.g. joyai_frame_select got 0).
|
||||
"joyai_memory": ("BOOLEAN", {
|
||||
"default": False,
|
||||
"tooltip": "JoyAI-Echo cross-shot memory bank. Generalizes mid_scene_guide from one anchor to a managed set of clean prior-shot frames injected into each scene via LTX guide attention, so character/scene identity carries across the whole chain (JoyAI-Echo's story-level consistency). The first joyai_fix_frames scenes are pinned permanently as a global anchor; the rest is a rolling most-recent window capped at joyai_memory_size. Supersedes mid_scene_guide when on. Video memory only; pair it with joyai_audio_memory for the soundtrack.",
|
||||
"tooltip": "JoyAI-Echo cross-shot memory bank. REQUIRES the JoyAI-Echo LoRA — without it the injected memory frames change nothing, because the base model was never trained to read them as memory. Generalizes mid_scene_guide from one anchor to a managed set of clean prior-shot frames injected into each scene via LTX guide attention, so character/scene identity carries across the whole chain (JoyAI-Echo's story-level consistency). The first joyai_fix_frames scenes are pinned permanently as a global anchor; the rest is a rolling most-recent window capped at joyai_memory_size. Supersedes mid_scene_guide when on. Video memory only; pair it with joyai_audio_memory for the soundtrack.",
|
||||
}),
|
||||
"joyai_memory_size": ("INT", {
|
||||
"default": 7, "min": 1, "max": 32,
|
||||
@@ -2762,7 +2762,7 @@ class FunPackLTXAVSceneChainSampler:
|
||||
# builder's positional reference-workflow mapping (extract_widgets) stays aligned.
|
||||
"joyai_audio_memory": ("BOOLEAN", {
|
||||
"default": False,
|
||||
"tooltip": "JoyAI-Echo PAIRED AUDIO memory. Alongside each video memory frame, pin the prior shot's clean audio latent into the audio stream so voice/timbre/ambience carry across shots the way the face now does. Deliberately breaks the audio pass-through invariant — off by default. Requires joyai_memory on; no effect on single-stream (video-only) LTXV.",
|
||||
"tooltip": "JoyAI-Echo PAIRED AUDIO memory. Needs the JoyAI-Echo LoRA, like the video memory it accompanies. Alongside each video memory frame, pin the prior shot's clean audio latent into the audio stream so voice/timbre/ambience carry across shots the way the face now does. Deliberately breaks the audio pass-through invariant — off by default. Requires joyai_memory on; no effect on single-stream (video-only) LTXV.",
|
||||
}),
|
||||
"v2a_grad_scale": ("FLOAT", {
|
||||
"default": 1.0, "min": 0.0, "max": 4.0, "step": 0.25,
|
||||
@@ -6680,6 +6680,12 @@ class FunPackLTXAVSceneChainSampler:
|
||||
"against LTX's 4096-wide cross-attention context, and the overlap "
|
||||
"tokens need LTX's patchifier; H3's native ref2va reference blocks "
|
||||
"are the equivalent and are not wired yet)")
|
||||
if joyai_memory:
|
||||
_dead.append("joyai_memory / JoyAI-Echo (the memory bank places frame i at "
|
||||
"sequence position i, and H3's packed layout pins only the FIRST "
|
||||
"or LAST frame — so every frame past the first is refused, and "
|
||||
"the one that lands REPLACES the scene's i2v anchor, since pins "
|
||||
"are keyed by frame index. Not inert on H3: harmful)")
|
||||
# Gated on joyai_audio_memory, not on the value alone: v2a_grad_scale is that
|
||||
# feature's coupling knob and is never installed without it (see the call site),
|
||||
# so reporting a left-over value as an H3 limitation blames the model for a knob
|
||||
@@ -6698,6 +6704,11 @@ class FunPackLTXAVSceneChainSampler:
|
||||
# that dies three minutes in is worse than a knob that says why it is inert.
|
||||
bounded_attention_enabled = False
|
||||
identity_transfer_enabled = False
|
||||
# Off for real, not merely hidden in the UI: unlike the two above, this one does
|
||||
# not fail to fire — it fires and overwrites the anchor pin. A stored value from
|
||||
# an LTX project must not keep doing that here.
|
||||
joyai_memory = False
|
||||
joyai_audio_memory = False
|
||||
v2a_grad_scale = 1.0
|
||||
# second_pass_op is NOT switched off here. It only needs a latent upsampler that
|
||||
# matches this model's latent width; which file that is depends on what is
|
||||
|
||||
Reference in New Issue
Block a user