chrome-devtools-frontend 1.0.1555174 → 1.0.1556696

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 (156) hide show
  1. package/front_end/core/protocol_client/InspectorBackend.ts +1 -1
  2. package/front_end/core/root/Runtime.ts +0 -4
  3. package/front_end/core/sdk/DOMModel.ts +101 -7
  4. package/front_end/entrypoints/formatter_worker/FormatterActions.ts +2 -0
  5. package/front_end/entrypoints/formatter_worker/ScopeParser.ts +75 -7
  6. package/front_end/entrypoints/formatter_worker/Substitute.ts +1 -1
  7. package/front_end/generated/InspectorBackendCommands.ts +1 -1
  8. package/front_end/generated/protocol.ts +0 -1
  9. package/front_end/models/ai_assistance/AiConversation.ts +71 -10
  10. package/front_end/models/ai_assistance/ArtifactsManager.ts +67 -0
  11. package/front_end/models/ai_assistance/ConversationHandler.ts +3 -2
  12. package/front_end/models/ai_assistance/agents/AiAgent.ts +17 -27
  13. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +152 -4
  14. package/front_end/models/ai_assistance/agents/StylingAgent.ts +2 -2
  15. package/front_end/models/ai_assistance/ai_assistance.ts +2 -0
  16. package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +1 -1
  17. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +0 -2
  18. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +1 -1
  19. package/front_end/{ui/components → models}/annotations/AnnotationRepository.ts +4 -4
  20. package/front_end/models/annotations/README.md +7 -0
  21. package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +8 -0
  22. package/front_end/models/greendev/Prototypes.ts +56 -0
  23. package/front_end/models/greendev/README.md +5 -0
  24. package/front_end/models/greendev/greendev.ts +5 -0
  25. package/front_end/models/stack_trace/StackTrace.ts +13 -2
  26. package/front_end/models/stack_trace/StackTraceImpl.ts +81 -6
  27. package/front_end/models/stack_trace/StackTraceModel.ts +35 -3
  28. package/front_end/models/trace/extras/TraceTree.ts +4 -2
  29. package/front_end/models/trace/insights/LCPDiscovery.ts +0 -2
  30. package/front_end/models/trace/types/TraceEvents.ts +0 -1
  31. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +116 -70
  32. package/front_end/panels/ai_assistance/aiAssistancePanel.css +16 -0
  33. package/front_end/panels/ai_assistance/components/ArtifactsViewer.ts +159 -0
  34. package/front_end/panels/ai_assistance/components/ChatView.ts +3 -2
  35. package/front_end/panels/ai_assistance/components/CollapsibleAssistanceContentWidget.ts +7 -8
  36. package/front_end/panels/ai_assistance/components/PerformanceAgentFlameChart.ts +15 -8
  37. package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +9 -9
  38. package/front_end/panels/ai_assistance/components/artifactsViewer.css +15 -0
  39. package/front_end/panels/ai_assistance/components/collapsibleAssistanceContentWidget.css +5 -6
  40. package/front_end/panels/application/AppManifestView.ts +263 -205
  41. package/front_end/panels/application/ApplicationPanelSidebar.ts +24 -57
  42. package/front_end/panels/application/OpenedWindowDetailsView.ts +2 -0
  43. package/front_end/panels/application/ServiceWorkersView.ts +2 -0
  44. package/front_end/panels/application/StorageView.ts +1 -0
  45. package/front_end/panels/application/appManifestView.css +48 -0
  46. package/front_end/panels/application/components/ProtocolHandlersView.ts +2 -2
  47. package/front_end/panels/application/preloading/PreloadingView.ts +12 -6
  48. package/front_end/panels/application/preloading/components/PreloadingDetailsReportView.ts +230 -237
  49. package/front_end/panels/application/preloading/components/PreloadingGrid.ts +96 -79
  50. package/front_end/panels/application/preloading/components/preloadingGrid.css +26 -29
  51. package/front_end/panels/application/preloading/preloadingView.css +6 -0
  52. package/front_end/panels/common/Annotation.ts +1 -1
  53. package/front_end/panels/common/AnnotationManager.ts +1 -1
  54. package/front_end/panels/common/ExtensionView.ts +1 -0
  55. package/front_end/panels/console/ConsoleContextSelector.ts +74 -9
  56. package/front_end/panels/console/consoleContextSelector.css +31 -29
  57. package/front_end/panels/coverage/coverageListView.css +59 -57
  58. package/front_end/panels/elements/ElementsPanel.ts +1 -1
  59. package/front_end/panels/elements/ElementsTreeElement.ts +39 -1
  60. package/front_end/panels/elements/ElementsTreeOutline.ts +23 -21
  61. package/front_end/panels/elements/TopLayerContainer.ts +26 -91
  62. package/front_end/panels/explain/components/ConsoleInsight.ts +3 -3
  63. package/front_end/panels/linear_memory_inspector/components/LinearMemoryInspector.ts +4 -8
  64. package/front_end/panels/linear_memory_inspector/components/LinearMemoryValueInterpreter.ts +148 -97
  65. package/front_end/panels/linear_memory_inspector/components/LinearMemoryViewer.ts +1 -1
  66. package/front_end/panels/linear_memory_inspector/components/linearMemoryValueInterpreter.css +37 -35
  67. package/front_end/panels/network/NetworkItemView.ts +1 -1
  68. package/front_end/panels/network/NetworkLogView.ts +1 -1
  69. package/front_end/panels/network/NetworkPanel.ts +1 -1
  70. package/front_end/panels/recorder/RecorderController.ts +0 -1
  71. package/front_end/panels/security/SecurityPanelSidebar.ts +5 -0
  72. package/front_end/panels/settings/SettingsScreen.ts +133 -1
  73. package/front_end/panels/settings/settings-meta.ts +24 -0
  74. package/front_end/panels/settings/settingsScreen.css +4 -0
  75. package/front_end/panels/sources/UISourceCodeFrame.ts +3 -17
  76. package/front_end/panels/timeline/TimelineUIUtils.ts +5 -8
  77. package/front_end/panels/timeline/components/TimelineSummary.ts +75 -54
  78. package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +18 -26
  79. package/front_end/panels/timeline/components/insights/Cache.ts +12 -8
  80. package/front_end/panels/timeline/components/insights/DOMSize.ts +25 -21
  81. package/front_end/panels/timeline/components/insights/DuplicatedJavaScript.ts +7 -7
  82. package/front_end/panels/timeline/components/insights/FontDisplay.ts +7 -5
  83. package/front_end/panels/timeline/components/insights/ForcedReflow.ts +11 -9
  84. package/front_end/panels/timeline/components/insights/INPBreakdown.ts +7 -6
  85. package/front_end/panels/timeline/components/insights/ImageDelivery.ts +7 -5
  86. package/front_end/panels/timeline/components/insights/InsightRenderer.ts +20 -18
  87. package/front_end/panels/timeline/components/insights/LCPBreakdown.ts +12 -12
  88. package/front_end/panels/timeline/components/insights/LegacyJavaScript.ts +7 -7
  89. package/front_end/panels/timeline/components/insights/ModernHTTP.ts +7 -5
  90. package/front_end/panels/timeline/components/insights/NetworkDependencyTree.ts +15 -13
  91. package/front_end/panels/timeline/components/insights/RenderBlocking.ts +2 -2
  92. package/front_end/panels/timeline/components/insights/SlowCSSSelector.ts +15 -14
  93. package/front_end/panels/timeline/components/insights/Table.ts +152 -130
  94. package/front_end/panels/timeline/components/insights/ThirdParties.ts +11 -9
  95. package/front_end/panels/timeline/components/timelineSummary.css +58 -57
  96. package/front_end/panels/timeline/thirdPartyTreeView.css +109 -0
  97. package/front_end/panels/timeline/timelineDetailsView.css +2 -4
  98. package/front_end/panels/timeline/timelinePanel.css +0 -110
  99. package/front_end/third_party/acorn/estree-legacy.d.ts +2 -0
  100. package/front_end/third_party/chromium/README.chromium +1 -1
  101. package/front_end/third_party/puppeteer/README.chromium +2 -2
  102. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/CDPSession.d.ts.map +1 -1
  103. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/CDPSession.js.map +1 -1
  104. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/ElementHandle.d.ts.map +1 -1
  105. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/ElementHandle.js.map +1 -1
  106. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Frame.d.ts.map +1 -1
  107. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Frame.js.map +1 -1
  108. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts.map +1 -1
  109. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js.map +1 -1
  110. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Connection.d.ts.map +1 -1
  111. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/BrowserConnector.js +21 -7
  112. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/BrowserConnector.js.map +1 -1
  113. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/EventEmitter.d.ts.map +1 -1
  114. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  115. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  116. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
  117. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
  118. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +15 -6
  119. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/CDPSession.d.ts.map +1 -1
  120. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/CDPSession.js.map +1 -1
  121. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/ElementHandle.d.ts.map +1 -1
  122. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/ElementHandle.js.map +1 -1
  123. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Frame.d.ts.map +1 -1
  124. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Frame.js.map +1 -1
  125. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts.map +1 -1
  126. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js.map +1 -1
  127. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Connection.d.ts.map +1 -1
  128. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/BrowserConnector.js +21 -7
  129. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/BrowserConnector.js.map +1 -1
  130. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/EventEmitter.d.ts.map +1 -1
  131. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
  132. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
  133. package/front_end/third_party/puppeteer/package/package.json +2 -2
  134. package/front_end/third_party/puppeteer/package/src/api/CDPSession.ts +1 -2
  135. package/front_end/third_party/puppeteer/package/src/api/ElementHandle.ts +2 -4
  136. package/front_end/third_party/puppeteer/package/src/api/Frame.ts +2 -4
  137. package/front_end/third_party/puppeteer/package/src/api/Page.ts +2 -4
  138. package/front_end/third_party/puppeteer/package/src/bidi/core/Connection.ts +3 -2
  139. package/front_end/third_party/puppeteer/package/src/common/BrowserConnector.ts +29 -10
  140. package/front_end/third_party/puppeteer/package/src/common/EventEmitter.ts +3 -3
  141. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  142. package/front_end/ui/components/report_view/ReportView.docs.ts +37 -0
  143. package/front_end/ui/components/report_view/ReportView.ts +1 -4
  144. package/front_end/ui/components/settings/SettingCheckbox.ts +1 -1
  145. package/front_end/ui/legacy/Floaty.ts +5 -9
  146. package/front_end/ui/legacy/InspectorView.ts +2 -1
  147. package/front_end/ui/legacy/ReportView.ts +5 -4
  148. package/front_end/ui/legacy/TabbedPane.ts +1 -1
  149. package/front_end/ui/legacy/ViewManager.ts +2 -32
  150. package/front_end/ui/legacy/Widget.ts +7 -0
  151. package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +0 -1
  152. package/front_end/ui/legacy/reportView.css +0 -24
  153. package/front_end/ui/visual_logging/KnownContextValues.ts +7 -0
  154. package/package.json +1 -1
  155. /package/front_end/{ui/components → models}/annotations/AnnotationType.ts +0 -0
  156. /package/front_end/{ui/components → models}/annotations/annotations.ts +0 -0
