chrome-devtools-frontend 1.0.1604514 → 1.0.1605390

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 (80) hide show
  1. package/AUTHORS +1 -0
  2. package/front_end/Images/src/dots-circle.svg +10 -0
  3. package/front_end/Tests.js +23 -7
  4. package/front_end/core/host/AidaClient.ts +114 -63
  5. package/front_end/core/host/AidaGcaTranslation.ts +6 -0
  6. package/front_end/core/host/GcaClient.ts +112 -0
  7. package/front_end/core/host/UserMetrics.ts +0 -1
  8. package/front_end/core/host/host.ts +2 -0
  9. package/front_end/core/root/ExperimentNames.ts +0 -1
  10. package/front_end/core/root/Runtime.ts +5 -0
  11. package/front_end/core/sdk/AutofillModel.ts +3 -2
  12. package/front_end/core/sdk/CSSModel.ts +3 -4
  13. package/front_end/core/sdk/CSSProperty.ts +1 -1
  14. package/front_end/core/sdk/ConsoleModel.ts +15 -13
  15. package/front_end/core/sdk/CookieModel.ts +5 -4
  16. package/front_end/core/sdk/DOMDebuggerModel.ts +20 -14
  17. package/front_end/core/sdk/DebuggerModel.ts +21 -36
  18. package/front_end/core/sdk/EventBreakpointsModel.ts +16 -6
  19. package/front_end/core/sdk/IsolateManager.ts +12 -7
  20. package/front_end/core/sdk/WebMCPModel.ts +57 -2
  21. package/front_end/entrypoints/main/MainImpl.ts +0 -4
  22. package/front_end/models/ai_assistance/agents/AiAgent.ts +9 -1
  23. package/front_end/models/ai_assistance/agents/ConversationSummaryAgent.ts +10 -9
  24. package/front_end/models/ai_assistance/agents/ExecuteJavascript.ts +301 -0
  25. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +50 -25
  26. package/front_end/models/ai_assistance/agents/StylingAgent.ts +12 -264
  27. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +1 -1
  28. package/front_end/models/emulation/DeviceModeModel.ts +21 -26
  29. package/front_end/models/trace/insights/LCPDiscovery.ts +14 -6
  30. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +2 -17
  31. package/front_end/panels/ai_assistance/components/ChatMessage.ts +165 -65
  32. package/front_end/panels/ai_assistance/components/ChatView.ts +2 -13
  33. package/front_end/panels/ai_assistance/components/ExportForAgentsDialog.ts +1 -1
  34. package/front_end/panels/ai_assistance/components/chatMessage.css +48 -2
  35. package/front_end/panels/ai_assistance/components/chatView.css +0 -8
  36. package/front_end/panels/application/ApplicationPanelSidebar.ts +6 -0
  37. package/front_end/panels/application/IndexedDBViews.ts +0 -9
  38. package/front_end/panels/application/WebMCPTreeElement.ts +35 -0
  39. package/front_end/panels/application/WebMCPView.ts +468 -0
  40. package/front_end/panels/application/application.ts +4 -0
  41. package/front_end/panels/application/webMCPView.css +90 -0
  42. package/front_end/panels/common/aiCodeCompletionSummaryToolbar.css +1 -1
  43. package/front_end/panels/console/consoleView.css +4 -0
  44. package/front_end/panels/elements/ElementsTreeOutline.ts +87 -0
  45. package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +23 -2
  46. package/front_end/panels/elements/StylesSidebarPane.ts +85 -20
  47. package/front_end/panels/elements/elementsPanel.css +14 -0
  48. package/front_end/panels/elements/elementsTreeOutline.css +21 -0
  49. package/front_end/panels/network/NetworkLogViewColumns.ts +3 -3
  50. package/front_end/panels/profiler/HeapDetachedElementsView.ts +0 -4
  51. package/front_end/panels/profiler/HeapProfileView.ts +0 -4
  52. package/front_end/panels/profiler/HeapProfilerPanel.ts +4 -13
  53. package/front_end/panels/profiler/HeapSnapshotView.ts +12 -16
  54. package/front_end/panels/profiler/ProfileHeader.ts +0 -11
  55. package/front_end/panels/profiler/ProfileTypeRegistry.ts +4 -12
  56. package/front_end/panels/profiler/ProfileView.ts +1 -6
  57. package/front_end/panels/profiler/ProfilesPanel.ts +60 -7
  58. package/front_end/panels/recorder/components/recordingView.css +0 -6
  59. package/front_end/panels/sensors/SensorsView.ts +28 -59
  60. package/front_end/panels/timeline/EventsTimelineTreeView.ts +3 -3
  61. package/front_end/panels/timeline/ThirdPartyTreeView.ts +37 -38
  62. package/front_end/panels/timeline/TimelineDetailsView.ts +47 -41
  63. package/front_end/panels/timeline/TimelinePanel.ts +11 -0
  64. package/front_end/panels/timeline/TimelineTreeView.ts +149 -60
  65. package/front_end/panels/timeline/components/CWVMetrics.ts +18 -2
  66. package/front_end/panels/timeline/components/LiveMetricsView.ts +839 -783
  67. package/front_end/panels/timeline/thirdPartyTreeView.css +2 -2
  68. package/front_end/panels/timeline/timeline-meta.ts +11 -0
  69. package/front_end/panels/timeline/utils/Helpers.ts +5 -0
  70. package/front_end/ui/components/buttons/button.css +2 -2
  71. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +0 -11
  72. package/front_end/ui/legacy/FilterBar.ts +2 -0
  73. package/front_end/ui/legacy/InspectorDrawerView.ts +206 -0
  74. package/front_end/ui/legacy/InspectorView.ts +41 -91
  75. package/front_end/ui/legacy/SplitWidget.ts +33 -27
  76. package/front_end/ui/legacy/ViewManager.ts +14 -5
  77. package/front_end/ui/legacy/Widget.ts +36 -28
  78. package/front_end/ui/legacy/inspectorDrawerTabbedPane.css +5 -0
  79. package/front_end/ui/visual_logging/KnownContextValues.ts +8 -1
  80. package/package.json +1 -1
