chrome-devtools-frontend 1.0.1590494 → 1.0.1592129

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 (79) hide show
  1. package/docs/ui_engineering.md +34 -1
  2. package/front_end/core/common/Gzip.ts +17 -2
  3. package/front_end/core/host/AidaClient.ts +38 -15
  4. package/front_end/core/host/DispatchHttpRequestClient.ts +7 -4
  5. package/front_end/core/host/InspectorFrontendHostAPI.ts +2 -0
  6. package/front_end/core/host/UserMetrics.ts +2 -1
  7. package/front_end/core/root/ExperimentNames.ts +1 -0
  8. package/front_end/core/root/Runtime.ts +5 -0
  9. package/front_end/core/sdk/CSSMetadata.ts +18 -0
  10. package/front_end/core/sdk/EmulationModel.ts +6 -1
  11. package/front_end/core/sdk/NetworkManager.ts +49 -2
  12. package/front_end/core/sdk/NetworkRequest.ts +4 -0
  13. package/front_end/core/sdk/RuntimeModel.ts +2 -1
  14. package/front_end/core/sdk/sdk-meta.ts +26 -0
  15. package/front_end/entrypoints/inspector_main/RenderingOptions.ts +34 -5
  16. package/front_end/entrypoints/main/MainImpl.ts +8 -0
  17. package/front_end/generated/InspectorBackendCommands.ts +1 -0
  18. package/front_end/generated/protocol-mapping.d.ts +10 -0
  19. package/front_end/generated/protocol-proxy-api.d.ts +8 -0
  20. package/front_end/generated/protocol.ts +6 -2
  21. package/front_end/models/ai_assistance/AiConversation.ts +9 -0
  22. package/front_end/models/ai_assistance/AiHistoryStorage.ts +1 -0
  23. package/front_end/models/ai_assistance/agents/AiAgent.ts +6 -1
  24. package/front_end/models/ai_assistance/agents/BreakpointDebuggerAgent.ts +722 -0
  25. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +1 -1
  26. package/front_end/models/ai_assistance/ai_assistance.ts +2 -0
  27. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +12 -12
  28. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +7 -7
  29. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +7 -7
  30. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +1 -1
  31. package/front_end/models/greendev/Prototypes.ts +7 -1
  32. package/front_end/models/javascript_metadata/NativeFunctions.js +5 -1
  33. package/front_end/models/trace/handlers/NetworkRequestsHandler.ts +3 -3
  34. package/front_end/models/trace/helpers/Network.ts +1 -1
  35. package/front_end/models/trace/insights/NetworkDependencyTree.ts +1 -1
  36. package/front_end/models/trace/insights/RenderBlocking.ts +5 -5
  37. package/front_end/models/trace/lantern/metrics/FirstContentfulPaint.ts +6 -6
  38. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +63 -0
  39. package/front_end/panels/ai_assistance/README.md +14 -0
  40. package/front_end/panels/ai_assistance/components/ChatInput.ts +1 -4
  41. package/front_end/panels/ai_assistance/components/ChatMessage.ts +45 -27
  42. package/front_end/panels/ai_assistance/components/chatInput.css +0 -8
  43. package/front_end/panels/ai_assistance/components/chatMessage.css +6 -0
  44. package/front_end/panels/browser_debugger/CategorizedBreakpointsSidebarPane.ts +25 -46
  45. package/front_end/panels/common/AiCodeGenerationTeaser.ts +9 -4
  46. package/front_end/panels/console/ConsoleViewMessage.ts +100 -4
  47. package/front_end/panels/elements/ComputedStyleWidget.ts +46 -18
  48. package/front_end/panels/elements/ElementsPanel.ts +2 -2
  49. package/front_end/panels/elements/StyleEditorWidget.ts +10 -2
  50. package/front_end/panels/elements/StylePropertyTreeElement.ts +1 -1
  51. package/front_end/panels/elements/StylesContainer.ts +2 -0
  52. package/front_end/panels/elements/StylesSidebarPane.ts +8 -0
  53. package/front_end/panels/network/NetworkDataGridNode.ts +1 -1
  54. package/front_end/panels/network/NetworkLogViewColumns.ts +1 -1
  55. package/front_end/panels/network/RequestPayloadView.ts +7 -6
  56. package/front_end/panels/network/RequestTimingView.ts +3 -3
  57. package/front_end/panels/search/SearchResultsPane.ts +2 -1
  58. package/front_end/panels/settings/SettingsScreen.ts +3 -2
  59. package/front_end/panels/settings/WorkspaceSettingsTab.ts +1 -1
  60. package/front_end/panels/sources/BreakpointsView.ts +1 -1
  61. package/front_end/panels/sources/CallStackSidebarPane.ts +1 -1
  62. package/front_end/panels/timeline/NetworkTrackAppender.ts +1 -1
  63. package/front_end/panels/timeline/components/IgnoreListSetting.ts +0 -1
  64. package/front_end/panels/timeline/components/NetworkRequestDetails.ts +4 -4
  65. package/front_end/panels/timeline/components/NetworkRequestTooltip.ts +2 -2
  66. package/front_end/panels/timeline/components/SidebarAnnotationsTab.ts +4 -4
  67. package/front_end/third_party/chromium/README.chromium +4 -2
  68. package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +5 -1
  69. package/front_end/third_party/lighthouse/locales/en-GB.json +2 -2
  70. package/front_end/third_party/lighthouse/locales/en-US.json +2 -2
  71. package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +1 -1
  72. package/front_end/ui/legacy/Treeoutline.ts +39 -0
  73. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +31 -8
  74. package/front_end/ui/legacy/components/object_ui/RemoteObjectPreviewFormatter.ts +10 -3
  75. package/front_end/ui/legacy/components/source_frame/XMLView.ts +20 -5
  76. package/front_end/ui/visual_logging/Debugging.ts +51 -34
  77. package/front_end/ui/visual_logging/KnownContextValues.ts +7 -1
  78. package/front_end/ui/visual_logging/LoggingEvents.ts +5 -2
  79. package/package.json +1 -1
