fix: retry web probe prompt fill
This commit is contained in:
@@ -1877,7 +1877,7 @@ async function sendPrompt(text, options = {}) {
|
||||
error.details = { beforeUrl, afterUrl: currentPageUrl(), controlRecovery, composerRecovery, snapshot, editorWaitError: errorSummary(editorWaitError), pageId, pageEpoch: controlPageEpoch, valuesRedacted: true };
|
||||
throw error;
|
||||
}
|
||||
await fillComposerEditor(editor, text);
|
||||
editor = await fillComposerEditorWithRetry(editor, text, { beforeUrl, controlRecovery });
|
||||
const primarySubmitSelector = '#command-send, #command-submit, [data-testid="command-submit"], [data-testid="composer-submit"], [data-testid="send-command"]';
|
||||
const primarySubmit = page.locator(primarySubmitSelector).last();
|
||||
const submit = await primarySubmit.isVisible().catch(() => false)
|
||||
@@ -2030,19 +2030,83 @@ async function sendPrompt(text, options = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
async function fillComposerEditor(editor, text) {
|
||||
async function fillComposerEditorWithRetry(initialEditor, text, context = {}) {
|
||||
let editor = initialEditor;
|
||||
let lastError = null;
|
||||
let recovery = null;
|
||||
for (let attempt = 1; attempt <= 2; attempt += 1) {
|
||||
try {
|
||||
if (attempt > 1 || !editor) editor = await resolveComposerEditor(8000);
|
||||
await fillComposerEditor(editor, text, { timeoutMs: 12000 });
|
||||
const retained = await composerEditorRetainsText(editor, text);
|
||||
if (retained) return editor;
|
||||
throw new Error("sendPrompt composer editor did not retain filled text");
|
||||
} catch (error) {
|
||||
lastError = error;
|
||||
await appendJsonl(files.control, eventRecord("sendPrompt-composer-fill-retry", {
|
||||
attempt,
|
||||
willRetry: attempt < 2,
|
||||
error: errorSummary(error),
|
||||
beforeUrl: context.beforeUrl || null,
|
||||
afterUrl: currentPageUrl(),
|
||||
controlRecovery: context.controlRecovery || null,
|
||||
pageId,
|
||||
pageEpoch: controlPageEpoch,
|
||||
valuesRedacted: true
|
||||
}));
|
||||
if (attempt >= 2) break;
|
||||
recovery = await forceRecoverControlPageForCommand("sendPrompt-composer-fill-failed");
|
||||
if (recovery.ok !== true) await page.waitForTimeout(250);
|
||||
editor = null;
|
||||
}
|
||||
}
|
||||
const snapshot = await controlPageLivenessSnapshot("sendPrompt-composer-fill-failed-final", 3000);
|
||||
const error = new Error("sendPrompt composer editor fill failed");
|
||||
error.details = {
|
||||
beforeUrl: context.beforeUrl || null,
|
||||
afterUrl: currentPageUrl(),
|
||||
controlRecovery: context.controlRecovery || null,
|
||||
recovery,
|
||||
snapshot,
|
||||
fillError: errorSummary(lastError),
|
||||
pageId,
|
||||
pageEpoch: controlPageEpoch,
|
||||
valuesRedacted: true
|
||||
};
|
||||
throw error;
|
||||
}
|
||||
|
||||
async function resolveComposerEditor(timeoutMs = 8000) {
|
||||
const primaryEditor = page.locator("#command-input").last();
|
||||
const candidate = await primaryEditor.isVisible().catch(() => false)
|
||||
? primaryEditor
|
||||
: page.locator('textarea, [role="textbox"], [contenteditable="true"], input[type="text"]').last();
|
||||
await candidate.waitFor({ state: "visible", timeout: timeoutMs });
|
||||
return candidate;
|
||||
}
|
||||
|
||||
async function fillComposerEditor(editor, text, options = {}) {
|
||||
const timeoutMs = Number.isFinite(Number(options.timeoutMs)) ? Math.max(1000, Math.trunc(Number(options.timeoutMs))) : 30000;
|
||||
const tag = await editor.evaluate((element) => element.tagName.toLowerCase()).catch(() => "");
|
||||
const editable = await editor.evaluate((element) => element.getAttribute("contenteditable") === "true").catch(() => false);
|
||||
if (tag === "textarea" || tag === "input") await editor.fill(text);
|
||||
if (tag === "textarea" || tag === "input") await editor.fill(text, { timeout: timeoutMs });
|
||||
else if (editable) {
|
||||
await editor.click();
|
||||
await editor.click({ timeout: timeoutMs });
|
||||
await page.keyboard.insertText(text);
|
||||
} else {
|
||||
await editor.click();
|
||||
await editor.click({ timeout: timeoutMs });
|
||||
await page.keyboard.insertText(text);
|
||||
}
|
||||
}
|
||||
|
||||
async function composerEditorRetainsText(editor, expectedText) {
|
||||
const expected = String(expectedText || "");
|
||||
return editor.evaluate((element, value) => {
|
||||
if (element instanceof HTMLTextAreaElement || element instanceof HTMLInputElement) return element.value === value;
|
||||
return (element.textContent || "") === value;
|
||||
}, expected).catch(() => false);
|
||||
}
|
||||
|
||||
async function clearComposerEditor(editor) {
|
||||
const tag = await editor.evaluate((element) => element.tagName.toLowerCase()).catch(() => "");
|
||||
const editable = await editor.evaluate((element) => element.getAttribute("contenteditable") === "true").catch(() => false);
|
||||
|
||||
Reference in New Issue
Block a user