Files
tutti/tools/scripts/agent-gui-dock-preview-performance-scenario.mjs
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

385 lines
12 KiB
JavaScript

import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import {
evaluate,
finishRendererScenario,
markRenderer,
startRendererScenario,
waitForEvaluation
} from "./agent-gui-performance-helpers.mjs";
import {
requiredScenarioData,
sqlString,
startupWorkspaceID
} from "./agent-gui-performance-snapshot-helpers.mjs";
import {
prepareAgentGUIWindowStressSnapshot,
waitForWorkbenchRendererIdle,
waitForWorkbenchRendererQuiet
} from "./agent-gui-window-performance-scenarios.mjs";
const dockPopupPreviewWindowCount = 50;
const dockPopupPreviewScreenshot = "workbench-dock-popup-preview.png";
const dockPopupPreviewMarkers = {
start: "tutti-perf:workbench-dock-popup-preview:start",
opened: "tutti-perf:workbench-dock-popup-preview:opened-observed",
ready: "tutti-perf:workbench-dock-popup-preview:ready-observed",
captured: "tutti-perf:workbench-dock-popup-preview:captured-observed",
end: "tutti-perf:workbench-dock-popup-preview:end"
};
export const workbenchDockPopupPreviewScenario = {
id: "workbench-dock-popup-preview",
markers: dockPopupPreviewMarkers,
milestones: [
{
key: "opened",
label: "Dock popup opened",
marker: dockPopupPreviewMarkers.opened
},
{
key: "ready",
label: "all preview images ready",
marker: dockPopupPreviewMarkers.ready
},
{
key: "captured",
label: "Dock popup pixels captured",
marker: dockPopupPreviewMarkers.captured
}
],
prepareSnapshot: prepareWorkbenchDockPopupPreviewDatabaseSnapshot,
prepare: prepareWorkbenchDockPopupPreview,
execute: executeWorkbenchDockPopupPreview,
describe(prepared) {
return `${prepared.expectedNodeIDs.length} mounted AgentGUI windows; fresh Dock preview cache`;
},
summarize(prepared, result) {
return scenarioSummary(
[
{
name: `${dockPopupPreviewWindowCount} Dock popup cards rendered`,
passed: result.cardCount === dockPopupPreviewWindowCount
},
{
name: "foreground preview rendered",
passed: result.foregroundReadyCount === 1
},
{
name: "background previews rendered",
passed:
result.backgroundReadyCount === dockPopupPreviewWindowCount - 1
},
{
name: "preview PNGs contain visible pixels",
passed: result.pixelReadyCount === dockPopupPreviewWindowCount
},
{
name: "preview titles rendered",
passed: result.titledCardCount === dockPopupPreviewWindowCount
},
{
name: "no loading or terminal fallback remained",
passed: result.unreadyCount === 0
},
{ name: "pixel screenshot written", passed: result.captured }
],
[
{ label: "Workspace", value: prepared.workspaceID },
{ label: "Dock popup cards", value: result.cardCount },
{
label: "Foreground/background previews",
value: `${result.foregroundReadyCount}/${result.backgroundReadyCount}`
},
{ label: "Pixel-ready previews", value: result.pixelReadyCount },
{ label: "Titled cards", value: result.titledCardCount },
{ label: "Screenshot", value: dockPopupPreviewScreenshot }
],
"an isolated empty preview cache forces 49 background AgentGUI cards through the serialized DOM-clone fallback; every resulting PNG must decode with visible, non-uniform pixels"
);
},
assessTrace: assessWorkbenchDockPopupPreviewTrace
};
export function prepareWorkbenchDockPopupPreviewSnapshot(snapshot) {
if (
!snapshot ||
typeof snapshot !== "object" ||
!Array.isArray(snapshot.nodes)
) {
throw new Error("invalid Workbench Dock popup preview snapshot input");
}
const stressedSnapshot = prepareAgentGUIWindowStressSnapshot(
snapshot,
dockPopupPreviewWindowCount
);
const agentGuiNodes = stressedSnapshot.nodes
.filter((node) => node?.data?.typeId === "agent-gui")
.map((node, index) => ({
...node,
title: `Dock Preview ${index + 1}`
}));
const agentGuiNodeByID = new Map(
agentGuiNodes.map((node) => [node.id, node])
);
return {
snapshot: {
...stressedSnapshot,
nodes: stressedSnapshot.nodes.map(
(node) => agentGuiNodeByID.get(node.id) ?? node
)
},
expectedNodeIDs: agentGuiNodes.map((node) => node.id),
expectedTitles: agentGuiNodes.map((node) => node.title)
};
}
export function assessWorkbenchDockPopupPreviewTrace(traceSummary) {
const maximumRendererTaskMs = 50;
const maximumObservedRendererTaskMs = traceSummary.timing.maxLongTaskMs;
return {
assertions: [
{
name: `renderer task <= ${maximumRendererTaskMs} ms`,
passed: maximumObservedRendererTaskMs <= maximumRendererTaskMs
}
],
details: [
{
label: "Maximum renderer task",
value: `${maximumObservedRendererTaskMs} ms`
},
{
label: "Renderer task budget",
value: `${maximumRendererTaskMs} ms`
}
]
};
}
async function prepareWorkbenchDockPopupPreviewDatabaseSnapshot(context) {
const workspaceID = await startupWorkspaceID(context);
const rows = await context.sqliteJSON(
context.databasePath,
`
SELECT snapshot_json AS snapshotJSON
FROM workspace_workbench_snapshots
WHERE workspace_id = '${sqlString(workspaceID)}'
LIMIT 1;
`
);
const prepared = prepareWorkbenchDockPopupPreviewSnapshot(
JSON.parse(rows[0]?.snapshotJSON ?? "null")
);
await context.sqliteExec(
context.databasePath,
`
UPDATE workspace_workbench_snapshots
SET snapshot_json = '${sqlString(JSON.stringify(prepared.snapshot))}'
WHERE workspace_id = '${sqlString(workspaceID)}';
`
);
return {
data: {
expectedNodeIDs: prepared.expectedNodeIDs,
workspaceID
}
};
}
async function prepareWorkbenchDockPopupPreview(context, options) {
const scenarioData = requiredScenarioData(
context,
"workbench-dock-popup-preview"
);
const expectedNodeIDs = scenarioData.expectedNodeIDs;
await waitForEvaluation(
context.pageClient,
`(() => {
const expectedNodeIDs = ${JSON.stringify(expectedNodeIDs)};
const shells = expectedNodeIDs.map((nodeID) =>
document.querySelector('[data-workbench-window-id="' + CSS.escape(nodeID) + '"]')
);
const mountedShellCount = shells.filter((shell) =>
shell instanceof HTMLElement &&
shell.dataset.minimizedMount === 'visible' &&
shell.dataset.presentationVisibility === 'visible'
).length;
const pendingHydrationCount = document.querySelectorAll(
'[data-agent-gui-workbench-hydration="pending"]'
).length;
const slot = document.querySelector(
'[data-desktop-dock-anchor-key="agent-gui:unified"]'
);
const button = slot?.querySelector('button');
if (!(button instanceof HTMLButtonElement)) {
return { ready: false, mountedShellCount, pendingHydrationCount };
}
const rect = button.getBoundingClientRect();
return {
ready:
mountedShellCount === expectedNodeIDs.length &&
pendingHydrationCount === 0 &&
rect.width > 0 &&
rect.height > 0,
mountedShellCount,
pendingHydrationCount,
expectedWindowCount: expectedNodeIDs.length
};
})()`,
options.timeoutMs,
"50 mounted AgentGUI windows and the unified Agent Dock button"
);
await waitForWorkbenchRendererQuiet(context.pageClient);
await waitForWorkbenchRendererIdle(context.pageClient);
return {
expectedNodeIDs,
workspaceID: scenarioData.workspaceID
};
}
async function executeWorkbenchDockPopupPreview(context, prepared, options) {
const { pageClient } = context;
await startRendererScenario(pageClient, dockPopupPreviewMarkers.start);
await evaluate(
pageClient,
`(() => {
const slot = document.querySelector(
'[data-desktop-dock-anchor-key="agent-gui:unified"]'
);
const button = slot?.querySelector('button');
if (!(button instanceof HTMLButtonElement)) {
throw new Error('Agent Dock button is unavailable');
}
button.click();
return true;
})()`
);
await waitForEvaluation(
pageClient,
`(() => {
const popup = document.querySelector(
'[data-desktop-dock-popup-root][data-popup-variant="default"]'
);
const cards = popup?.querySelectorAll('[data-desktop-dock-popup-card]');
return { ready: cards?.length === ${dockPopupPreviewWindowCount} };
})()`,
options.timeoutMs,
"Agent Dock popup with 50 cards"
);
await markRenderer(pageClient, dockPopupPreviewMarkers.opened);
await waitForEvaluation(
pageClient,
`(() => {
const cards = [...document.querySelectorAll(
'[data-desktop-dock-popup-root][data-popup-variant="default"] [data-desktop-dock-popup-card]'
)];
const images = cards.map((card) =>
card.querySelector('[data-preview-state="ready"][data-preview-kind="image"] img')
);
return {
ready:
cards.length === ${dockPopupPreviewWindowCount} &&
images.every((image) =>
image instanceof HTMLImageElement &&
image.complete &&
image.naturalWidth > 0 &&
image.naturalHeight > 0
)
};
})()`,
options.timeoutMs,
"decoded foreground and background Dock preview images"
);
const previewState = await evaluate(
pageClient,
`Promise.all([...document.querySelectorAll(
'[data-desktop-dock-popup-root][data-popup-variant="default"] [data-desktop-dock-popup-card]'
)].map(async (card) => {
const image = card.querySelector(
'[data-preview-state="ready"][data-preview-kind="image"] img'
);
if (!(image instanceof HTMLImageElement)) {
return {
active: card.getAttribute('data-active') === 'true',
pixelReady: false,
ready: false,
title: card.querySelector('[role="button"]')?.getAttribute('aria-label') ?? ''
};
}
await image.decode().catch(() => undefined);
const canvas = document.createElement('canvas');
canvas.width = Math.min(64, image.naturalWidth);
canvas.height = Math.min(64, image.naturalHeight);
const context = canvas.getContext('2d', { willReadFrequently: true });
if (!context) throw new Error('Dock preview pixel canvas unavailable');
context.drawImage(image, 0, 0, canvas.width, canvas.height);
const pixels = context.getImageData(0, 0, canvas.width, canvas.height).data;
let visiblePixels = 0;
const colorBuckets = new Set();
for (let index = 0; index < pixels.length; index += 4) {
if (pixels[index + 3] <= 8) continue;
visiblePixels += 1;
colorBuckets.add(
(pixels[index] >> 5) + ':' +
(pixels[index + 1] >> 5) + ':' +
(pixels[index + 2] >> 5)
);
}
const totalPixels = canvas.width * canvas.height;
return {
active: card.getAttribute('data-active') === 'true',
pixelReady:
totalPixels > 0 &&
visiblePixels / totalPixels >= 0.05 &&
colorBuckets.size >= 2,
ready: true,
title: card.querySelector('[role="button"]')?.getAttribute('aria-label') ?? ''
};
}))`,
true
);
await markRenderer(pageClient, dockPopupPreviewMarkers.ready);
await capturePageScreenshot(
context,
join(context.outputDirectory, dockPopupPreviewScreenshot)
);
await markRenderer(pageClient, dockPopupPreviewMarkers.captured);
await finishRendererScenario(pageClient, dockPopupPreviewMarkers.end);
return {
backgroundReadyCount: previewState.filter(
(preview) => !preview.active && preview.ready
).length,
captured: true,
cardCount: previewState.length,
foregroundReadyCount: previewState.filter(
(preview) => preview.active && preview.ready
).length,
pixelReadyCount: previewState.filter((preview) => preview.pixelReady)
.length,
titledCardCount: previewState.filter((preview) => preview.title.trim())
.length,
unreadyCount: previewState.filter((preview) => !preview.ready).length
};
}
async function capturePageScreenshot(context, outputPath) {
const screenshot = await context.pageClient.send("Page.captureScreenshot", {
captureBeyondViewport: false,
format: "png",
fromSurface: true
});
await writeFile(outputPath, Buffer.from(screenshot.data, "base64"));
}
function scenarioSummary(assertions, details, stabilityCriterion) {
return {
outcome: assertions.every((assertion) => assertion.passed)
? "passed"
: "failed",
assertions,
details,
stabilityCriterion
};
}