@@ -171,7 +171,7 @@ addElementAnnotation and specify an annotation reason.
171
171
  - CRITICAL: Each time you describe a network request as being problematic you MUST call the function
172
172
  addNetworkRequestAnnotation and specify an annotation reason.
173
173
  - CRITICAL: If you spot ANY of the following problems:
174
- - Render blocking elements/network requests.
174
+ - Render-blocking elements/network requests.
175
175
  - Significant long task (especially on main thread).
176
176
  - Layout shifts (e.g. due to unsized images).
177
177
  ... then you MUST call addNetworkRequestAnnotation for ALL network requests and addaddElementAnnotation for all
@@ -4,6 +4,7 @@
4
4
 
5
5
  import * as AgentProject from './AgentProject.js';
6
6
  import * as AiAgent from './agents/AiAgent.js';
7
+ import * as BreakpointDebuggerAgent from './agents/BreakpointDebuggerAgent.js';
7
8
  import * as ContextSelectionAgent from './agents/ContextSelectionAgent.js';
8
9
  import * as FileAgent from './agents/FileAgent.js';
9
10
  import * as NetworkAgent from './agents/NetworkAgent.js';
@@ -39,6 +40,7 @@ export {
39
40
  AiHistoryStorage,
40
41
  AIQueries,
41
42
  AiUtils,
43
+ BreakpointDebuggerAgent,
42
44
  BuiltInAi,
43
45
  ChangeManager,
44
46
  ContextSelectionAgent,
@@ -25,7 +25,7 @@ Status code: 200
25
25
  MIME Type: image/webp
26
26
  Protocol: h2
27
27
  Priority: High
28
- Render blocking: No
28
+ Render-blocking: No
29
29
  From a service worker: No
30
30
  Initiators (root request to the request that directly loaded this one): file:///Users/cjamcl/surge/misc/display-dpr/index.html
31
31
  Response headers
@@ -86,7 +86,7 @@ Status code: 200
86
86
  MIME Type: image/svg+xml
87
87
  Protocol: unknown
88
88
  Priority: VeryHigh
89
- Render blocking: No
89
+ Render-blocking: No
90
90
  From a service worker: No
91
91
  Initiators (root request to the request that directly loaded this one): none
92
92
 
@@ -130,15 +130,15 @@ We can break this time down into the 2 phases that combine to make the LCP time:
130
130
  - https://web.dev/articles/optimize-lcp
131
131
  === end content
132
132
 
133
- Title: PerformanceInsightFormatter Render blocking requests tells the LLM if there are no render blocking requests
133
+ Title: PerformanceInsightFormatter Render-blocking requests tells the LLM if there are no render-blocking requests
134
134
  Content:
135
- ## Insight Title: Render blocking requests
135
+ ## Insight Title: Render-blocking requests
136
136
 
137
137
  ## Insight Summary:
138
- This insight identifies network requests that were render blocking. Render blocking requests are impactful because they are deemed critical to the page and therefore the browser stops rendering the page until it has dealt with these resources. For this insight make sure you fully inspect the details of each render blocking network request and prioritize your suggestions to the user based on the impact of each render blocking request.
138
+ This insight identifies network requests that were render-blocking. Render-blocking requests are impactful because they are deemed critical to the page and therefore the browser stops rendering the page until it has dealt with these resources. For this insight make sure you fully inspect the details of each render-blocking network request and prioritize your suggestions to the user based on the impact of each render-blocking request.
139
139
 
140
140
  ## Detailed analysis:
141
- There are no network requests that are render blocking.
141
+ There are no network requests that are render-blocking.
142
142
 
143
143
  ## Estimated savings: FCP 0 ms, LCP 0 ms
144
144
 
@@ -148,15 +148,15 @@ There are no network requests that are render blocking.
148
148
  - https://web.dev/articles/optimize-lcp
149
149
  === end content
150
150
 
151
- Title: PerformanceInsightFormatter Render blocking requests serializes the correct details
151
+ Title: PerformanceInsightFormatter Render-blocking requests serializes the correct details
152
152
  Content:
153
- ## Insight Title: Render blocking requests
153
+ ## Insight Title: Render-blocking requests
154
154
 
155
155
  ## Insight Summary:
156
- This insight identifies network requests that were render blocking. Render blocking requests are impactful because they are deemed critical to the page and therefore the browser stops rendering the page until it has dealt with these resources. For this insight make sure you fully inspect the details of each render blocking network request and prioritize your suggestions to the user based on the impact of each render blocking request.
156
+ This insight identifies network requests that were render-blocking. Render-blocking requests are impactful because they are deemed critical to the page and therefore the browser stops rendering the page until it has dealt with these resources. For this insight make sure you fully inspect the details of each render-blocking network request and prioritize your suggestions to the user based on the impact of each render-blocking request.
157
157
 
158
158
  ## Detailed analysis:
159
- Here is a list of the network requests that were render blocking on this page and their duration:
159
+ Here is a list of the network requests that were render-blocking on this page and their duration:
160
160
 
161
161
 
162
162
  Network requests data:
@@ -210,7 +210,7 @@ MIME Type: image/jpeg
210
210
  Protocol: http/1.1
211
211
  Initial priority: Low
212
212
  Final priority: High
213
- Render blocking: No
213
+ Render-blocking: No
214
214
  From a service worker: No
215
215
  Initiators (root request to the request that directly loaded this one): http://localhost:8787/lcp-discovery-delay/index.html, http://localhost:8787/lcp-discovery-delay/app.js
216
216
  Response headers
@@ -276,7 +276,7 @@ Status code: 200
276
276
  MIME Type: text/html
277
277
  Protocol: http/1.1
278
278
  Priority: VeryHigh
279
- Render blocking: No
279
+ Render-blocking: No
280
280
  From a service worker: No
281
281
  Initiators (root request to the request that directly loaded this one): none
282
282
  Response headers
@@ -182,8 +182,8 @@ export class PerformanceInsightFormatter {
182
182
  return [{title: 'How do I optimize my network dependency tree?'}];
183
183
  case 'RenderBlocking':
184
184
  return [
185
- {title: 'Show me the most impactful render blocking requests that I should focus on'},
186
- {title: 'How can I reduce the number of render blocking requests?'}
185
+ {title: 'Show me the most impactful render-blocking requests that I should focus on'},
186
+ {title: 'How can I reduce the number of render-blocking requests?'}
187
187
  ];
188
188
  case 'SlowCSSSelector':
189
189
  return [{title: 'How can I optimize my CSS to increase the performance of CSS selectors?'}];
@@ -769,18 +769,18 @@ ${requestSummary}`;
769
769
  }
770
770
 
771
771
  /**
772
- * Create an AI prompt string out of the Render Blocking Insight model to use with Ask AI.
773
- * @param insight The Render Blocking Model to query.
772
+ * Create an AI prompt string out of the Render-blocking Insight model to use with Ask AI.
773
+ * @param insight The Render-blocking Model to query.
774
774
  * @returns a string formatted for sending to Ask AI.
775
775
  */
776
776
  formatRenderBlockingInsight(insight: Trace.Insights.Models.RenderBlocking.RenderBlockingInsightModel): string {
777
777
  const requestSummary = this.#traceFormatter.formatNetworkRequests(insight.renderBlockingRequests);
778
778
 
779
779
  if (requestSummary.length === 0) {
780
- return 'There are no network requests that are render blocking.';
780
+ return 'There are no network requests that are render-blocking.';
781
781
  }
782
782
 
783
- return `Here is a list of the network requests that were render blocking on this page and their duration:
783
+ return `Here is a list of the network requests that were render-blocking on this page and their duration:
784
784
 
785
785
  ${requestSummary}`;
786
786
  }
@@ -1136,7 +1136,7 @@ It is important that all of these checks pass to minimize the delay between the
1136
1136
  3. The maximum of 4 preconnects should be respected.
1137
1137
  - Opportunities to add [preconnect] for a faster loading experience.`;
1138
1138
  case 'RenderBlocking':
1139
- return 'This insight identifies network requests that were render blocking. Render blocking requests are impactful because they are deemed critical to the page and therefore the browser stops rendering the page until it has dealt with these resources. For this insight make sure you fully inspect the details of each render blocking network request and prioritize your suggestions to the user based on the impact of each render blocking request.';
1139
+ return 'This insight identifies network requests that were render-blocking. Render-blocking requests are impactful because they are deemed critical to the page and therefore the browser stops rendering the page until it has dealt with these resources. For this insight make sure you fully inspect the details of each render-blocking network request and prioritize your suggestions to the user based on the impact of each render-blocking request.';
1140
1140
  case 'SlowCSSSelector':
1141
1141
  return `This insight identifies CSS selectors that are slowing down your page's rendering performance.`;
1142
1142
  case 'ThirdParties':
@@ -615,8 +615,8 @@ Available insights:
615
615
  - insight name: RenderBlocking
616
616
  description: Requests are blocking the page's initial render, which may delay LCP. [Deferring or inlining](https://developer.chrome.com/docs/performance/insights/render-blocking) can move these network requests out of the critical path.
617
617
  relevant trace bounds: {min: 171608170438, max: 171608877165}
618
- example question: Show me the most impactful render blocking requests that I should focus on
619
- example question: How can I reduce the number of render blocking requests?
618
+ example question: Show me the most impactful render-blocking requests that I should focus on
619
+ example question: How can I reduce the number of render-blocking requests?
620
620
 
621
621
  ## insight set id: NAVIGATION_1
622
622
 
@@ -639,8 +639,8 @@ Available insights:
639
639
  - insight name: RenderBlocking
640
640
  description: Requests are blocking the page's initial render, which may delay LCP. [Deferring or inlining](https://developer.chrome.com/docs/performance/insights/render-blocking) can move these network requests out of the critical path.
641
641
  relevant trace bounds: {min: 171614330544, max: 171615043224}
642
- example question: Show me the most impactful render blocking requests that I should focus on
643
- example question: How can I reduce the number of render blocking requests?
642
+ example question: Show me the most impactful render-blocking requests that I should focus on
643
+ example question: How can I reduce the number of render-blocking requests?
644
644
  === end content
645
645
 
646
646
  Title: PerformanceTraceFormatter formatTraceSummary deals with CrUX manager errors
@@ -1064,7 +1064,7 @@ Status code: 200
1064
1064
  MIME Type: text/html
1065
1065
  Protocol: http/1.1
1066
1066
  Priority: VeryHigh
1067
- Render blocking: No
1067
+ Render-blocking: No
1068
1068
  From a service worker: No
1069
1069
  Initiators (root request to the request that directly loaded this one): none
1070
1070
  Response headers
@@ -1094,7 +1094,7 @@ Status code: 200
1094
1094
  MIME Type: text/css
1095
1095
  Protocol: unknown
1096
1096
  Priority: VeryHigh
1097
- Render blocking: Yes
1097
+ Render-blocking: Yes
1098
1098
  From a service worker: No
1099
1099
  Initiators (root request to the request that directly loaded this one): https://chromedevtools.github.io/performance-stories/lcp-large-image/index.html
1100
1100
  Response headers
@@ -1134,7 +1134,7 @@ Status code: 200
1134
1134
  MIME Type: text/css
1135
1135
  Protocol: unknown
1136
1136
  Priority: VeryHigh
1137
- Render blocking: Yes
1137
+ Render-blocking: Yes
1138
1138
  From a service worker: No
1139
1139
  Initiators (root request to the request that directly loaded this one): https://chromedevtools.github.io/performance-stories/lcp-large-image/index.html
1140
1140
  Response headers
@@ -675,7 +675,7 @@ Status code: ${statusCode}
675
675
  MIME Type: ${mimeType}
676
676
  Protocol: ${protocol}
677
677
  ${priorityLines.join('\n')}
678
- Render blocking: ${renderBlocking ? 'Yes' : 'No'}
678
+ Render-blocking: ${renderBlocking ? 'Yes' : 'No'}
679
679
  From a service worker: ${fromServiceWorker ? 'Yes' : 'No'}
680
680
  Initiators (root request to the request that directly loaded this one): ${initiatorUrls.join(', ') || 'none'}
681
681
  ${NetworkRequestFormatter.formatHeaders('Response headers', responseHeaders ?? [], true)}`;
@@ -10,6 +10,7 @@ let instance: Prototypes|null = null;
10
10
  export interface GreenDevSettings {
11
11
  aiAnnotations: Common.Settings.Setting<boolean>;
12
12
  copyToGemini: Common.Settings.Setting<boolean>;
13
+ breakpointDebuggerAgent: Common.Settings.Setting<boolean>;
13
14
  }
14
15
 
15
16
  export class Prototypes {
@@ -42,7 +43,12 @@ export class Prototypes {
42
43
  );
43
44
  const copyToGemini =
44
45
  settings.createSetting('greendev-copy-to-gemini-enabled', false, Common.Settings.SettingStorageType.LOCAL);
46
+ const breakpointDebuggerAgent = settings.createSetting(
47
+ 'greendev-breakpoint-debugger-agent-enabled',
48
+ false,
49
+ Common.Settings.SettingStorageType.LOCAL,
50
+ );
45
51
 
46
- return {aiAnnotations, copyToGemini};
52
+ return {aiAnnotations, copyToGemini, breakpointDebuggerAgent};
47
53
  }
48
54
  }
@@ -6716,7 +6716,7 @@ export const NativeFunctions = [
6716
6716
  signatures: [["?options"]]
6717
6717
  },
6718
6718
  {
6719
- name: "getValueRange",
6719
+ name: "createValueRange",
6720
6720
  signatures: [["start","end"]]
6721
6721
  },
6722
6722
  {
@@ -7021,6 +7021,10 @@ export const NativeFunctions = [
7021
7021
  name: "Highlight",
7022
7022
  signatures: [["...initRanges"]]
7023
7023
  },
7024
+ {
7025
+ name: "CanvasPaintEvent",
7026
+ signatures: [["type","?eventInitDict"]]
7027
+ },
7024
7028
  {
7025
7029
  name: "getElementTransform",
7026
7030
  signatures: [["element","draw_transform"]]
@@ -512,9 +512,9 @@ export async function finalize(): Promise<void> {
512
512
  const requestingFrameUrl =
513
513
  Helpers.Trace.activeURLForFrameAtTime(frame, finalSendRequest.ts, rendererProcessesByFrame) || '';
514
514
 
515
- // A resource that is preloaded (and not marked as render blocking) can
516
- // become render blocked later via a PreloadRenderBlockingStatusChange. In
517
- // this case, we take the render blocking value of the last
515
+ // A resource that is preloaded (and not marked as render-blocking) can
516
+ // become render-blocked later via a PreloadRenderBlockingStatusChange. In
517
+ // this case, we take the render-blocking value of the last
518
518
  // PreloadRenderBlockingStatusChange for this request.
519
519
  const preloadRenderBlockingStatusChange =
520
520
  request.preloadRenderBlockingStatusChange?.at(-1)?.args.data.renderBlocking;
@@ -12,7 +12,7 @@ import type {RenderBlocking, SyntheticNetworkRequest} from '../types/TraceEvents
12
12
  // browser.
13
13
  // 3. Therefore, from a developer's point of view, there is nothing more they
14
14
  // can do if they've put `async` on, and within the context of Insights, we
15
- // shouldn't report an async script as render blocking.
15
+ // shouldn't report an async script as render-blocking.
16
16
  // In the future we may want to consider suggesting the use of `defer` over
17
17
  // `async`, as it doesn't have this concern, but for now we'll allow `async`
18
18
  // and not report it as an issue.
@@ -194,7 +194,7 @@ function isCritical(request: Types.Events.SyntheticNetworkRequest, context: Insi
194
194
  return false;
195
195
  }
196
196
 
197
- // Iframes are considered High Priority but they are not render blocking
197
+ // Iframes are considered High Priority but they are not render-blocking
198
198
  const isIframe = request.args.data.resourceType === Protocol.Network.ResourceType.Document &&
199
199
  request.args.data.frame !== context.frameId;
200
200
 
@@ -24,7 +24,7 @@ export const UIStrings = {
24
24
  /**
25
25
  * @description Title of an insight that provides the user with the list of network requests that blocked and therefore slowed down the page rendering and becoming visible to the user.
26
26
  */
27
- title: 'Render blocking requests',
27
+ title: 'Render-blocking requests',
28
28
  /**
29
29
  * @description Text to describe that there are requests blocking rendering, which may affect LCP.
30
30
  */
@@ -42,7 +42,7 @@ export const UIStrings = {
42
42
  /**
43
43
  * @description Text status indicating that no requests blocked the initial render of a navigation
44
44
  */
45
- noRenderBlocking: 'No render blocking requests for this navigation',
45
+ noRenderBlocking: 'No render-blocking requests for this navigation',
46
46
  } as const;
47
47
 
48
48
  const str_ = i18n.i18n.registerUIStrings('models/trace/insights/RenderBlocking.ts', UIStrings);
@@ -154,7 +154,7 @@ function computeSavings(
154
154
  if (requestIdToWastedMs.size) {
155
155
  metricSavings.FCP = estimateSavingsWithGraphs(deferredNodeIds, context.lantern);
156
156
 
157
- // In most cases, render blocking resources only affect LCP if LCP isn't an image.
157
+ // In most cases, render-blocking resources only affect LCP if LCP isn't an image.
158
158
  if (!hasImageLCP(data, context)) {
159
159
  metricSavings.LCP = metricSavings.FCP;
160
160
  }
@@ -209,12 +209,12 @@ export function generateInsight(
209
209
  continue;
210
210
  }
211
211
 
212
- // If a request is marked `in_body_parser_blocking` it should only be considered render blocking if it is a
212
+ // If a request is marked `in_body_parser_blocking` it should only be considered render-blocking if it is a
213
213
  // high enough priority. Some requests (e.g. scripts) are not marked as high priority if they are fetched
214
214
  // after a non-preloaded image. (See "early" definition in https://web.dev/articles/fetch-priority)
215
215
  //
216
216
  // There are edge cases and exceptions (e.g. priority hints) but this gives us the best approximation
217
- // of render blocking resources in the document body.
217
+ // of render-blocking resources in the document body.
218
218
  if (req.args.data.renderBlocking === 'in_body_parser_blocking') {
219
219
  const priority = req.args.data.priority;
220
220
  const isScript = req.args.data.resourceType === Protocol.Network.ResourceType.Script;
@@ -51,8 +51,8 @@ class FirstContentfulPaint extends Metric {
51
51
  const cpuNodes: Graph.CPUNode[] = [];
52
52
  graph.traverse(node => {
53
53
  if (node.type === Graph.BaseNode.types.CPU) {
54
- // A task is *possibly* render blocking if it *started* before cutoffTimestamp.
55
- // We use startTime here because the paint event can be *inside* the task that was render blocking.
54
+ // A task is *possibly* render-blocking if it *started* before cutoffTimestamp.
55
+ // We use startTime here because the paint event can be *inside* the task that was render-blocking.
56
56
  if (node.startTime <= cutoffTimestamp) {
57
57
  cpuNodes.push(node);
58
58
  }
@@ -69,7 +69,7 @@ class FirstContentfulPaint extends Metric {
69
69
 
70
70
  cpuNodes.sort((a, b) => a.startTime - b.startTime);
71
71
 
72
- // A script is *possibly* render blocking if it finished loading before cutoffTimestamp.
72
+ // A script is *possibly* render-blocking if it finished loading before cutoffTimestamp.
73
73
  const possiblyRenderBlockingScriptUrls = Metric.getScriptUrls(graph, node => {
74
74
  // The optimistic LCP treatNodeAsRenderBlocking fn wants to exclude some images in the graph,
75
75
  // but here it only receives scripts to evaluate. It's a no-op in this case, but it will
@@ -77,7 +77,7 @@ class FirstContentfulPaint extends Metric {
77
77
  return node.endTime <= cutoffTimestamp && treatNodeAsRenderBlocking(node);
78
78
  });
79
79
 
80
- // A script is *definitely not* render blocking if its EvaluateScript task started after cutoffTimestamp.
80
+ // A script is *definitely not* render-blocking if its EvaluateScript task started after cutoffTimestamp.
81
81
  const definitelyNotRenderBlockingScriptUrls = new Set<string>();
82
82
  const renderBlockingCpuNodeIds = new Set<string>();
83
83
  for (const url of possiblyRenderBlockingScriptUrls) {
@@ -156,7 +156,7 @@ class FirstContentfulPaint extends Metric {
156
156
  return false;
157
157
  }
158
158
 
159
- // Lastly, build up the FCP graph of all nodes we consider render blocking
159
+ // Lastly, build up the FCP graph of all nodes we consider render-blocking
160
160
  return treatNodeAsRenderBlocking(node);
161
161
  }
162
162
  // If it's a CPU node, just check if it was blocking.
@@ -168,7 +168,7 @@ class FirstContentfulPaint extends Metric {
168
168
  dependencyGraph: Graph.Node<T>, processedNavigation: Types.Simulation.ProcessedNavigation): Graph.Node<T> {
169
169
  return this.getFirstPaintBasedGraph(dependencyGraph, {
170
170
  cutoffTimestamp: processedNavigation.timestamps.firstContentfulPaint,
171
- // In the optimistic graph we exclude resources that appeared to be render blocking but were
171
+ // In the optimistic graph we exclude resources that appeared to be render-blocking but were
172
172
  // initiated by a script. While they typically have a very high importance and tend to have a
173
173
  // significant impact on the page's content, these resources don't technically block rendering.
174
174
  treatNodeAsRenderBlocking: node => node.hasRenderBlockingPriority() && node.initiatorType !== 'script',
@@ -278,6 +278,13 @@ async function getEmptyStateSuggestions(conversation?: AiAssistanceModel.AiConve
278
278
  {title: 'What performance issues exist with my page?', jslogContext: 'performance-default'},
279
279
  ];
280
280
  }
281
+ case AiAssistanceModel.AiHistoryStorage.ConversationType.BREAKPOINT: {
282
+ return [
283
+ {title: 'Why did the code pause here?'},
284
+ {title: 'What function does this breakpoint belong to?'},
285
+ {title: 'Why is this error thrown?'},
286
+ ];
287
+ }
281
288
 
282
289
  case AiAssistanceModel.AiHistoryStorage.ConversationType.NONE: {
283
290
  return [
@@ -504,6 +511,14 @@ function createFileContext(file: Workspace.UISourceCode.UISourceCode|null): AiAs
504
511
  return new AiAssistanceModel.FileAgent.FileContext(file);
505
512
  }
506
513
 
514
+ function createBreakpointContext(uiLocation: Workspace.UISourceCode.UILocation|null):
515
+ AiAssistanceModel.BreakpointDebuggerAgent.BreakpointContext|null {
516
+ if (!uiLocation) {
517
+ return null;
518
+ }
519
+ return new AiAssistanceModel.BreakpointDebuggerAgent.BreakpointContext(uiLocation);
520
+ }
521
+
507
522
  function createRequestContext(request: SDK.NetworkRequest.NetworkRequest|null):
508
523
  AiAssistanceModel.NetworkAgent.RequestContext|null {
509
524
  if (!request) {
@@ -564,6 +579,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
564
579
  #selectedElement: AiAssistanceModel.StylingAgent.NodeContext|null = null;
565
580
  #selectedPerformanceTrace: AiAssistanceModel.PerformanceAgent.PerformanceTraceContext|null = null;
566
581
  #selectedRequest: AiAssistanceModel.NetworkAgent.RequestContext|null = null;
582
+ #selectedBreakpoint: AiAssistanceModel.BreakpointDebuggerAgent.BreakpointContext|null = null;
567
583
  // Messages displayed in the `ChatView` component.
568
584
  #messages: Message[] = [];
569
585
 
@@ -804,6 +820,10 @@ export class AiAssistancePanel extends UI.Panel.Panel {
804
820
  targetConversationType = AiAssistanceModel.AiHistoryStorage.ConversationType.STYLING;
805
821
  } else if (isNetworkPanelVisible && hostConfig.devToolsAiAssistanceNetworkAgent?.enabled) {
806
822
  targetConversationType = AiAssistanceModel.AiHistoryStorage.ConversationType.NETWORK;
823
+ } else if (
824
+ isSourcesPanelVisible &&
825
+ this.#conversation?.type === AiAssistanceModel.AiHistoryStorage.ConversationType.BREAKPOINT) {
826
+ targetConversationType = AiAssistanceModel.AiHistoryStorage.ConversationType.BREAKPOINT;
807
827
  } else if (isSourcesPanelVisible && hostConfig.devToolsAiAssistanceFileAgent?.enabled) {
808
828
  targetConversationType = AiAssistanceModel.AiHistoryStorage.ConversationType.FILE;
809
829
  } else if (isPerformancePanelVisible && hostConfig.devToolsAiAssistancePerformanceAgent?.enabled) {
@@ -895,6 +915,27 @@ export class AiAssistancePanel extends UI.Panel.Panel {
895
915
  this.requestUpdate();
896
916
  }
897
917
 
918
+ async handleBreakpointConversation(uiLocation: Workspace.UISourceCode.UILocation): Promise<void> {
919
+ const context = new AiAssistanceModel.BreakpointDebuggerAgent.BreakpointContext(uiLocation);
920
+ this.#selectedBreakpoint = context;
921
+ const conversation = new AiAssistanceModel.AiConversation.AiConversation(
922
+ AiAssistanceModel.AiHistoryStorage.ConversationType.BREAKPOINT,
923
+ [],
924
+ undefined,
925
+ false,
926
+ this.#aidaClient,
927
+ this.#changeManager,
928
+ false,
929
+ this.#handlePerformanceRecordAndReload.bind(this),
930
+ this.#handleInspectElement.bind(this),
931
+ NetworkPanel.NetworkPanel.NetworkPanel.instance().networkLogView.timeCalculator(),
932
+ );
933
+ this.#updateConversationState(conversation);
934
+ this.#conversation?.setContext(context);
935
+ this.requestUpdate();
936
+ await UI.ViewManager.ViewManager.instance().showView(AiAssistancePanel.panelName);
937
+ }
938
+
898
939
  override wasShown(): void {
899
940
  super.wasShown();
900
941
  this.#viewOutput.chatView?.restoreScrollPosition();
@@ -907,6 +948,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
907
948
  this.#selectedPerformanceTrace =
908
949
  createPerformanceTraceContext(UI.Context.Context.instance().flavor(AiAssistanceModel.AIContext.AgentFocus));
909
950
  this.#selectedFile = createFileContext(UI.Context.Context.instance().flavor(Workspace.UISourceCode.UISourceCode));
951
+ this.#selectedBreakpoint =
952
+ createBreakpointContext(UI.Context.Context.instance().flavor(Workspace.UISourceCode.UILocation));
910
953
  this.#updateConversationState(this.#conversation);
911
954
 
912
955
  this.#aiAssistanceEnabledSetting?.addChangeListener(this.requestUpdate, this);
@@ -921,6 +964,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
921
964
  AiAssistanceModel.AIContext.AgentFocus, this.#handlePerformanceTraceFlavorChange);
922
965
  UI.Context.Context.instance().addFlavorChangeListener(
923
966
  Workspace.UISourceCode.UISourceCode, this.#handleUISourceCodeFlavorChange);
967
+ UI.Context.Context.instance().addFlavorChangeListener(
968
+ Workspace.UISourceCode.UILocation, this.#handleBreakpointFlavorChange);
924
969
 
925
970
  UI.ViewManager.ViewManager.instance().addEventListener(
926
971
  UI.ViewManager.Events.VIEW_VISIBILITY_CHANGED, this.#selectDefaultAgentIfNeeded, this);
@@ -1050,6 +1095,17 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1050
1095
  this.#updateConversationState(this.#conversation);
1051
1096
  };
1052
1097
 
1098
+ #handleBreakpointFlavorChange =
1099
+ (ev: Common.EventTarget.EventTargetEvent<Workspace.UISourceCode.UILocation>): void => {
1100
+ const newBreakpoint = ev.data;
1101
+
1102
+ if (!newBreakpoint || this.#selectedBreakpoint?.getItem() === newBreakpoint) {
1103
+ return;
1104
+ }
1105
+ this.#selectedBreakpoint = new AiAssistanceModel.BreakpointDebuggerAgent.BreakpointContext(newBreakpoint);
1106
+ this.#updateConversationState(this.#conversation);
1107
+ };
1108
+
1053
1109
  #getChangeSummary(): string|undefined {
1054
1110
  if (!isAiAssistancePatchingEnabled() || !this.#conversation || this.#conversation?.isReadOnly) {
1055
1111
  return;
@@ -1146,6 +1202,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1146
1202
 
1147
1203
  return lockedString(UIStringsNotTranslate.inputPlaceholderForPerformanceWithNoRecording);
1148
1204
  }
1205
+ case AiAssistanceModel.AiHistoryStorage.ConversationType.BREAKPOINT:
1206
+ return lockedString(UIStringsNotTranslate.inputPlaceholderForNoContext);
1149
1207
  case AiAssistanceModel.AiHistoryStorage.ConversationType.NONE:
1150
1208
  if (AiAssistanceModel.AiUtils.isGeminiBranding()) {
1151
1209
  return lockedString(UIStringsNotTranslate.inputPlaceholderForNoContextBranded);
@@ -1186,6 +1244,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1186
1244
  }
1187
1245
  return lockedString(UIStringsNotTranslate.inputDisclaimerForPerformance);
1188
1246
 
1247
+ case AiAssistanceModel.AiHistoryStorage.ConversationType.BREAKPOINT:
1189
1248
  case AiAssistanceModel.AiHistoryStorage.ConversationType.NONE:
1190
1249
  if (noLogging) {
1191
1250
  return lockedString(UIStringsNotTranslate.inputDisclaimerForNoContextEnterpriseNoLogging);
@@ -1441,6 +1500,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1441
1500
  return this.#selectedRequest;
1442
1501
  case AiAssistanceModel.AiHistoryStorage.ConversationType.PERFORMANCE:
1443
1502
  return this.#selectedPerformanceTrace;
1503
+ case AiAssistanceModel.AiHistoryStorage.ConversationType.BREAKPOINT:
1504
+ return this.#selectedBreakpoint;
1444
1505
  case AiAssistanceModel.AiHistoryStorage.ConversationType.NONE:
1445
1506
  case undefined:
1446
1507
  return null;
@@ -1456,6 +1517,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1456
1517
  this.#selectedRequest = data;
1457
1518
  } else if (data instanceof AiAssistanceModel.PerformanceAgent.PerformanceTraceContext) {
1458
1519
  this.#selectedPerformanceTrace = data;
1520
+ } else if (data instanceof AiAssistanceModel.BreakpointDebuggerAgent.BreakpointContext) {
1521
+ this.#selectedBreakpoint = data;
1459
1522
  }
1460
1523
 
1461
1524
  void VisualLogging.logFunctionCall(`context-change-${this.#conversation?.type}`);
@@ -69,3 +69,17 @@ The key to the walkthrough feature lies in the `parts` array of a `ModelChatMess
69
69
  - `text`: The markdown-formatted text of the answer.
70
70
 
71
71
  A single `ModelChatMessage` will typically have **zero or more `StepPart`s** followed by **one `AnswerPart`**. This structure allows the UI to first show the final answer and provide the option to progressively disclose the "thinking" steps that led to it via the `WalkthroughView`.
72
+
73
+ ## Understanding Step Loading States
74
+
75
+ There are two distinct `isLoading` properties related to the AI's response generation, serving different purposes:
76
+
77
+ 1. **`step.isLoading`**: This property resides within a single `Step` object and indicates the immediate parsing status of that specific step from the AI's response stream. It becomes `true` when a new step begins (e.g., "Querying...") and is set to `false` almost immediately once the first piece of meaningful information for that step (like a "thought" or a "code" block) is received. Essentially, it's a short-lived internal parsing state.
78
+
79
+ 2. **Conversation `isLoading`** (passed down to the `ChatMessage` component): This top-level property reflects the overall state of the entire conversation's response generation process. It is set to `true` as soon as the user submits a query and remains `true` until the AI has completed its entire thought process, including all steps, and has provided the final answer.
80
+
81
+ The spinner displayed next to a step in the UI is intentionally tied to the **conversation `isLoading`** property, not the individual `step.isLoading`. This design choice provides a better user experience by:
82
+
83
+ * **Providing Continuous Feedback**: Using the conversation's `isLoading` ensures a persistent visual indicator that the AI is actively working on the query, even if individual steps are quickly parsed. This prevents the UI from appearing unresponsive.
84
+ * **Avoiding a "Stuck" Feeling**: If the spinner were tied to `step.isLoading`, it would flicker on and off rapidly, potentially making the user feel that the AI has stopped processing or is stuck.
85
+ * **Clear Progress Visualization**: The spinner is dynamically moved to the *last* active step in the list as long as the overall conversation is loading. Once a step is completed, it receives a checkmark, and the spinner moves to the next active step.
@@ -321,10 +321,7 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTML
321
321
  ></devtools-button>`
322
322
  : Lit.nothing}
323
323
  <div
324
- class=${Lit.Directives.classMap({
325
- 'resource-link': true,
326
- 'has-picker-behavior': input.conversationType === AiAssistanceModel.AiHistoryStorage.ConversationType.STYLING,
327
- })}
324
+ class="resource-link"
328
325
  >
329
326
  ${
330
327
  input.selectedContext instanceof AiAssistanceModel.StylingAgent.NodeContext ?