fix: align web probe fresh session by session route (#1497)
This commit is contained in:
@@ -649,7 +649,7 @@ async function createFreshSession(page, args, actions) {
|
||||
const alignment = await waitForFreshSessionAlignment(page, args, before, timeoutMs);
|
||||
const after = alignment.after;
|
||||
actions.push({ action: "fresh-session", selector, settled: Boolean(settled), aligned: alignment.ok, timeoutMs, shellReady, before, after, alignment });
|
||||
if (!settled || !alignment.ok) throw new Error(`fresh session did not settle: ${JSON.stringify({ settled: Boolean(settled), alignment, timeoutMs })}`);
|
||||
if (!alignment.ok) throw new Error(`fresh session did not settle: ${JSON.stringify({ settled: Boolean(settled), alignment, timeoutMs })}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -661,16 +661,16 @@ async function waitForFreshSessionAlignment(page, args, before, timeoutMs) {
|
||||
while (Date.now() - startedAt < timeoutMs) {
|
||||
const check = freshSessionAlignment(before, after);
|
||||
bestCandidate = bestCandidate ?? freshSessionCandidate(before, after);
|
||||
attempts.push({ elapsedMs: Date.now() - startedAt, ok: check.ok, reason: check.reason, conversationId: check.conversationId, routeConversationId: check.routeConversationId, selectedConversationId: check.selectedConversationId, apiConversationPresent: check.apiConversationPresent });
|
||||
attempts.push(freshSessionAttemptSummary(check, Date.now() - startedAt));
|
||||
if (check.ok) return { ok: true, reason: null, attempts, after, check };
|
||||
await page.waitForTimeout(500);
|
||||
after = await collectSessionState(page, args);
|
||||
}
|
||||
const check = freshSessionAlignment(before, after);
|
||||
bestCandidate = bestCandidate ?? freshSessionCandidate(before, after);
|
||||
attempts.push({ elapsedMs: Date.now() - startedAt, ok: check.ok, reason: check.reason, conversationId: check.conversationId, routeConversationId: check.routeConversationId, selectedConversationId: check.selectedConversationId, apiConversationPresent: check.apiConversationPresent });
|
||||
if (!check.ok && bestCandidate?.conversationId) {
|
||||
const repair = await realignFreshSession(page, args, bestCandidate.conversationId);
|
||||
attempts.push(freshSessionAttemptSummary(check, Date.now() - startedAt));
|
||||
if (!check.ok && bestCandidate?.id) {
|
||||
const repair = await realignFreshSession(page, args, bestCandidate.id);
|
||||
after = await collectSessionState(page, args);
|
||||
const repaired = freshSessionAlignment(before, after);
|
||||
return { ok: repaired.ok, reason: repaired.reason, attempts, after, check: repaired, repair };
|
||||
@@ -678,19 +678,39 @@ async function waitForFreshSessionAlignment(page, args, before, timeoutMs) {
|
||||
return { ok: false, reason: check.reason, attempts, after, check };
|
||||
}
|
||||
|
||||
function freshSessionCandidate(before, after) {
|
||||
const previousConversationId = firstNonEmpty(before?.routeConversationId, before?.api?.workspace?.selectedConversationId, before?.activeTab?.conversationId);
|
||||
const items = Array.isArray(after?.api?.conversations?.items) ? after.api.conversations.items : [];
|
||||
return items.find((item) => item.conversationId && item.conversationId !== previousConversationId && Number(item.messagesCount ?? 0) === 0) ?? null;
|
||||
function freshSessionAttemptSummary(check, elapsedMs) {
|
||||
return {
|
||||
elapsedMs,
|
||||
ok: check.ok,
|
||||
reason: check.reason,
|
||||
id: check.id,
|
||||
routeId: check.routeId,
|
||||
selectedConversationId: check.selectedConversationId,
|
||||
activeTabSessionId: check.activeTabSessionId,
|
||||
activeTabConversationId: check.activeTabConversationId,
|
||||
apiConversationPresent: check.apiConversationPresent,
|
||||
workspaceApiAvailable: check.workspaceApiAvailable,
|
||||
conversationsApiAvailable: check.conversationsApiAvailable
|
||||
};
|
||||
}
|
||||
|
||||
async function realignFreshSession(page, args, conversationId) {
|
||||
const selected = await selectConversationViaApi(page, args, conversationId, "web-live-dom-probe-fresh-realign");
|
||||
const target = new URL(`/workbench/sessions/${encodeURIComponent(conversationId)}`, args.url).toString();
|
||||
function freshSessionCandidate(before, after) {
|
||||
const previousConversationId = sessionAuthorityId(before);
|
||||
const items = Array.isArray(after?.api?.conversations?.items) ? after.api.conversations.items : [];
|
||||
const apiCandidate = items.find((item) => item.conversationId && item.conversationId !== previousConversationId && Number(item.messagesCount ?? 0) === 0);
|
||||
if (apiCandidate) return { ...apiCandidate, id: apiCandidate.conversationId, source: "api-conversations" };
|
||||
const tabs = Array.isArray(after?.sessionTabs) ? after.sessionTabs : [];
|
||||
const tabCandidate = tabs.find((item) => firstNonEmpty(item.sessionId, item.conversationId) && firstNonEmpty(item.sessionId, item.conversationId) !== previousConversationId && item.running !== "true");
|
||||
return tabCandidate ? { ...tabCandidate, id: firstNonEmpty(tabCandidate.sessionId, tabCandidate.conversationId), source: "session-tab" } : null;
|
||||
}
|
||||
|
||||
async function realignFreshSession(page, args, sessionOrConversationId) {
|
||||
const selected = await selectConversationViaApi(page, args, sessionOrConversationId, "web-live-dom-probe-fresh-realign").catch((error) => ({ ok: false, phase: "select-conversation", error: error instanceof Error ? error.message : String(error) }));
|
||||
const target = new URL(`/workbench/sessions/${encodeURIComponent(sessionOrConversationId)}`, args.url).toString();
|
||||
await page.goto(target, { waitUntil: "domcontentloaded", timeout: args.timeoutMs });
|
||||
await page.locator("#workspace").waitFor({ state: "visible", timeout: args.timeoutMs });
|
||||
await page.locator("#command-input").waitFor({ state: "visible", timeout: args.timeoutMs });
|
||||
return { action: "fresh-session-realign", conversationId, target, selected };
|
||||
return { action: "fresh-session-realign", id: sessionOrConversationId, target, selected };
|
||||
}
|
||||
|
||||
async function selectConversationViaApi(page, args, conversationId, updatedByClient) {
|
||||
@@ -719,15 +739,19 @@ async function selectConversationViaApi(page, args, conversationId, updatedByCli
|
||||
}
|
||||
|
||||
function freshSessionAlignment(before, after) {
|
||||
const previousConversationId = firstNonEmpty(before?.routeConversationId, before?.api?.workspace?.selectedConversationId, before?.activeTab?.conversationId);
|
||||
const conversationId = firstNonEmpty(after?.routeConversationId, after?.api?.workspace?.selectedConversationId, after?.activeTab?.conversationId);
|
||||
const previousConversationId = sessionAuthorityId(before);
|
||||
const conversationId = sessionAuthorityId(after);
|
||||
const selectedConversationId = after?.api?.workspace?.selectedConversationId ?? null;
|
||||
const routeConversationId = after?.routeConversationId ?? null;
|
||||
const apiConversation = conversationId ? after?.api?.conversations?.items?.find((item) => item.conversationId === conversationId) ?? null : null;
|
||||
const activeTabSessionId = after?.activeTab?.sessionId ?? null;
|
||||
const activeTabConversationId = after?.activeTab?.conversationId ?? null;
|
||||
const workspaceApiAvailable = after?.api?.workspace?.ok === true;
|
||||
const conversationsApiAvailable = after?.api?.conversations?.ok === true;
|
||||
const apiConversation = conversationId ? after?.api?.conversations?.items?.find((item) => item.conversationId === conversationId || item.sessionId === conversationId) ?? null : null;
|
||||
const routeMatches = Boolean(routeConversationId && conversationId && routeConversationId === conversationId);
|
||||
const workspaceMatches = Boolean(selectedConversationId && conversationId && selectedConversationId === conversationId);
|
||||
const apiConversationPresent = Boolean(apiConversation);
|
||||
const activeTabMatches = !after?.activeTab?.conversationId || after.activeTab.conversationId === conversationId;
|
||||
const workspaceMatches = workspaceApiAvailable ? Boolean(selectedConversationId && conversationId && selectedConversationId === conversationId) : true;
|
||||
const apiConversationPresent = conversationsApiAvailable ? Boolean(apiConversation) : true;
|
||||
const activeTabMatches = Boolean(!activeTabSessionId && !activeTabConversationId) || activeTabSessionId === conversationId || activeTabConversationId === conversationId;
|
||||
const changed = Boolean(conversationId && conversationId !== previousConversationId);
|
||||
const commandReady = after?.command?.inputDisabled === false;
|
||||
const empty = after?.messageCount === 0;
|
||||
@@ -740,7 +764,11 @@ function freshSessionAlignment(before, after) {
|
||||
: !activeTabMatches ? "fresh-session-active-tab-not-aligned"
|
||||
: !commandReady ? "fresh-session-command-not-ready"
|
||||
: "fresh-session-not-empty";
|
||||
return { ok, reason, previousConversationId, conversationId, routeConversationId, selectedConversationId, apiConversationPresent, activeTabConversationId: after?.activeTab?.conversationId ?? null, commandReady, command: after?.command ?? null, messageCount: after?.messageCount ?? null };
|
||||
return { ok, reason, previousConversationId, conversationId, id: conversationId, routeId: routeConversationId, routeConversationId, selectedConversationId, workspaceApiAvailable, conversationsApiAvailable, apiConversationPresent, activeTabConversationId, activeTabSessionId, commandReady, command: after?.command ?? null, messageCount: after?.messageCount ?? null };
|
||||
}
|
||||
|
||||
function sessionAuthorityId(state) {
|
||||
return firstNonEmpty(state?.routeConversationId, state?.api?.workspace?.selectedConversationId, state?.activeTab?.conversationId, state?.activeTab?.sessionId);
|
||||
}
|
||||
|
||||
async function waitForSessionShellReady(page, args, actions) {
|
||||
@@ -763,6 +791,14 @@ async function waitForSessionShellReady(page, args, actions) {
|
||||
async function collectSessionState(page, args = null) {
|
||||
const dom = await page.evaluate(() => {
|
||||
const activeTab = document.querySelector(".session-tab[data-active='true'], .session-tab[aria-selected='true']");
|
||||
const sessionTabs = [...document.querySelectorAll(".session-tab")].map((tab) => ({
|
||||
title: tab.querySelector("strong")?.textContent?.trim() ?? tab.getAttribute("title") ?? null,
|
||||
conversationId: tab.getAttribute("data-conversation-id") ?? null,
|
||||
sessionId: tab.getAttribute("data-session-id") ?? null,
|
||||
status: tab.getAttribute("data-status") ?? null,
|
||||
running: tab.getAttribute("data-running") ?? null,
|
||||
active: tab.getAttribute("data-active") === "true" || tab.getAttribute("aria-selected") === "true"
|
||||
}));
|
||||
const routeMatch = window.location.pathname.match(/\/workbench\/sessions\/([^/]+)/u) ?? window.location.pathname.match(/\/workspace\/sessions\/([^/]+)/u);
|
||||
return {
|
||||
finalUrl: window.location.href,
|
||||
@@ -778,6 +814,7 @@ async function collectSessionState(page, args = null) {
|
||||
running: activeTab.getAttribute("data-running") ?? null
|
||||
} : null,
|
||||
tabCount: document.querySelectorAll(".session-tab").length,
|
||||
sessionTabs: sessionTabs.slice(0, 20),
|
||||
messageCount: document.querySelectorAll(".message-card").length,
|
||||
emptyVisible: Boolean(document.querySelector("[data-conversation-empty]")),
|
||||
command: {
|
||||
@@ -1088,6 +1125,7 @@ function compactSessionState(state) {
|
||||
selectedConversationId: state.api?.workspace?.selectedConversationId ?? null,
|
||||
revision: state.api?.workspace?.revision ?? null,
|
||||
activeTab: state.activeTab ?? null,
|
||||
sessionTabs: Array.isArray(state.sessionTabs) ? state.sessionTabs.slice(0, 6) : [],
|
||||
messageCount: state.messageCount ?? null,
|
||||
command: state.command ?? null,
|
||||
conversationsCount: state.api?.conversations?.count ?? null
|
||||
|
||||
Reference in New Issue
Block a user