chrome-devtools-frontend 1.0.1642246 → 1.0.1642899

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.
Files changed (59) hide show
  1. package/SECURITY.md +1 -0
  2. package/front_end/core/host/UserMetrics.ts +2 -1
  3. package/front_end/core/sdk/CSSMatchedStyles.ts +55 -26
  4. package/front_end/core/sdk/CSSRule.ts +1 -0
  5. package/front_end/core/sdk/DebuggerModel.ts +5 -0
  6. package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +4 -3
  7. package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +4 -3
  8. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +11 -0
  9. package/front_end/models/ai_assistance/AiAgent2.ts +80 -16
  10. package/front_end/models/ai_assistance/AiConversation.ts +3 -2
  11. package/front_end/models/ai_assistance/README.md +8 -0
  12. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +50 -39
  13. package/front_end/models/ai_assistance/agents/AiAgent.ts +17 -6
  14. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +2 -2
  15. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +195 -147
  16. package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +1 -26
  17. package/front_end/models/ai_assistance/agents/StylingAgent.ts +24 -309
  18. package/front_end/models/ai_assistance/ai_assistance.ts +8 -0
  19. package/front_end/models/ai_assistance/contexts/DOMNodeContext.snapshot.txt +51 -0
  20. package/front_end/models/ai_assistance/contexts/DOMNodeContext.ts +200 -0
  21. package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +13 -12
  22. package/front_end/models/ai_assistance/skills/styling.md +36 -2
  23. package/front_end/models/ai_assistance/tools/GetStyles.ts +137 -0
  24. package/front_end/models/ai_assistance/tools/Tool.ts +55 -0
  25. package/front_end/models/ai_assistance/tools/ToolRegistry.ts +34 -0
  26. package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +4 -0
  27. package/front_end/models/javascript_metadata/NativeFunctions.js +16 -0
  28. package/front_end/models/lighthouse/LighthouseReporterTypes.ts +5 -0
  29. package/front_end/models/live-metrics/LiveMetrics.ts +24 -13
  30. package/front_end/models/stack_trace/DetailedErrorStackParser.ts +2 -2
  31. package/front_end/models/stack_trace/StackTrace.ts +4 -1
  32. package/front_end/models/stack_trace/StackTraceImpl.ts +9 -2
  33. package/front_end/models/stack_trace/StackTraceModel.ts +17 -4
  34. package/front_end/models/stack_trace/Trie.ts +1 -1
  35. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +19 -15
  36. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +16 -0
  37. package/front_end/panels/ai_assistance/components/ChatInput.ts +2 -2
  38. package/front_end/panels/application/DOMStorageItemsView.ts +4 -0
  39. package/front_end/panels/application/KeyValueStorageItemsView.ts +39 -7
  40. package/front_end/panels/common/ExtensionServer.ts +26 -15
  41. package/front_end/panels/console/SymbolizedErrorWidget.ts +96 -2
  42. package/front_end/panels/console/symbolizedErrorWidget.css +48 -0
  43. package/front_end/panels/elements/StandaloneStylesContainer.ts +1 -1
  44. package/front_end/panels/elements/StylePropertiesSection.ts +8 -0
  45. package/front_end/panels/elements/StylePropertyHighlighter.ts +4 -2
  46. package/front_end/panels/elements/StylePropertyTreeElement.ts +6 -5
  47. package/front_end/panels/elements/StylesContainer.ts +1 -1
  48. package/front_end/panels/elements/StylesSidebarPane.ts +4 -4
  49. package/front_end/panels/layer_viewer/PaintProfilerView.ts +106 -132
  50. package/front_end/panels/lighthouse/LighthousePanel.ts +4 -3
  51. package/front_end/panels/network/NetworkLogView.ts +3 -0
  52. package/front_end/panels/network/networkLogView.css +0 -15
  53. package/front_end/third_party/chromium/README.chromium +1 -1
  54. package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +36 -3
  55. package/front_end/ui/legacy/components/data_grid/dataGridAiButton.css +20 -0
  56. package/front_end/ui/legacy/components/utils/Linkifier.ts +19 -4
  57. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  58. package/front_end/ui/visual_logging/LoggingDriver.ts +13 -0
  59. package/package.json +1 -1