@@ -125,6 +125,7 @@ export interface RequestOptions {
125
125
  export interface AgentOptions {
126
126
  aidaClient: Host.AidaClient.AidaClient;
127
127
  serverSideLoggingEnabled?: boolean;
128
+ sessionId?: string;
128
129
  confirmSideEffectForTest?: typeof Promise.withResolvers;
129
130
  }
130
131
 
@@ -270,7 +271,7 @@ export abstract class AiAgent<T> {
270
271
  abstract readonly userTier: string|undefined;
271
272
  abstract handleContextDetails(select: ConversationContext<T>|null): AsyncGenerator<ContextResponse, void, void>;
272
273
 
273
- readonly #sessionId: string = crypto.randomUUID();
274
+ readonly #sessionId: string;
274
275
  readonly #aidaClient: Host.AidaClient.AidaClient;
275
276
  readonly #serverSideLoggingEnabled: boolean;
276
277
  readonly confirmSideEffect: typeof Promise.withResolvers;
@@ -284,12 +285,6 @@ export abstract class AiAgent<T> {
284
285
  aidaResponse: Host.AidaClient.DoConversationResponse,
285
286
  }> = [];
286
287
 
287
- /**
288
- * Might need to be part of history in case we allow chatting in
289
- * historical conversations.
290
- */
291
- #origin?: string;
292
-
293
288
  /**
294
289
  * `context` does not change during `AiAgent.run()`, ensuring that calls to JS
295
290
  * have the correct `context`. We don't want element selection by the user to
@@ -297,7 +292,6 @@ export abstract class AiAgent<T> {
297
292
  */
298
293
  protected context?: ConversationContext<T>;
299
294
 
300
- #id: string = crypto.randomUUID();
301
295
  #history: Host.AidaClient.Content[] = [];
302
296
 
303
297
  #facts: Set<Host.AidaClient.RequestFact> = new Set<Host.AidaClient.RequestFact>();
@@ -305,6 +299,7 @@ export abstract class AiAgent<T> {
305
299
  constructor(opts: AgentOptions) {
306
300
  this.#aidaClient = opts.aidaClient;
307
301
  this.#serverSideLoggingEnabled = opts.serverSideLoggingEnabled ?? false;
302
+ this.#sessionId = opts.sessionId ?? crypto.randomUUID();
308
303
  this.confirmSideEffect = opts.confirmSideEffectForTest ?? (() => Promise.withResolvers());
309
304
  }
310
305
 
@@ -393,12 +388,8 @@ export abstract class AiAgent<T> {
393
388
  return request;
394
389
  }
395
390
 
396
- get id(): string {
397
- return this.#id;
398
- }
399
-
400
- get origin(): string|undefined {
401
- return this.#origin;
391
+ get sessionId(): string {
392
+ return this.#sessionId;
402
393
  }
403
394
 
404
395
  /**
@@ -496,15 +487,8 @@ export abstract class AiAgent<T> {
496
487
  multimodalInput?: MultimodalInput,
497
488
  ): AsyncGenerator<ResponseData, void, void> {
498
489
  await options.selected?.refresh();
499
-
500
490
  if (options.selected) {
501
- // First context set on the agent determines its origin from now on.
502
- if (this.#origin === undefined) {
503
- this.#origin = options.selected.getOrigin();
504
- }
505
- if (options.selected.isOriginAllowed(this.#origin)) {
506
- this.context = options.selected;
507
- }
491
+ this.context = options.selected;
508
492
  }
509
493
 
510
494
  const enhancedQuery = await this.enhanceQuery(initialQuery, options.selected, multimodalInput?.type);
@@ -596,10 +580,16 @@ export abstract class AiAgent<T> {
596
580
 
597
581
  if (functionCall) {
598
582
  try {
599
- const result = yield* this.#callFunction(functionCall.name, functionCall.args, {
600
- ...options,
601
- explanation: textResponse,
602
- });
583
+ const result = yield*
584
+ this.#callFunction(
585
+ functionCall.name,
586
+ functionCall.args,
587
+ {
588
+ ...options,
589
+ explanation: textResponse,
590
+ },
591
+ );
592
+
603
593
  if (options.signal?.aborted) {
604
594
  yield this.#createErrorResponse(ErrorType.ABORT);
605
595
  break;
@@ -720,7 +710,7 @@ export abstract class AiAgent<T> {
720
710
 
721
711
  result = await call.handler(args, {
722
712
  ...options,
723
- approved: approvedRun,
713
+ approved: true,
724
714
  });
725
715
  }
726
716
 
@@ -9,9 +9,11 @@ import * as Platform from '../../../core/platform/platform.js';
9
9
  import * as Root from '../../../core/root/root.js';
10
10
  import * as SDK from '../../../core/sdk/sdk.js';
11
11
  import * as Tracing from '../../../services/tracing/tracing.js';
12
- import * as Annotations from '../../../ui/components/annotations/annotations.js';
12
+ import * as Annotations from '../../annotations/annotations.js';
13
+ import * as Logs from '../../logs/logs.js';
13
14
  import * as SourceMapScopes from '../../source_map_scopes/source_map_scopes.js';
14
15
  import * as Trace from '../../trace/trace.js';
16
+ import {ArtifactsManager} from '../ArtifactsManager.js';
15
17
  import {
16
18
  PerformanceInsightFormatter,
17
19
  } from '../data_formatters/PerformanceInsightFormatter.js';
@@ -67,7 +69,49 @@ const greenDevAdditionalAnnotationsGuidelines = `
67
69
  - The annotationMessage should be descriptive and relevant to why the element or network request is being highlighted.
68
70
  `;
69
71
 
70
- const greenDevAdditionalWidgetGuidelines = `
72
+ const getGreenDevAdditionalWidgetGuidelines = (): string => {
73
+ // GreenDev is experimenting with multiple ways to display widget:
74
+ // if widgetsFromFunctionCalls is true, then we use function calls to add widgets
75
+ // otherwise we use ai-insight tags
76
+ const widgetsFromFunctionCalls = true;
77
+
78
+ if (widgetsFromFunctionCalls) {
79
+ return `
80
+ - CRITICAL: You have access to three functions for adding rich, interactive widgets to your response:
81
+ \`addInsightWidget\`, \`addNetworkRequestWidget\`, and \`addFlameChartWidget\`.
82
+ You MUST use these functions whenever you refer to a corresponding entity.
83
+
84
+ - **\`addInsightWidget({insightType: '...'})\`**:
85
+ - **When to use**: Call this function every time you mention a specific performance insight (e.g., LCP, INP,
86
+ CLS culprits).
87
+ - **Purpose**: It embeds an interactive widget that provides a detailed breakdown and visualization of the
88
+ insight.
89
+ - **Example**: If you are explaining the causes of a poor LCP score, you MUST also call
90
+ \`addInsightWidget({insightType: 'LCPBreakdown'})\`. This provides the user with the data to explore
91
+ alongside your explanation.
92
+ - **\`addNetworkRequestWidget({eventKey: '...'})\`**:
93
+ - **When to use**: Call this function whenever you discuss a specific network request.
94
+ - **Purpose**: It adds a widget displaying the full details of the network request, such as its timing,
95
+ headers, and priority.
96
+ - **Critical**: The eventKey should be the trace event key (only the number, no letters prefix or -) of that
97
+ script's network request.
98
+ - **Example**: If you identify a render-blocking script, you MUST also call
99
+ \`addNetworkRequestWidget({eventKey: '...'})\` with the trace event key (only the number, no letters prefix
100
+ or -) of that script's network request.
101
+ - **\`addFlameChartWidget({start: ..., end: ...})\`**:
102
+ - **When to use**: Call this function to highlight a specific time range within the trace, especially when
103
+ discussing long tasks, specific events, or periods of high activity.
104
+ - **Purpose**: It embeds a focused flame chart visualization for the given time range (in microseconds).
105
+ - **Example**: If you find a long task that is blocking the main thread, you MUST also call
106
+ \`addFlameChartWidget({start: 123456, end: 789012})\`. This provides the user with the data to explore
107
+ alongside your explanation.
108
+ - **General Rules**:
109
+ - You MUST call these functions as soon as you identify the entity you are discussing.
110
+ - Do NOT add more than one widget for the same insight, network request, or time range to avoid redundancy.
111
+ `;
112
+ }
113
+
114
+ return `
71
115
  - **Visualizing Insights**: When discussing the breakdown of specific metrics or a performance problem,
72
116
  you must render the appropriate Insight Overview component. Use these tags on a new line within your response:
73
117
  - For LCP breakdown: <ai-insight value="LCPBreakdown">
@@ -102,6 +146,7 @@ you must render the appropriate Insight Overview component. Use these tags on a
102
146
  - For example, for LCP, the phases like Time to First Byte will be part of the insight widget, so you must not state them in the text. This applies to other insights and network request timings.
103
147
  - Do not display any of the same widgets more than once. For example, if you have already displayed a network request widget for a specific event, do not display it again in the same response.
104
148
  `;
149
+ };
105
150
 
106
151
  /**
107
152
  * Preamble clocks in at ~1341 tokens.
@@ -111,7 +156,7 @@ you must render the appropriate Insight Overview component. Use these tags on a
111
156
  * Check token length in https://aistudio.google.com/
112
157
  */
113
158
  const buildPreamble = (): string => {
114
- const greenDevEnabled = Root.Runtime.hostConfig.devToolsGreenDevUi?.enabled;
159
+ const greenDevEnabled = Boolean(Root.Runtime.hostConfig.devToolsGreenDevUi?.enabled);
115
160
  const annotationsEnabled = Annotations.AnnotationRepository.annotationsEnabled();
116
161
  return `You are an assistant, expert in web performance and highly skilled with Chrome DevTools.
117
162
 
@@ -166,7 +211,7 @@ Note: if the user asks a specific question about the trace (such as "What is my
166
211
  - Be direct and to the point. Avoid unnecessary introductory phrases or filler content. Focus on delivering actionable advice efficiently.
167
212
 
168
213
  ${annotationsEnabled ? greenDevAdditionalAnnotationsGuidelines : ''}
169
- ${greenDevEnabled ? greenDevAdditionalWidgetGuidelines : ''}
214
+ ${greenDevEnabled ? getGreenDevAdditionalWidgetGuidelines() : ''}
170
215
 
171
216
  ## Strict Constraints
172
217
 
@@ -1200,6 +1245,109 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
1200
1245
  },
1201
1246
  });
1202
1247
  }
1248
+
1249
+ if (Root.Runtime.hostConfig.devToolsGreenDevUi?.enabled) {
1250
+ this.declareFunction<{insightType: Trace.Insights.Types.InsightKeys}>('addInsightWidget', {
1251
+ description:
1252
+ 'Adds an insight widget to the response. When mentioning an insight, call this function to also display an appropriate widget.',
1253
+ parameters: {
1254
+ type: Host.AidaClient.ParametersTypes.OBJECT,
1255
+ description: '',
1256
+ nullable: false,
1257
+ properties: {
1258
+ insightType: {
1259
+ type: Host.AidaClient.ParametersTypes.STRING,
1260
+ description:
1261
+ 'The name of the insight. Only use the insight names given in the "Available insights" list.',
1262
+ nullable: false,
1263
+ },
1264
+ },
1265
+ },
1266
+ handler: async _params => {
1267
+ ArtifactsManager.instance().addArtifact({type: 'insight', insightType: _params.insightType});
1268
+ return {result: {success: true}};
1269
+ },
1270
+ });
1271
+
1272
+ this.declareFunction<{eventKey: string}, object|{error: string}>('addNetworkRequestWidget', {
1273
+ description:
1274
+ 'Adds a network request widget to the response. When mentioning a network request, call this function with its trace event key.',
1275
+ parameters: {
1276
+ type: Host.AidaClient.ParametersTypes.OBJECT,
1277
+ description: '',
1278
+ nullable: false,
1279
+ properties: {
1280
+ eventKey: {
1281
+ type: Host.AidaClient.ParametersTypes.STRING,
1282
+ description: 'The trace event key for the network request.',
1283
+ nullable: false,
1284
+ },
1285
+ },
1286
+ },
1287
+ handler: async _params => {
1288
+ const rawTraceEvent =
1289
+ Trace.Helpers.SyntheticEvents.SyntheticEventsManager.getActiveManager().getRawTraceEvents().at(
1290
+ Number(_params.eventKey));
1291
+ // Get the trace event object if it is available.
1292
+ // If the trace is uploaded, we need to use the synthetic event.
1293
+ if (rawTraceEvent && Trace.Types.Events.isSyntheticNetworkRequest(rawTraceEvent)) {
1294
+ const rawTraceEventId = rawTraceEvent?.args?.data?.requestId;
1295
+ const rawTraceEventUrl = rawTraceEvent?.args?.data?.url;
1296
+ const networkRequest = rawTraceEvent ? Logs.NetworkLog.NetworkLog.instance()
1297
+ .requestsForId(rawTraceEventId)
1298
+ .find(r => r.url() === rawTraceEventUrl) :
1299
+ null;
1300
+ if (networkRequest) {
1301
+ ArtifactsManager.instance().addArtifact({type: 'network-request', request: networkRequest});
1302
+ return {result: {success: true}};
1303
+ }
1304
+ }
1305
+
1306
+ const syntheticRequest =
1307
+ Trace.Helpers.SyntheticEvents.SyntheticEventsManager.getActiveManager().syntheticEventForRawEventIndex(
1308
+ Number(_params.eventKey));
1309
+
1310
+ if (syntheticRequest && Trace.Types.Events.isSyntheticNetworkRequest(syntheticRequest)) {
1311
+ ArtifactsManager.instance().addArtifact({
1312
+ type: 'network-request',
1313
+ request: syntheticRequest,
1314
+ });
1315
+ return {result: {success: true}};
1316
+ }
1317
+
1318
+ return {result: {error: 'Could not find network request'}};
1319
+ },
1320
+ });
1321
+
1322
+ this.declareFunction<{start: number, end: number}, object|{error: string}>('addFlameChartWidget', {
1323
+ description: 'Adds a flame chart widget to the response.',
1324
+ parameters: {
1325
+ type: Host.AidaClient.ParametersTypes.OBJECT,
1326
+ description: '',
1327
+ nullable: false,
1328
+ properties: {
1329
+ start: {
1330
+ type: Host.AidaClient.ParametersTypes.INTEGER,
1331
+ description: 'The start time of the flame chart in microseconds.',
1332
+ nullable: false,
1333
+ },
1334
+ end: {
1335
+ type: Host.AidaClient.ParametersTypes.INTEGER,
1336
+ description: 'The end time of the flame chart in microseconds.',
1337
+ nullable: false,
1338
+ },
1339
+ },
1340
+ },
1341
+ handler: async _params => {
1342
+ ArtifactsManager.instance().addArtifact({
1343
+ type: 'flamechart',
1344
+ start: Trace.Types.Timing.Micro(_params.start),
1345
+ end: Trace.Types.Timing.Micro(_params.end),
1346
+ });
1347
+ return {result: {success: true}};
1348
+ },
1349
+ });
1350
+ }
1203
1351
  }
1204
1352
 
1205
1353
  async addElementAnnotation(elementId: string, annotationMessage: string):
@@ -8,7 +8,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
10
  import type * as Protocol from '../../../generated/protocol.js';
11
- import * as Annotations from '../../../ui/components/annotations/annotations.js';
11
+ import * as Annotations from '../../annotations/annotations.js';
12
12
  import {ChangeManager} from '../ChangeManager.js';
13
13
  import {debugLog} from '../debug.js';
14
14
  import {EvaluateAction, formatError, SideEffectError} from '../EvaluateAction.js';
@@ -275,7 +275,7 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
275
275
  this.#changes = opts.changeManager || new ChangeManager();
276
276
  this.#execJs = opts.execJs ?? executeJsCode;
277
277
  this.#createExtensionScope = opts.createExtensionScope ?? ((changes: ChangeManager) => {
278
- return new ExtensionScope(changes, this.id, this.context?.getItem() ?? null);
278
+ return new ExtensionScope(changes, this.sessionId, this.context?.getItem() ?? null);
279
279
  });
280
280
 
281
281
  this.declareFunction<{
@@ -13,6 +13,7 @@ import * as StylingAgent from './agents/StylingAgent.js';
13
13
  import * as AiConversation from './AiConversation.js';
14
14
  import * as AiHistoryStorage from './AiHistoryStorage.js';
15
15
  import * as AiUtils from './AiUtils.js';
16
+ import * as ArtifactsManager from './ArtifactsManager.js';
16
17
  import * as BuiltInAi from './BuiltInAi.js';
17
18
  import * as ChangeManager from './ChangeManager.js';
18
19
  import * as ConversationHandler from './ConversationHandler.js';
@@ -38,6 +39,7 @@ export {
38
39
  AiHistoryStorage,
39
40
  AIQueries,
40
41
  AiUtils,
42
+ ArtifactsManager,
41
43
  BuiltInAi,
42
44
  ChangeManager,
43
45
  ConversationHandler,
@@ -3,7 +3,7 @@
3
3
  // found in the LICENSE file.
4
4
 
5
5
  import type * as SDK from '../../../core/sdk/sdk.js';
6
- import * as Annotations from '../../../ui/components/annotations/annotations.js';
6
+ import * as Annotations from '../../annotations/annotations.js';
7
7
  import * as Logs from '../../logs/logs.js';
8
8
  import * as NetworkTimeCalculator from '../../network_time_calculator/network_time_calculator.js';
9
9
  import * as TextUtils from '../../text_utils/text_utils.js';
@@ -262,8 +262,6 @@ export class PerformanceInsightFormatter {
262
262
  });
263
263
 
264
264
  rootCauses.unsizedImages.forEach(img => {
265
- // TODO(b/413284569): if we store a nice human readable name for this
266
- // image in the trace metadata, we can do something much nicer here.
267
265
  const url = img.paintImageEvent.args.data.url;
268
266
  const nodeName = img.paintImageEvent.args.data.nodeName;
269
267
  const extraText = url ? `url: ${this.#formatUrl(url)}` : `id: ${img.backendNodeId}`;
@@ -4,7 +4,7 @@
4
4
 
5
5
  import type * as Platform from '../../../core/platform/platform.js';
6
6
  import type * as Protocol from '../../../generated/protocol.js';
7
- import * as Annotations from '../../../ui/components/annotations/annotations.js';
7
+ import * as Annotations from '../../annotations/annotations.js';
8
8
  import * as CrUXManager from '../../crux-manager/crux-manager.js';
9
9
  import type * as SourceMapScopes from '../../source_map_scopes/source_map_scopes.js';
10
10
  import * as Trace from '../../trace/trace.js';
@@ -2,9 +2,9 @@
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 * as Root from '../../../core/root/root.js';
7
- import type * as SDK from '../../../core/sdk/sdk.js';
5
+ import * as Common from '../../core/common/common.js';
6
+ import type * as SDK from '../../core/sdk/sdk.js';
7
+ import * as GreenDev from '../greendev/greendev.js';
8
8
 
9
9
  import {AnnotationType} from './AnnotationType.js';
10
10
 
@@ -63,7 +63,7 @@ export class AnnotationRepository {
63
63
  }
64
64
 
65
65
  static annotationsEnabled(): boolean {
66
- const enabled = Boolean(Root.Runtime.hostConfig.devToolsGreenDevUi?.enabled);
66
+ const enabled = GreenDev.Prototypes.instance().isEnabled('aiAnnotations');
67
67
  // TODO(finnur): Fix race when Repository is created before feature flags have been set properly.
68
68
  if (!enabled) {
69
69
  this.#hasRepliedGreenDevDisabled = true;
@@ -0,0 +1,7 @@
1
+ # Annotations Model
2
+
3
+ **IMPORTANT**: this model exists because on the GreenDev project we prototyped a build of DevTools that is able to add annotations to various parts of the UI.
4
+
5
+ This feature is only enabled when Chromium is run with the GreenDev feature flag enabled. There are currently NO PLANS to ship this code to production.
6
+
7
+ If you are reading this and you want to use this code, please speak to jacktfranklin@ first. This code is for a prototype and not in a production state.
@@ -191,6 +191,14 @@ export class DebuggerWorkspaceBinding implements SDK.TargetManager.SDKModelObser
191
191
  return await model.createFromProtocolRuntime(stackTrace, this.#translateRawFrames.bind(this));
192
192
  }
193
193
 
194
+ async createStackTraceFromDebuggerPaused(
195
+ pausedDetails: SDK.DebuggerModel.DebuggerPausedDetails,
196
+ target: SDK.Target.Target): Promise<StackTrace.StackTrace.DebuggableStackTrace> {
197
+ const model =
198
+ target.model(StackTraceImpl.StackTraceModel.StackTraceModel) as StackTraceImpl.StackTraceModel.StackTraceModel;
199
+ return await model.createFromDebuggerPaused(pausedDetails, this.#translateRawFrames.bind(this));
200
+ }
201
+
194
202
  async createLiveLocation(
195
203
  rawLocation: SDK.DebuggerModel.Location, updateDelegate: (arg0: LiveLocation) => Promise<void>,
196
204
  locationPool: LiveLocationPool): Promise<Location|null> {
@@ -0,0 +1,56 @@
1
+ // Copyright 2025 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 Common from '../../core/common/common.js';
6
+ import * as Root from '../../core/root/root.js';
7
+
8
+ let instance: Prototypes|null = null;
9
+
10
+ export interface GreenDevSettings {
11
+ inDevToolsFloaty: Common.Settings.Setting<boolean>;
12
+ inlineWidgets: Common.Settings.Setting<boolean>;
13
+ artifactViewer: Common.Settings.Setting<boolean>;
14
+ aiAnnotations: Common.Settings.Setting<boolean>;
15
+ }
16
+
17
+ export class Prototypes {
18
+ private constructor() {
19
+ }
20
+
21
+ static instance(): Prototypes {
22
+ if (instance) {
23
+ return instance;
24
+ }
25
+ instance = new Prototypes();
26
+ return instance;
27
+ }
28
+
29
+ /**
30
+ * Returns true if the specific setting is turned on AND the GreenDev flag is enabled
31
+ */
32
+ isEnabled(setting: keyof GreenDevSettings): boolean {
33
+ const greendevFlagEnabled = Boolean(Root.Runtime.hostConfig.devToolsGreenDevUi?.enabled);
34
+
35
+ return greendevFlagEnabled && this.settings()[setting].get();
36
+ }
37
+
38
+ settings(): Readonly<GreenDevSettings> {
39
+ const settings = Common.Settings.Settings.instance();
40
+ const inDevToolsFloaty =
41
+ settings.createSetting('greendev-in-devtools-floaty-enabled', false, Common.Settings.SettingStorageType.LOCAL);
42
+
43
+ const inlineWidgets =
44
+ settings.createSetting('greendev-inline-widgets-enabled', false, Common.Settings.SettingStorageType.LOCAL);
45
+
46
+ const aiAnnotations = settings.createSetting(
47
+ 'greendev-ai-annotations-enabled',
48
+ false,
49
+ Common.Settings.SettingStorageType.LOCAL,
50
+ );
51
+
52
+ const artifactViewer =
53
+ settings.createSetting('greendev-artifact-viewer-enabled', false, Common.Settings.SettingStorageType.LOCAL);
54
+ return {inDevToolsFloaty, inlineWidgets, aiAnnotations, artifactViewer};
55
+ }
56
+ }
@@ -0,0 +1,5 @@
1
+ # GreenDev Model
2
+
3
+ As part of GreenDev we are building a bunch of prototypes into DevTools to user test. This model holds which prototypes are enabled for a given user.
4
+
5
+ The settings is only stored in local storage, and not synced across devices or persisted in anyway beyond that.
@@ -0,0 +1,5 @@
1
+ // Copyright 2025 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
+ export * from './Prototypes.js';
@@ -6,8 +6,11 @@ import type * as Common from '../../core/common/common.js';
6
6
  import type * as SDK from '../../core/sdk/sdk.js';
7
7
  import type * as Workspace from '../workspace/workspace.js';
8
8
 
9
- export interface StackTrace extends Common.EventTarget.EventTarget<EventTypes> {
10
- readonly syncFragment: Fragment;
9
+ export type StackTrace = BaseStackTrace<Fragment>;
10
+ export type DebuggableStackTrace = BaseStackTrace<DebuggableFragment>;
11
+
12
+ export interface BaseStackTrace<SyncFragmentT extends Fragment> extends Common.EventTarget.EventTarget<EventTypes> {
13
+ readonly syncFragment: SyncFragmentT;
11
14
  readonly asyncFragments: readonly AsyncFragment[];
12
15
  }
13
16
 
@@ -19,6 +22,10 @@ export interface AsyncFragment extends Fragment {
19
22
  readonly description: string;
20
23
  }
21
24
 
25
+ export interface DebuggableFragment {
26
+ readonly frames: readonly DebuggableFrame[];
27
+ }
28
+
22
29
  export interface Frame {
23
30
  readonly url?: string;
24
31
  readonly uiSourceCode?: Workspace.UISourceCode.UISourceCode;
@@ -29,6 +36,10 @@ export interface Frame {
29
36
  readonly missingDebugInfo?: MissingDebugInfo;
30
37
  }
31
38
 
39
+ export interface DebuggableFrame extends Frame {
40
+ readonly sdkFrame: SDK.DebuggerModel.CallFrame;
41
+ }
42
+
32
43
  export const enum MissingDebugInfoType {
33
44
  /** No debug information at all for the call frame */
34
45
  NO_INFO = 'NO_INFO',
@@ -3,29 +3,36 @@
3
3
  // found in the LICENSE file.
4
4
 
5
5
  import * as Common from '../../core/common/common.js';
6
+ import type * as SDK from '../../core/sdk/sdk.js';
6
7
  import type * as Workspace from '../workspace/workspace.js';
7
8
 
8
9
  import type * as StackTrace from './stack_trace.js';
9
10
  import type {FrameNode} from './Trie.js';
10
11
 
11
- export class StackTraceImpl extends Common.ObjectWrapper.ObjectWrapper<StackTrace.StackTrace.EventTypes> implements
12
- StackTrace.StackTrace.StackTrace {
13
- readonly syncFragment: FragmentImpl;
12
+ export type AnyStackTraceImpl = StackTraceImpl<FragmentImpl|DebuggableFragmentImpl>;
13
+
14
+ export class StackTraceImpl<SyncFragmentT extends FragmentImpl|DebuggableFragmentImpl = FragmentImpl> extends
15
+ Common.ObjectWrapper.ObjectWrapper<StackTrace.StackTrace.EventTypes> implements
16
+ StackTrace.StackTrace.BaseStackTrace<SyncFragmentT> {
17
+ readonly syncFragment: SyncFragmentT;
14
18
  readonly asyncFragments: readonly AsyncFragmentImpl[];
15
19
 
16
- constructor(syncFragment: FragmentImpl, asyncFragments: AsyncFragmentImpl[]) {
20
+ constructor(syncFragment: SyncFragmentT, asyncFragments: AsyncFragmentImpl[]) {
17
21
  super();
18
22
  this.syncFragment = syncFragment;
19
23
  this.asyncFragments = asyncFragments;
20
24
 
21
- syncFragment.stackTraces.add(this);
25
+ const fragment =
26
+ syncFragment instanceof DebuggableFragmentImpl ? syncFragment.fragment : syncFragment as FragmentImpl;
27
+ fragment.stackTraces.add(this);
28
+
22
29
  this.asyncFragments.forEach(asyncFragment => asyncFragment.fragment.stackTraces.add(this));
23
30
  }
24
31
  }
25
32
 
26
33
  export class FragmentImpl implements StackTrace.StackTrace.Fragment {
27
34
  readonly node: FrameNode;
28
- readonly stackTraces = new Set<StackTraceImpl>();
35
+ readonly stackTraces = new Set<AnyStackTraceImpl>();
29
36
 
30
37
  /**
31
38
  * Fragments are deduplicated based on the node.
@@ -83,3 +90,71 @@ export class FrameImpl implements StackTrace.StackTrace.Frame {
83
90
  this.missingDebugInfo = missingDebugInfo;
84
91
  }
85
92
  }
93
+
94
+ /**
95
+ * A DebuggableFragmentImpl wraps an existing FragmentImpl. This is important: We can pause at the
96
+ * same location multiple times and the paused information changes each and everytime while the underlying
97
+ * FragmentImpl will stay the same.
98
+ */
99
+ export class DebuggableFragmentImpl implements StackTrace.StackTrace.DebuggableFragment {
100
+ constructor(readonly fragment: FragmentImpl, private readonly callFrames: SDK.DebuggerModel.CallFrame[]) {
101
+ }
102
+
103
+ get frames(): DebuggableFrameImpl[] {
104
+ const frames: DebuggableFrameImpl[] = [];
105
+
106
+ let index = 0;
107
+ for (const node of this.fragment.node.getCallStack()) {
108
+ for (const frame of node.frames) {
109
+ // Each inlined frame gets the same DebugerModel.CallFrame for debugging.
110
+ frames.push(new DebuggableFrameImpl(frame, this.callFrames[index]));
111
+ }
112
+ index++;
113
+ }
114
+
115
+ return frames;
116
+ }
117
+ }
118
+
119
+ /**
120
+ * A DebuggableFrameImpl wraps an existing FrameImpl. This is important: We can pause at the
121
+ * same location multiple times and the paused information changes each and everytime while the underlying
122
+ * FrameImpl will stay the same.
123
+ */
124
+ export class DebuggableFrameImpl implements StackTrace.StackTrace.DebuggableFrame {
125
+ readonly #frame: FrameImpl;
126
+ readonly #sdkFrame: SDK.DebuggerModel.CallFrame;
127
+
128
+ constructor(frame: FrameImpl, sdkFrame: SDK.DebuggerModel.CallFrame) {
129
+ this.#frame = frame;
130
+ this.#sdkFrame = sdkFrame;
131
+ }
132
+
133
+ get url(): string|undefined {
134
+ return this.#frame.url;
135
+ }
136
+
137
+ get uiSourceCode(): Workspace.UISourceCode.UISourceCode|undefined {
138
+ return this.#frame.uiSourceCode;
139
+ }
140
+
141
+ get name(): string|undefined {
142
+ return this.#frame.name;
143
+ }
144
+
145
+ get line(): number {
146
+ return this.#frame.line;
147
+ }
148
+
149
+ get column(): number {
150
+ return this.#frame.column;
151
+ }
152
+
153
+ get missingDebugInfo(): StackTrace.StackTrace.MissingDebugInfo|undefined {
154
+ return this.#frame.missingDebugInfo;
155
+ }
156
+
157
+ get sdkFrame(): SDK.DebuggerModel.CallFrame {
158
+ return this.#sdkFrame;
159
+ }
160
+ }