fix: soft-detect submission + only NEW completion messages count
- countDoneMsgs baseline before submit: lingering 'has been scheduled' chatter from the PREVIOUS gen no longer triggers an instant post-gen reload (the self-reload bug) - promptEchoed: chat echoing the prompt = strongest it-stuck signal, added to the post-Enter check; and on retry it means the earlier submit registered -> skip re-typing entirely (no double generation / double credits) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
7fbde35e47
commit
39d133ddfb
65
content.js
65
content.js
@ -221,13 +221,24 @@ function persistentError() {
|
|||||||
(e.textContent || '').length < 180);
|
(e.textContent || '').length < 180);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The agent's end-of-generation chatter. John's law: this message LIES — "scheduled /
|
// The agent's end-of-generation chatter. John's law #1: this message LIES — "scheduled /
|
||||||
// waiting in the queue due to high demand" often means it's actually DONE, and the
|
// waiting in the queue" usually means it's actually DONE (refresh to see it).
|
||||||
// stale page won't show the asset until a refresh.
|
// John's law #2: OLD messages linger in the chat history, so never match absolutely —
|
||||||
function agentSaysDone() {
|
// COUNT matches and only act when a NEW one appears after our submit.
|
||||||
return [...document.querySelectorAll('*')].some(e => visible(e) &&
|
function countDoneMsgs() {
|
||||||
/has been scheduled|waiting in the queue|check back in a few|is ready|i'?ve (generated|created)|here('s| is) (your|the) video/i.test(e.textContent || '') &&
|
const m = (document.body.innerText || '').match(
|
||||||
(e.textContent || '').length < 240);
|
/has been scheduled|waiting in the queue|check back in a few|is ready|i'?ve (generated|created)|here('s| is) (your|the) video/gi);
|
||||||
|
return m ? m.length : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The chat panel echoes the submitted prompt — the strongest "it stuck" signal, and
|
||||||
|
// on a retry it means the PREVIOUS submit registered (so don't type it again).
|
||||||
|
function promptEchoed(prompt) {
|
||||||
|
const needle = String(prompt).slice(0, 60).trim();
|
||||||
|
if (!needle) return false;
|
||||||
|
return [...document.querySelectorAll('div, p, span')].some(e => visible(e) &&
|
||||||
|
!e.closest('[contenteditable="true"], textarea') &&
|
||||||
|
(e.textContent || '').includes(needle) && (e.textContent || '').length < needle.length + 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow's "Try again" button, shown beside the "Something went wrong" banner.
|
// Flow's "Try again" button, shown beside the "Something went wrong" banner.
|
||||||
@ -348,25 +359,31 @@ async function executeTask(task) {
|
|||||||
if (!input) return await requeueWithReload(task, 'agent input never became ready');
|
if (!input) return await requeueWithReload(task, 'agent input never became ready');
|
||||||
|
|
||||||
const before = snapshotAssets();
|
const before = snapshotAssets();
|
||||||
|
const doneBase = countDoneMsgs(); // old "finished" chatter lingers — only a NEW one counts
|
||||||
|
|
||||||
const landed = await typeIntoEditor(input, task.prompt);
|
// Soft-detect first: if the chat already echoes this prompt, the PREVIOUS attempt's
|
||||||
if (!landed) return await requeueWithReload(task, 'prompt did not register in the editor');
|
// submit registered before its reload — re-typing would double-generate. Skip to waiting.
|
||||||
log('info', `Prompt set (${landed} chars). Submitting…`);
|
const alreadySubmitted = promptEchoed(task.prompt);
|
||||||
await sleep(600); // John's ritual: paste, wait a sec, THEN enter
|
if (alreadySubmitted) {
|
||||||
|
log('info', 'Prompt already echoed in the session (earlier submit registered) — not re-typing.');
|
||||||
|
} else {
|
||||||
|
const landed = await typeIntoEditor(input, task.prompt);
|
||||||
|
if (!landed) return await requeueWithReload(task, 'prompt did not register in the editor');
|
||||||
|
log('info', `Prompt set (${landed} chars). Submitting…`);
|
||||||
|
await sleep(600); // John's ritual: paste, wait a sec, THEN enter
|
||||||
|
|
||||||
await submitEditor(input); // trusted Enter via the DevTools Protocol — this submits
|
await submitEditor(input); // trusted Enter via the DevTools Protocol — this submits
|
||||||
// Success signal = the square stop button appears (or the box empties). If neither,
|
// "It stuck" = stop square appears, OR the box empties, OR the chat echoes the prompt.
|
||||||
// try the labelled submit button once, then hard-refresh — Enter into a wedged
|
const stuck = () => findStopSquare() || editorText(input).length === 0 || promptEchoed(task.prompt);
|
||||||
// session never recovers on its own.
|
let took = await waitFor(stuck, 6000, 300);
|
||||||
let took = await waitFor(() => findStopSquare() || editorText(input).length === 0, 6000, 300);
|
if (!took) {
|
||||||
if (!took) {
|
const submit = findSubmit(input);
|
||||||
const submit = findSubmit(input);
|
if (submit) { submit.click(); log('info', 'Enter fallback → clicked submit.'); }
|
||||||
if (submit) { submit.click(); log('info', 'Enter fallback → clicked submit.'); }
|
took = await waitFor(stuck, 6000, 300);
|
||||||
took = await waitFor(() => findStopSquare() || editorText(input).length === 0, 6000, 300);
|
}
|
||||||
|
if (!took) return await requeueWithReload(task, 'submission never stuck (no stop square, no echo, prompt still in box)');
|
||||||
|
log('info', 'Submitted (soft-detect confirmed). Waiting for generation…');
|
||||||
}
|
}
|
||||||
if (!took) return await requeueWithReload(task, 'submission never stuck (no stop button, prompt still in box)');
|
|
||||||
|
|
||||||
log('info', 'Submitted (stop square seen). Waiting for generation…');
|
|
||||||
|
|
||||||
const timeoutMs = task.kind === 'image' ? 3 * 60 * 1000 : settings.genTimeoutMs;
|
const timeoutMs = task.kind === 'image' ? 3 * 60 * 1000 : settings.genTimeoutMs;
|
||||||
|
|
||||||
@ -379,7 +396,7 @@ async function executeTask(task) {
|
|||||||
let signal = null;
|
let signal = null;
|
||||||
while (Date.now() - t0 < timeoutMs) {
|
while (Date.now() - t0 < timeoutMs) {
|
||||||
if (snapshotAssets().size > before.size) { signal = 'asset in grid'; break; }
|
if (snapshotAssets().size > before.size) { signal = 'asset in grid'; break; }
|
||||||
if (agentSaysDone()) { signal = 'agent completion message'; break; }
|
if (countDoneMsgs() > doneBase) { signal = 'NEW agent completion message'; break; }
|
||||||
if (Date.now() - t0 > 6000 && persistentError()) { await handleRateLimit(task); return; }
|
if (Date.now() - t0 > 6000 && persistentError()) { await handleRateLimit(task); return; }
|
||||||
if (Date.now() - t0 > 8000 && (findTryAgain() || flowError()))
|
if (Date.now() - t0 > 8000 && (findTryAgain() || flowError()))
|
||||||
return await requeueWithReload(task, 'Flow errored during video generation');
|
return await requeueWithReload(task, 'Flow errored during video generation');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user