@@ -2,6 +2,8 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
 
5
+ import * as Common from '../../../core/common/common.js';
6
+ import type * as Platform from '../../../core/platform/platform.js';
5
7
  import type * as SDK from '../../../core/sdk/sdk.js';
6
8
  import * as Protocol from '../../../generated/protocol.js';
7
9
  import * as Annotations from '../../annotations/annotations.js';
@@ -68,17 +70,16 @@ export class NetworkRequestFormatter {
68
70
  return `${title}\n<binary data>`;
69
71
  }
70
72
 
71
- static formatInitiatorUrl(initiatorUrl: string, allowedOrigin: string): string {
72
- try {
73
- // Some scheme or URLs might cause errors depending on the runtime environment.
74
- const initiatorOrigin = new URL(initiatorUrl).origin;
75
- if (initiatorOrigin === allowedOrigin) {
76
- return initiatorUrl;
77
- }
78
- return '<redacted cross-origin initiator URL>';
79
- } catch {
80
- return '<redacted cross-origin initiator URL>';
73
+ static formatInitiatorUrl(
74
+ initiatorUrl: Platform.DevToolsPath.UrlString,
75
+ allowedOrigin: Platform.DevToolsPath.UrlString,
76
+ ): string {
77
+ // We extract the origin, and if it is invalid/empty we default to redacting.
78
+ const initiatorOrigin = Common.ParsedURL.ParsedURL.extractOrigin(initiatorUrl);
79
+ if (initiatorOrigin && initiatorOrigin === allowedOrigin) {
80
+ return initiatorUrl;
81
81
  }
82
+ return '<redacted cross-origin initiator URL>';
82
83
  }
83
84
 
84
85
  static formatStatus(status: {
@@ -196,7 +197,7 @@ Request initiator chain:\n${this.formatRequestInitiatorChain()}`;
196
197
  * the request's origin.
197
198
  */
198
199
  formatRequestInitiatorChain(): string {
199
- const allowedOrigin = new URL(this.#request.url()).origin;
200
+ const allowedOrigin = Common.ParsedURL.ParsedURL.extractOrigin(this.#request.url());
200
201
  let initiatorChain = '';
201
202
  let lineStart = '- URL: ';
202
203
  const graph = Logs.NetworkLog.NetworkLog.instance().initiatorGraphForRequest(this.#request);
@@ -268,7 +269,7 @@ Request initiator chain:\n${this.formatRequestInitiatorChain()}`;
268
269
  parentRequest: SDK.NetworkRequest.NetworkRequest,
269
270
  initiatorChain: string,
270
271
  lineStart: string,
271
- allowedOrigin: string,
272
+ allowedOrigin: Platform.DevToolsPath.UrlString,
272
273
  ): string {
273
274
  const visited = new Set<SDK.NetworkRequest.NetworkRequest>();
274
275
 
@@ -1,6 +1,40 @@
1
1
  ---
2
2
  name: styling
3
3
  description: Helping with CSS and styling
4
- allowed-tools: []
4
+ allowed-tools:
5
+ - getStyles
5
6
  ---
6
- You are a CSS expert helping the user style elements.
7
+ You are a CSS/DOM/HTML debugging assistant.
8
+ You always suggest considering the best web development practices and the newest platform features such as view transitions.
9
+ The user selected a DOM element in the browser's DevTools and sends a query about the page or the selected DOM element.
10
+ First, examine the provided context, then use the getStyles function to gather additional context and resolve the user request.
11
+
12
+ # Considerations
13
+
14
+ * Meticulously investigate all potential causes for the observed behavior before moving on. Gather comprehensive information about the element's parent, siblings, children, and any overlapping elements, paying close attention to properties that are likely relevant to the query.
15
+ * Be aware of the different node types (element, text, comment, document fragment, etc.) and their properties. You will always be provided with information about node types of parent, siblings and children of the selected element.
16
+ * Avoid making assumptions without sufficient evidence, and always seek further clarification if needed.
17
+ * Always explore multiple possible explanations for the observed behavior before settling on a conclusion.
18
+ * When presenting solutions, clearly distinguish between the primary cause and contributing factors.
19
+ * Please answer only if you are sure about the answer. Otherwise, explain why you're not able to answer.
20
+ * When answering, always consider MULTIPLE possible solutions.
21
+ * When answering, remember to consider CSS concepts such as the CSS cascade, explicit and implicit stacking contexts and various CSS layout types.
22
+ * Use the getStyles function available to you to investigate and fulfill the user request.
23
+ * ALWAYS OUTPUT a list of follow-up queries at the end of your text response. The format is SUGGESTIONS: ["suggestion1", "suggestion2", "suggestion3"]. Make sure that the array and the `SUGGESTIONS: ` text is in the same line.
24
+ * Use the precision of Strunk & White, the brevity of Hemingway, and the simple clarity of Vonnegut. Don't add repeated information, and keep the whole answer short.
25
+ * **CRITICAL** When answering questions about positioning or layout, ALWAYS inspect `position`, `display` and all other related properties. You MUST provide a specific list of CSS property names when calling getStyles. Do not use generic values like "all" or "*".
26
+ * **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.
27
+
28
+ ## Response Structure
29
+
30
+ If the user asks a question that requires an investigation of a problem, use this structure:
31
+ - If available, point out the root cause(s) of the problem.
32
+ - Example: "**Root Cause**: The page is slow because of [reason]."
33
+ - Example: "**Root Causes**:"
34
+ - [Reason 1]
35
+ - [Reason 2]
36
+ - if applicable, list actionable solution suggestion(s) in order of impact:
37
+ - Example: "**Suggestion**: [Suggestion 1]
38
+ - Example: "**Suggestions**:"
39
+ - [Suggestion 1]
40
+ - [Suggestion 2]
@@ -0,0 +1,137 @@
1
+ // Copyright 2026 The Chromium Authors
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import * as Host from '../../../core/host/host.js';
6
+ import * as SDK from '../../../core/sdk/sdk.js';
7
+ import type * as Protocol from '../../../generated/protocol.js';
8
+ import type {ComputedStyleAiWidget, FunctionCallHandlerResult} from '../agents/AiAgent.js';
9
+ import {DOMNodeContext} from '../contexts/DOMNodeContext.js';
10
+ import {debugLog} from '../debug.js';
11
+
12
+ import {type Tool, type ToolArgs, type ToolContext, ToolName} from './Tool.js';
13
+
14
+ export interface GetStylesArgs extends ToolArgs {
15
+ elements: number[];
16
+ styleProperties: string[];
17
+ explanation: string;
18
+ }
19
+
20
+ export class GetStylesTool implements Tool<GetStylesArgs, unknown> {
21
+ readonly name = ToolName.GET_STYLES;
22
+ readonly description =
23
+ `Get computed and source styles for one or multiple elements on the inspected page for multiple elements at once by uid.
24
+
25
+ **CRITICAL** An element uid is a number, not a selector.
26
+ **CRITICAL** Use selectors to refer to elements in the text output. Do not use uids.
27
+ **CRITICAL** Always provide the explanation argument to explain what and why you query.
28
+ **CRITICAL** You MUST provide a specific list of CSS property names. Do not use generic values like "all" or "*".`;
29
+
30
+ readonly parameters: Host.AidaClient.FunctionObjectParam<keyof GetStylesArgs> = {
31
+ type: Host.AidaClient.ParametersTypes.OBJECT,
32
+ description: '',
33
+ nullable: false,
34
+ properties: {
35
+ explanation: {
36
+ type: Host.AidaClient.ParametersTypes.STRING,
37
+ description: 'Explain why you want to get styles',
38
+ nullable: false,
39
+ },
40
+ elements: {
41
+ type: Host.AidaClient.ParametersTypes.ARRAY,
42
+ description: 'A list of element uids to get data for. These are numbers, not selectors.',
43
+ items: {type: Host.AidaClient.ParametersTypes.INTEGER, description: 'An element uid.'},
44
+ nullable: false,
45
+ },
46
+ styleProperties: {
47
+ type: Host.AidaClient.ParametersTypes.ARRAY,
48
+ description:
49
+ 'One or more specific CSS style property names to fetch. Generic values like "all" or "*" are not supported.',
50
+ nullable: false,
51
+ items: {
52
+ type: Host.AidaClient.ParametersTypes.STRING,
53
+ description: 'A CSS style property name to retrieve. For example, \'background-color\'.'
54
+ }
55
+ },
56
+ },
57
+ required: ['explanation', 'elements', 'styleProperties']
58
+ };
59
+
60
+ displayInfoFromArgs(params: GetStylesArgs): {
61
+ title: string,
62
+ thought: string,
63
+ action: string,
64
+ } {
65
+ return {
66
+ title: 'Reading computed and source styles',
67
+ thought: params.explanation,
68
+ action: `getStyles(${JSON.stringify(params.elements)}, ${JSON.stringify(params.styleProperties)})`,
69
+ };
70
+ }
71
+
72
+ async handler(params: GetStylesArgs, context: ToolContext): Promise<FunctionCallHandlerResult<unknown>> {
73
+ const widgets: ComputedStyleAiWidget[] = [];
74
+ const result:
75
+ Record<string, {computed: Record<string, string|undefined>, authored: Record<string, string|undefined>}> = {};
76
+
77
+ const activeContext = context.conversationContext;
78
+ if (!activeContext || !(activeContext instanceof DOMNodeContext)) {
79
+ return {error: 'Error: Could not find the currently selected element.'};
80
+ }
81
+
82
+ const selectedNode = activeContext.getItem();
83
+ if (!selectedNode) {
84
+ return {error: 'Error: Could not find the currently selected element.'};
85
+ }
86
+
87
+ for (const uid of params.elements) {
88
+ result[uid] = {computed: {}, authored: {}};
89
+ debugLog(`Action to execute: uid=${uid}`);
90
+ const node =
91
+ new SDK.DOMModel.DeferredDOMNode(selectedNode.domModel().target(), uid as Protocol.DOM.BackendNodeId);
92
+ const resolved = await node.resolvePromise();
93
+ if (!resolved) {
94
+ return {error: 'Error: Could not find the element with uid=' + uid};
95
+ }
96
+ const newContext = new DOMNodeContext(resolved);
97
+ if (activeContext.getOrigin() !== newContext.getOrigin()) {
98
+ return {error: 'Error: Node does not belong to the current origin.'};
99
+ }
100
+ const styles = await resolved.domModel().cssModel().getComputedStyle(resolved.id);
101
+ if (!styles) {
102
+ return {error: 'Error: Could not get computed styles.'};
103
+ }
104
+ const matchedStyles = await resolved.domModel().cssModel().getMatchedStyles(resolved.id);
105
+ if (!matchedStyles) {
106
+ return {error: 'Error: Could not get authored styles.'};
107
+ }
108
+ widgets.push({
109
+ name: 'COMPUTED_STYLES',
110
+ data: {
111
+ computedStyles: styles,
112
+ backendNodeId: node.backendNodeId(),
113
+ matchedCascade: matchedStyles,
114
+ properties: params.styleProperties,
115
+ }
116
+ });
117
+ for (const prop of params.styleProperties) {
118
+ result[uid].computed[prop] = styles.get(prop);
119
+ }
120
+ for (const style of matchedStyles.nodeStyles()) {
121
+ for (const property of style.allProperties()) {
122
+ if (!params.styleProperties.includes(property.name)) {
123
+ continue;
124
+ }
125
+ const state = matchedStyles.propertyState(property);
126
+ if (state === SDK.CSSMatchedStyles.PropertyState.ACTIVE) {
127
+ result[uid].authored[property.name] = property.value;
128
+ }
129
+ }
130
+ }
131
+ }
132
+ return {
133
+ result: JSON.stringify(result, null, 2),
134
+ widgets,
135
+ };
136
+ }
137
+ }
@@ -0,0 +1,55 @@
1
+ // Copyright 2026 The Chromium Authors
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import type * as Host from '../../../core/host/host.js';
6
+ import type {ConversationContext, FunctionCallHandlerResult,} from '../agents/AiAgent.js';
7
+
8
+ /**
9
+ * Context provided to the tool's handler execution.
10
+ */
11
+ export interface ToolContext {
12
+ conversationContext: ConversationContext<unknown>|null;
13
+ }
14
+
15
+ /**
16
+ * Base argument type for AI Tools.
17
+ */
18
+ export type ToolArgs = Record<string, unknown>;
19
+
20
+ export const enum ToolName {
21
+ GET_STYLES = 'getStyles',
22
+ }
23
+
24
+ /**
25
+ * Non-generic metadata interface for a Tool.
26
+ * Used for storing and retrieving tools generically without type-erasure concerns.
27
+ */
28
+ export interface BaseTool {
29
+ readonly name: ToolName;
30
+ readonly description: string;
31
+ /**
32
+ * JSON schema representing the parameters this tool accepts.
33
+ */
34
+ readonly parameters: Host.AidaClient.FunctionObjectParam<string|number|symbol>;
35
+ }
36
+
37
+ /**
38
+ * Main generic interface for defining a Tool.
39
+ * Binds the parameter schema properties and the handler implementation to a strict `Args` contract.
40
+ *
41
+ * @template Args - The expected object type for tool arguments. Must be an object type.
42
+ * @template ReturnType - The type of data returned by the handler function.
43
+ */
44
+ export interface Tool<Args extends ToolArgs = ToolArgs, ReturnType = unknown, > extends BaseTool {
45
+ readonly parameters: Host.AidaClient.FunctionObjectParam<keyof Args>;
46
+ readonly displayInfoFromArgs?: (
47
+ args: Args,
48
+ ) => {
49
+ title?: string, thought?: string, action?: string, suggestions?: [string, ...string[]],
50
+ };
51
+ handler(
52
+ args: Args,
53
+ context: ToolContext,
54
+ ): Promise<FunctionCallHandlerResult<ReturnType>>;
55
+ }
@@ -0,0 +1,34 @@
1
+ // Copyright 2026 The Chromium Authors
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import {GetStylesTool} from './GetStyles.js';
6
+ import {type Tool, ToolName} from './Tool.js';
7
+
8
+ /**
9
+ * Plain object registry containing concrete instantiated tools.
10
+ * Keep this type concrete (no type-erasure) to preserve exact tool types.
11
+ */
12
+ export const TOOLS = {
13
+ [ToolName.GET_STYLES]: new GetStylesTool(),
14
+ };
15
+
16
+ /**
17
+ * Registry class for registering and querying AI Assistance Tools.
18
+ */
19
+ export class ToolRegistry {
20
+ /**
21
+ * Retrieves a tool by its literal name with 100% type safety.
22
+ *
23
+ * @template K - A key from the `TOOLS` registry.
24
+ * @returns The concrete class type of the requested tool.
25
+ */
26
+ static get<K extends keyof typeof TOOLS>(name: K): typeof TOOLS[K];
27
+ /**
28
+ * Fallback retrieval signature for general or runtime string lookups.
29
+ */
30
+ static get(name: string): Tool|undefined;
31
+ static get(name: string): Tool|undefined {
32
+ return Object.prototype.hasOwnProperty.call(TOOLS, name) ? TOOLS[name as keyof typeof TOOLS] as Tool : undefined;
33
+ }
34
+ }
@@ -289,6 +289,10 @@ export class HeapSnapshotProxy extends HeapSnapshotProxyObject {
289
289
  return this.callMethodPromise('nodeClassKey', snapshotObjectId);
290
290
  }
291
291
 
292
+ nodeIndexForId(nodeId: number): Promise<number|undefined> {
293
+ return this.callMethodPromise('nodeIndexForId', nodeId);
294
+ }
295
+
292
296
  createEdgesProvider(nodeIndex: number): HeapSnapshotProviderProxy {
293
297
  return this.callFactoryMethod('createEdgesProvider', HeapSnapshotProviderProxy, nodeIndex);
294
298
  }
@@ -6489,6 +6489,22 @@ export const NativeFunctions = [
6489
6489
  name: "XRLayerEvent",
6490
6490
  signatures: [["type","eventInitDict"]]
6491
6491
  },
6492
+ {
6493
+ name: "XRMediaBinding",
6494
+ signatures: [["session"]]
6495
+ },
6496
+ {
6497
+ name: "createQuadLayer",
6498
+ signatures: [["video","init"]]
6499
+ },
6500
+ {
6501
+ name: "createCylinderLayer",
6502
+ signatures: [["video","init"]]
6503
+ },
6504
+ {
6505
+ name: "createEquirectLayer",
6506
+ signatures: [["video","init"]]
6507
+ },
6492
6508
  {
6493
6509
  name: "XRRay",
6494
6510
  signatures: [["transform"],["?origin","?direction"]]
@@ -77,6 +77,11 @@ export interface ReportJSON {
77
77
  audits: Record<string, AuditResultJSON>;
78
78
  categories: Record<CategoryId, CategoryJSON>;
79
79
  categoryGroups: Record<string, GroupJSON>;
80
+ /**
81
+ * Identifies if the report was imported from a file (untrusted).
82
+ * Used to disable page-touching AI assistance tools for security.
83
+ */
84
+ isImported?: boolean;
80
85
  }
81
86
 
82
87
  export type DetailsJSON =
@@ -64,17 +64,22 @@ export class LiveMetrics extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
64
64
  super();
65
65
  const targetManager = SDK.TargetManager.TargetManager.instance();
66
66
  targetManager.observeTargets(this, {scoped: true});
67
- // Listen for target info changes to detect prerender activation.
68
- // Scoped observers don't receive events when a prerendered target becomes
69
- // primary because setScopeTarget() isn't called during that transition.
70
- targetManager.addEventListener(
71
- SDK.TargetManager.Events.AVAILABLE_TARGETS_CHANGED, this.#onAvailableTargetsChanged, this);
67
+ targetManager.addModelListener(
68
+ SDK.ResourceTreeModel.ResourceTreeModel, SDK.ResourceTreeModel.Events.PrimaryPageChanged,
69
+ this.#onPrimaryPageChanged, this);
72
70
  }
73
71
 
74
- #onAvailableTargetsChanged(): void {
72
+ #onPrimaryPageChanged(
73
+ event: Common.EventTarget.EventTargetEvent<
74
+ {frame: SDK.ResourceTreeModel.ResourceTreeFrame, type: SDK.ResourceTreeModel.PrimaryPageChangeType}>): void {
75
75
  const primaryTarget = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
76
- if (primaryTarget && primaryTarget !== this.#target) {
77
- // Primary target changed (e.g., prerender activation). Switch to it.
76
+ if (!primaryTarget) {
77
+ return;
78
+ }
79
+ if (primaryTarget !== this.#target || event.data.type === SDK.ResourceTreeModel.PrimaryPageChangeType.ACTIVATION) {
80
+ // Primary target changed or prerender activated. Switch to it and reset metrics.
81
+ this.#clearMetrics();
82
+ this.#sendStatusUpdate();
78
83
  void this.#switchToTarget(primaryTarget);
79
84
  }
80
85
  }
@@ -381,11 +386,7 @@ export class LiveMetrics extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
381
386
  break;
382
387
  }
383
388
  case 'reset': {
384
- this.#lcpValue = undefined;
385
- this.#clsValue = undefined;
386
- this.#inpValue = undefined;
387
- this.#interactions.clear();
388
- this.#layoutShifts = [];
389
+ this.#clearMetrics();
389
390
  break;
390
391
  }
391
392
  }
@@ -393,6 +394,15 @@ export class LiveMetrics extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
393
394
  this.#sendStatusUpdate();
394
395
  }
395
396
 
397
+ #clearMetrics(): void {
398
+ this.#lcpValue = undefined;
399
+ this.#clsValue = undefined;
400
+ this.#inpValue = undefined;
401
+ this.#interactions.clear();
402
+ this.#interactionsByGroupId.clear();
403
+ this.#layoutShifts = [];
404
+ }
405
+
396
406
  #isPrimaryFrameExecutionContext(executionContextId: Protocol.Runtime.ExecutionContextId): boolean {
397
407
  if (!this.#target) {
398
408
  return false;
@@ -460,6 +470,7 @@ export class LiveMetrics extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
460
470
 
461
471
  clearInteractions(): void {
462
472
  this.#interactions.clear();
473
+ this.#interactionsByGroupId.clear();
463
474
  this.#sendStatusUpdate();
464
475
  }
465
476
 
@@ -142,12 +142,12 @@ export function parseRawFramesFromErrorStack(stack: string): RawFrame[]|null {
142
142
  functionName,
143
143
  lineNumber,
144
144
  columnNumber,
145
+ isWasm,
145
146
  parsedFrameInfo: {
146
147
  isAsync,
147
148
  isConstructor,
148
149
  isEval,
149
150
  evalOrigin,
150
- isWasm,
151
151
  wasmModuleName,
152
152
  wasmFunctionIndex,
153
153
  typeName,
@@ -181,7 +181,7 @@ export function parseMessage(stack: string): string {
181
181
  export function augmentRawFramesWithScriptIds(
182
182
  rawFrames: RawFrame[], protocolStackTrace: Protocol.Runtime.StackTrace): void {
183
183
  function augmentFrame(rawFrame: RawFrame): void {
184
- const isWasm = rawFrame.parsedFrameInfo?.isWasm;
184
+ const isWasm = rawFrame.isWasm;
185
185
  const protocolFrame = protocolStackTrace.callFrames.find(frame => {
186
186
  if (isWasm) {
187
187
  // The parser parses Wasm offsets into the `columnNumber` field. The `lineNumber` is always -1.
@@ -44,6 +44,10 @@ export interface Frame {
44
44
  * of the containing function.
45
45
  */
46
46
  readonly rawName?: string;
47
+ /**
48
+ * Whether the corresponding raw frame is JS or WASM.
49
+ */
50
+ readonly isWasm?: boolean;
47
51
  }
48
52
 
49
53
  export interface ParsedErrorStackFrame extends Frame {
@@ -51,7 +55,6 @@ export interface ParsedErrorStackFrame extends Frame {
51
55
  readonly isConstructor?: boolean;
52
56
  readonly isEval?: boolean;
53
57
  readonly evalOrigin?: ParsedErrorStackFrame;
54
- readonly isWasm?: boolean;
55
58
  readonly wasmModuleName?: string;
56
59
  readonly wasmFunctionIndex?: number;
57
60
  readonly typeName?: string;
@@ -88,10 +88,12 @@ export class FrameImpl implements StackTrace.StackTrace.Frame {
88
88
 
89
89
  readonly missingDebugInfo?: StackTrace.StackTrace.MissingDebugInfo;
90
90
  readonly rawName?: string;
91
+ readonly isWasm?: boolean;
91
92
 
92
93
  constructor(
93
94
  url: string|undefined, uiSourceCode: Workspace.UISourceCode.UISourceCode|undefined, name: string|undefined,
94
- line: number, column: number, missingDebugInfo?: StackTrace.StackTrace.MissingDebugInfo, rawName?: string) {
95
+ line: number, column: number, missingDebugInfo?: StackTrace.StackTrace.MissingDebugInfo, rawName?: string,
96
+ isWasm?: boolean) {
95
97
  this.url = url;
96
98
  this.uiSourceCode = uiSourceCode;
97
99
  this.name = name;
@@ -99,6 +101,7 @@ export class FrameImpl implements StackTrace.StackTrace.Frame {
99
101
  this.column = column;
100
102
  this.missingDebugInfo = missingDebugInfo;
101
103
  this.rawName = rawName;
104
+ this.isWasm = isWasm;
102
105
  }
103
106
  }
104
107
 
@@ -192,7 +195,7 @@ export class ParsedErrorStackFrameImpl implements StackTrace.StackTrace.ParsedEr
192
195
  return this.#evalOrigin;
193
196
  }
194
197
  get isWasm(): boolean|undefined {
195
- return this.#parsedFrameInfo?.isWasm;
198
+ return this.#frame.isWasm;
196
199
  }
197
200
  get wasmModuleName(): string|undefined {
198
201
  return this.#parsedFrameInfo?.wasmModuleName;
@@ -284,6 +287,10 @@ export class DebuggableFrameImpl implements StackTrace.StackTrace.DebuggableFram
284
287
  return this.#frame.rawName;
285
288
  }
286
289
 
290
+ get isWasm(): boolean|undefined {
291
+ return this.#frame.isWasm;
292
+ }
293
+
287
294
  get sdkFrame(): SDK.DebuggerModel.CallFrame {
288
295
  return this.#sdkFrame;
289
296
  }
@@ -48,8 +48,14 @@ export class StackTraceModel extends SDK.SDKModel.SDKModel<unknown> {
48
48
 
49
49
  async createFromProtocolRuntime(stackTrace: Protocol.Runtime.StackTrace, rawFramesToUIFrames: TranslateRawFrames):
50
50
  Promise<StackTrace.StackTrace.StackTrace> {
51
+ const debuggerModel = this.target().model(SDK.DebuggerModel.DebuggerModel);
52
+ const syncFrames = stackTrace.callFrames.map((frame): RawFrame => {
53
+ const isWasm = debuggerModel?.isWasm(frame.scriptId) ?? false;
54
+ return {...frame, isWasm};
55
+ });
56
+
51
57
  const [syncFragment, asyncFragments] = await Promise.all([
52
- this.#createFragment(stackTrace.callFrames, rawFramesToUIFrames),
58
+ this.#createFragment(syncFrames, rawFramesToUIFrames),
53
59
  this.#createAsyncFragments(stackTrace, rawFramesToUIFrames),
54
60
  ]);
55
61
 
@@ -126,6 +132,7 @@ export class StackTraceModel extends SDK.SDKModel.SDKModel<unknown> {
126
132
  functionName: frame.functionName,
127
133
  lineNumber: frame.location().lineNumber,
128
134
  columnNumber: frame.location().columnNumber,
135
+ isWasm: frame.script.isWasm(),
129
136
  })),
130
137
  rawFramesToUIFrames);
131
138
  return new DebuggableFragmentImpl(fragment, pausedDetails.callFrames);
@@ -144,8 +151,14 @@ export class StackTraceModel extends SDK.SDKModel.SDKModel<unknown> {
144
151
  continue;
145
152
  }
146
153
  const model = StackTraceModel.#modelForTarget(target);
154
+ const targetDebuggerModel = target.model(SDK.DebuggerModel.DebuggerModel);
155
+ const asyncFrames = asyncStackTrace.callFrames.map((frame): RawFrame => {
156
+ const isWasm = targetDebuggerModel?.isWasm(frame.scriptId) ?? false;
157
+ return {...frame, isWasm};
158
+ });
159
+
147
160
  const asyncFragmentPromise =
148
- model.#createFragment(asyncStackTrace.callFrames, rawFramesToUIFrames)
161
+ model.#createFragment(asyncFrames, rawFramesToUIFrames)
149
162
  .then(fragment => new AsyncFragmentImpl(asyncStackTrace.description ?? '', fragment));
150
163
  asyncFragments.push(asyncFragmentPromise);
151
164
  }
@@ -201,7 +214,7 @@ export class StackTraceModel extends SDK.SDKModel.SDKModel<unknown> {
201
214
  node.frames = uiFrames[i++].map(
202
215
  frame => new FrameImpl(
203
216
  frame.url, frame.uiSourceCode, frame.name, frame.line, frame.column, frame.missingDebugInfo,
204
- node.rawFrame.functionName));
217
+ node.rawFrame.functionName, node.rawFrame.isWasm));
205
218
 
206
219
  if (node.parsedFrameInfo?.evalOrigin) {
207
220
  node.evalOrigin = evalOrigins[evalI++];
@@ -243,7 +256,7 @@ async function translateEvalOrigin(
243
256
  const frames = uiFrames[0].map(
244
257
  frame => new FrameImpl(
245
258
  frame.url, frame.uiSourceCode, frame.name, frame.line, frame.column, frame.missingDebugInfo,
246
- rawFrame.functionName));
259
+ rawFrame.functionName, rawFrame.isWasm));
247
260
 
248
261
  let parentEvalOrigin: EvalOrigin|undefined;
249
262
  if (rawFrame.parsedFrameInfo?.evalOrigin) {
@@ -11,7 +11,6 @@ export interface ParsedFrameInfo {
11
11
  readonly isConstructor?: boolean;
12
12
  readonly isEval?: boolean;
13
13
  readonly evalOrigin?: RawFrame;
14
- readonly isWasm?: boolean;
15
14
  readonly wasmModuleName?: string;
16
15
  readonly wasmFunctionIndex?: number;
17
16
  readonly typeName?: string;
@@ -30,6 +29,7 @@ export interface RawFrame {
30
29
  readonly columnNumber: number;
31
30
 
32
31
  readonly parsedFrameInfo?: ParsedFrameInfo;
32
+ readonly isWasm?: boolean;
33
33
  }
34
34
 
35
35
  /**