@@ -99,8 +99,9 @@ export class CookieModel extends SDKModel<EventTypes> {
99
99
  if (cookie.expires()) {
100
100
  expires = Math.floor(Date.parse(`${cookie.expires()}`) / 1000);
101
101
  }
102
- const enabled =
103
- Root.Runtime.experiments.isEnabled(Root.ExperimentNames.ExperimentName.EXPERIMENTAL_COOKIE_FEATURES);
102
+ const schemeBindingEnabled =
103
+ Boolean(Root.Runtime.hostConfig.devToolsEnableOriginBoundCookies?.schemeBindingEnabled);
104
+ const portBindingEnabled = Boolean(Root.Runtime.hostConfig.devToolsEnableOriginBoundCookies?.portBindingEnabled);
104
105
  const preserveUnset = (scheme: Protocol.Network.CookieSourceScheme): Protocol.Network.CookieSourceScheme.Unset|
105
106
  undefined => scheme === Protocol.Network.CookieSourceScheme.Unset ? scheme : undefined;
106
107
  const protocolCookie = {
@@ -115,8 +116,8 @@ export class CookieModel extends SDKModel<EventTypes> {
115
116
  expires,
116
117
  priority: cookie.priority(),
117
118
  partitionKey: cookie.partitionKey(),
118
- sourceScheme: enabled ? cookie.sourceScheme() : preserveUnset(cookie.sourceScheme()),
119
- sourcePort: enabled ? cookie.sourcePort() : undefined,
119
+ sourceScheme: schemeBindingEnabled ? cookie.sourceScheme() : preserveUnset(cookie.sourceScheme()),
120
+ sourcePort: portBindingEnabled ? cookie.sourcePort() : undefined,
120
121
  };
121
122
  const response = await this.target().networkAgent().invoke_setCookie(protocolCookie);
122
123
  const error = response.getError();
@@ -4,7 +4,7 @@
4
4
 
5
5
  import type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';
6
6
  import * as Protocol from '../../generated/protocol.js';
7
- import * as Common from '../common/common.js';
7
+ import type * as Common from '../common/common.js';
8
8
  import * as Platform from '../platform/platform.js';
9
9
 
10
10
  import {CategorizedBreakpoint, Category} from './CategorizedBreakpoint.js';
@@ -38,7 +38,7 @@ export class DOMDebuggerModel extends SDKModel<EventTypes> {
38
38
  this.#domModel.addEventListener(DOMModelEvents.NodeRemoved, this.nodeRemoved, this);
39
39
 
40
40
  this.#domBreakpoints = [];
41
- this.#domBreakpointsSetting = Common.Settings.Settings.instance().createLocalSetting('dom-breakpoints', []);
41
+ this.#domBreakpointsSetting = this.target().targetManager().settings.createLocalSetting('dom-breakpoints', []);
42
42
  if (this.#domModel.existingDocument()) {
43
43
  void this.documentUpdated();
44
44
  }
@@ -498,9 +498,11 @@ export class CSPViolationBreakpoint extends CategorizedBreakpoint {
498
498
 
499
499
  export class DOMEventListenerBreakpoint extends CategorizedBreakpoint {
500
500
  readonly eventTargetNames: string[];
501
- constructor(eventName: string, eventTargetNames: string[], category: Category) {
501
+ readonly #targetManager: TargetManager;
502
+ constructor(eventName: string, eventTargetNames: string[], category: Category, targetManager: TargetManager) {
502
503
  super(category, eventName);
503
504
  this.eventTargetNames = eventTargetNames;
505
+ this.#targetManager = targetManager;
504
506
  }
505
507
 
506
508
  override setEnabled(enabled: boolean): void {
@@ -508,7 +510,7 @@ export class DOMEventListenerBreakpoint extends CategorizedBreakpoint {
508
510
  return;
509
511
  }
510
512
  super.setEnabled(enabled);
511
- for (const model of TargetManager.instance().models(DOMDebuggerModel)) {
513
+ for (const model of this.#targetManager.models(DOMDebuggerModel)) {
512
514
  this.updateOnModel(model);
513
515
  }
514
516
  }
@@ -534,9 +536,11 @@ export class DOMDebuggerManager implements SDKModelObserver<DOMDebuggerModel> {
534
536
 
535
537
  readonly #cspViolationsToBreakOn: CSPViolationBreakpoint[] = [];
536
538
  readonly #eventListenerBreakpoints: DOMEventListenerBreakpoint[] = [];
539
+ readonly #targetManager: TargetManager;
537
540
 
538
- constructor() {
539
- this.#xhrBreakpointsSetting = Common.Settings.Settings.instance().createLocalSetting('xhr-breakpoints', []);
541
+ constructor(targetManager: TargetManager = TargetManager.instance()) {
542
+ this.#targetManager = targetManager;
543
+ this.#xhrBreakpointsSetting = this.#targetManager.settings.createLocalSetting('xhr-breakpoints', []);
540
544
  for (const breakpoint of this.#xhrBreakpointsSetting.get()) {
541
545
  this.#xhrBreakpoints.set(breakpoint.url, breakpoint.enabled);
542
546
  }
@@ -659,15 +663,16 @@ export class DOMDebuggerManager implements SDKModelObserver<DOMDebuggerModel> {
659
663
  Category.XHR, ['readystatechange', 'load', 'loadstart', 'loadend', 'abort', 'error', 'progress', 'timeout'],
660
664
  ['xmlhttprequest', 'xmlhttprequestupload']);
661
665
 
662
- TargetManager.instance().observeModels(DOMDebuggerModel, this);
666
+ this.#targetManager.observeModels(DOMDebuggerModel, this);
663
667
  }
664
668
 
665
669
  static instance(opts: {
666
670
  forceNew: boolean|null,
671
+ targetManager?: TargetManager,
667
672
  } = {forceNew: null}): DOMDebuggerManager {
668
- const {forceNew} = opts;
673
+ const {forceNew, targetManager} = opts;
669
674
  if (!domDebuggerManagerInstance || forceNew) {
670
- domDebuggerManagerInstance = new DOMDebuggerManager();
675
+ domDebuggerManagerInstance = new DOMDebuggerManager(targetManager);
671
676
  }
672
677
 
673
678
  return domDebuggerManagerInstance;
@@ -679,7 +684,8 @@ export class DOMDebuggerManager implements SDKModelObserver<DOMDebuggerModel> {
679
684
 
680
685
  private createEventListenerBreakpoints(category: Category, eventNames: string[], eventTargetNames: string[]): void {
681
686
  for (const eventName of eventNames) {
682
- this.#eventListenerBreakpoints.push(new DOMEventListenerBreakpoint(eventName, eventTargetNames, category));
687
+ this.#eventListenerBreakpoints.push(
688
+ new DOMEventListenerBreakpoint(eventName, eventTargetNames, category, this.#targetManager));
683
689
  }
684
690
  }
685
691
 
@@ -710,7 +716,7 @@ export class DOMDebuggerManager implements SDKModelObserver<DOMDebuggerModel> {
710
716
 
711
717
  updateCSPViolationBreakpoints(): void {
712
718
  const violationTypes = this.#cspViolationsToBreakOn.filter(v => v.enabled()).map(v => v.type());
713
- for (const model of TargetManager.instance().models(DOMDebuggerModel)) {
719
+ for (const model of this.#targetManager.models(DOMDebuggerModel)) {
714
720
  this.updateCSPViolationBreakpointsForModel(model, violationTypes);
715
721
  }
716
722
  }
@@ -735,7 +741,7 @@ export class DOMDebuggerManager implements SDKModelObserver<DOMDebuggerModel> {
735
741
  addXHRBreakpoint(url: string, enabled: boolean): void {
736
742
  this.#xhrBreakpoints.set(url, enabled);
737
743
  if (enabled) {
738
- for (const model of TargetManager.instance().models(DOMDebuggerModel)) {
744
+ for (const model of this.#targetManager.models(DOMDebuggerModel)) {
739
745
  void model.agent.invoke_setXHRBreakpoint({url});
740
746
  }
741
747
  }
@@ -746,7 +752,7 @@ export class DOMDebuggerManager implements SDKModelObserver<DOMDebuggerModel> {
746
752
  const enabled = this.#xhrBreakpoints.get(url);
747
753
  this.#xhrBreakpoints.delete(url);
748
754
  if (enabled) {
749
- for (const model of TargetManager.instance().models(DOMDebuggerModel)) {
755
+ for (const model of this.#targetManager.models(DOMDebuggerModel)) {
750
756
  void model.agent.invoke_removeXHRBreakpoint({url});
751
757
  }
752
758
  }
@@ -755,7 +761,7 @@ export class DOMDebuggerManager implements SDKModelObserver<DOMDebuggerModel> {
755
761
 
756
762
  toggleXHRBreakpoint(url: string, enabled: boolean): void {
757
763
  this.#xhrBreakpoints.set(url, enabled);
758
- for (const model of TargetManager.instance().models(DOMDebuggerModel)) {
764
+ for (const model of this.#targetManager.models(DOMDebuggerModel)) {
759
765
  if (enabled) {
760
766
  void model.agent.invoke_setXHRBreakpoint({url});
761
767
  } else {
@@ -173,30 +173,19 @@ export class DebuggerModel extends SDKModel<EventTypes> {
173
173
  (compiledURL, sourceMappingURL, payload, script) =>
174
174
  new SourceMap(compiledURL, sourceMappingURL, payload, script));
175
175
 
176
- Common.Settings.Settings.instance()
177
- .moduleSetting('pause-on-exception-enabled')
178
- .addChangeListener(this.pauseOnExceptionStateChanged, this);
179
- Common.Settings.Settings.instance()
180
- .moduleSetting('pause-on-caught-exception')
181
- .addChangeListener(this.pauseOnExceptionStateChanged, this);
182
- Common.Settings.Settings.instance()
183
- .moduleSetting('pause-on-uncaught-exception')
184
- .addChangeListener(this.pauseOnExceptionStateChanged, this);
185
- Common.Settings.Settings.instance()
186
- .moduleSetting('disable-async-stack-traces')
187
- .addChangeListener(this.asyncStackTracesStateChanged, this);
188
- Common.Settings.Settings.instance()
189
- .moduleSetting('breakpoints-active')
190
- .addChangeListener(this.breakpointsActiveChanged, this);
176
+ const settings = this.target().targetManager().settings;
177
+ settings.moduleSetting('pause-on-exception-enabled').addChangeListener(this.pauseOnExceptionStateChanged, this);
178
+ settings.moduleSetting('pause-on-caught-exception').addChangeListener(this.pauseOnExceptionStateChanged, this);
179
+ settings.moduleSetting('pause-on-uncaught-exception').addChangeListener(this.pauseOnExceptionStateChanged, this);
180
+ settings.moduleSetting('disable-async-stack-traces').addChangeListener(this.asyncStackTracesStateChanged, this);
181
+ settings.moduleSetting('breakpoints-active').addChangeListener(this.breakpointsActiveChanged, this);
191
182
 
192
183
  if (!target.suspended()) {
193
184
  void this.enableDebugger();
194
185
  }
195
186
 
196
- this.#sourceMapManager.setEnabled(
197
- Common.Settings.Settings.instance().moduleSetting('js-source-maps-enabled').get());
198
- Common.Settings.Settings.instance()
199
- .moduleSetting('js-source-maps-enabled')
187
+ this.#sourceMapManager.setEnabled(settings.moduleSetting('js-source-maps-enabled').get());
188
+ settings.moduleSetting('js-source-maps-enabled')
200
189
  .addChangeListener(event => this.#sourceMapManager.setEnabled((event.data as boolean)));
201
190
 
202
191
  const resourceTreeModel = (target.model(ResourceTreeModel) as ResourceTreeModel);
@@ -273,7 +262,8 @@ export class DebuggerModel extends SDKModel<EventTypes> {
273
262
  }
274
263
  this.pauseOnExceptionStateChanged();
275
264
  void this.asyncStackTracesStateChanged();
276
- if (!Common.Settings.Settings.instance().moduleSetting('breakpoints-active').get()) {
265
+ const settings = this.target().targetManager().settings;
266
+ if (!settings.moduleSetting('breakpoints-active').get()) {
277
267
  this.breakpointsActiveChanged();
278
268
  }
279
269
  this.dispatchEventToListeners(Events.DebuggerWasEnabled, this);
@@ -364,11 +354,11 @@ export class DebuggerModel extends SDKModel<EventTypes> {
364
354
  }
365
355
 
366
356
  private pauseOnExceptionStateChanged(): void {
367
- const pauseOnCaughtEnabled = Common.Settings.Settings.instance().moduleSetting('pause-on-caught-exception').get();
357
+ const settings = this.target().targetManager().settings;
358
+ const pauseOnCaughtEnabled = settings.moduleSetting('pause-on-caught-exception').get();
368
359
  let state: Protocol.Debugger.SetPauseOnExceptionsRequestState;
369
360
 
370
- const pauseOnUncaughtEnabled =
371
- Common.Settings.Settings.instance().moduleSetting('pause-on-uncaught-exception').get();
361
+ const pauseOnUncaughtEnabled = settings.moduleSetting('pause-on-uncaught-exception').get();
372
362
  if (pauseOnCaughtEnabled && pauseOnUncaughtEnabled) {
373
363
  state = Protocol.Debugger.SetPauseOnExceptionsRequestState.All;
374
364
  } else if (pauseOnCaughtEnabled) {
@@ -383,15 +373,15 @@ export class DebuggerModel extends SDKModel<EventTypes> {
383
373
 
384
374
  private asyncStackTracesStateChanged(): Promise<Protocol.ProtocolResponseWithError> {
385
375
  const maxAsyncStackChainDepth = 32;
386
- const enabled =
387
- !Common.Settings.Settings.instance().moduleSetting('disable-async-stack-traces').get() && this.#debuggerEnabled;
376
+ const settings = this.target().targetManager().settings;
377
+ const enabled = !settings.moduleSetting('disable-async-stack-traces').get() && this.#debuggerEnabled;
388
378
  const maxDepth = enabled ? maxAsyncStackChainDepth : 0;
389
379
  return this.agent.invoke_setAsyncCallStackDepth({maxDepth});
390
380
  }
391
381
 
392
382
  private breakpointsActiveChanged(): void {
393
- void this.agent.invoke_setBreakpointsActive(
394
- {active: Common.Settings.Settings.instance().moduleSetting('breakpoints-active').get()});
383
+ const settings = this.target().targetManager().settings;
384
+ void this.agent.invoke_setBreakpointsActive({active: settings.moduleSetting('breakpoints-active').get()});
395
385
  }
396
386
 
397
387
  setComputeAutoStepRangesCallback(callback: ((arg0: StepMode, arg1: CallFrame) => Promise<LocationRange[]>)|null):
@@ -872,15 +862,10 @@ export class DebuggerModel extends SDKModel<EventTypes> {
872
862
  if (this.#debuggerId) {
873
863
  debuggerIdToModel.delete(this.#debuggerId);
874
864
  }
875
- Common.Settings.Settings.instance()
876
- .moduleSetting('pause-on-exception-enabled')
877
- .removeChangeListener(this.pauseOnExceptionStateChanged, this);
878
- Common.Settings.Settings.instance()
879
- .moduleSetting('pause-on-caught-exception')
880
- .removeChangeListener(this.pauseOnExceptionStateChanged, this);
881
- Common.Settings.Settings.instance()
882
- .moduleSetting('disable-async-stack-traces')
883
- .removeChangeListener(this.asyncStackTracesStateChanged, this);
865
+ const settings = this.target().targetManager().settings;
866
+ settings.moduleSetting('pause-on-exception-enabled').removeChangeListener(this.pauseOnExceptionStateChanged, this);
867
+ settings.moduleSetting('pause-on-caught-exception').removeChangeListener(this.pauseOnExceptionStateChanged, this);
868
+ settings.moduleSetting('disable-async-stack-traces').removeChangeListener(this.asyncStackTracesStateChanged, this);
884
869
  }
885
870
 
886
871
  override async suspendModel(): Promise<void> {
@@ -56,12 +56,18 @@ export class EventBreakpointsModel extends SDKModel<void> {
56
56
  * instrumentation breakpoints in targets that run JS but do not have a DOM.
57
57
  **/
58
58
  class EventListenerBreakpoint extends CategorizedBreakpoint {
59
+ readonly #targetManager: TargetManager;
60
+ constructor(category: Category, name: string, targetManager: TargetManager) {
61
+ super(category, name);
62
+ this.#targetManager = targetManager;
63
+ }
64
+
59
65
  override setEnabled(enabled: boolean): void {
60
66
  if (this.enabled() === enabled) {
61
67
  return;
62
68
  }
63
69
  super.setEnabled(enabled);
64
- for (const model of TargetManager.instance().models(EventBreakpointsModel)) {
70
+ for (const model of this.#targetManager.models(EventBreakpointsModel)) {
65
71
  this.updateOnModel(model);
66
72
  }
67
73
  }
@@ -81,8 +87,10 @@ let eventBreakpointManagerInstance: EventBreakpointsManager;
81
87
 
82
88
  export class EventBreakpointsManager implements SDKModelObserver<EventBreakpointsModel> {
83
89
  readonly #eventListenerBreakpoints: EventListenerBreakpoint[] = [];
90
+ readonly #targetManager: TargetManager;
84
91
 
85
- constructor() {
92
+ constructor(targetManager: TargetManager = TargetManager.instance()) {
93
+ this.#targetManager = targetManager;
86
94
  this.createInstrumentationBreakpoints(Category.AUCTION_WORKLET, [
87
95
  InstrumentationNames.BEFORE_BIDDER_WORKLET_BIDDING_START,
88
96
  InstrumentationNames.BEFORE_BIDDER_WORKLET_REPORTING_START,
@@ -135,15 +143,16 @@ export class EventBreakpointsManager implements SDKModelObserver<EventBreakpoint
135
143
  InstrumentationNames.AUDIO_CONTEXT_SUSPENDED,
136
144
  ]);
137
145
 
138
- TargetManager.instance().observeModels(EventBreakpointsModel, this);
146
+ this.#targetManager.observeModels(EventBreakpointsModel, this);
139
147
  }
140
148
 
141
149
  static instance(opts: {
142
150
  forceNew: boolean|null,
151
+ targetManager?: TargetManager,
143
152
  } = {forceNew: null}): EventBreakpointsManager {
144
- const {forceNew} = opts;
153
+ const {forceNew, targetManager} = opts;
145
154
  if (!eventBreakpointManagerInstance || forceNew) {
146
- eventBreakpointManagerInstance = new EventBreakpointsManager();
155
+ eventBreakpointManagerInstance = new EventBreakpointsManager(targetManager);
147
156
  }
148
157
 
149
158
  return eventBreakpointManagerInstance;
@@ -151,7 +160,8 @@ export class EventBreakpointsManager implements SDKModelObserver<EventBreakpoint
151
160
 
152
161
  private createInstrumentationBreakpoints(category: Category, instrumentationNames: InstrumentationNames[]): void {
153
162
  for (const instrumentationName of instrumentationNames) {
154
- this.#eventListenerBreakpoints.push(new EventListenerBreakpoint(category, instrumentationName));
163
+ this.#eventListenerBreakpoints.push(
164
+ new EventListenerBreakpoint(category, instrumentationName, this.#targetManager));
155
165
  }
156
166
  }
157
167
 
@@ -19,18 +19,21 @@ export class IsolateManager extends Common.ObjectWrapper.ObjectWrapper<EventType
19
19
  #isolateIdByModel = new Map<RuntimeModel, string|null>();
20
20
  #observers = new Set<Observer>();
21
21
  #pollId = 0;
22
+ readonly #targetManager: TargetManager;
22
23
 
23
- constructor() {
24
+ constructor(targetManager: TargetManager = TargetManager.instance()) {
24
25
  super();
26
+ this.#targetManager = targetManager;
25
27
 
26
- TargetManager.instance().observeModels(RuntimeModel, this);
28
+ this.#targetManager.observeModels(RuntimeModel, this);
27
29
  }
28
30
 
29
- static instance({forceNew}: {
31
+ static instance({forceNew, targetManager}: {
30
32
  forceNew: boolean,
33
+ targetManager?: TargetManager,
31
34
  } = {forceNew: false}): IsolateManager {
32
35
  if (!isolateManagerInstance || forceNew) {
33
- isolateManagerInstance = new IsolateManager();
36
+ isolateManagerInstance = new IsolateManager(targetManager);
34
37
  }
35
38
 
36
39
  return isolateManagerInstance;
@@ -67,7 +70,7 @@ export class IsolateManager extends Common.ObjectWrapper.ObjectWrapper<EventType
67
70
  this.#isolateIdByModel.set(model, isolateId);
68
71
  let isolate = this.#isolates.get(isolateId);
69
72
  if (!isolate) {
70
- isolate = new Isolate(isolateId);
73
+ isolate = new Isolate(isolateId, this);
71
74
  this.#isolates.set(isolateId, isolate);
72
75
  }
73
76
  isolate.models().add(model);
@@ -145,9 +148,11 @@ export class Isolate {
145
148
  readonly #models: Set<RuntimeModel>;
146
149
  #usedHeapSize: number;
147
150
  readonly #memoryTrend: MemoryTrend;
151
+ readonly #manager: IsolateManager;
148
152
 
149
- constructor(id: string) {
153
+ constructor(id: string, manager: IsolateManager) {
150
154
  this.#id = id;
155
+ this.#manager = manager;
151
156
  this.#models = new Set();
152
157
  this.#usedHeapSize = 0;
153
158
  const count = MemoryTrendWindowMs / PollIntervalMs;
@@ -179,7 +184,7 @@ export class Isolate {
179
184
  }
180
185
  this.#usedHeapSize = usage.usedSize + (usage.embedderHeapUsedSize ?? 0) + (usage.backingStorageSize ?? 0);
181
186
  this.#memoryTrend.add(this.#usedHeapSize);
182
- IsolateManager.instance().dispatchEventToListeners(Events.MEMORY_CHANGED, this);
187
+ this.#manager.dispatchEventToListeners(Events.MEMORY_CHANGED, this);
183
188
  }
184
189
 
185
190
  samplesCount(): number {
@@ -13,15 +13,32 @@ import {Capability, type Target} from './Target.js';
13
13
  export const enum Events {
14
14
  TOOLS_ADDED = 'ToolsAdded',
15
15
  TOOLS_REMOVED = 'ToolsRemoved',
16
+ TOOL_INVOKED = 'ToolInvoked',
17
+ TOOL_RESPONDED = 'ToolResponded',
18
+ }
19
+
20
+ export interface Call {
21
+ invocationId: string;
22
+ input: string;
23
+ tool: Protocol.WebMCP.Tool;
24
+ result?: {
25
+ status: Protocol.WebMCP.InvocationStatus,
26
+ output?: unknown,
27
+ errorText?: string,
28
+ exception?: Protocol.Runtime.RemoteObject,
29
+ };
16
30
  }
17
31
 
18
32
  export interface EventTypes {
19
33
  [Events.TOOLS_ADDED]: ReadonlyArray<Readonly<Protocol.WebMCP.Tool>>;
20
34
  [Events.TOOLS_REMOVED]: ReadonlyArray<Readonly<Protocol.WebMCP.Tool>>;
35
+ [Events.TOOL_INVOKED]: Call;
36
+ [Events.TOOL_RESPONDED]: Call;
21
37
  }
22
38
 
23
39
  export class WebMCPModel extends SDKModel<EventTypes> {
24
40
  readonly #tools = new Map<Protocol.Page.FrameId, Map<string, Protocol.WebMCP.Tool>>();
41
+ readonly #calls = new Map<string, Call>();
25
42
  readonly agent: ProtocolProxyApi.WebMCPApi;
26
43
  #enabled = false;
27
44
 
@@ -43,6 +60,14 @@ export class WebMCPModel extends SDKModel<EventTypes> {
43
60
  return this.#tools.values().flatMap(toolMap => toolMap.values());
44
61
  }
45
62
 
63
+ get toolCalls(): Call[] {
64
+ return [...this.#calls.values()];
65
+ }
66
+
67
+ clearCalls(): void {
68
+ this.#calls.clear();
69
+ }
70
+
46
71
  async enable(): Promise<void> {
47
72
  if (this.#enabled) {
48
73
  return;
@@ -78,6 +103,34 @@ export class WebMCPModel extends SDKModel<EventTypes> {
78
103
  }
79
104
  this.dispatchEventToListeners(Events.TOOLS_ADDED, tools);
80
105
  }
106
+
107
+ toolInvoked(params: Protocol.WebMCP.ToolInvokedEvent): void {
108
+ const tool = this.#tools.get(params.frameId)?.get(params.toolName);
109
+ if (!tool) {
110
+ return;
111
+ }
112
+ const call: Call = {
113
+ invocationId: params.invocationId,
114
+ input: params.input,
115
+ tool,
116
+ };
117
+ this.#calls.set(params.invocationId, call);
118
+ this.dispatchEventToListeners(Events.TOOL_INVOKED, call);
119
+ }
120
+
121
+ toolResponded(params: Protocol.WebMCP.ToolRespondedEvent): void {
122
+ const call = this.#calls.get(params.invocationId);
123
+ if (!call) {
124
+ return;
125
+ }
126
+ call.result = {
127
+ status: params.status,
128
+ output: params.output,
129
+ errorText: params.errorText,
130
+ exception: params.exception,
131
+ };
132
+ this.dispatchEventToListeners(Events.TOOL_RESPONDED, call);
133
+ }
81
134
  }
82
135
 
83
136
  class WebMCPDispatcher implements ProtocolProxyApi.WebMCPDispatcher {
@@ -94,10 +147,12 @@ class WebMCPDispatcher implements ProtocolProxyApi.WebMCPDispatcher {
94
147
  this.#model.onToolsRemoved(params.tools);
95
148
  }
96
149
 
97
- toolInvoked(): void {
150
+ toolInvoked(params: Protocol.WebMCP.ToolInvokedEvent): void {
151
+ this.#model.toolInvoked(params);
98
152
  }
99
153
 
100
- toolResponded(): void {
154
+ toolResponded(params: Protocol.WebMCP.ToolRespondedEvent): void {
155
+ this.#model.toolResponded(params);
101
156
  }
102
157
  }
103
158
 
@@ -397,10 +397,6 @@ export class MainImpl {
397
397
  Root.ExperimentNames.ExperimentName.FONT_EDITOR, 'New font editor in the Styles tab',
398
398
  'https://developer.chrome.com/blog/new-in-devtools-89/#font');
399
399
 
400
- // New cookie features.
401
- Root.Runtime.experiments.register(
402
- Root.ExperimentNames.ExperimentName.EXPERIMENTAL_COOKIE_FEATURES, 'Experimental cookie features');
403
-
404
400
  Root.Runtime.experiments.registerHostExperiment({
405
401
  name: Root.ExperimentNames.ExperimentName.DURABLE_MESSAGES,
406
402
  title: 'Durable Messages',
@@ -290,9 +290,17 @@ export interface TimelineRangeSummaryAiWidget {
290
290
  };
291
291
  }
292
292
 
293
+ export interface BottomUpTreeAiWidget {
294
+ name: 'BOTTOM_UP_TREE';
295
+ data: {
296
+ bounds: Trace.Types.Timing.TraceWindowMicro,
297
+ parsedTrace: Trace.TraceModel.ParsedTrace,
298
+ };
299
+ }
300
+
293
301
  // This type will grow as we add more widgets.
294
302
  export type AiWidget = ComputedStyleAiWidget|CoreVitalsAiWidget|StylePropertiesAiWidget|DomTreeAiWidget|
295
- PerformanceTraceAiWidget|LcpBreakdownAiWidget|TimelineRangeSummaryAiWidget;
303
+ PerformanceTraceAiWidget|LcpBreakdownAiWidget|TimelineRangeSummaryAiWidget|BottomUpTreeAiWidget;
296
304
 
297
305
  export type FunctionCallHandlerResult<Result> = {
298
306
  requiresApproval: true,
@@ -8,30 +8,31 @@ import * as Root from '../../../core/root/root.js';
8
8
  import {AiAgent, type ContextResponse, ConversationContext, type RequestOptions, ResponseType} from './AiAgent.js';
9
9
 
10
10
  const preamble = `### Role
11
- You are a Performance Expert. Your task is to extract a diagnostic narrative from raw DevTools logs and present it as a self-contained, actionable Markdown summary. You provide high-density technical analysis without conversational fluff.
11
+ You are a Conversation Summarizer. Your task is to take a transcript of a conversation between a user and a DevTools AI agent and produce a succinct, actionable Markdown summary. This summary will be used to help apply fixes in an IDE, so it must capture all relevant technical details, findings, and proposed code changes without any conversational fluff.
12
12
 
13
13
  ### Critical Constraints
14
14
  - **Persona:** Do not mention that you are an AI or refer to yourself in the third person.
15
15
  - **Domain Scope:** Do not provide answers on non-web-development topics (e.g., legal, financial, medical, or personal advice).
16
- - **Sensitive Topics:** If the conversation history touches on sensitive topics (religion, race, politics, sexuality, gender, etc.), respond only with: "My expertise is limited to website performance analysis. I cannot provide information on that topic."
17
- - **Data Portability:** The recipient of this summary does NOT have access to the raw logs.
16
+ - **Sensitive Topics:** If the conversation history touches on sensitive topics (religion, race, politics, sexuality, gender, etc.), respond only with: "My expertise is limited to summarizing DevTools AI conversations. I cannot provide information on that topic."
17
+ - **Data Portability:** The recipient of this summary does NOT have access to the raw logs or the full conversation transcript.
18
18
  - **No UIDs/Internal IDs:** Never refer to elements by internal IDs (e.g., \`uid=123\`).
19
19
  - **Standard Selectors:** Identify elements using HTML tags, classes, or IDs (e.g., \`button.submit-form\`).
20
20
  - **No Metadata:** Remove internal constants like \`NAVIGATION_0\` or \`INSIGHT_0\`.
21
- - **No Process Narration:** Do not describe internal "thinking" or API calls. Skip phrases like "The agent investigated..." or "The user then asked...". Jump straight to the findings.
21
+ - **No Process Narration:** Do not describe internal "thinking" or API calls. Skip phrases like "The agent investigated..." or "The user then asked...". Jump straight to the findings and their technical context.
22
+ - **Suggest, Don't Prescribe:** When summarizing code changes made during the session (e.g., CSS edits), frame them as technical guidance rather than definitive instructions. Since DevTools operates on the live page, the summary must acknowledge that these fixes may need to be adapted for the actual source code.
22
23
 
23
24
  ### Objectives
24
25
  1. **Identify Intent:** Define the core technical goal of the session.
25
- 2. **Value-Only Diagnostics:** List only the technical data points discovered. Omit steps that didn't yield a result.
26
- 3. **Focus on Code Intent:** When code is executed in the logs, summarize the **purpose** and the **result**. Do not include the raw JavaScript unless it is a specific fix for the user to implement.
27
- 4. **Actionable Recommendations:** Provide specific code/strategy fixes based on the findings.
26
+ 2. **Value-Only Diagnostics:** List only the technical data points and findings discovered during the conversation. Omit steps that didn't yield a result.
27
+ 3. **Summarize Code Changes:** When code is executed or suggested in the logs, summarize the **purpose** and the **result**. Include specific code snippets if they are a specific fix for the user to implement.
28
+ 4. **Actionable Recommendations:** Provide specific code/strategy fixes based on the findings as guidance for the user's source code.
28
29
 
29
30
  ### Formatting Rules
30
31
  - **Header:** Use ## [Brief Topic Title]
31
- - **Context:** Describe the target element/page and the core metric being analyzed.
32
+ - **Context:** Describe the target element/page and the core issue or technical goal being analyzed.
32
33
  - **Diagnostics:** A bulleted list of technical findings.
33
34
  - **Tabular Data:** Use a **Markdown Table** for any lists of URLs, metrics, or comparison data.
34
- - **Code Fixes:** Use fenced code blocks for suggested CSS/JS optimizations.
35
+ - **Code Fixes:** Use fenced code blocks for suggested code optimizations. Use language that frames them as illustrative examples or context (e.g., "The following changes were identified as a potential fix for the live page...") rather than strict instructions.
35
36
 
36
37
  ---
37
38