chrome-devtools-frontend 1.0.1596535 → 1.0.1597624
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agents/prompts/ui-widgets.md +7 -8
- package/docs/ui_engineering.md +10 -11
- package/front_end/core/host/AidaClient.ts +4 -0
- package/front_end/core/host/InspectorFrontendHostAPI.ts +1 -0
- package/front_end/core/host/UserMetrics.ts +12 -0
- package/front_end/core/root/Runtime.ts +5 -0
- package/front_end/core/sdk/CPUThrottlingManager.ts +14 -13
- package/front_end/core/sdk/CSSMatchedStyles.ts +2 -0
- package/front_end/core/sdk/CSSPropertyParserMatchers.ts +28 -0
- package/front_end/core/sdk/PageResourceLoader.ts +22 -1
- package/front_end/devtools_compatibility.js +2 -1
- package/front_end/models/ai_assistance/AiConversation.ts +29 -8
- package/front_end/models/ai_assistance/ChangeManager.ts +16 -0
- package/front_end/models/ai_assistance/ExtensionScope.ts +11 -3
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +127 -0
- package/front_end/models/ai_assistance/agents/AiAgent.ts +26 -3
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +1 -1
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +11 -8
- package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +24 -0
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +323 -16
- package/front_end/models/ai_assistance/ai_assistance.ts +2 -0
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +27 -0
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +21 -0
- package/front_end/models/greendev/Prototypes.ts +7 -1
- package/front_end/models/trace/Processor.ts +1 -0
- package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +33 -0
- package/front_end/models/trace/insights/CharacterSet.ts +172 -0
- package/front_end/models/trace/insights/Models.ts +1 -0
- package/front_end/models/trace/insights/types.ts +1 -0
- package/front_end/models/trace/types/TraceEvents.ts +17 -0
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +51 -36
- package/front_end/panels/ai_assistance/PatchWidget.ts +6 -6
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +93 -74
- package/front_end/panels/ai_assistance/components/ChatView.ts +6 -11
- package/front_end/panels/ai_assistance/components/MarkdownRendererWithCodeBlock.ts +18 -9
- package/front_end/panels/ai_assistance/components/StylingAgentMarkdownRenderer.ts +200 -0
- package/front_end/panels/ai_assistance/components/chatMessage.css +11 -8
- package/front_end/panels/application/AppManifestView.ts +3 -4
- package/front_end/panels/application/DeviceBoundSessionsView.ts +18 -22
- package/front_end/panels/application/FrameDetailsView.ts +9 -15
- package/front_end/panels/application/OriginTrialTreeView.ts +2 -3
- package/front_end/panels/application/ReportingApiView.ts +13 -17
- package/front_end/panels/application/ServiceWorkerCacheViews.ts +1 -1
- package/front_end/panels/application/components/BackForwardCacheView.ts +3 -3
- package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +2 -3
- package/front_end/panels/browser_debugger/DOMBreakpointsSidebarPane.ts +3 -2
- package/front_end/panels/changes/ChangesView.ts +6 -4
- package/front_end/panels/common/ExtensionServer.ts +15 -0
- package/front_end/panels/console/ConsolePinPane.ts +3 -3
- package/front_end/panels/coverage/CoverageListView.ts +1 -1
- package/front_end/panels/css_overview/CSSOverviewPanel.ts +11 -15
- package/front_end/panels/developer_resources/DeveloperResourcesView.ts +3 -5
- package/front_end/panels/elements/ElementsTreeElement.ts +55 -47
- package/front_end/panels/elements/ElementsTreeOutline.ts +149 -28
- package/front_end/panels/elements/EventListenersWidget.ts +3 -2
- package/front_end/panels/elements/StandaloneStylesContainer.ts +21 -6
- package/front_end/panels/elements/StylePropertyTreeElement.ts +49 -4
- package/front_end/panels/layer_viewer/Layers3DView.ts +5 -4
- package/front_end/panels/lighthouse/LighthousePanel.ts +8 -0
- package/front_end/panels/linear_memory_inspector/components/LinearMemoryInspector.ts +5 -6
- package/front_end/panels/linear_memory_inspector/components/LinearMemoryValueInterpreter.ts +6 -11
- package/front_end/panels/network/RequestCookiesView.ts +3 -4
- package/front_end/panels/network/RequestInitiatorView.ts +7 -5
- package/front_end/panels/network/RequestResponseView.ts +10 -15
- package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +3 -4
- package/front_end/panels/recorder/components/RecordingView.ts +31 -36
- package/front_end/panels/recorder/components/StepEditor.ts +6 -7
- package/front_end/panels/search/SearchView.ts +2 -3
- package/front_end/panels/settings/SettingsScreen.ts +3 -2
- package/front_end/panels/settings/WorkspaceSettingsTab.ts +2 -5
- package/front_end/panels/timeline/components/LiveMetricsView.ts +5 -8
- package/front_end/panels/timeline/components/insights/Cache.ts +8 -10
- package/front_end/panels/timeline/components/insights/CharacterSet.ts +38 -0
- package/front_end/panels/timeline/components/insights/DOMSize.ts +16 -20
- package/front_end/panels/timeline/components/insights/DocumentLatency.ts +2 -6
- package/front_end/panels/timeline/components/insights/DuplicatedJavaScript.ts +3 -4
- package/front_end/panels/timeline/components/insights/FontDisplay.ts +3 -4
- package/front_end/panels/timeline/components/insights/ForcedReflow.ts +5 -7
- package/front_end/panels/timeline/components/insights/INPBreakdown.ts +3 -4
- package/front_end/panels/timeline/components/insights/ImageDelivery.ts +3 -4
- package/front_end/panels/timeline/components/insights/ImageRef.ts +2 -4
- package/front_end/panels/timeline/components/insights/InsightRenderer.ts +2 -0
- package/front_end/panels/timeline/components/insights/LCPBreakdown.ts +5 -7
- package/front_end/panels/timeline/components/insights/LCPDiscovery.ts +2 -4
- package/front_end/panels/timeline/components/insights/LegacyJavaScript.ts +3 -4
- package/front_end/panels/timeline/components/insights/ModernHTTP.ts +3 -4
- package/front_end/panels/timeline/components/insights/NetworkDependencyTree.ts +7 -11
- package/front_end/panels/timeline/components/insights/NodeLink.ts +2 -4
- package/front_end/panels/timeline/components/insights/RenderBlocking.ts +3 -4
- package/front_end/panels/timeline/components/insights/SlowCSSSelector.ts +7 -10
- package/front_end/panels/timeline/components/insights/ThirdParties.ts +5 -7
- package/front_end/panels/timeline/components/insights/insights.ts +2 -0
- package/front_end/panels/web_audio/WebAudioView.ts +3 -4
- package/front_end/ui/components/settings/SettingCheckbox.ts +2 -0
- package/front_end/ui/legacy/UIUtils.ts +5 -5
- package/front_end/ui/legacy/Widget.ts +33 -2
- package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +3 -3
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +8 -8
- package/front_end/ui/visual_logging/Debugging.ts +0 -32
- package/front_end/ui/visual_logging/KnownContextValues.ts +3 -0
- package/package.json +1 -1
|
@@ -7,23 +7,27 @@ import * as i18n from '../../../core/i18n/i18n.js';
|
|
|
7
7
|
import * as Platform from '../../../core/platform/platform.js';
|
|
8
8
|
import * as Root from '../../../core/root/root.js';
|
|
9
9
|
import * as SDK from '../../../core/sdk/sdk.js';
|
|
10
|
-
import
|
|
10
|
+
import * as Protocol from '../../../generated/protocol.js';
|
|
11
|
+
import * as Greendev from '../../../models/greendev/greendev.js';
|
|
11
12
|
import * as Annotations from '../../annotations/annotations.js';
|
|
13
|
+
import * as Emulation from '../../emulation/emulation.js';
|
|
12
14
|
import {ChangeManager} from '../ChangeManager.js';
|
|
13
15
|
import {debugLog} from '../debug.js';
|
|
14
16
|
import {EvaluateAction, formatError, SideEffectError} from '../EvaluateAction.js';
|
|
15
17
|
import {ExtensionScope} from '../ExtensionScope.js';
|
|
16
|
-
import {FREESTYLER_WORLD_NAME} from '../injected.js';
|
|
18
|
+
import {AI_ASSISTANCE_CSS_CLASS_NAME, FREESTYLER_WORLD_NAME} from '../injected.js';
|
|
17
19
|
|
|
18
20
|
import {
|
|
19
21
|
type AgentOptions as BaseAgentOptions,
|
|
20
22
|
AiAgent,
|
|
23
|
+
type AnswerResponse,
|
|
21
24
|
type ComputedStyleAiWidget,
|
|
22
25
|
type ContextResponse,
|
|
23
26
|
ConversationContext,
|
|
24
27
|
type ConversationSuggestions,
|
|
25
28
|
type FunctionCallHandlerResult,
|
|
26
29
|
type FunctionHandlerOptions,
|
|
30
|
+
type MultimodalInput,
|
|
27
31
|
MultimodalInputType,
|
|
28
32
|
type RequestOptions,
|
|
29
33
|
ResponseType
|
|
@@ -45,13 +49,14 @@ const UIStringsNotTranslate = {
|
|
|
45
49
|
|
|
46
50
|
const lockedString = i18n.i18n.lockedString;
|
|
47
51
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
function getPreamble(): string {
|
|
53
|
+
/**
|
|
54
|
+
* WARNING: preamble defined in code is only used when userTier is
|
|
55
|
+
* TESTERS. Otherwise, a server-side preamble is used (see
|
|
56
|
+
* chrome_preambles.gcl). Sync local changes with the server-side.
|
|
57
|
+
*/
|
|
58
|
+
/* clang-format off */
|
|
59
|
+
let preamble = `You are the most advanced CSS/DOM/HTML debugging assistant integrated into Chrome DevTools.
|
|
55
60
|
You always suggest considering the best web development practices and the newest platform features such as view transitions.
|
|
56
61
|
The user selected a DOM element in the browser's DevTools and sends a query about the page or the selected DOM element.
|
|
57
62
|
First, examine the provided context, then use the functions to gather additional context and resolve the user request.
|
|
@@ -73,6 +78,47 @@ First, examine the provided context, then use the functions to gather additional
|
|
|
73
78
|
* **CRITICAL** NEVER output text before a function call. Always do a function call first.
|
|
74
79
|
* **CRITICAL** When answering questions about positioning or layout, ALWAYS inspect \`position\`, \`display\` and ALL related properties.
|
|
75
80
|
* **CRITICAL** You are a CSS/DOM/HTML debugging assistant. NEVER provide answers to questions of unrelated topics such as legal advice, financial advice, personal opinions, medical advice, religion, race, politics, sexuality, gender, or any other non web-development topics. Answer "Sorry, I can't answer that. I'm best at questions about debugging web pages." to such questions.`;
|
|
81
|
+
|
|
82
|
+
const greenDevEmulationEnabled = Greendev.Prototypes.instance().isEnabled('emulationCapabilities');
|
|
83
|
+
if (greenDevEmulationEnabled) {
|
|
84
|
+
preamble += `
|
|
85
|
+
# Emulation and Screenshots
|
|
86
|
+
|
|
87
|
+
* If asked to verify whether the page is visually broken or if there are display problems with specific devices, use the \`activateDeviceEmulation\` tool. This tool will activate emulation for a specified device and capture a screenshot.
|
|
88
|
+
* **DEVICE SELECTION**: You must choose the most closely related device match from the allowed list.
|
|
89
|
+
* If the user asks about a specific device (e.g., "iPhone 6"), choose the closest match (e.g., "iPhone 6/7/8").
|
|
90
|
+
* If the user specifies a generic category (e.g., "Android phone", "iPhone", "Samsung"), choose the device with the highest version number available in that category (e.g., "Pixel 7" or "Samsung Galaxy S20" for Android, "iPhone 14 Pro Max" for iPhone).
|
|
91
|
+
* **VISION DEFICIENCY**: If the user asks about checking for color blindness or vision issues, you can pass an optional \`visionDeficiency\` parameter to \`activateDeviceEmulation\`. Allowed values are: 'blurredVision', 'reducedContrast', 'achromatopsia', 'deuteranopia', 'protanopia', 'tritanopia'.
|
|
92
|
+
* **IMPORTANT**: This is a **TWO-STEP** process.
|
|
93
|
+
* **STEP 1**: Call \`activateDeviceEmulation\`. After calling this tool, YOU MUST STOP and tell the user that the screenshot has been captured and ask them whether they would like you to focus on specific sections of the screenshot or review it all for possible problems.
|
|
94
|
+
* **STEP 2**: The captured screenshot will be automatically attached to the user's **NEXT** query.
|
|
95
|
+
* **CRITICAL**: DO NOT try to investigate/analyze the page state or element visibility automatically. But, after the user has requested to analyze the page, you can prompt the user to select one of the problematic elements if they want to diagnose further.
|
|
96
|
+
* **CRITICAL**: The output of the analysis should only be in json form (no supplemental text) and the json should list the problems found on the device, with a short description of the problem. If identical problems are identified acress multiple devices, feel free to combine sections.
|
|
97
|
+
* **CRITICAL**: ALWAYS escape single and double quotes within the json output strings (\' and \").
|
|
98
|
+
*
|
|
99
|
+
* Example (with no duplication):
|
|
100
|
+
|
|
101
|
+
[
|
|
102
|
+
{
|
|
103
|
+
"Problem": "Element not resizing",
|
|
104
|
+
"Element": "Hero banner",
|
|
105
|
+
"NodeId": "23",
|
|
106
|
+
"Details": "The \"hero\" element is not resizing because... etc etc."
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
# Additional notes:
|
|
111
|
+
|
|
112
|
+
When referring to an element for which you know the nodeId, annotate your output using markdown link syntax:
|
|
113
|
+
- For example, if nodeId is 23: ([link](#node-23))
|
|
114
|
+
- Always prefix the nodeId with the 'node-' prefix when using the markdown syntax.
|
|
115
|
+
- This link will reveal the element in the Elements panel
|
|
116
|
+
- Never mention node or nodeId when referring to the element, and especially not in the link text.`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return preamble;
|
|
120
|
+
}
|
|
121
|
+
|
|
76
122
|
/* clang-format on */
|
|
77
123
|
|
|
78
124
|
const promptForScreenshot =
|
|
@@ -149,6 +195,8 @@ async function executeJsCode(
|
|
|
149
195
|
const MAX_OBSERVATION_BYTE_LENGTH = 25_000;
|
|
150
196
|
const OBSERVATION_TIMEOUT = 5_000;
|
|
151
197
|
|
|
198
|
+
export const AI_ASSISTANCE_FILTER_REGEX = `\\.${AI_ASSISTANCE_CSS_CLASS_NAME}-.*&`;
|
|
199
|
+
|
|
152
200
|
type CreateExtensionScopeFunction = (changes: ChangeManager) => {
|
|
153
201
|
install(): Promise<void>, uninstall(): Promise<void>,
|
|
154
202
|
};
|
|
@@ -237,10 +285,11 @@ export class NodeContext extends ConversationContext<SDK.DOMModel.DOMNode> {
|
|
|
237
285
|
* instance for a new conversation.
|
|
238
286
|
*/
|
|
239
287
|
export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
|
|
240
|
-
preamble =
|
|
288
|
+
preamble = getPreamble();
|
|
241
289
|
readonly clientFeature = Host.AidaClient.ClientFeature.CHROME_STYLING_AGENT;
|
|
242
290
|
get userTier(): string|undefined {
|
|
243
|
-
|
|
291
|
+
const greenDevEmulationEnabled = Greendev.Prototypes.instance().isEnabled('emulationCapabilities');
|
|
292
|
+
return greenDevEmulationEnabled ? 'TESTERS' : Root.Runtime.hostConfig.devToolsFreestyler?.userTier;
|
|
244
293
|
}
|
|
245
294
|
get executionMode(): Root.Runtime.HostConfigFreestylerExecutionMode {
|
|
246
295
|
return Root.Runtime.hostConfig.devToolsFreestyler?.executionMode ??
|
|
@@ -269,15 +318,19 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
|
|
|
269
318
|
|
|
270
319
|
#changes: ChangeManager;
|
|
271
320
|
#createExtensionScope: CreateExtensionScopeFunction;
|
|
321
|
+
#greenDevEmulationScreenshot: string|null = null;
|
|
322
|
+
#greenDevEmulationAxTree: string|null = null;
|
|
323
|
+
#currentTurnId = 0;
|
|
272
324
|
|
|
273
325
|
constructor(opts: AgentOptions) {
|
|
274
326
|
super(opts);
|
|
275
327
|
|
|
276
328
|
this.#changes = opts.changeManager || new ChangeManager();
|
|
277
329
|
this.#execJs = opts.execJs ?? executeJsCode;
|
|
278
|
-
this.#createExtensionScope =
|
|
279
|
-
|
|
280
|
-
|
|
330
|
+
this.#createExtensionScope =
|
|
331
|
+
opts.createExtensionScope ?? ((changes: ChangeManager) => {
|
|
332
|
+
return new ExtensionScope(changes, this.sessionId, this.context?.getItem() ?? null, this.#currentTurnId);
|
|
333
|
+
});
|
|
281
334
|
|
|
282
335
|
this.declareFunction<{
|
|
283
336
|
elements: number[],
|
|
@@ -447,6 +500,37 @@ const data = {
|
|
|
447
500
|
},
|
|
448
501
|
});
|
|
449
502
|
}
|
|
503
|
+
|
|
504
|
+
this.declareFunction<{
|
|
505
|
+
deviceName: string,
|
|
506
|
+
visionDeficiency?: string,
|
|
507
|
+
}>('activateDeviceEmulation', {
|
|
508
|
+
description:
|
|
509
|
+
'Sets emulation viewing mode for a specific device and optionally enables vision deficiency emulation.',
|
|
510
|
+
parameters: {
|
|
511
|
+
type: Host.AidaClient.ParametersTypes.OBJECT,
|
|
512
|
+
description: '',
|
|
513
|
+
nullable: false,
|
|
514
|
+
properties: {
|
|
515
|
+
deviceName: {
|
|
516
|
+
type: Host.AidaClient.ParametersTypes.STRING,
|
|
517
|
+
description:
|
|
518
|
+
'The name of the device to emulate. Allowed values: Pixel 3 XL, Pixel 7, Samsung Galaxy S8+, Samsung Galaxy S20 Ultra, Surface Pro 7, Surface Duo, Galaxy Z Fold 5, Asus Zenbook Fold, Samsung Galaxy A51/71, Nest Hub Max, Nest Hub, iPhone 4, iPhone 5/SE, iPhone 6/7/8, iPhone SE, iPhone XR, iPhone 12 Pro, iPhone 14 Pro Max, iPad Mini, iPad Air, iPad Pro.',
|
|
519
|
+
nullable: false,
|
|
520
|
+
},
|
|
521
|
+
visionDeficiency: {
|
|
522
|
+
type: Host.AidaClient.ParametersTypes.STRING,
|
|
523
|
+
description:
|
|
524
|
+
'Optional vision deficiency to emulate. Allowed values: blurredVision, reducedContrast, achromatopsia, deuteranopia, protanopia, tritanopia.',
|
|
525
|
+
nullable: true,
|
|
526
|
+
},
|
|
527
|
+
},
|
|
528
|
+
required: ['deviceName']
|
|
529
|
+
},
|
|
530
|
+
handler: async params => {
|
|
531
|
+
return await this.activateDeviceEmulation(params.deviceName, params.visionDeficiency);
|
|
532
|
+
},
|
|
533
|
+
});
|
|
450
534
|
}
|
|
451
535
|
|
|
452
536
|
async generateObservation(
|
|
@@ -761,6 +845,198 @@ const data = {
|
|
|
761
845
|
};
|
|
762
846
|
}
|
|
763
847
|
|
|
848
|
+
async #compressScreenshot(base64Data: string): Promise<string> {
|
|
849
|
+
return await new Promise((resolve, reject) => {
|
|
850
|
+
const img = new Image();
|
|
851
|
+
img.onload = () => {
|
|
852
|
+
// eslint-disable-next-line @devtools/no-imperative-dom-api
|
|
853
|
+
const canvas = document.createElement('canvas');
|
|
854
|
+
const maxDimension = 2000;
|
|
855
|
+
let scale = 1;
|
|
856
|
+
if (img.width > maxDimension || img.height > maxDimension) {
|
|
857
|
+
scale = maxDimension / Math.max(img.width, img.height);
|
|
858
|
+
}
|
|
859
|
+
canvas.width = img.width * scale;
|
|
860
|
+
canvas.height = img.height * scale;
|
|
861
|
+
|
|
862
|
+
const ctx = canvas.getContext('2d');
|
|
863
|
+
if (!ctx) {
|
|
864
|
+
reject(new Error('Could not get canvas context'));
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
ctx.imageSmoothingEnabled = true;
|
|
868
|
+
ctx.imageSmoothingQuality = 'high';
|
|
869
|
+
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
|
870
|
+
const dataUrl = canvas.toDataURL('image/jpeg', 0.9);
|
|
871
|
+
resolve(dataUrl.split(',')[1]);
|
|
872
|
+
};
|
|
873
|
+
img.onerror = e => reject(new Error('Image load error: ' + e));
|
|
874
|
+
img.src = 'data:image/png;base64,' + base64Data;
|
|
875
|
+
});
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
async activateDeviceEmulation(deviceName: string, visionDeficiency?: string):
|
|
879
|
+
Promise<FunctionCallHandlerResult<unknown>> {
|
|
880
|
+
const greenDevEmulationEnabled = Greendev.Prototypes.instance().isEnabled('emulationCapabilities');
|
|
881
|
+
if (!greenDevEmulationEnabled) {
|
|
882
|
+
return {error: `GreenDev emulation capabilities not enabled`};
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// eslint-disable-next-line no-console
|
|
886
|
+
console.log('activateDeviceEmulation called with device:', deviceName, 'visionDeficiency:', visionDeficiency);
|
|
887
|
+
|
|
888
|
+
this.#greenDevEmulationScreenshot = null;
|
|
889
|
+
this.#greenDevEmulationAxTree = null;
|
|
890
|
+
|
|
891
|
+
const emulatedDevicesList = Emulation.EmulatedDevices.EmulatedDevicesList.instance();
|
|
892
|
+
const device = emulatedDevicesList.standard().find(d => d.title === deviceName);
|
|
893
|
+
|
|
894
|
+
if (!device) {
|
|
895
|
+
return {
|
|
896
|
+
error: `Could not find device "${deviceName}" in the list of emulated devices.`,
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
const deviceModeModel = Emulation.DeviceModeModel.DeviceModeModel.instance();
|
|
901
|
+
|
|
902
|
+
const verticalMode = device.modesForOrientation(Emulation.EmulatedDevices.Vertical)[0];
|
|
903
|
+
if (!verticalMode) {
|
|
904
|
+
return {
|
|
905
|
+
error: `Could not find vertical mode for "${deviceName}".`,
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
deviceModeModel.emulate(Emulation.DeviceModeModel.Type.Device, device, verticalMode);
|
|
909
|
+
|
|
910
|
+
// Get the selected node early to use for both vision deficiency and wait mechanism.
|
|
911
|
+
const selectedNode = this.#getSelectedNode();
|
|
912
|
+
|
|
913
|
+
// Apply vision deficiency if provided (and turn it off when not provided).
|
|
914
|
+
try {
|
|
915
|
+
if (selectedNode) {
|
|
916
|
+
const target = selectedNode.domModel().target();
|
|
917
|
+
const emulationModel = target.model(SDK.EmulationModel.EmulationModel);
|
|
918
|
+
if (emulationModel) {
|
|
919
|
+
let type = Protocol.Emulation.SetEmulatedVisionDeficiencyRequestType.None;
|
|
920
|
+
if (visionDeficiency && visionDeficiency !== 'none') {
|
|
921
|
+
type = visionDeficiency as Protocol.Emulation.SetEmulatedVisionDeficiencyRequestType;
|
|
922
|
+
}
|
|
923
|
+
await target.emulationAgent().invoke_setEmulatedVisionDeficiency({type});
|
|
924
|
+
}
|
|
925
|
+
} else {
|
|
926
|
+
console.error('No selected node context to retrieve EmulationModel.');
|
|
927
|
+
}
|
|
928
|
+
} catch {
|
|
929
|
+
return {
|
|
930
|
+
error: `Unable to apply vision deficiency "${visionDeficiency}".`,
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
// Wait for the layout to settle after emulation changes.
|
|
935
|
+
// We use a double requestAnimationFrame to ensure at least one frame is rendered.
|
|
936
|
+
if (selectedNode) {
|
|
937
|
+
try {
|
|
938
|
+
const code = 'await new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)))';
|
|
939
|
+
// We use throwOnSideEffect: false because this is a benign wait, not a modification of the page state relevant to the user.
|
|
940
|
+
await this.#execJs(code, {throwOnSideEffect: false, contextNode: selectedNode});
|
|
941
|
+
} catch (e) {
|
|
942
|
+
console.error('Failed to wait for layout settle:', e);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
const orientation = device.orientationByName(Emulation.EmulatedDevices.Vertical);
|
|
947
|
+
const width = orientation.width;
|
|
948
|
+
|
|
949
|
+
// TODO(finnur): Investigate better screen capture alternatives (that can do the whole page).
|
|
950
|
+
let documentHeight = 2000;
|
|
951
|
+
if (selectedNode) {
|
|
952
|
+
try {
|
|
953
|
+
const heightJs = 'document.body.scrollHeight';
|
|
954
|
+
const result = await this.#execJs(heightJs, {throwOnSideEffect: false, contextNode: selectedNode});
|
|
955
|
+
const parsedHeight = Number(result);
|
|
956
|
+
if (!isNaN(parsedHeight)) {
|
|
957
|
+
documentHeight = Math.min(parsedHeight, 2000);
|
|
958
|
+
}
|
|
959
|
+
} catch (e) {
|
|
960
|
+
console.error('Failed to get document height:', e);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
// Specify a clip capping the height to the top 5000px.
|
|
965
|
+
const clip: Protocol.Page.Viewport = {
|
|
966
|
+
x: 0,
|
|
967
|
+
y: 0,
|
|
968
|
+
width,
|
|
969
|
+
height: documentHeight,
|
|
970
|
+
scale: 1,
|
|
971
|
+
};
|
|
972
|
+
|
|
973
|
+
// Capture using the clip. fullSize must be false when clip is used.
|
|
974
|
+
const screenshot = await deviceModeModel.captureScreenshot(false, clip);
|
|
975
|
+
|
|
976
|
+
if (!screenshot) {
|
|
977
|
+
return {
|
|
978
|
+
error: `Emulation for ${deviceName} activated, but failed to capture screenshot.`,
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
try {
|
|
983
|
+
this.#greenDevEmulationScreenshot = await this.#compressScreenshot(screenshot);
|
|
984
|
+
} catch (e) {
|
|
985
|
+
console.error('Screenshot compression failed, using original', e);
|
|
986
|
+
this.#greenDevEmulationScreenshot = screenshot;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
try {
|
|
990
|
+
if (selectedNode) {
|
|
991
|
+
const accessibilityModel = selectedNode.domModel().target().model(SDK.AccessibilityModel.AccessibilityModel);
|
|
992
|
+
if (accessibilityModel) {
|
|
993
|
+
await accessibilityModel.resumeModel();
|
|
994
|
+
const axResponse = await accessibilityModel.agent.invoke_getFullAXTree({});
|
|
995
|
+
if (!axResponse.getError()) {
|
|
996
|
+
this.#greenDevEmulationAxTree = JSON.stringify(axResponse.nodes);
|
|
997
|
+
} else {
|
|
998
|
+
console.error('Failed to capture Accessibility Tree:', axResponse.getError());
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
} catch (e) {
|
|
1003
|
+
console.error('Exception capturing Accessibility Tree:', e);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
let resultMsg = `Emulation for ${deviceName} activated and screenshot has been captured.`;
|
|
1007
|
+
if (visionDeficiency) {
|
|
1008
|
+
resultMsg += ` Vision deficiency "${visionDeficiency}" was also applied.`;
|
|
1009
|
+
}
|
|
1010
|
+
resultMsg += ' Ready for analysis.';
|
|
1011
|
+
|
|
1012
|
+
return {
|
|
1013
|
+
result: resultMsg,
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
override popPendingMultimodalInput(): MultimodalInput|undefined {
|
|
1018
|
+
const greenDevEmulationEnabled = Greendev.Prototypes.instance().isEnabled('emulationCapabilities');
|
|
1019
|
+
if (!greenDevEmulationEnabled) {
|
|
1020
|
+
return undefined;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
if (this.#greenDevEmulationScreenshot) {
|
|
1024
|
+
const data = this.#greenDevEmulationScreenshot;
|
|
1025
|
+
this.#greenDevEmulationScreenshot = null;
|
|
1026
|
+
return {
|
|
1027
|
+
type: MultimodalInputType.SCREENSHOT,
|
|
1028
|
+
input: {
|
|
1029
|
+
inlineData: {
|
|
1030
|
+
data,
|
|
1031
|
+
mimeType: 'image/jpeg',
|
|
1032
|
+
},
|
|
1033
|
+
},
|
|
1034
|
+
id: crypto.randomUUID(),
|
|
1035
|
+
};
|
|
1036
|
+
}
|
|
1037
|
+
return undefined;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
764
1040
|
override async *
|
|
765
1041
|
handleContextDetails(selectedElement: ConversationContext<SDK.DOMModel.DOMNode>|null):
|
|
766
1042
|
AsyncGenerator<ContextResponse, void, void> {
|
|
@@ -777,15 +1053,46 @@ const data = {
|
|
|
777
1053
|
};
|
|
778
1054
|
}
|
|
779
1055
|
|
|
1056
|
+
protected override async preRun(): Promise<void> {
|
|
1057
|
+
this.#currentTurnId++;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
protected override async finalizeAnswer(answer: AnswerResponse): Promise<AnswerResponse> {
|
|
1061
|
+
if (!Root.Runtime.hostConfig.devToolsAiAssistanceV2?.enabled) {
|
|
1062
|
+
return answer;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
const changedNodeIds = this.#changes.getChangedNodesForGroupId(this.sessionId, this.#currentTurnId);
|
|
1066
|
+
if (changedNodeIds.length === 0) {
|
|
1067
|
+
return answer;
|
|
1068
|
+
}
|
|
1069
|
+
answer.widgets = [
|
|
1070
|
+
...(answer.widgets ?? []),
|
|
1071
|
+
...changedNodeIds.map(id => ({
|
|
1072
|
+
name: 'STYLE_PROPERTIES' as const,
|
|
1073
|
+
data: {
|
|
1074
|
+
backendNodeId: id,
|
|
1075
|
+
selector: AI_ASSISTANCE_FILTER_REGEX,
|
|
1076
|
+
},
|
|
1077
|
+
})),
|
|
1078
|
+
];
|
|
1079
|
+
return answer;
|
|
1080
|
+
}
|
|
780
1081
|
override async enhanceQuery(
|
|
781
1082
|
query: string, selectedElement: ConversationContext<SDK.DOMModel.DOMNode>|null,
|
|
782
1083
|
multimodalInputType?: MultimodalInputType): Promise<string> {
|
|
1084
|
+
let multimodalInputEnhancementQuery =
|
|
1085
|
+
this.multimodalInputEnabled && multimodalInputType ? MULTIMODAL_ENHANCEMENT_PROMPTS[multimodalInputType] : '';
|
|
1086
|
+
|
|
1087
|
+
if (this.#greenDevEmulationAxTree) {
|
|
1088
|
+
multimodalInputEnhancementQuery += '\n# Accessibility Tree\n\n' + this.#greenDevEmulationAxTree;
|
|
1089
|
+
this.#greenDevEmulationAxTree = null;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
783
1092
|
const elementEnchancementQuery = selectedElement ?
|
|
784
1093
|
`# Inspected element\n\n${
|
|
785
1094
|
await StylingAgent.describeElement(selectedElement.getItem())}\n\n# User request\n\n` :
|
|
786
1095
|
'';
|
|
787
|
-
const multimodalInputEnhancementQuery =
|
|
788
|
-
this.multimodalInputEnabled && multimodalInputType ? MULTIMODAL_ENHANCEMENT_PROMPTS[multimodalInputType] : '';
|
|
789
1096
|
return `${multimodalInputEnhancementQuery}${elementEnchancementQuery}QUERY: ${query}`;
|
|
790
1097
|
}
|
|
791
1098
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
5
|
import * as AgentProject from './AgentProject.js';
|
|
6
|
+
import * as AccessibilityAgent from './agents/AccessibilityAgent.js';
|
|
6
7
|
import * as AiAgent from './agents/AiAgent.js';
|
|
7
8
|
import * as BreakpointDebuggerAgent from './agents/BreakpointDebuggerAgent.js';
|
|
8
9
|
import * as ContextSelectionAgent from './agents/ContextSelectionAgent.js';
|
|
@@ -32,6 +33,7 @@ import * as AIContext from './performance/AIContext.js';
|
|
|
32
33
|
import * as AIQueries from './performance/AIQueries.js';
|
|
33
34
|
|
|
34
35
|
export {
|
|
36
|
+
AccessibilityAgent,
|
|
35
37
|
AgentProject,
|
|
36
38
|
AiAgent,
|
|
37
39
|
AICallTree,
|
|
@@ -203,6 +203,10 @@ export class PerformanceInsightFormatter {
|
|
|
203
203
|
{title: 'Is my site polyfilling modern JavaScript features?'},
|
|
204
204
|
{title: 'How can I reduce the amount of legacy JavaScript on my page?'},
|
|
205
205
|
];
|
|
206
|
+
case 'CharacterSet':
|
|
207
|
+
return [
|
|
208
|
+
{title: 'How do I declare a character encoding for my page?'},
|
|
209
|
+
];
|
|
206
210
|
default:
|
|
207
211
|
throw new Error(`Unknown insight key '${this.#insight.insightKey}'`);
|
|
208
212
|
}
|
|
@@ -881,6 +885,20 @@ ${requestSummary}`;
|
|
|
881
885
|
* @param insight The Network Dependency Tree Insight Model to query.
|
|
882
886
|
* @returns a string formatted for sending to Ask AI.
|
|
883
887
|
*/
|
|
888
|
+
formatCharacterSetInsight(insight: Trace.Insights.Models.CharacterSet.CharacterSetInsightModel): string {
|
|
889
|
+
let output = '';
|
|
890
|
+
if (insight.data) {
|
|
891
|
+
output += 'HTTP Content-Type header charset: ' + (insight.data.hasHttpCharset ? 'present' : 'missing') + '.\n';
|
|
892
|
+
output += 'HTML meta charset disposition: ' + (insight.data.metaCharsetDisposition ?? 'unknown') + '.\n';
|
|
893
|
+
|
|
894
|
+
if (!insight.data.hasHttpCharset && insight.data.metaCharsetDisposition !== 'found-in-first-1024-bytes') {
|
|
895
|
+
output +=
|
|
896
|
+
'\nThe page does not declare character encoding via HTTP header or a meta charset tag in the first 1024 bytes.\n';
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
return output;
|
|
900
|
+
}
|
|
901
|
+
|
|
884
902
|
formatViewportInsight(insight: Trace.Insights.Models.Viewport.ViewportInsightModel): string {
|
|
885
903
|
let output = '';
|
|
886
904
|
|
|
@@ -995,6 +1013,10 @@ ${this.#links()}`;
|
|
|
995
1013
|
return this.formatViewportInsight(this.#insight);
|
|
996
1014
|
}
|
|
997
1015
|
|
|
1016
|
+
if (Trace.Insights.Models.CharacterSet.isCharacterSetInsight(this.#insight)) {
|
|
1017
|
+
return this.formatCharacterSetInsight(this.#insight);
|
|
1018
|
+
}
|
|
1019
|
+
|
|
998
1020
|
return '';
|
|
999
1021
|
}
|
|
1000
1022
|
|
|
@@ -1074,6 +1096,9 @@ ${this.#links()}`;
|
|
|
1074
1096
|
links.push('https://web.dev/articles/baseline-and-polyfills');
|
|
1075
1097
|
links.push('https://philipwalton.com/articles/the-state-of-es5-on-the-web/');
|
|
1076
1098
|
break;
|
|
1099
|
+
case 'CharacterSet':
|
|
1100
|
+
links.push('https://developer.chrome.com/docs/insights/charset/');
|
|
1101
|
+
break;
|
|
1077
1102
|
}
|
|
1078
1103
|
|
|
1079
1104
|
return links.map(link => '- ' + link).join('\n');
|
|
@@ -1158,6 +1183,8 @@ To pass this insight, ensure your server supports and prioritizes a modern HTTP
|
|
|
1158
1183
|
return `This insight identified legacy JavaScript in your application's modules that may be creating unnecessary code.
|
|
1159
1184
|
|
|
1160
1185
|
Polyfills and transforms enable older browsers to use new JavaScript features. However, many are not necessary for modern browsers. Consider modifying your JavaScript build process to not transpile Baseline features, unless you know you must support older browsers.`;
|
|
1186
|
+
case 'CharacterSet':
|
|
1187
|
+
return `This insight checks that the page declares a character encoding, ideally via the Content-Type HTTP response header. A missing or late charset declaration can force the browser to re-parse the document once it finally determines the encoding, delaying first contentful paint. Best practice: include charset=utf-8 in the Content-Type header and add <meta charset="utf-8"> as the very first element inside <head>.`;
|
|
1161
1188
|
}
|
|
1162
1189
|
}
|
|
1163
1190
|
}
|
package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt
CHANGED
|
@@ -467,6 +467,7 @@ Here are all the insights that contain some related request from the given range
|
|
|
467
467
|
- DocumentLatency: news.yahoo.com/ (news.yahoo.com) (eventKey: s-2116, ts: 157423489126)
|
|
468
468
|
- ThirdParties: cmp.js (consent.cmp.oath.com) (eventKey: s-3382, ts: 157423742399), gpt.js (securepubads.g.doubleclick.net) (eventKey: s-6244, ts: 157423760529), loader.js (cdn.taboola.com) (eventKey: s-6352, ts: 157423761978)
|
|
469
469
|
- Cache: prebid-2.0.js (s.yimg.com) (eventKey: s-6279, ts: 157423760925), cmp.js (consent.cmp.oath.com) (eventKey: s-3382, ts: 157423742399), d1irmdsmbztlvx.js (s.yimg.com) (eventKey: s-6185, ts: 157423759200), consent.js (s.yimg.com) (eventKey: s-3384, ts: 157423742450), wnsrvbjmeprtfrnfx.js (s.yimg.com) (eventKey: s-6273, ts: 157423760794)
|
|
470
|
+
- CharacterSet: news.yahoo.com/ (news.yahoo.com) (eventKey: s-2116, ts: 157423489126)
|
|
470
471
|
- LegacyJavaScript: benji-2.2.99.js (s.yimg.com) (eventKey: s-3387, ts: 157423742567), 25fa214.caas-news_web.min.js (s.yimg.com) (eventKey: s-3412, ts: 157423743431), wnsrvbjmeprtfrnfx.js (s.yimg.com) (eventKey: s-6273, ts: 157423760794), consent.js (s.yimg.com) (eventKey: s-3384, ts: 157423742450), news.yahoo.com/ (news.yahoo.com) (eventKey: s-2116, ts: 157423489126)
|
|
471
472
|
=== end content
|
|
472
473
|
|
|
@@ -510,6 +511,10 @@ Available insights:
|
|
|
510
511
|
description: 3rd party code can significantly impact load performance. [Reduce and defer loading of 3rd party code](https://developer.chrome.com/docs/performance/insights/third-parties) to prioritize your page's content.
|
|
511
512
|
relevant trace bounds: {min: 1020034871372, max: 1020035171789}
|
|
512
513
|
example question: Which third parties are having the largest impact on my page performance?
|
|
514
|
+
- insight name: CharacterSet
|
|
515
|
+
description: A character encoding declaration is required. It can be done with a meta charset tag in the first 1024 bytes of the HTML or in the Content-Type HTTP response header. [Learn more about declaring the character encoding](https://developer.chrome.com/docs/insights/charset/).
|
|
516
|
+
relevant trace bounds: {min: 1020034836013, max: 1020034892491}
|
|
517
|
+
example question: How do I declare a character encoding for my page?
|
|
513
518
|
=== end content
|
|
514
519
|
|
|
515
520
|
Title: PerformanceTraceFormatter formatTraceSummary yahoo-news.json.gz
|
|
@@ -617,6 +622,10 @@ Available insights:
|
|
|
617
622
|
relevant trace bounds: {min: 171608170438, max: 171608877165}
|
|
618
623
|
example question: Show me the most impactful render-blocking requests that I should focus on
|
|
619
624
|
example question: How can I reduce the number of render-blocking requests?
|
|
625
|
+
- insight name: CharacterSet
|
|
626
|
+
description: A character encoding declaration is required. It can be done with a meta charset tag in the first 1024 bytes of the HTML or in the Content-Type HTTP response header. [Learn more about declaring the character encoding](https://developer.chrome.com/docs/insights/charset/).
|
|
627
|
+
relevant trace bounds: {min: 171607584346, max: 171608171143}
|
|
628
|
+
example question: How do I declare a character encoding for my page?
|
|
620
629
|
|
|
621
630
|
## insight set id: NAVIGATION_1
|
|
622
631
|
|
|
@@ -641,6 +650,10 @@ Available insights:
|
|
|
641
650
|
relevant trace bounds: {min: 171614330544, max: 171615043224}
|
|
642
651
|
example question: Show me the most impactful render-blocking requests that I should focus on
|
|
643
652
|
example question: How can I reduce the number of render-blocking requests?
|
|
653
|
+
- insight name: CharacterSet
|
|
654
|
+
description: A character encoding declaration is required. It can be done with a meta charset tag in the first 1024 bytes of the HTML or in the Content-Type HTTP response header. [Learn more about declaring the character encoding](https://developer.chrome.com/docs/insights/charset/).
|
|
655
|
+
relevant trace bounds: {min: 171613750986, max: 171614330870}
|
|
656
|
+
example question: How do I declare a character encoding for my page?
|
|
644
657
|
=== end content
|
|
645
658
|
|
|
646
659
|
Title: PerformanceTraceFormatter formatTraceSummary deals with CrUX manager errors
|
|
@@ -714,6 +727,10 @@ Available insights:
|
|
|
714
727
|
description: 3rd party code can significantly impact load performance. [Reduce and defer loading of 3rd party code](https://developer.chrome.com/docs/performance/insights/third-parties) to prioritize your page's content.
|
|
715
728
|
relevant trace bounds: {min: 59728701403, max: 59729465969}
|
|
716
729
|
example question: Which third parties are having the largest impact on my page performance?
|
|
730
|
+
- insight name: CharacterSet
|
|
731
|
+
description: A character encoding declaration is required. It can be done with a meta charset tag in the first 1024 bytes of the HTML or in the Content-Type HTTP response header. [Learn more about declaring the character encoding](https://developer.chrome.com/docs/insights/charset/).
|
|
732
|
+
relevant trace bounds: {min: 59728651057, max: 59728790724}
|
|
733
|
+
example question: How do I declare a character encoding for my page?
|
|
717
734
|
=== end content
|
|
718
735
|
|
|
719
736
|
Title: PerformanceTraceFormatter formatTraceSummary image-delivery.json.gz
|
|
@@ -794,6 +811,10 @@ Available insights:
|
|
|
794
811
|
description: 3rd party code can significantly impact load performance. [Reduce and defer loading of 3rd party code](https://developer.chrome.com/docs/performance/insights/third-parties) to prioritize your page's content.
|
|
795
812
|
relevant trace bounds: {min: 59728701403, max: 59729465969}
|
|
796
813
|
example question: Which third parties are having the largest impact on my page performance?
|
|
814
|
+
- insight name: CharacterSet
|
|
815
|
+
description: A character encoding declaration is required. It can be done with a meta charset tag in the first 1024 bytes of the HTML or in the Content-Type HTTP response header. [Learn more about declaring the character encoding](https://developer.chrome.com/docs/insights/charset/).
|
|
816
|
+
relevant trace bounds: {min: 59728651057, max: 59728790724}
|
|
817
|
+
example question: How do I declare a character encoding for my page?
|
|
797
818
|
=== end content
|
|
798
819
|
|
|
799
820
|
Title: PerformanceTraceFormatter formatTraceSummary includes INP insight when there is no navigation
|
|
@@ -11,6 +11,7 @@ export interface GreenDevSettings {
|
|
|
11
11
|
aiAnnotations: Common.Settings.Setting<boolean>;
|
|
12
12
|
copyToGemini: Common.Settings.Setting<boolean>;
|
|
13
13
|
breakpointDebuggerAgent: Common.Settings.Setting<boolean>;
|
|
14
|
+
emulationCapabilities: Common.Settings.Setting<boolean>;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export class Prototypes {
|
|
@@ -48,7 +49,12 @@ export class Prototypes {
|
|
|
48
49
|
false,
|
|
49
50
|
Common.Settings.SettingStorageType.LOCAL,
|
|
50
51
|
);
|
|
52
|
+
const emulationCapabilities = settings.createSetting(
|
|
53
|
+
'greendev-emulation-capabilities-enabled',
|
|
54
|
+
false,
|
|
55
|
+
Common.Settings.SettingStorageType.LOCAL,
|
|
56
|
+
);
|
|
51
57
|
|
|
52
|
-
return {aiAnnotations, copyToGemini, breakpointDebuggerAgent};
|
|
58
|
+
return {aiAnnotations, copyToGemini, breakpointDebuggerAgent, emulationCapabilities};
|
|
53
59
|
}
|
|
54
60
|
}
|
|
@@ -40,11 +40,17 @@ let metricScoresByFrameId = new Map<FrameId, Map<AnyNavigationStart, Map<MetricN
|
|
|
40
40
|
*/
|
|
41
41
|
let allMarkerEvents: Types.Events.PageLoadEvent[] = [];
|
|
42
42
|
|
|
43
|
+
// Grouped by navigation to make it easier for insights to scope checks.
|
|
44
|
+
let metaCharsetCheckEventsByNavigation = new Map<AnyNavigationStart, Types.Events.MetaCharsetCheck[]>();
|
|
45
|
+
let metaCharsetCheckEventsArray: Types.Events.MetaCharsetCheck[] = [];
|
|
46
|
+
|
|
43
47
|
export function reset(): void {
|
|
44
48
|
metricScoresByFrameId = new Map();
|
|
45
49
|
pageLoadEventsArray = [];
|
|
46
50
|
allMarkerEvents = [];
|
|
47
51
|
selectedLCPCandidateEvents = new Set();
|
|
52
|
+
metaCharsetCheckEventsByNavigation = new Map();
|
|
53
|
+
metaCharsetCheckEventsArray = [];
|
|
48
54
|
}
|
|
49
55
|
|
|
50
56
|
let pageLoadEventsArray: Types.Events.PageLoadEvent[] = [];
|
|
@@ -60,6 +66,11 @@ let pageLoadEventsArray: Types.Events.PageLoadEvent[] = [];
|
|
|
60
66
|
let selectedLCPCandidateEvents = new Set<Types.Events.AnyLargestContentfulPaintCandidate>();
|
|
61
67
|
|
|
62
68
|
export function handleEvent(event: Types.Events.Event): void {
|
|
69
|
+
if (Types.Events.isMetaCharsetCheck(event)) {
|
|
70
|
+
metaCharsetCheckEventsArray.push(event);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
63
74
|
if (!Types.Events.eventIsPageLoadEvent(event)) {
|
|
64
75
|
return;
|
|
65
76
|
}
|
|
@@ -393,6 +404,23 @@ export async function finalize(): Promise<void> {
|
|
|
393
404
|
storePageLoadMetricAgainstNavigationId(navigation, pageLoadEvent);
|
|
394
405
|
}
|
|
395
406
|
}
|
|
407
|
+
|
|
408
|
+
const {navigationsByFrameId} = metaHandlerData();
|
|
409
|
+
metaCharsetCheckEventsArray.sort((a, b) => a.ts - b.ts);
|
|
410
|
+
for (const metaCharsetCheckEvent of metaCharsetCheckEventsArray) {
|
|
411
|
+
const frameId = metaCharsetCheckEvent.args.data?.frame;
|
|
412
|
+
if (!frameId) {
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
const navigation = Helpers.Trace.getNavigationForTraceEvent(metaCharsetCheckEvent, frameId, navigationsByFrameId);
|
|
416
|
+
if (!navigation) {
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
const eventsForNavigation =
|
|
420
|
+
Platform.MapUtilities.getWithDefault(metaCharsetCheckEventsByNavigation, navigation, () => []);
|
|
421
|
+
eventsForNavigation.push(metaCharsetCheckEvent);
|
|
422
|
+
}
|
|
423
|
+
|
|
396
424
|
// NOTE: if you are looking for the TBT calculation, it has temporarily been
|
|
397
425
|
// removed. See crbug.com/1424335 for details.
|
|
398
426
|
const allFinalLCPEvents = gatherFinalLCPEvents();
|
|
@@ -421,12 +449,17 @@ export interface PageLoadMetricsData {
|
|
|
421
449
|
* main frame.
|
|
422
450
|
*/
|
|
423
451
|
allMarkerEvents: Types.Events.PageLoadEvent[];
|
|
452
|
+
/**
|
|
453
|
+
* MetaCharsetCheck events grouped by navigation.
|
|
454
|
+
*/
|
|
455
|
+
metaCharsetCheckEventsByNavigation: Map<AnyNavigationStart, Types.Events.MetaCharsetCheck[]>;
|
|
424
456
|
}
|
|
425
457
|
|
|
426
458
|
export function data(): PageLoadMetricsData {
|
|
427
459
|
return {
|
|
428
460
|
metricScoresByFrameId,
|
|
429
461
|
allMarkerEvents,
|
|
462
|
+
metaCharsetCheckEventsByNavigation,
|
|
430
463
|
};
|
|
431
464
|
}
|
|
432
465
|
|