fix: expand workbench session rail in web probe

This commit is contained in:
Codex
2026-06-27 02:39:04 +00:00
parent 2107937b78
commit b4186fbd59
5 changed files with 118 additions and 14 deletions
@@ -57,9 +57,10 @@ const runtimeAlerts = buildRuntimeAlerts(samples, control, network, consoleEvent
const apiDomLag = buildApiDomLagReport(samples, network);
const projectManagement = buildProjectManagementReport(samples, control, network, pagePerformance, projectManagementConfig);
const runnerErrors = errors.slice(-8).map((item) => {
const attempts = Array.isArray(item.error?.attempts) ? item.error.attempts : [];
const details = item.error?.details && typeof item.error.details === "object" ? item.error.details : {};
const attempts = Array.isArray(item.error?.attempts) ? item.error.attempts : Array.isArray(details.attempts) ? details.attempts : [];
const lastAttempt = attempts.length > 0 ? attempts[attempts.length - 1] : null;
const readiness = lastAttempt?.readiness || item.error?.navigationReadiness || null;
const readiness = lastAttempt?.readiness || lastAttempt?.readinessBeforeClick || details.readinessBeforeClick || details.readinessAfterWait || item.error?.navigationReadiness || null;
const readinessSnapshot = readiness?.snapshot || readiness;
return {
ts: item.ts ?? null,
@@ -78,7 +79,13 @@ const runnerErrors = errors.slice(-8).map((item) => {
path: readinessSnapshot.path ?? null,
readyState: readinessSnapshot.readyState ?? null,
workbenchShellVisible: readinessSnapshot.workbenchShellVisible === true,
sessionCreatePresent: readinessSnapshot.sessionCreatePresent === true,
sessionCreateVisible: readinessSnapshot.sessionCreateVisible === true,
sessionRailPresent: readinessSnapshot.sessionRailPresent === true,
sessionRailCollapsed: readinessSnapshot.sessionRailCollapsed ?? null,
sessionCollapseTogglePresent: readinessSnapshot.sessionCollapseTogglePresent === true,
sessionCollapseToggleVisible: readinessSnapshot.sessionCollapseToggleVisible === true,
sessionCollapseToggleExpanded: readinessSnapshot.sessionCollapseToggleExpanded ?? null,
commandInputPresent: readinessSnapshot.commandInputPresent === true,
activeTabPresent: readinessSnapshot.activeTabPresent === true,
warningPresent: readinessSnapshot.warningPresent === true,
+8 -3
View File
@@ -399,13 +399,18 @@ function renderWebObserveCollectTable(value: Record<string, unknown>): string {
"JSONL tail:",
webObserveTable(["TS", "ROLE", "TYPE", "COMMAND", "MSG", "TRACE", "TRACE_IDS", "MSG_STATUS", "LOAD", "ATTEMPTS", "READY", "DOM", "PATH", "MESSAGE"], jsonlTail.map((item) => {
const error = record(item.error);
const attempts = Array.isArray(error.attempts) ? error.attempts : [];
const details = record(error.details);
const attempts = Array.isArray(error.attempts) ? error.attempts : Array.isArray(details.attempts) ? details.attempts : [];
const lastAttempt = attempts.length > 0 ? record(attempts[attempts.length - 1]) : {};
const rawReadiness = record(lastAttempt.readiness ?? error.navigationReadiness);
const rawReadiness = record(lastAttempt.readiness ?? lastAttempt.readinessBeforeClick ?? details.readinessBeforeClick ?? details.readinessAfterWait ?? error.navigationReadiness);
const readiness = record(rawReadiness.snapshot ?? rawReadiness);
const createState = readiness.sessionCreateVisible === true ? "Y" : readiness.sessionCreatePresent === true ? "h" : "n";
const railState = readiness.sessionRailCollapsed === true ? "C" : readiness.sessionRailCollapsed === false ? "O" : "-";
const domBits = [
`shell=${readiness.workbenchShellVisible === true ? "Y" : "n"}`,
`create=${readiness.sessionCreateVisible === true ? "Y" : "n"}`,
`create=${createState}`,
`rail=${railState}`,
`toggle=${readiness.sessionCollapseToggleVisible === true ? "Y" : "n"}`,
`input=${readiness.commandInputPresent === true ? "Y" : "n"}`,
`tab=${readiness.activeTabPresent === true ? "Y" : "n"}`,
`login=${readiness.loginVisible === true ? "Y" : "n"}`,
@@ -1188,12 +1188,21 @@ async function workbenchReadinessSnapshot(targetPage) {
const style = window.getComputedStyle(element);
return rect.width > 0 && rect.height > 0 && style.visibility !== "hidden" && style.display !== "none";
};
const sessionCreate = document.querySelector("#session-create");
const sessionRail = document.querySelector("#session-sidebar");
const sessionCollapseToggle = document.querySelector("#session-collapse-toggle");
return {
url: window.location.href,
path: window.location.pathname,
readyState: document.readyState,
workbenchShellVisible: visible(document.querySelector("#workspace, .workbench-route")),
sessionCreateVisible: visible(document.querySelector("#session-create")),
sessionCreatePresent: Boolean(sessionCreate),
sessionCreateVisible: visible(sessionCreate),
sessionRailPresent: Boolean(sessionRail),
sessionRailCollapsed: sessionRail ? sessionRail.getAttribute("data-collapsed") === "true" || sessionRail.classList.contains("is-collapsed") : null,
sessionCollapseTogglePresent: Boolean(sessionCollapseToggle),
sessionCollapseToggleVisible: visible(sessionCollapseToggle),
sessionCollapseToggleExpanded: sessionCollapseToggle ? sessionCollapseToggle.getAttribute("aria-expanded") : null,
commandInputPresent: visible(document.querySelector("#command-input")),
activeTabPresent: visible(document.querySelector(".session-tab[data-active='true'], .session-tab[aria-selected='true']")),
warningPresent: visible(document.querySelector(".composer-warning")),
@@ -1280,6 +1289,37 @@ function requestFailureSummary(request) {
};
}
async function ensureSessionRailExpanded() {
const before = await workbenchReadinessSnapshot(page);
if (before?.sessionCreateVisible === true) {
return { ok: true, action: "already-visible", before, after: before, valuesRedacted: true };
}
const toggle = page.locator("#session-collapse-toggle").first();
const toggleVisible = await toggle.isVisible({ timeout: 2000 }).catch(() => false);
if (before?.sessionRailCollapsed !== true || !toggleVisible) {
return { ok: false, action: "not-expanded", reason: before?.sessionRailCollapsed === true ? "collapse-toggle-not-visible" : "session-rail-not-collapsed", before, after: before, valuesRedacted: true };
}
await toggle.click();
await page.waitForFunction(() => {
const visible = (element) => {
if (!element) return false;
const rect = element.getBoundingClientRect();
const style = window.getComputedStyle(element);
return rect.width > 0 && rect.height > 0 && style.visibility !== "hidden" && style.display !== "none";
};
const rail = document.querySelector("#session-sidebar");
return Boolean(visible(document.querySelector("#session-create")) || (rail && rail.getAttribute("data-collapsed") === "false"));
}, null, { timeout: 5000 }).catch(() => null);
const after = await workbenchReadinessSnapshot(page);
return {
ok: after?.sessionCreateVisible === true,
action: "expanded-session-rail",
before,
after,
valuesRedacted: true
};
}
async function clickAndWaitForAgentSessionCreate(create) {
let removeRequestFailedListener = () => {};
const requestFailedPromise = new Promise((resolve) => {
@@ -1316,9 +1356,17 @@ async function createSessionFromUi() {
const attempts = [];
let createResponse = null;
for (let attempt = 1; attempt <= 2; attempt += 1) {
const readinessBeforeClick = await workbenchReadinessSnapshot(page);
const railExpansion = await ensureSessionRailExpanded();
const readinessBeforeClick = railExpansion.after || await workbenchReadinessSnapshot(page);
const create = page.locator("#session-create").first();
await create.waitFor({ state: "visible", timeout: 15000 });
try {
await create.waitFor({ state: "visible", timeout: 15000 });
} catch (error) {
const readinessAfterWait = await workbenchReadinessSnapshot(page);
const createError = new Error("newSession session create button is not visible");
createError.details = { beforeUrl, afterUrl: currentPageUrl(), before, attempts, attempt, readinessBeforeClick, readinessAfterWait, railExpansion, waitError: errorSummary(error), pageId, valuesRedacted: true };
throw createError;
}
const createButtonState = await create.evaluate((element) => {
const rect = element.getBoundingClientRect();
const style = window.getComputedStyle(element);
@@ -1335,7 +1383,7 @@ async function createSessionFromUi() {
const outcome = await clickAndWaitForAgentSessionCreate(create);
if (outcome?.kind === "response") {
createResponse = outcome.response;
attempts.push({ attempt, outcome: "response", readinessBeforeClick, createButtonState, valuesRedacted: true });
attempts.push({ attempt, outcome: "response", readinessBeforeClick, railExpansion, createButtonState, valuesRedacted: true });
break;
}
const afterAttempt = await workbenchSessionSnapshot();
@@ -1343,6 +1391,7 @@ async function createSessionFromUi() {
attempt,
outcome: outcome?.kind || "unknown",
readinessBeforeClick,
railExpansion,
createButtonState,
waitError: outcome?.waitError || null,
requestFailure: outcome?.requestFailure || null,
@@ -777,9 +777,10 @@ async function ensureWorkbenchComposerReady(options = {}) {
}
async function createProbeSessionFromUi(options = {}) {
const railExpansion = await ensureSessionRailExpandedForProbe();
const create = page.locator("#session-create").first();
if (!(await create.isVisible({ timeout: Math.min(timeoutMs, 5000) }).catch(() => false))) {
return { ok: false, method: "ui-click", reason: "session-create-not-visible" };
return { ok: false, method: "ui-click", reason: "session-create-not-visible", railExpansion };
}
const before = await collectWorkbenchReadyState();
await create.click();
@@ -797,10 +798,36 @@ async function createProbeSessionFromUi(options = {}) {
method: "ui-click",
before: before.workspace,
after: after.workspace,
composer: after.composer
composer: after.composer,
railExpansion
};
}
async function ensureSessionRailExpandedForProbe() {
const before = await collectWorkbenchReadyState();
if (before?.workspace?.sessionCreateVisible === true) {
return { ok: true, action: "already-visible", before: before.workspace, after: before.workspace, valuesRedacted: true };
}
const toggle = page.locator("#session-collapse-toggle").first();
const toggleVisible = await toggle.isVisible({ timeout: Math.min(timeoutMs, 2000) }).catch(() => false);
if (before?.workspace?.sessionRailCollapsed !== true || !toggleVisible) {
return { ok: false, action: "not-expanded", reason: before?.workspace?.sessionRailCollapsed === true ? "collapse-toggle-not-visible" : "session-rail-not-collapsed", before: before.workspace, after: before.workspace, valuesRedacted: true };
}
await toggle.click();
await page.waitForFunction(() => {
const visible = (element) => {
if (!element) return false;
const rect = element.getBoundingClientRect();
const style = window.getComputedStyle(element);
return rect.width > 0 && rect.height > 0 && style.visibility !== "hidden" && style.display !== "none";
};
const rail = document.querySelector("#session-sidebar");
return Boolean(visible(document.querySelector("#session-create")) || (rail && rail.getAttribute("data-collapsed") === "false"));
}, null, { timeout: Math.min(timeoutMs, 5000) }).catch(() => null);
const after = await collectWorkbenchReadyState();
return { ok: after?.workspace?.sessionCreateVisible === true, action: "expanded-session-rail", before: before.workspace, after: after.workspace, valuesRedacted: true };
}
async function collectWorkbenchReadyState() {
return page.evaluate(() => {
const activeTab = document.querySelector(".session-tab[data-active='true'], .session-tab[aria-selected='true']");
@@ -808,6 +835,15 @@ async function collectWorkbenchReadyState() {
const input = document.querySelector("#command-input");
const send = document.querySelector("#command-send");
const form = document.querySelector("#command-form");
const visible = (element) => {
if (!element) return false;
const rect = element.getBoundingClientRect();
const style = window.getComputedStyle(element);
return rect.width > 0 && rect.height > 0 && style.visibility !== "hidden" && style.display !== "none";
};
const sessionCreate = document.querySelector("#session-create");
const sessionRail = document.querySelector("#session-sidebar");
const sessionCollapseToggle = document.querySelector("#session-collapse-toggle");
const warning = document.querySelector(".composer-warning")?.textContent?.trim() || null;
const mode = document.querySelector(".composer-mode")?.textContent?.trim() || null;
const draft = input && typeof input.value === "string" ? input.value : "";
@@ -831,7 +867,14 @@ async function collectWorkbenchReadyState() {
activeSessionId: sessionId,
activeConversationId: conversationId,
activeStatus: activeTab?.getAttribute("data-status") || null,
tabCount: document.querySelectorAll(".session-tab").length
tabCount: document.querySelectorAll(".session-tab").length,
sessionCreatePresent: Boolean(sessionCreate),
sessionCreateVisible: visible(sessionCreate),
sessionRailPresent: Boolean(sessionRail),
sessionRailCollapsed: sessionRail ? sessionRail.getAttribute("data-collapsed") === "true" || sessionRail.classList.contains("is-collapsed") : null,
sessionCollapseTogglePresent: Boolean(sessionCollapseToggle),
sessionCollapseToggleVisible: visible(sessionCollapseToggle),
sessionCollapseToggleExpanded: sessionCollapseToggle ? sessionCollapseToggle.getAttribute("aria-expanded") : null
},
composer: {
ready: composerReady,
+2 -2
View File
@@ -1782,8 +1782,8 @@ export function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOption
"const slimDomSample = (item) => { const v = objectOrNull(item) || {}; return { seq: v.seq ?? null, ts: v.ts ?? null, source: clip(v.source, 32), diagnosticCode: clip(v.diagnosticCode, 48), traceId: clip(v.traceId, 64), httpStatus: v.httpStatus ?? null, idleSeconds: v.idleSeconds ?? null, waitingFor: clip(v.waitingFor, 48), lastEventLabel: clip(v.lastEventLabel, 80), text: clip(v.text ?? v.preview, 180) }; };",
"const slimConsoleGroup = (item) => { const v = objectOrNull(item) || {}; return { count: v.count ?? null, type: clip(v.type, 24), status: v.status ?? null, path: clip(v.path ?? v.urlPath, 96), lastAt: v.lastAt ?? v.firstAt ?? null, firstAt: v.firstAt ?? null, traceIds: Array.isArray(v.traceIds) ? v.traceIds.slice(0, 3).map((x) => clip(x, 64)) : [] }; };",
"const slimConsoleSample = (item) => { const v = objectOrNull(item) || {}; return { ts: v.ts ?? null, type: clip(v.type, 24), status: v.status ?? null, path: clip(v.path ?? v.urlPath, 96), traceId: clip(v.traceId, 64), text: clip(v.text ?? v.preview, 180) }; };",
"const slimRunnerError = (item) => { const v = objectOrNull(item) || {}; const readiness = objectOrNull(v.lastReadiness); return { ts: v.ts ?? null, type: clip(v.type, 32), commandId: clip(v.commandId, 80), sampleSeq: v.sampleSeq ?? null, message: clip(v.message, 240), retry: clip(v.retry, 24), retryExhausted: v.retryExhausted === true, lastError: clip(v.lastError, 180), attemptCount: v.attemptCount ?? null, lastFailureKind: clip(v.lastFailureKind, 48), lastReadinessReason: clip(v.lastReadinessReason, 48), lastReadiness: readiness ? { reason: clip(readiness.reason, 48), path: clip(readiness.path, 96), readyState: clip(readiness.readyState, 24), workbenchShellVisible: readiness.workbenchShellVisible === true, sessionCreateVisible: readiness.sessionCreateVisible === true, commandInputPresent: readiness.commandInputPresent === true, activeTabPresent: readiness.activeTabPresent === true, warningPresent: readiness.warningPresent === true, loginVisible: readiness.loginVisible === true, bodyTextHash: clip(readiness.bodyTextHash, 80) } : null }; };",
"const slimRunnerErrorFromJsonl = (item) => { const v = objectOrNull(item) || {}; const error = objectOrNull(v.error) || {}; const attempts = Array.isArray(error.attempts) ? error.attempts : []; const lastAttempt = attempts.length > 0 ? objectOrNull(attempts[attempts.length - 1]) || {} : {}; const rawReadiness = objectOrNull(lastAttempt.readiness) || objectOrNull(error.navigationReadiness); const readiness = objectOrNull(rawReadiness?.snapshot) || rawReadiness; return { ts: v.ts ?? null, type: v.type ?? null, commandId: v.commandId ?? null, sampleSeq: v.sampleSeq ?? null, message: error.message ?? v.message ?? null, attemptCount: attempts.length, lastFailureKind: lastAttempt.failureKind ?? null, lastReadinessReason: rawReadiness?.reason ?? readiness?.reason ?? null, lastReadiness: readiness ?? null }; };",
"const slimRunnerError = (item) => { const v = objectOrNull(item) || {}; const readiness = objectOrNull(v.lastReadiness); return { ts: v.ts ?? null, type: clip(v.type, 32), commandId: clip(v.commandId, 80), sampleSeq: v.sampleSeq ?? null, message: clip(v.message, 240), retry: clip(v.retry, 24), retryExhausted: v.retryExhausted === true, lastError: clip(v.lastError, 180), attemptCount: v.attemptCount ?? null, lastFailureKind: clip(v.lastFailureKind, 48), lastReadinessReason: clip(v.lastReadinessReason, 48), lastReadiness: readiness ? { reason: clip(readiness.reason, 48), path: clip(readiness.path, 96), readyState: clip(readiness.readyState, 24), workbenchShellVisible: readiness.workbenchShellVisible === true, sessionCreatePresent: readiness.sessionCreatePresent === true, sessionCreateVisible: readiness.sessionCreateVisible === true, sessionRailPresent: readiness.sessionRailPresent === true, sessionRailCollapsed: readiness.sessionRailCollapsed ?? null, sessionCollapseTogglePresent: readiness.sessionCollapseTogglePresent === true, sessionCollapseToggleVisible: readiness.sessionCollapseToggleVisible === true, sessionCollapseToggleExpanded: readiness.sessionCollapseToggleExpanded ?? null, commandInputPresent: readiness.commandInputPresent === true, activeTabPresent: readiness.activeTabPresent === true, warningPresent: readiness.warningPresent === true, loginVisible: readiness.loginVisible === true, bodyTextHash: clip(readiness.bodyTextHash, 80) } : null }; };",
"const slimRunnerErrorFromJsonl = (item) => { const v = objectOrNull(item) || {}; const error = objectOrNull(v.error) || {}; const details = objectOrNull(error.details) || {}; const attempts = Array.isArray(error.attempts) ? error.attempts : Array.isArray(details.attempts) ? details.attempts : []; const lastAttempt = attempts.length > 0 ? objectOrNull(attempts[attempts.length - 1]) || {} : {}; const rawReadiness = objectOrNull(lastAttempt.readiness) || objectOrNull(lastAttempt.readinessBeforeClick) || objectOrNull(details.readinessBeforeClick) || objectOrNull(details.readinessAfterWait) || objectOrNull(error.navigationReadiness); const readiness = objectOrNull(rawReadiness?.snapshot) || rawReadiness; return { ts: v.ts ?? null, type: v.type ?? null, commandId: v.commandId ?? null, sampleSeq: v.sampleSeq ?? null, message: error.message ?? v.message ?? null, attemptCount: attempts.length, lastFailureKind: lastAttempt.failureKind ?? null, lastReadinessReason: rawReadiness?.reason ?? readiness?.reason ?? null, lastReadiness: readiness ?? null }; };",
"const slimCommandFailure = (item) => { const v = objectOrNull(item) || {}; return { ts: v.ts ?? null, commandId: clip(v.commandId, 80), type: clip(v.type, 32), source: clip(v.source, 24), durationMs: v.durationMs ?? null, beforePath: clip(v.beforePath, 80), afterPath: clip(v.afterPath, 80), name: clip(v.name, 48), failureKind: clip(v.failureKind, 48), sampleSeq: v.sampleSeq ?? null, failureSampleOk: v.failureSampleOk === true, message: clip(v.message, 240) }; };",
"const slimJump = (item) => { const v = objectOrNull(item) || {}; return { columnLabel: v.columnLabel ?? null, pageRole: clip(v.pageRole, 24), pageId: clip(v.pageId, 32), pageEpoch: v.pageEpoch ?? null, promptIndex: v.promptIndex ?? null, fromSeq: v.fromSeq ?? null, toSeq: v.toSeq ?? null, fromValue: v.fromValue ?? null, toValue: v.toValue ?? null, delta: v.delta ?? null, sampleDeltaSeconds: v.sampleDeltaSeconds ?? null, allowedIncreaseSeconds: v.allowedIncreaseSeconds ?? null, traceId: v.traceId ?? null }; };",
"const slimTraceOrderAnomaly = (item) => { const v = objectOrNull(item) || {}; return { sampleIndex: v.sampleIndex ?? v.seq ?? null, seq: v.seq ?? null, timestamp: v.timestamp ?? v.ts ?? null, pageRole: clip(v.pageRole, 24), traceId: clip(v.traceId, 64), previousRowIndex: v.previousRowIndex ?? null, currentRowIndex: v.currentRowIndex ?? null, reasons: Array.isArray(v.reasons) ? v.reasons.slice(0, 6).map((x) => clip(x, 48)) : [], previousTotalSeconds: v.previousTotalSeconds ?? null, currentTotalSeconds: v.currentTotalSeconds ?? null, previousClockSeconds: v.previousClockSeconds ?? null, currentClockSeconds: v.currentClockSeconds ?? null, previousPreview: clip(v.previousPreview, 180), currentPreview: clip(v.currentPreview, 180) }; };",