Merge pull request #1049 from pikasTech/fix/1020-newsession-requestfailed-retry
修复 #1020 newSession 网络切换后重试
This commit is contained in:
@@ -1189,41 +1189,113 @@ function isProjectManagementPathname(value) {
|
||||
return projectManagement.targetPaths.some((target) => pathname === target || pathname.startsWith(target + "/"));
|
||||
}
|
||||
|
||||
function isAgentSessionCreateRequest(requestOrUrl) {
|
||||
const method = typeof requestOrUrl?.method === "function" ? requestOrUrl.method().toUpperCase() : "";
|
||||
if (method && method !== "POST") return false;
|
||||
const url = typeof requestOrUrl === "string" ? requestOrUrl : typeof requestOrUrl?.url === "function" ? requestOrUrl.url() : "";
|
||||
try {
|
||||
return new URL(url).pathname === "/v1/agent/sessions";
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function requestFailureSummary(request) {
|
||||
let failure = null;
|
||||
try {
|
||||
failure = request.failure();
|
||||
} catch {}
|
||||
let urlPath = null;
|
||||
try {
|
||||
urlPath = new URL(request.url()).pathname;
|
||||
} catch {}
|
||||
return {
|
||||
method: typeof request.method === "function" ? request.method().toUpperCase() : null,
|
||||
urlPath,
|
||||
failureText: failure?.errorText || null,
|
||||
valuesRedacted: true
|
||||
};
|
||||
}
|
||||
|
||||
async function clickAndWaitForAgentSessionCreate(create) {
|
||||
let removeRequestFailedListener = () => {};
|
||||
const requestFailedPromise = new Promise((resolve) => {
|
||||
let timeout = null;
|
||||
const handler = (request) => {
|
||||
if (!isAgentSessionCreateRequest(request)) return;
|
||||
removeRequestFailedListener();
|
||||
resolve({ kind: "requestfailed", requestFailure: requestFailureSummary(request) });
|
||||
};
|
||||
removeRequestFailedListener = () => {
|
||||
page.off("requestfailed", handler);
|
||||
if (timeout !== null) clearTimeout(timeout);
|
||||
timeout = null;
|
||||
};
|
||||
page.on("requestfailed", handler);
|
||||
timeout = setTimeout(() => {
|
||||
removeRequestFailedListener();
|
||||
resolve(null);
|
||||
}, 45000);
|
||||
});
|
||||
const createResponsePromise = page.waitForResponse((response) => {
|
||||
const request = response.request();
|
||||
return isAgentSessionCreateRequest(request) || isAgentSessionCreateRequest(response.url());
|
||||
}, { timeout: 45000 }).then((response) => ({ kind: "response", response })).catch((error) => ({ kind: "wait-error", waitError: errorSummary(error) }));
|
||||
await create.click();
|
||||
const outcome = await Promise.race([createResponsePromise, requestFailedPromise]);
|
||||
removeRequestFailedListener();
|
||||
return outcome ?? await createResponsePromise;
|
||||
}
|
||||
|
||||
async function createSessionFromUi() {
|
||||
const beforeUrl = currentPageUrl();
|
||||
const before = await workbenchSessionSnapshot();
|
||||
const readinessBeforeClick = await workbenchReadinessSnapshot(page);
|
||||
const create = page.locator("#session-create").first();
|
||||
await create.waitFor({ state: "visible", timeout: 15000 });
|
||||
const createButtonState = await create.evaluate((element) => {
|
||||
const rect = element.getBoundingClientRect();
|
||||
const style = window.getComputedStyle(element);
|
||||
return {
|
||||
tag: element.tagName.toLowerCase(),
|
||||
id: element.id || null,
|
||||
disabled: Boolean(element.disabled),
|
||||
ariaDisabled: element.getAttribute("aria-disabled") || null,
|
||||
visible: rect.width > 0 && rect.height > 0 && style.visibility !== "hidden" && style.display !== "none",
|
||||
rect: { width: Math.round(rect.width), height: Math.round(rect.height) },
|
||||
valuesRedacted: true
|
||||
};
|
||||
}).catch((error) => ({ error: errorSummary(error), valuesRedacted: true }));
|
||||
const createResponsePromise = page.waitForResponse((response) => {
|
||||
const request = response.request();
|
||||
if (request.method().toUpperCase() !== "POST") return false;
|
||||
try {
|
||||
return new URL(response.url()).pathname === "/v1/agent/sessions";
|
||||
} catch {
|
||||
return false;
|
||||
const attempts = [];
|
||||
let createResponse = null;
|
||||
for (let attempt = 1; attempt <= 2; attempt += 1) {
|
||||
const readinessBeforeClick = await workbenchReadinessSnapshot(page);
|
||||
const create = page.locator("#session-create").first();
|
||||
await create.waitFor({ state: "visible", timeout: 15000 });
|
||||
const createButtonState = await create.evaluate((element) => {
|
||||
const rect = element.getBoundingClientRect();
|
||||
const style = window.getComputedStyle(element);
|
||||
return {
|
||||
tag: element.tagName.toLowerCase(),
|
||||
id: element.id || null,
|
||||
disabled: Boolean(element.disabled),
|
||||
ariaDisabled: element.getAttribute("aria-disabled") || null,
|
||||
visible: rect.width > 0 && rect.height > 0 && style.visibility !== "hidden" && style.display !== "none",
|
||||
rect: { width: Math.round(rect.width), height: Math.round(rect.height) },
|
||||
valuesRedacted: true
|
||||
};
|
||||
}).catch((error) => ({ error: errorSummary(error), valuesRedacted: true }));
|
||||
const outcome = await clickAndWaitForAgentSessionCreate(create);
|
||||
if (outcome?.kind === "response") {
|
||||
createResponse = outcome.response;
|
||||
attempts.push({ attempt, outcome: "response", readinessBeforeClick, createButtonState, valuesRedacted: true });
|
||||
break;
|
||||
}
|
||||
}, { timeout: 45000 }).catch((error) => ({ waitError: errorSummary(error) }));
|
||||
await create.click();
|
||||
const createResponse = await createResponsePromise;
|
||||
if (createResponse?.waitError) {
|
||||
const error = new Error("newSession did not observe POST /v1/agent/sessions response after click: " + (createResponse.waitError.message || createResponse.waitError.name || "timeout"));
|
||||
error.details = { beforeUrl, afterUrl: currentPageUrl(), before, readinessBeforeClick, createButtonState, waitError: createResponse.waitError, pageId, valuesRedacted: true };
|
||||
const afterAttempt = await workbenchSessionSnapshot();
|
||||
attempts.push({
|
||||
attempt,
|
||||
outcome: outcome?.kind || "unknown",
|
||||
readinessBeforeClick,
|
||||
createButtonState,
|
||||
waitError: outcome?.waitError || null,
|
||||
requestFailure: outcome?.requestFailure || null,
|
||||
after: afterAttempt,
|
||||
valuesRedacted: true
|
||||
});
|
||||
if (attempt < 2 && outcome?.kind === "requestfailed") {
|
||||
await page.waitForTimeout(1500);
|
||||
continue;
|
||||
}
|
||||
const waitError = outcome?.waitError || outcome?.requestFailure || { name: outcome?.kind || "unknown", valuesRedacted: true };
|
||||
const error = new Error("newSession did not observe POST /v1/agent/sessions response after click: " + (waitError.message || waitError.failureText || waitError.name || "timeout"));
|
||||
error.details = { beforeUrl, afterUrl: currentPageUrl(), before, attempts, pageId, valuesRedacted: true };
|
||||
throw error;
|
||||
}
|
||||
if (createResponse === null) throw new Error("newSession did not produce an authoritative session create response");
|
||||
const createStatus = createResponse.status();
|
||||
let createPayload = null;
|
||||
let createPayloadError = null;
|
||||
@@ -1252,7 +1324,7 @@ async function createSessionFromUi() {
|
||||
const ok = Boolean(afterSessionId === createdSessionId && after?.routeSessionId === createdSessionId && after?.composerReady);
|
||||
if (!ok) {
|
||||
const error = new Error("newSession did not select the authoritative newly created workbench session");
|
||||
error.details = { beforeUrl, afterUrl: currentPageUrl(), before, after, createdSessionId, pageId, valuesRedacted: true };
|
||||
error.details = { beforeUrl, afterUrl: currentPageUrl(), before, after, createdSessionId, attempts, pageId, valuesRedacted: true };
|
||||
throw error;
|
||||
}
|
||||
return {
|
||||
@@ -1261,6 +1333,7 @@ async function createSessionFromUi() {
|
||||
ok,
|
||||
before,
|
||||
after,
|
||||
attempts,
|
||||
sessionId: createdSessionId,
|
||||
createSession: { status: createStatus, statusText: createResponse.statusText(), responseParsed: createPayload !== null, responseParseError: createPayloadError, createdSessionId, valuesRedacted: true },
|
||||
pageId
|
||||
|
||||
Reference in New Issue
Block a user