chrome-devtools-frontend 1.0.1604514 → 1.0.1605219
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AUTHORS +1 -0
- package/front_end/Tests.js +23 -7
- package/front_end/core/host/AidaClient.ts +114 -63
- package/front_end/core/host/AidaGcaTranslation.ts +6 -0
- package/front_end/core/host/GcaClient.ts +112 -0
- package/front_end/core/host/UserMetrics.ts +0 -1
- package/front_end/core/host/host.ts +2 -0
- package/front_end/core/root/ExperimentNames.ts +0 -1
- package/front_end/core/root/Runtime.ts +5 -0
- package/front_end/core/sdk/AutofillModel.ts +3 -2
- package/front_end/core/sdk/CSSModel.ts +3 -4
- package/front_end/core/sdk/CSSProperty.ts +1 -1
- package/front_end/core/sdk/ConsoleModel.ts +15 -13
- package/front_end/core/sdk/CookieModel.ts +5 -4
- package/front_end/core/sdk/DOMDebuggerModel.ts +20 -14
- package/front_end/core/sdk/DebuggerModel.ts +21 -36
- package/front_end/core/sdk/EventBreakpointsModel.ts +16 -6
- package/front_end/core/sdk/IsolateManager.ts +12 -7
- package/front_end/entrypoints/main/MainImpl.ts +0 -4
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +31 -17
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +1 -1
- package/front_end/models/emulation/DeviceModeModel.ts +21 -26
- package/front_end/models/trace/insights/LCPDiscovery.ts +14 -6
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +2 -17
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +36 -20
- package/front_end/panels/ai_assistance/components/chatMessage.css +5 -1
- package/front_end/panels/application/ApplicationPanelSidebar.ts +6 -0
- package/front_end/panels/application/IndexedDBViews.ts +0 -9
- package/front_end/panels/application/WebMCPTreeElement.ts +35 -0
- package/front_end/panels/application/WebMCPView.ts +118 -0
- package/front_end/panels/application/application.ts +4 -0
- package/front_end/panels/application/webMCPView.css +65 -0
- package/front_end/panels/common/aiCodeCompletionSummaryToolbar.css +1 -1
- package/front_end/panels/console/consoleView.css +4 -0
- package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +23 -2
- package/front_end/panels/elements/StylesSidebarPane.ts +85 -20
- package/front_end/panels/elements/elementsPanel.css +14 -0
- package/front_end/panels/network/NetworkLogViewColumns.ts +3 -3
- package/front_end/panels/recorder/components/recordingView.css +0 -6
- package/front_end/panels/sensors/SensorsView.ts +28 -59
- package/front_end/panels/timeline/EventsTimelineTreeView.ts +2 -2
- package/front_end/panels/timeline/ThirdPartyTreeView.ts +35 -36
- package/front_end/panels/timeline/TimelineDetailsView.ts +47 -41
- package/front_end/panels/timeline/TimelineTreeView.ts +13 -13
- package/front_end/panels/timeline/components/LiveMetricsView.ts +839 -783
- package/front_end/panels/timeline/thirdPartyTreeView.css +2 -2
- package/front_end/ui/components/buttons/button.css +2 -2
- package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +0 -11
- package/front_end/ui/legacy/InspectorDrawerView.ts +206 -0
- package/front_end/ui/legacy/InspectorView.ts +41 -91
- package/front_end/ui/legacy/ViewManager.ts +14 -5
- package/front_end/ui/legacy/inspectorDrawerTabbedPane.css +5 -0
- package/front_end/ui/visual_logging/KnownContextValues.ts +2 -1
- package/package.json +1 -1
|
@@ -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 =
|
|
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
|
-
|
|
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
|
|
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.#
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
387
|
-
|
|
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
|
-
|
|
394
|
-
|
|
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
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
187
|
+
this.#manager.dispatchEventToListeners(Events.MEMORY_CHANGED, this);
|
|
183
188
|
}
|
|
184
189
|
|
|
185
190
|
samplesCount(): number {
|
|
@@ -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',
|
|
@@ -82,7 +82,7 @@ Your primary goal is to provide actionable advice to web developers about their
|
|
|
82
82
|
|
|
83
83
|
You will be provided a summary of a trace: some performance metrics; the most critical network requests; a bottom-up call graph summary; and a brief overview of available insights. Each insight has information about potential performance issues with the page.
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
Always call getInsightDetails to gather more data on an insight or the actual LCP element BEFORE mentioning any specific details about them.
|
|
86
86
|
|
|
87
87
|
You have functions available to learn more about the trace. Use these to confirm hypotheses, or to further explore the trace when diagnosing performance issues.
|
|
88
88
|
|
|
@@ -105,23 +105,41 @@ Note: if the user asks a specific question about the trace (such as "What is my
|
|
|
105
105
|
|
|
106
106
|
### Step 1: Determine a performance problem to investigate
|
|
107
107
|
|
|
108
|
+
- If the trace summary indicates that the main performance metrics (LCP, INP, CLS) are all within good thresholds, acknowledge this to the user. In this case, let the user know that they can try recording a trace with mobile emulation and throttling options and show them how.
|
|
108
109
|
- With help from the user, determine what performance problem to focus on.
|
|
109
|
-
- If the user is not specific about what problem to investigate, help them by doing a investigation yourself. Present to the user options with 1-sentence summaries. Mention what performance metrics each option impacts. Call as many functions and confirm the data thoroughly: never present an option without being certain it is a real performance issue.
|
|
110
|
-
-
|
|
111
|
-
- Don't present more than 2 options.
|
|
110
|
+
- If the user is not specific about what problem to investigate, help them by doing a investigation yourself focus on performance improvements for better LCP, INP and CLS. Present to the user options with 1-sentence summaries. Mention what performance metrics each option impacts. Call as many functions and confirm the data thoroughly: never present an option without being certain it is a real performance issue.
|
|
111
|
+
- Focus on identifying the problem in Step 1 and save solution suggestions for Step 2.
|
|
112
112
|
- Once a performance problem has been identified for investigation, move on to step 2.
|
|
113
113
|
|
|
114
|
+
#### Response Structure
|
|
115
|
+
|
|
116
|
+
- Rank the options from most impactful to least impactful, and present them to the user in that order.
|
|
117
|
+
- Limit the number of performance problem options presented to the user to a maximum of 2.
|
|
118
|
+
|
|
114
119
|
### Step 2: Suggest solutions
|
|
115
120
|
|
|
116
121
|
- Suggest solutions to remedy the identified performance problem. Be as specific as possible, using data from the trace via the provided functions to back up everything you say. You should prefer specific solutions, but absent any specific solution you may suggest general solutions (such as from an insight's documentation links).
|
|
117
122
|
- If you are unsure, be honest and present information that can be helpful for further investigation.
|
|
118
123
|
- A good first step to discover solutions is to consider the insights, but you should also validate all potential advice by analyzing the trace until you are confident about the root cause of a performance issue.
|
|
119
124
|
|
|
125
|
+
#### Response Structure
|
|
126
|
+
|
|
127
|
+
- If available, point out the root cause(s) of the problem.
|
|
128
|
+
- Example: "**Root Cause**: The page is slow because of [reason]."
|
|
129
|
+
- Example: "**Root Causes**:"
|
|
130
|
+
- [Reason 1]
|
|
131
|
+
- [Reason 2]
|
|
132
|
+
- if applicable, list actionable solution suggestion(s) in order of impact:
|
|
133
|
+
- Example: "**Suggestion**: [Suggestion 1]
|
|
134
|
+
- Example: "**Suggestions**:"
|
|
135
|
+
- [Suggestion 1]
|
|
136
|
+
- [Suggestion 2]
|
|
137
|
+
|
|
120
138
|
## Guidelines
|
|
121
139
|
|
|
122
140
|
- Use the provided functions to get detailed performance data. Prioritize functions that provide context relevant to the performance issue being investigated.
|
|
123
141
|
- Before finalizing your advice, look over it and validate using any relevant functions. If something seems off, refine the advice before giving it to the user.
|
|
124
|
-
-
|
|
142
|
+
- Base your analysis and advice solely on the data retrieved through the provided functions. Always use the provided functions to gather sufficient data when needed.
|
|
125
143
|
- Use the track summary functions to get high-level detail about portions of the trace. For the \`bounds\` parameter, default to using the bounds of the trace. Never specifically ask the user for a bounds. You can use more narrow bounds (such as the bounds relevant to a specific insight) when appropriate. Narrow the bounds given functions when possible.
|
|
126
144
|
- Use \`getEventByKey\` to get data on a specific trace event. This is great for root-cause analysis or validating any assumptions.
|
|
127
145
|
- Provide clear, actionable recommendations. Avoid technical jargon unless necessary, and explain any technical terms used.
|
|
@@ -147,15 +165,6 @@ Adhere to the following critical requirements:
|
|
|
147
165
|
- If asked about sensitive topics (religion, race, politics, sexuality, gender, etc.), respond with: "My expertise is limited to website performance analysis. I cannot provide information on that topic.".
|
|
148
166
|
- Do not provide answers on non-web-development topics, such as legal, financial, medical, or personal advice.
|
|
149
167
|
- Use the precision of Strunk & White, the brevity of Hemingway, and the simple clarity of Vonnegut. Don't add repeated information, and keep the whole answer short.
|
|
150
|
-
|
|
151
|
-
## Response Structure
|
|
152
|
-
|
|
153
|
-
- If available, point out the root cause of the problem. It may be a bullet point list.
|
|
154
|
-
- Example: "**Root Cause**: The page is slow because of [reason]."
|
|
155
|
-
- if applicable, list actionable solution suggestion(s) in order of impact:
|
|
156
|
-
- Example: "**Suggestions**:
|
|
157
|
-
- [Suggestion 1]
|
|
158
|
-
- [Suggestion 2]
|
|
159
168
|
`;
|
|
160
169
|
};
|
|
161
170
|
|
|
@@ -166,7 +175,7 @@ When referring to a trace event that has a corresponding \`eventKey\`, annotate
|
|
|
166
175
|
- When referring to a URL for which you know the eventKey of: [https://www.example.com](#s-1827)
|
|
167
176
|
- Never show the eventKey (like "eventKey: s-1852"); instead, use a markdown link as described above.
|
|
168
177
|
|
|
169
|
-
When asking the user to make a choice between
|
|
178
|
+
When asking the user to make a choice between options, output a list of choices at the end of your text response. The format is \`SUGGESTIONS: ["suggestion1", "suggestion2", "suggestion3"]\`. This MUST start on a newline, and be a single line.
|
|
170
179
|
`;
|
|
171
180
|
|
|
172
181
|
const buildExtraPreambleWhenFreshTrace = (): string => {
|
|
@@ -231,8 +240,13 @@ export class PerformanceTraceContext extends ConversationContext<AgentFocus> {
|
|
|
231
240
|
}
|
|
232
241
|
|
|
233
242
|
override getOrigin(): string {
|
|
234
|
-
|
|
235
|
-
|
|
243
|
+
try {
|
|
244
|
+
const url = new URL(this.#focus.parsedTrace.data.Meta.mainFrameURL);
|
|
245
|
+
return url.origin;
|
|
246
|
+
} catch {
|
|
247
|
+
const {min, max} = this.#focus.parsedTrace.data.Meta.traceBounds;
|
|
248
|
+
return `trace-${min}-${max}`;
|
|
249
|
+
}
|
|
236
250
|
}
|
|
237
251
|
|
|
238
252
|
override getItem(): AgentFocus {
|
package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt
CHANGED
|
@@ -226,7 +226,7 @@ Response headers
|
|
|
226
226
|
|
|
227
227
|
The result of the checks for this insight are:
|
|
228
228
|
- fetchpriority=high should be applied: FAILED
|
|
229
|
-
-
|
|
229
|
+
- LCP resources should not use loading=lazy: PASSED
|
|
230
230
|
- Request is discoverable in initial document: PASSED
|
|
231
231
|
|
|
232
232
|
## Estimated savings: none
|
|
@@ -795,35 +795,30 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
|
|
|
795
795
|
overlayModel.setShowViewportSizeOnResize(false);
|
|
796
796
|
}
|
|
797
797
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
const orientation = this.#device.orientationByName(this.#mode.orientation);
|
|
810
|
-
deviceMetrics.width = orientation.width;
|
|
811
|
-
deviceMetrics.height = orientation.height;
|
|
812
|
-
const dispFeature = this.getDisplayFeature();
|
|
813
|
-
if (dispFeature) {
|
|
814
|
-
// @ts-expect-error: displayFeature isn't in protocol.ts but is an
|
|
815
|
-
// experimental flag:
|
|
816
|
-
// https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-setDeviceMetricsOverride
|
|
817
|
-
deviceMetrics.displayFeature = dispFeature;
|
|
818
|
-
}
|
|
819
|
-
} else {
|
|
820
|
-
deviceMetrics.width = 0;
|
|
821
|
-
deviceMetrics.height = 0;
|
|
798
|
+
if (this.#emulationModel && this.#device && this.#mode) {
|
|
799
|
+
const orientation = this.#device.orientationByName(this.#mode.orientation);
|
|
800
|
+
const deviceMetrics: Protocol.Emulation.SetDeviceMetricsOverrideRequest = {
|
|
801
|
+
width: orientation.width,
|
|
802
|
+
height: orientation.height,
|
|
803
|
+
deviceScaleFactor: this.#device.deviceScaleFactor,
|
|
804
|
+
mobile: this.isMobile(),
|
|
805
|
+
};
|
|
806
|
+
const dispFeature = this.getDisplayFeature();
|
|
807
|
+
if (dispFeature) {
|
|
808
|
+
deviceMetrics.displayFeature = dispFeature;
|
|
822
809
|
}
|
|
823
810
|
await this.#emulationModel.emulateDevice(deviceMetrics);
|
|
824
811
|
}
|
|
825
|
-
|
|
826
|
-
|
|
812
|
+
|
|
813
|
+
try {
|
|
814
|
+
const screenshot = await screenCaptureModel.captureScreenshot(
|
|
815
|
+
Protocol.Page.CaptureScreenshotRequestFormat.Png, 100, screenshotMode, clip);
|
|
816
|
+
return screenshot;
|
|
817
|
+
} finally {
|
|
818
|
+
await this.#emulationModel?.emulateDevice(null);
|
|
819
|
+
overlayModel?.setShowViewportSizeOnResize(this.#type === Type.None);
|
|
820
|
+
this.calculateAndEmulate(false);
|
|
821
|
+
}
|
|
827
822
|
}
|
|
828
823
|
|
|
829
824
|
private applyTouch(touchEnabled: boolean, mobile: boolean): void {
|
|
@@ -41,14 +41,18 @@ export const UIStrings = {
|
|
|
41
41
|
* @description Text to tell the user that a fetchpriority property value of "high" should be applied to the LCP request.
|
|
42
42
|
*/
|
|
43
43
|
fetchPriorityShouldBeApplied: 'fetchpriority=high should be applied',
|
|
44
|
+
/**
|
|
45
|
+
* @description Text to tell the user that a fetchpriority property value of "high" should be applied to the preload request that loads the LCP image.
|
|
46
|
+
*/
|
|
47
|
+
fetchPriorityShouldBeAppliedToImagePreload: 'fetchpriority=high should be applied to the image preload request',
|
|
44
48
|
/**
|
|
45
49
|
* @description Text to tell the user that the LCP request is discoverable in the initial document.
|
|
46
50
|
*/
|
|
47
51
|
requestDiscoverable: 'Request is discoverable in initial document',
|
|
48
52
|
/**
|
|
49
|
-
* @description Text to tell the user that
|
|
53
|
+
* @description Text to tell the user that LCP resources should avoid using loading=lazy.
|
|
50
54
|
*/
|
|
51
|
-
lazyLoadNotApplied: '
|
|
55
|
+
lazyLoadNotApplied: 'LCP resources should not use loading=lazy',
|
|
52
56
|
/**
|
|
53
57
|
* @description Text status indicating that the the Largest Contentful Paint (LCP) metric timing was not found. "LCP" is an acronym and should not be translated.
|
|
54
58
|
*/
|
|
@@ -133,12 +137,17 @@ export function generateInsight(
|
|
|
133
137
|
lcpRequest?.args.data.initiator?.type === 'parser' && docRequest.args.data.url === initiatorUrl;
|
|
134
138
|
const imgPreloadedOrFoundInHTML = lcpRequest?.args.data.isLinkPreload || initiatedByMainDoc;
|
|
135
139
|
|
|
136
|
-
const imageLoadingAttr = lcpEvent.args.data?.loadingAttr;
|
|
137
140
|
const imageFetchPriorityHint = lcpRequest?.args.data.fetchPriorityHint;
|
|
138
141
|
// This is the earliest discovery time an LCP request could have - it's TTFB (as an absolute timestamp).
|
|
139
142
|
const earliestDiscoveryTime = calculateDocFirstByteTs(docRequest);
|
|
140
143
|
|
|
141
144
|
const priorityHintFound = imageFetchPriorityHint === 'high';
|
|
145
|
+
const missingPriorityHintLabel = lcpRequest.args.data.isLinkPreload ?
|
|
146
|
+
i18nString(UIStrings.fetchPriorityShouldBeAppliedToImagePreload) :
|
|
147
|
+
i18nString(UIStrings.fetchPriorityShouldBeApplied);
|
|
148
|
+
// A lazy-loaded LCP image can still be eagerly loaded when its request is
|
|
149
|
+
// initiated by a preload.
|
|
150
|
+
const lcpNotLazyLoaded = lcpEvent.args.data?.loadingAttr !== 'lazy' || lcpRequest.args.data.isLinkPreload;
|
|
142
151
|
|
|
143
152
|
return finalize({
|
|
144
153
|
lcpEvent,
|
|
@@ -146,12 +155,11 @@ export function generateInsight(
|
|
|
146
155
|
earliestDiscoveryTimeTs: earliestDiscoveryTime ? Types.Timing.Micro(earliestDiscoveryTime) : undefined,
|
|
147
156
|
checklist: {
|
|
148
157
|
priorityHinted: {
|
|
149
|
-
label: priorityHintFound ? i18nString(UIStrings.fetchPriorityApplied) :
|
|
150
|
-
i18nString(UIStrings.fetchPriorityShouldBeApplied),
|
|
158
|
+
label: priorityHintFound ? i18nString(UIStrings.fetchPriorityApplied) : missingPriorityHintLabel,
|
|
151
159
|
value: priorityHintFound
|
|
152
160
|
},
|
|
153
161
|
requestDiscoverable: {label: i18nString(UIStrings.requestDiscoverable), value: imgPreloadedOrFoundInHTML},
|
|
154
|
-
eagerlyLoaded: {label: i18nString(UIStrings.lazyLoadNotApplied), value:
|
|
162
|
+
eagerlyLoaded: {label: i18nString(UIStrings.lazyLoadNotApplied), value: lcpNotLazyLoaded},
|
|
155
163
|
},
|
|
156
164
|
});
|
|
157
165
|
}
|
|
@@ -379,14 +379,6 @@ interface ToolbarViewInput {
|
|
|
379
379
|
showChatActions: boolean;
|
|
380
380
|
showActiveConversationActions: boolean;
|
|
381
381
|
isLoading: boolean;
|
|
382
|
-
|
|
383
|
-
walkthrough: {
|
|
384
|
-
isExpanded: boolean,
|
|
385
|
-
isInlined: boolean,
|
|
386
|
-
onToggle: (isOpen: boolean, message: ModelChatMessage) => void,
|
|
387
|
-
activeSidebarMessage: ModelChatMessage|null,
|
|
388
|
-
inlineExpandedMessages: ModelChatMessage[],
|
|
389
|
-
};
|
|
390
382
|
}
|
|
391
383
|
|
|
392
384
|
export const enum ViewState {
|
|
@@ -514,7 +506,7 @@ function defaultView(input: ViewInput, output: PanelViewOutput, target: HTMLElem
|
|
|
514
506
|
if (Root.Runtime.hostConfig.devToolsAiAssistanceV2?.enabled ||
|
|
515
507
|
Greendev.Prototypes.instance().isEnabled('breakpointDebuggerAgent')) {
|
|
516
508
|
|
|
517
|
-
const shouldShowWalkthrough = input.state === ViewState.CHAT_VIEW && input.walkthrough.isExpanded;
|
|
509
|
+
const shouldShowWalkthrough = input.state === ViewState.CHAT_VIEW && input.props.walkthrough.isExpanded;
|
|
518
510
|
/**
|
|
519
511
|
* We want to mark the walkthrough as loading only if it's showing the last
|
|
520
512
|
* message. Otherwise, a previous walkthrough will show as loading if we
|
|
@@ -535,7 +527,7 @@ function defaultView(input: ViewInput, output: PanelViewOutput, target: HTMLElem
|
|
|
535
527
|
name="ai-assistance-split-view-state"
|
|
536
528
|
direction="column"
|
|
537
529
|
sidebar-position="second"
|
|
538
|
-
sidebar-visibility=${shouldShowWalkthrough && !input.walkthrough.isInlined ? 'visible' : 'hidden'}
|
|
530
|
+
sidebar-visibility=${shouldShowWalkthrough && !input.props.walkthrough.isInlined ? 'visible' : 'hidden'}
|
|
539
531
|
sidebar-initial-size=${WALKTHROUGH_SIDEBAR_INITIAL_WIDTH}
|
|
540
532
|
>
|
|
541
533
|
<div slot="main" class="main-view">
|
|
@@ -716,13 +708,6 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
716
708
|
onSettingsClick: () => {
|
|
717
709
|
void UI.ViewManager.ViewManager.instance().showView('chrome-ai');
|
|
718
710
|
},
|
|
719
|
-
walkthrough: {
|
|
720
|
-
isExpanded: this.#walkthrough.isExpanded,
|
|
721
|
-
isInlined: this.#walkthrough.isInlined,
|
|
722
|
-
onToggle: this.#toggleWalkthrough.bind(this),
|
|
723
|
-
activeSidebarMessage: this.#walkthrough.activeSidebarMessage,
|
|
724
|
-
inlineExpandedMessages: this.#walkthrough.inlineExpandedMessages,
|
|
725
|
-
}
|
|
726
711
|
};
|
|
727
712
|
}
|
|
728
713
|
|