chrome-devtools-frontend 1.0.1598808 → 1.0.1601661
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/.agents/README.md +13 -0
- package/{agents/prompts/creating-a-model.md → .agents/skills/creating-a-model/SKILL.md} +7 -1
- package/{agents/prompts/devtools-imports.md → .agents/skills/devtools-imports/SKILL.md} +10 -5
- package/{agents/prompts/merging-devtools-module.md → .agents/skills/merging-devtools-module/SKILL.md} +5 -0
- package/{agents/prompts/ui-widgets.md → .agents/skills/ui-widgets/SKILL.md} +5 -0
- package/{agents/prompts/verification.md → .agents/skills/verification/SKILL.md} +5 -0
- package/front_end/core/common/Settings.ts +24 -1
- package/front_end/core/dom_extension/DOMExtension.ts +1 -0
- package/front_end/core/host/AidaClient.ts +5 -2
- package/front_end/core/host/AidaGcaTranslation.ts +377 -0
- package/front_end/core/host/GcaTypes.ts +520 -0
- package/front_end/core/host/UserMetrics.ts +0 -3
- package/front_end/core/host/host.ts +4 -0
- package/front_end/core/root/ExperimentNames.ts +0 -3
- package/front_end/core/sdk/CPUThrottlingManager.ts +12 -9
- package/front_end/core/sdk/ResourceTreeModel.ts +1 -1
- package/front_end/core/sdk/SourceMap.ts +4 -2
- package/front_end/entrypoints/main/MainImpl.ts +1 -12
- package/front_end/generated/Deprecation.ts +16 -0
- package/front_end/generated/InspectorBackendCommands.ts +4 -6
- package/front_end/generated/protocol.ts +46 -77
- package/front_end/models/ai_assistance/AiConversation.ts +49 -22
- package/front_end/models/ai_assistance/AiHistoryStorage.snapshot.txt +1 -1
- package/front_end/models/ai_assistance/AiHistoryStorage.ts +1 -0
- package/front_end/models/ai_assistance/ConversationHandler.ts +16 -11
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +76 -36
- package/front_end/models/ai_assistance/agents/AiAgent.ts +26 -2
- package/front_end/models/ai_assistance/agents/BreakpointDebuggerAgent.ts +0 -1
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +11 -0
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +39 -0
- package/front_end/models/ai_assistance/agents/ConversationSummaryAgent.ts +53 -12
- package/front_end/models/ai_assistance/agents/FileAgent.ts +0 -15
- package/front_end/models/ai_assistance/agents/NetworkAgent.ts +0 -5
- package/front_end/models/ai_assistance/agents/PerformanceAgent.snapshot.txt +57 -0
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +87 -15
- package/front_end/models/ai_assistance/agents/PerformanceAnnotationsAgent.ts +0 -10
- package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +0 -6
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +1 -5
- package/front_end/models/ai_assistance/ai_assistance.ts +2 -0
- package/front_end/models/ai_assistance/data_formatters/LighthouseFormatter.snapshot.txt +84 -0
- package/front_end/models/ai_assistance/data_formatters/LighthouseFormatter.ts +172 -0
- package/front_end/models/breakpoints/BreakpointManager.ts +20 -12
- package/front_end/models/emulation/DeviceModeModel.ts +5 -1
- package/front_end/models/emulation/EmulatedDevices.ts +3 -2
- package/front_end/models/javascript_metadata/NativeFunctions.js +60 -0
- package/front_end/models/lighthouse/LighthouseReporterTypes.ts +104 -10
- package/front_end/models/lighthouse/RunTypes.ts +42 -0
- package/front_end/models/lighthouse/lighthouse.ts +2 -0
- package/front_end/models/live-metrics/web-vitals-injected/web-vitals-injected.ts +59 -35
- package/front_end/models/stack_trace/StackTrace.ts +5 -0
- package/front_end/models/stack_trace/StackTraceImpl.ts +7 -1
- package/front_end/models/stack_trace/StackTraceModel.ts +2 -1
- package/front_end/models/stack_trace/stack_trace.ts +4 -0
- package/front_end/models/trace/ModelImpl.ts +4 -0
- package/front_end/models/trace/helpers/SamplesIntegrator.ts +1 -8
- package/front_end/models/trace/types/Configuration.ts +0 -5
- package/front_end/panels/accessibility/AccessibilityNodeView.ts +7 -3
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +163 -74
- package/front_end/panels/ai_assistance/ExportConversation.ts +25 -0
- package/front_end/panels/ai_assistance/ai_assistance.ts +2 -0
- package/front_end/panels/ai_assistance/components/ChatInput.ts +2 -0
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +120 -32
- package/front_end/panels/ai_assistance/components/ChatView.ts +44 -0
- package/front_end/panels/ai_assistance/components/ExportForAgentsDialog.ts +240 -0
- package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +4 -12
- package/front_end/panels/ai_assistance/components/StylingAgentMarkdownRenderer.ts +5 -27
- package/front_end/panels/ai_assistance/components/WalkthroughView.ts +115 -17
- package/front_end/panels/ai_assistance/components/chatMessage.css +65 -1
- package/front_end/panels/ai_assistance/components/chatView.css +8 -0
- package/front_end/panels/ai_assistance/components/exportForAgentsDialog.css +82 -0
- package/front_end/panels/ai_assistance/components/walkthroughView.css +9 -1
- package/front_end/panels/animation/AnimationTimeline.ts +5 -5
- package/front_end/panels/application/AppManifestView.ts +13 -7
- package/front_end/panels/application/FrameDetailsView.ts +4 -4
- package/front_end/panels/application/preloading/PreloadingView.ts +2 -4
- package/front_end/panels/application/preloading/components/PreloadingDetailsReportView.ts +6 -3
- package/front_end/panels/application/preloading/components/PreloadingString.ts +15 -2
- package/front_end/panels/application/preloading/helper/PreloadingForward.ts +31 -2
- package/front_end/panels/browser_debugger/DOMBreakpointsSidebarPane.ts +3 -2
- package/front_end/panels/common/DOMLinkifier.ts +10 -8
- package/front_end/panels/console/ConsoleView.ts +24 -2
- package/front_end/panels/console/ConsoleViewMessage.ts +22 -23
- package/front_end/panels/console/console.ts +0 -2
- package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +5 -5
- package/front_end/panels/elements/ElementsTreeElement.ts +2 -3
- package/front_end/panels/elements/PropertiesWidget.ts +5 -3
- package/front_end/panels/elements/StandaloneStylesContainer.ts +21 -9
- package/front_end/panels/elements/StylePropertiesSection.ts +98 -50
- package/front_end/panels/elements/StylePropertyTreeElement.ts +38 -4
- package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +43 -35
- package/front_end/panels/elements/StylesSidebarPane.ts +154 -24
- package/front_end/panels/elements/components/ComputedStyleTrace.ts +3 -2
- package/front_end/panels/event_listeners/EventListenersView.ts +16 -4
- package/front_end/panels/explain/components/ConsoleInsight.ts +6 -9
- package/front_end/panels/explain/explain-meta.ts +5 -0
- package/front_end/panels/issues/AffectedResourcesView.ts +5 -9
- package/front_end/panels/issues/AffectedSelectivePermissionsInterventionView.ts +1 -1
- package/front_end/panels/lighthouse/LighthouseController.ts +154 -164
- package/front_end/panels/lighthouse/LighthousePanel.ts +5 -9
- package/front_end/panels/lighthouse/LighthouseProtocolService.ts +1 -0
- package/front_end/panels/lighthouse/LighthouseReportRenderer.ts +9 -6
- package/front_end/panels/lighthouse/LighthouseStartView.ts +7 -6
- package/front_end/panels/lighthouse/LighthouseStatusView.ts +32 -8
- package/front_end/panels/linear_memory_inspector/components/LinearMemoryInspector.ts +7 -3
- package/front_end/panels/network/NetworkDataGridNode.ts +34 -0
- package/front_end/panels/network/NetworkLogViewColumns.ts +10 -0
- package/front_end/panels/network/RequestPayloadView.ts +4 -1
- package/front_end/panels/network/RequestTimingView.ts +8 -2
- package/front_end/panels/performance_monitor/performanceMonitor.css +6 -4
- package/front_end/panels/recorder/RecorderController.ts +52 -14
- package/front_end/panels/recorder/components/RecordingView.ts +2 -1
- package/front_end/panels/recorder/models/RecordingStorage.ts +15 -20
- package/front_end/panels/sensors/SensorsView.ts +333 -157
- package/front_end/panels/settings/emulation/DevicesSettingsTab.ts +18 -4
- package/front_end/panels/sources/DebuggerPausedMessage.ts +6 -6
- package/front_end/panels/sources/FilteredUISourceCodeListProvider.ts +2 -3
- package/front_end/panels/sources/NavigatorView.ts +11 -7
- package/front_end/panels/sources/ScopeChainSidebarPane.ts +1 -1
- package/front_end/panels/sources/SourcesPanel.ts +12 -34
- package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +5 -1
- package/front_end/panels/sources/sources-meta.ts +6 -0
- package/front_end/panels/timeline/StatusDialog.ts +159 -83
- package/front_end/panels/timeline/ThirdPartyTreeView.ts +6 -2
- package/front_end/panels/timeline/TimelineController.ts +0 -4
- package/front_end/panels/timeline/TimelineDetailsView.ts +35 -3
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +6 -1
- package/front_end/panels/timeline/TimelineFlameChartNetworkDataProvider.ts +9 -4
- package/front_end/panels/timeline/TimelinePanel.ts +36 -11
- package/front_end/panels/timeline/TimelineTreeView.ts +14 -3
- package/front_end/panels/timeline/TimelineUIUtils.ts +5 -57
- package/front_end/panels/timeline/components/InteractionBreakdown.ts +2 -1
- package/front_end/panels/timeline/components/LiveMetricsView.ts +2 -2
- package/front_end/panels/timeline/components/NetworkRequestTooltip.ts +3 -7
- package/front_end/panels/timeline/components/Sidebar.ts +11 -19
- package/front_end/panels/timeline/components/SidebarInsightsTab.ts +2 -1
- package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +60 -27
- package/front_end/panels/timeline/components/TimelineRangeSummaryView.ts +66 -0
- package/front_end/panels/timeline/components/TimelineSummary.ts +7 -19
- package/front_end/panels/timeline/components/components.ts +2 -0
- package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +55 -28
- package/front_end/panels/timeline/components/insights/NodeLink.ts +3 -3
- package/front_end/panels/timeline/components/insights/baseInsightComponent.css +7 -0
- package/front_end/panels/timeline/components/insights/insights.ts +0 -2
- package/front_end/panels/timeline/components/timelineRangeSummaryView.css +20 -0
- package/front_end/panels/timeline/overlays/OverlaysImpl.ts +7 -7
- package/front_end/panels/timeline/timeline-meta.ts +11 -0
- package/front_end/panels/timeline/timelineDetailsView.css +0 -9
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/onINP.js +11 -2
- package/front_end/third_party/web-vitals/package/src/attribution/onINP.ts +11 -2
- package/front_end/third_party/web-vitals/patches/0001-Add-onEachInteraction-to-onINP-options.patch +65 -4
- package/front_end/ui/kit/link/link.css +2 -2
- package/front_end/ui/legacy/Widget.ts +5 -3
- package/front_end/ui/legacy/components/object_ui/CustomPreviewComponent.ts +7 -2
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +57 -35
- package/front_end/ui/legacy/components/source_frame/PreviewFactory.ts +1 -0
- package/front_end/ui/visual_logging/KnownContextValues.ts +6 -1
- package/package.json +1 -1
- package/agents/prompts/README.md +0 -18
- package/front_end/panels/timeline/components/insights/InsightRenderer.ts +0 -93
- /package/front_end/{panels/console → models/stack_trace}/ErrorStackParser.ts +0 -0
|
@@ -11,7 +11,9 @@ import * as SDK from '../../../core/sdk/sdk.js';
|
|
|
11
11
|
import type * as Protocol from '../../../generated/protocol.js';
|
|
12
12
|
import * as Tracing from '../../../services/tracing/tracing.js';
|
|
13
13
|
import * as Annotations from '../../annotations/annotations.js';
|
|
14
|
+
import * as Logs from '../../logs/logs.js';
|
|
14
15
|
import * as SourceMapScopes from '../../source_map_scopes/source_map_scopes.js';
|
|
16
|
+
import * as TextUtils from '../../text_utils/text_utils.js';
|
|
15
17
|
import * as Trace from '../../trace/trace.js';
|
|
16
18
|
import {
|
|
17
19
|
PerformanceInsightFormatter,
|
|
@@ -35,10 +37,6 @@ import {
|
|
|
35
37
|
} from './AiAgent.js';
|
|
36
38
|
|
|
37
39
|
const UIStringsNotTranslated = {
|
|
38
|
-
/**
|
|
39
|
-
*@description Shown when the agent is investigating a trace
|
|
40
|
-
*/
|
|
41
|
-
analyzingTrace: 'Analyzing trace',
|
|
42
40
|
/**
|
|
43
41
|
* @description Shown when the agent is investigating network activity
|
|
44
42
|
*/
|
|
@@ -318,7 +316,6 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
318
316
|
#formatter: PerformanceTraceFormatter|null = null;
|
|
319
317
|
#lastEventForEnhancedQuery: Trace.Types.Events.Event|undefined;
|
|
320
318
|
#lastInsightForEnhancedQuery: Trace.Insights.Types.InsightModel|undefined;
|
|
321
|
-
#hasShownAnalyzeTraceContext = false;
|
|
322
319
|
|
|
323
320
|
/**
|
|
324
321
|
* Cache of all function calls made by the agent. This allows us to include (as a
|
|
@@ -351,6 +348,32 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
351
348
|
};
|
|
352
349
|
#traceFacts: Host.AidaClient.RequestFact[] = [];
|
|
353
350
|
|
|
351
|
+
/**
|
|
352
|
+
* These facts do not contain page data, they are static instructions to the
|
|
353
|
+
* LLM, so we don't need to add them to the disclosure.
|
|
354
|
+
*/
|
|
355
|
+
#factsToNeverDisclose = new Set<Host.AidaClient.RequestFact>([
|
|
356
|
+
this.#callFrameDataDescriptionFact,
|
|
357
|
+
this.#networkDataDescriptionFact,
|
|
358
|
+
this.#freshTraceExtraPreambleFact,
|
|
359
|
+
this.#notExternalExtraPreambleFact,
|
|
360
|
+
]);
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* When we enhance the query with additional information, we need to know it
|
|
364
|
+
* so we can show it in the disclosure UI. This is cleared and then populated
|
|
365
|
+
* on each prompt.
|
|
366
|
+
*/
|
|
367
|
+
#additionalSelectionsForQuery: string[] = [];
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* The CWV widget is shown when we analyze the trace summary, but we don't
|
|
371
|
+
* want to show it on every single "Analyzing data..." pill, as we show one
|
|
372
|
+
* after every prompt. So we make sure for a given Insight Set (which is based on navigation)
|
|
373
|
+
* we only show it once.
|
|
374
|
+
*/
|
|
375
|
+
#hasShownWidgetForInsightSet = new WeakSet<Trace.Insights.Types.InsightSet>();
|
|
376
|
+
|
|
354
377
|
get preamble(): string {
|
|
355
378
|
return buildPreamble();
|
|
356
379
|
}
|
|
@@ -379,13 +402,19 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
379
402
|
return;
|
|
380
403
|
}
|
|
381
404
|
|
|
382
|
-
|
|
383
|
-
|
|
405
|
+
const contextDisclosure: string[] = [];
|
|
406
|
+
|
|
407
|
+
for (const fact of this.currentFacts()) {
|
|
408
|
+
if (this.#factsToNeverDisclose.has(fact)) {
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
contextDisclosure.push(fact.text);
|
|
384
412
|
}
|
|
413
|
+
contextDisclosure.push(...this.#additionalSelectionsForQuery);
|
|
385
414
|
|
|
386
415
|
const widgets: AiWidget[] = [];
|
|
387
416
|
const primaryInsightSet = context.getItem().primaryInsightSet;
|
|
388
|
-
if (primaryInsightSet) {
|
|
417
|
+
if (primaryInsightSet && !this.#hasShownWidgetForInsightSet.has(primaryInsightSet)) {
|
|
389
418
|
widgets.push({
|
|
390
419
|
name: 'CORE_VITALS',
|
|
391
420
|
data: {
|
|
@@ -393,21 +422,19 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
393
422
|
insightSetKey: primaryInsightSet.id,
|
|
394
423
|
},
|
|
395
424
|
});
|
|
425
|
+
this.#hasShownWidgetForInsightSet.add(primaryInsightSet);
|
|
396
426
|
}
|
|
397
427
|
|
|
398
428
|
yield {
|
|
399
429
|
type: ResponseType.CONTEXT,
|
|
400
|
-
title: lockedString(UIStringsNotTranslated.analyzingTrace),
|
|
401
430
|
details: [
|
|
402
431
|
{
|
|
403
|
-
title: 'Trace',
|
|
404
|
-
text:
|
|
432
|
+
title: 'Trace details',
|
|
433
|
+
text: contextDisclosure.join('\n'),
|
|
405
434
|
},
|
|
406
435
|
],
|
|
407
436
|
widgets,
|
|
408
437
|
};
|
|
409
|
-
|
|
410
|
-
this.#hasShownAnalyzeTraceContext = true;
|
|
411
438
|
}
|
|
412
439
|
|
|
413
440
|
#callTreeContextSet = new WeakSet();
|
|
@@ -536,6 +563,7 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
536
563
|
}
|
|
537
564
|
}
|
|
538
565
|
|
|
566
|
+
this.#additionalSelectionsForQuery = selected;
|
|
539
567
|
if (!selected.length) {
|
|
540
568
|
return query;
|
|
541
569
|
}
|
|
@@ -752,7 +780,8 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
752
780
|
const details = new PerformanceInsightFormatter(focus, insight).formatInsight();
|
|
753
781
|
|
|
754
782
|
const widgets: AiWidget[] = [];
|
|
755
|
-
if (
|
|
783
|
+
if (Trace.Insights.Models.LCPDiscovery.isLCPDiscoveryInsight(insight) ||
|
|
784
|
+
Trace.Insights.Models.LCPBreakdown.isLCPBreakdownInsight(insight)) {
|
|
756
785
|
const lcpMetric = Trace.Insights.Common.getLCP(insightSet);
|
|
757
786
|
const lcpEvent = lcpMetric?.event;
|
|
758
787
|
if (lcpEvent && Trace.Types.Events.isAnyLargestContentfulPaintCandidate(lcpEvent)) {
|
|
@@ -767,15 +796,38 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
767
796
|
const node = nodeMap?.get(nodeId);
|
|
768
797
|
if (node) {
|
|
769
798
|
const snapshot = await node.takeSnapshot();
|
|
799
|
+
let networkRequest;
|
|
800
|
+
const lcpSyntheticRequest = insight.lcpRequest;
|
|
801
|
+
if (lcpSyntheticRequest) {
|
|
802
|
+
networkRequest = {
|
|
803
|
+
url: lcpSyntheticRequest.args.data.url,
|
|
804
|
+
size: lcpSyntheticRequest.args.data.decodedBodyLength ??
|
|
805
|
+
lcpSyntheticRequest.args.data.encodedDataLength ?? 0,
|
|
806
|
+
resourceType: lcpSyntheticRequest.args.data.resourceType,
|
|
807
|
+
mimeType: lcpSyntheticRequest.args.data.mimeType ?? '',
|
|
808
|
+
imageUrl: await this.#getNetworkRequestImageData(lcpSyntheticRequest),
|
|
809
|
+
};
|
|
810
|
+
}
|
|
770
811
|
widgets.push({
|
|
771
812
|
name: 'DOM_TREE',
|
|
772
|
-
data: {
|
|
813
|
+
data: {
|
|
814
|
+
root: snapshot,
|
|
815
|
+
networkRequest,
|
|
816
|
+
},
|
|
773
817
|
});
|
|
774
818
|
processedNodeIds.add(nodeId);
|
|
775
819
|
}
|
|
776
820
|
}
|
|
777
821
|
}
|
|
778
822
|
}
|
|
823
|
+
if (params.insightName === 'LCPBreakdown') {
|
|
824
|
+
widgets.push({
|
|
825
|
+
name: 'LCP_BREAKDOWN',
|
|
826
|
+
data: {
|
|
827
|
+
lcpData: insight as Trace.Insights.Models.LCPBreakdown.LCPBreakdownInsightModel,
|
|
828
|
+
},
|
|
829
|
+
});
|
|
830
|
+
}
|
|
779
831
|
}
|
|
780
832
|
|
|
781
833
|
const key = `getInsightDetails('${params.insightSetId}', '${params.insightName}')`;
|
|
@@ -1258,4 +1310,24 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
1258
1310
|
Annotations.AnnotationRepository.instance().addNetworkRequestAnnotation(annotationMessage, requestId);
|
|
1259
1311
|
return {result: {success: true}};
|
|
1260
1312
|
}
|
|
1313
|
+
|
|
1314
|
+
async #getNetworkRequestImageData(lcpRequest: Trace.Types.Events.SyntheticNetworkRequest): Promise<string|undefined> {
|
|
1315
|
+
const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
|
|
1316
|
+
const networkManager = target?.model(SDK.NetworkManager.NetworkManager);
|
|
1317
|
+
if (!target || !networkManager) {
|
|
1318
|
+
return undefined;
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
const networkLog = Logs.NetworkLog.NetworkLog.instance();
|
|
1322
|
+
const requestId = lcpRequest.args.data.requestId;
|
|
1323
|
+
const sdkRequest = networkLog.requestByManagerAndId(networkManager, requestId);
|
|
1324
|
+
|
|
1325
|
+
if (sdkRequest?.contentType().isImage()) {
|
|
1326
|
+
const contentData = await sdkRequest.requestContentData();
|
|
1327
|
+
if (!TextUtils.ContentData.ContentData.isError(contentData)) {
|
|
1328
|
+
return contentData.asDataUrl() ?? undefined;
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
return undefined;
|
|
1332
|
+
}
|
|
1261
1333
|
}
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
5
|
import * as Host from '../../../core/host/host.js';
|
|
6
|
-
import * as i18n from '../../../core/i18n/i18n.js';
|
|
7
6
|
import * as Root from '../../../core/root/root.js';
|
|
8
7
|
import type {AICallTree} from '../performance/AICallTree.js';
|
|
9
8
|
import type {AgentFocus} from '../performance/AIContext.js';
|
|
@@ -11,14 +10,6 @@ import type {AgentFocus} from '../performance/AIContext.js';
|
|
|
11
10
|
import {AiAgent, type ContextResponse, type ConversationContext, type RequestOptions, ResponseType} from './AiAgent.js';
|
|
12
11
|
import {PerformanceTraceContext} from './PerformanceAgent.js';
|
|
13
12
|
|
|
14
|
-
const UIStringsNotTranslated = {
|
|
15
|
-
analyzingCallTree: 'Analyzing call tree',
|
|
16
|
-
/**
|
|
17
|
-
* @description Shown when the agent is investigating network activity
|
|
18
|
-
*/
|
|
19
|
-
} as const;
|
|
20
|
-
const lockedString = i18n.i18n.lockedString;
|
|
21
|
-
|
|
22
13
|
/**
|
|
23
14
|
* Preamble clocks in at ~970 tokens.
|
|
24
15
|
* The prose is around 4.5 chars per token.
|
|
@@ -124,7 +115,6 @@ export class PerformanceAnnotationsAgent extends AiAgent<AgentFocus> {
|
|
|
124
115
|
|
|
125
116
|
yield {
|
|
126
117
|
type: ResponseType.CONTEXT,
|
|
127
|
-
title: lockedString(UIStringsNotTranslated.analyzingCallTree),
|
|
128
118
|
details: [
|
|
129
119
|
{
|
|
130
120
|
title: 'Selected call tree',
|
|
@@ -216,7 +216,6 @@ Content:
|
|
|
216
216
|
[
|
|
217
217
|
{
|
|
218
218
|
"type": "context",
|
|
219
|
-
"title": "Analyzing the prompt",
|
|
220
219
|
"details": [
|
|
221
220
|
{
|
|
222
221
|
"title": "Data used",
|
|
@@ -296,7 +295,6 @@ Content:
|
|
|
296
295
|
[
|
|
297
296
|
{
|
|
298
297
|
"type": "context",
|
|
299
|
-
"title": "Analyzing the prompt",
|
|
300
298
|
"details": [
|
|
301
299
|
{
|
|
302
300
|
"title": "Data used",
|
|
@@ -321,7 +319,6 @@ Content:
|
|
|
321
319
|
[
|
|
322
320
|
{
|
|
323
321
|
"type": "context",
|
|
324
|
-
"title": "Analyzing the prompt",
|
|
325
322
|
"details": [
|
|
326
323
|
{
|
|
327
324
|
"title": "Data used",
|
|
@@ -349,7 +346,6 @@ Content:
|
|
|
349
346
|
[
|
|
350
347
|
{
|
|
351
348
|
"type": "context",
|
|
352
|
-
"title": "Analyzing the prompt",
|
|
353
349
|
"details": [
|
|
354
350
|
{
|
|
355
351
|
"title": "Data used",
|
|
@@ -374,7 +370,6 @@ Content:
|
|
|
374
370
|
[
|
|
375
371
|
{
|
|
376
372
|
"type": "context",
|
|
377
|
-
"title": "Analyzing the prompt",
|
|
378
373
|
"details": [
|
|
379
374
|
{
|
|
380
375
|
"title": "Data used",
|
|
@@ -397,7 +392,6 @@ Content:
|
|
|
397
392
|
[
|
|
398
393
|
{
|
|
399
394
|
"type": "context",
|
|
400
|
-
"title": "Analyzing the prompt",
|
|
401
395
|
"details": [
|
|
402
396
|
{
|
|
403
397
|
"title": "Data used",
|
|
@@ -37,10 +37,6 @@ import {
|
|
|
37
37
|
* Strings that don't need to be translated at this time.
|
|
38
38
|
*/
|
|
39
39
|
const UIStringsNotTranslate = {
|
|
40
|
-
/**
|
|
41
|
-
* @description Title for context details for Freestyler.
|
|
42
|
-
*/
|
|
43
|
-
analyzingThePrompt: 'Analyzing the prompt',
|
|
44
40
|
/**
|
|
45
41
|
* @description Heading text for context details of Freestyler agent.
|
|
46
42
|
*/
|
|
@@ -1045,7 +1041,6 @@ const data = {
|
|
|
1045
1041
|
}
|
|
1046
1042
|
yield {
|
|
1047
1043
|
type: ResponseType.CONTEXT,
|
|
1048
|
-
title: lockedString(UIStringsNotTranslate.analyzingThePrompt),
|
|
1049
1044
|
details: [{
|
|
1050
1045
|
title: lockedString(UIStringsNotTranslate.dataUsed),
|
|
1051
1046
|
text: await StylingAgent.describeElement(selectedElement.getItem()),
|
|
@@ -1078,6 +1073,7 @@ const data = {
|
|
|
1078
1073
|
];
|
|
1079
1074
|
return answer;
|
|
1080
1075
|
}
|
|
1076
|
+
|
|
1081
1077
|
override async enhanceQuery(
|
|
1082
1078
|
query: string, selectedElement: ConversationContext<SDK.DOMModel.DOMNode>|null,
|
|
1083
1079
|
multimodalInputType?: MultimodalInputType): Promise<string> {
|
|
@@ -21,6 +21,7 @@ import * as BuiltInAi from './BuiltInAi.js';
|
|
|
21
21
|
import * as ChangeManager from './ChangeManager.js';
|
|
22
22
|
import * as ConversationHandler from './ConversationHandler.js';
|
|
23
23
|
import * as FileFormatter from './data_formatters/FileFormatter.js';
|
|
24
|
+
import * as LighthouseFormatter from './data_formatters/LighthouseFormatter.js';
|
|
24
25
|
import * as NetworkRequestFormatter from './data_formatters/NetworkRequestFormatter.js';
|
|
25
26
|
import * as PerformanceInsightFormatter from './data_formatters/PerformanceInsightFormatter.js';
|
|
26
27
|
import * as PerformanceTraceFormatter from './data_formatters/PerformanceTraceFormatter.js';
|
|
@@ -55,6 +56,7 @@ export {
|
|
|
55
56
|
FileAgent,
|
|
56
57
|
FileFormatter,
|
|
57
58
|
Injected,
|
|
59
|
+
LighthouseFormatter,
|
|
58
60
|
NetworkAgent,
|
|
59
61
|
NetworkRequestFormatter,
|
|
60
62
|
PatchAgent,
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
Title: LighthouseFormatter generates a summary
|
|
2
|
+
Content:
|
|
3
|
+
# Lighthouse Report Summary
|
|
4
|
+
URL: https://example.com
|
|
5
|
+
Fetch Time: 2025-01-01T00:00:00.000Z
|
|
6
|
+
Lighthouse Version: 12.0.0
|
|
7
|
+
|
|
8
|
+
## Category Scores
|
|
9
|
+
- Performance: 80
|
|
10
|
+
- Accessibility: 100
|
|
11
|
+
=== end content
|
|
12
|
+
|
|
13
|
+
Title: LighthouseFormatter generates audits for a category
|
|
14
|
+
Content:
|
|
15
|
+
# Audits for Performance
|
|
16
|
+
|
|
17
|
+
The following audits in this category have a score below 90 and may need attention:
|
|
18
|
+
- **First Audit**: 80 (1.2s)
|
|
19
|
+
* Description of first audit
|
|
20
|
+
=== end content
|
|
21
|
+
|
|
22
|
+
Title: LighthouseFormatter indicates when all audits passed
|
|
23
|
+
Content:
|
|
24
|
+
# Audits for Accessibility
|
|
25
|
+
|
|
26
|
+
All audits in this category passed (score >= 90).
|
|
27
|
+
=== end content
|
|
28
|
+
|
|
29
|
+
Title: LighthouseFormatter handles missing category
|
|
30
|
+
Content:
|
|
31
|
+
Category "seo" not found.
|
|
32
|
+
=== end content
|
|
33
|
+
|
|
34
|
+
Title: LighthouseFormatter formats table details
|
|
35
|
+
Content:
|
|
36
|
+
# Audits for Performance
|
|
37
|
+
|
|
38
|
+
The following audits in this category have a score below 90 and may need attention:
|
|
39
|
+
- **Table Audit**: 50
|
|
40
|
+
* Audit with a table
|
|
41
|
+
|
|
42
|
+
| URL | Wasted Bytes | Node | Location |
|
|
43
|
+
| https://example.com/script.js | 1024 | div.main (path: 1,HTML,1,BODY,5,DIV) | https://example.com/script.js:10:5 |
|
|
44
|
+
| https://example.com/style.css | 512 | body > p (selector: body > p) (path: 1,HTML,1,BODY,10,P) | https://example.com/style.css |
|
|
45
|
+
=== end content
|
|
46
|
+
|
|
47
|
+
Title: LighthouseFormatter formats opportunity details
|
|
48
|
+
Content:
|
|
49
|
+
# Audits for Performance
|
|
50
|
+
|
|
51
|
+
The following audits in this category have a score below 90 and may need attention:
|
|
52
|
+
- **Opportunity Audit**: 50
|
|
53
|
+
* Audit with an opportunity
|
|
54
|
+
|
|
55
|
+
Potential savings: 500ms, Potential savings: 2048 bytes
|
|
56
|
+
| URL | Wasted Bytes |
|
|
57
|
+
| https://example.com/large-script.js | 2048 |
|
|
58
|
+
=== end content
|
|
59
|
+
|
|
60
|
+
Title: LighthouseFormatter formats table details with summary
|
|
61
|
+
Content:
|
|
62
|
+
# Audits for Performance
|
|
63
|
+
|
|
64
|
+
The following audits in this category have a score below 90 and may need attention:
|
|
65
|
+
- **Summary Audit**: 50
|
|
66
|
+
* Audit with a table summary
|
|
67
|
+
|
|
68
|
+
Wasted time: 100ms
|
|
69
|
+
Wasted bytes: 512
|
|
70
|
+
| Text |
|
|
71
|
+
| Some detail |
|
|
72
|
+
=== end content
|
|
73
|
+
|
|
74
|
+
Title: LighthouseFormatter formats landmark-one-main audit with node explanation
|
|
75
|
+
Content:
|
|
76
|
+
# Audits for Accessibility
|
|
77
|
+
|
|
78
|
+
The following audits in this category have a score below 90 and may need attention:
|
|
79
|
+
- **Document does not have a main landmark.**: 0
|
|
80
|
+
* One main landmark helps screen reader users navigate a web page. [Learn more about landmarks](https://dequeuniversity.com/rules/axe/4.11/landmark-one-main).
|
|
81
|
+
|
|
82
|
+
| Failing Elements |
|
|
83
|
+
| html (selector: html) (path: 1,HTML) (explanation: Fix all of the following: Document does not have a main landmark) |
|
|
84
|
+
=== end content
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// Copyright 2026 The Chromium Authors
|
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
import type * as LHModel from '../../lighthouse/lighthouse.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A formatter that takes a raw Lighthouse report JSON and creates a markdown
|
|
9
|
+
* summary for an AI Agent.
|
|
10
|
+
*/
|
|
11
|
+
export class LighthouseFormatter {
|
|
12
|
+
/**
|
|
13
|
+
* Returns an overall summary and high-level overview of the Lighthouse report.
|
|
14
|
+
*/
|
|
15
|
+
summary(report: LHModel.ReporterTypes.ReportJSON): string {
|
|
16
|
+
const lines: string[] = [];
|
|
17
|
+
lines.push('# Lighthouse Report Summary');
|
|
18
|
+
lines.push(`URL: ${report.finalDisplayedUrl}`);
|
|
19
|
+
lines.push(`Fetch Time: ${report.fetchTime}`);
|
|
20
|
+
lines.push(`Lighthouse Version: ${report.lighthouseVersion}`);
|
|
21
|
+
lines.push('');
|
|
22
|
+
lines.push('## Category Scores');
|
|
23
|
+
for (const category of Object.values(report.categories)) {
|
|
24
|
+
const score = category.score !== null ? Math.round(category.score * 100) : 'n/a';
|
|
25
|
+
lines.push(`- ${category.title}: ${score}`);
|
|
26
|
+
}
|
|
27
|
+
return lines.join('\n');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Returns a markdown list of all audits in a given category.
|
|
32
|
+
* Highlight failing audits (score < 90).
|
|
33
|
+
*/
|
|
34
|
+
audits(report: LHModel.ReporterTypes.ReportJSON, categoryId: LHModel.RunTypes.CategoryId): string {
|
|
35
|
+
const category = report.categories[categoryId];
|
|
36
|
+
if (!category) {
|
|
37
|
+
return `Category "${categoryId}" not found.`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const lines: string[] = [];
|
|
41
|
+
lines.push(`# Audits for ${category.title}`);
|
|
42
|
+
if (category.description) {
|
|
43
|
+
lines.push(`${category.description.replace(/\n/g, ' ')}`);
|
|
44
|
+
}
|
|
45
|
+
lines.push('');
|
|
46
|
+
|
|
47
|
+
const failingAudits = category.auditRefs.filter(ref => {
|
|
48
|
+
const audit = report.audits[ref.id];
|
|
49
|
+
return audit && audit.score !== null && audit.score < 0.9;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
if (failingAudits.length === 0) {
|
|
53
|
+
lines.push('All audits in this category passed (score >= 90).');
|
|
54
|
+
return lines.join('\n');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
lines.push('The following audits in this category have a score below 90 and may need attention:');
|
|
58
|
+
for (const ref of failingAudits) {
|
|
59
|
+
const audit = report.audits[ref.id];
|
|
60
|
+
if (!audit) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const score = audit.score !== null ? Math.round(audit.score * 100) : 'n/a';
|
|
64
|
+
let line = `- **${audit.title}**: ${score}`;
|
|
65
|
+
if (audit.displayValue) {
|
|
66
|
+
line += ` (${audit.displayValue})`;
|
|
67
|
+
}
|
|
68
|
+
lines.push(line);
|
|
69
|
+
lines.push(` * ${audit.description.replace(/\n/g, ' ')}`);
|
|
70
|
+
if (audit.details) {
|
|
71
|
+
const formattedDetails = this.#formatDetails(audit.details);
|
|
72
|
+
if (formattedDetails) {
|
|
73
|
+
lines.push('');
|
|
74
|
+
lines.push(formattedDetails.split('\n').map(l => ` ${l}`).join('\n'));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return lines.join('\n');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
#formatDetails(details: LHModel.ReporterTypes.DetailsJSON): string {
|
|
83
|
+
switch (details.type) {
|
|
84
|
+
case 'table': {
|
|
85
|
+
const lines: string[] = [];
|
|
86
|
+
if (details.summary) {
|
|
87
|
+
const summaryParts = [];
|
|
88
|
+
// Purposefully rule out 0 because we want to skip if there is 0 wasted time.
|
|
89
|
+
if (details.summary.wastedMs) {
|
|
90
|
+
summaryParts.push(`Wasted time: ${details.summary.wastedMs}ms`);
|
|
91
|
+
}
|
|
92
|
+
// Purposefully rule out 0 because we want to skip if there is 0 wasted time.
|
|
93
|
+
if (details.summary.wastedBytes) {
|
|
94
|
+
summaryParts.push(`Wasted bytes: ${details.summary.wastedBytes}`);
|
|
95
|
+
}
|
|
96
|
+
if (summaryParts.length > 0) {
|
|
97
|
+
lines.push(summaryParts.join('\n'));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
lines.push(this.#formatTable(details.headings, details.items));
|
|
101
|
+
return lines.join('\n');
|
|
102
|
+
}
|
|
103
|
+
case 'opportunity': {
|
|
104
|
+
const lines: string[] = [];
|
|
105
|
+
const summaryParts = [];
|
|
106
|
+
if (details.overallSavingsMs) {
|
|
107
|
+
summaryParts.push(`Potential savings: ${details.overallSavingsMs}ms`);
|
|
108
|
+
}
|
|
109
|
+
if (details.overallSavingsBytes) {
|
|
110
|
+
summaryParts.push(`Potential savings: ${details.overallSavingsBytes} bytes`);
|
|
111
|
+
}
|
|
112
|
+
if (summaryParts.length > 0) {
|
|
113
|
+
lines.push(summaryParts.join(', '));
|
|
114
|
+
}
|
|
115
|
+
lines.push(this.#formatTable(details.headings, details.items));
|
|
116
|
+
return lines.join('\n');
|
|
117
|
+
}
|
|
118
|
+
default:
|
|
119
|
+
return '';
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
#formatTable(headings: LHModel.ReporterTypes.TableHeadingJSON[], items: Array<Record<string, unknown>>): string {
|
|
124
|
+
const lines: string[] = [];
|
|
125
|
+
lines.push(`| ${headings.map(h => h.label).join(' | ')} |`);
|
|
126
|
+
for (const item of items) {
|
|
127
|
+
const row = headings.map(h => this.#formatTableValue(item[h.key] as LHModel.ReporterTypes.TableItemValue));
|
|
128
|
+
lines.push(`| ${row.join(' | ')} |`);
|
|
129
|
+
}
|
|
130
|
+
return lines.join('\n');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
#formatTableValue(value: LHModel.ReporterTypes.TableItemValue|undefined): string {
|
|
134
|
+
if (value === undefined || value === null) {
|
|
135
|
+
return '';
|
|
136
|
+
}
|
|
137
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
138
|
+
return String(value);
|
|
139
|
+
}
|
|
140
|
+
if (typeof value === 'object' && 'type' in value) {
|
|
141
|
+
switch (value.type) {
|
|
142
|
+
case 'node': {
|
|
143
|
+
let label = value.nodeLabel || value.selector || value.snippet || '(node)';
|
|
144
|
+
if (value.selector) {
|
|
145
|
+
label += ` (selector: ${value.selector})`;
|
|
146
|
+
}
|
|
147
|
+
if (value.path) {
|
|
148
|
+
label += ` (path: ${value.path})`;
|
|
149
|
+
}
|
|
150
|
+
if (value.explanation) {
|
|
151
|
+
label += ` (explanation: ${value.explanation.replace(/\n/g, ' ')})`;
|
|
152
|
+
}
|
|
153
|
+
return label;
|
|
154
|
+
}
|
|
155
|
+
case 'source-location': {
|
|
156
|
+
const parts = [];
|
|
157
|
+
if (value.url) {
|
|
158
|
+
parts.push(value.url);
|
|
159
|
+
}
|
|
160
|
+
if (value.line) {
|
|
161
|
+
parts.push(String(value.line));
|
|
162
|
+
}
|
|
163
|
+
if (value.column) {
|
|
164
|
+
parts.push(String(value.column));
|
|
165
|
+
}
|
|
166
|
+
return parts.join(':');
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return '';
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -19,7 +19,7 @@ const INITIAL_RESTORE_BREAKPOINT_COUNT = 100;
|
|
|
19
19
|
|
|
20
20
|
export class BreakpointManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes> implements
|
|
21
21
|
SDK.TargetManager.SDKModelObserver<SDK.DebuggerModel.DebuggerModel> {
|
|
22
|
-
readonly storage
|
|
22
|
+
readonly storage: Storage;
|
|
23
23
|
readonly #workspace: Workspace.Workspace.WorkspaceImpl;
|
|
24
24
|
readonly targetManager: SDK.TargetManager.TargetManager;
|
|
25
25
|
readonly debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding;
|
|
@@ -38,11 +38,12 @@ export class BreakpointManager extends Common.ObjectWrapper.ObjectWrapper<EventT
|
|
|
38
38
|
private constructor(
|
|
39
39
|
targetManager: SDK.TargetManager.TargetManager, workspace: Workspace.Workspace.WorkspaceImpl,
|
|
40
40
|
debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding,
|
|
41
|
-
restoreInitialBreakpointCount?: number) {
|
|
41
|
+
settings: Common.Settings.Settings, restoreInitialBreakpointCount?: number) {
|
|
42
42
|
super();
|
|
43
43
|
this.#workspace = workspace;
|
|
44
44
|
this.targetManager = targetManager;
|
|
45
45
|
this.debuggerWorkspaceBinding = debuggerWorkspaceBinding;
|
|
46
|
+
this.storage = new Storage(settings);
|
|
46
47
|
|
|
47
48
|
this.storage.mute();
|
|
48
49
|
this.#setInitialBreakpoints(restoreInitialBreakpointCount ?? INITIAL_RESTORE_BREAKPOINT_COUNT);
|
|
@@ -73,18 +74,26 @@ export class BreakpointManager extends Common.ObjectWrapper.ObjectWrapper<EventT
|
|
|
73
74
|
targetManager: SDK.TargetManager.TargetManager|null,
|
|
74
75
|
workspace: Workspace.Workspace.WorkspaceImpl|null,
|
|
75
76
|
debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding|null,
|
|
77
|
+
settings: Common.Settings.Settings|null,
|
|
76
78
|
restoreInitialBreakpointCount?: number,
|
|
77
|
-
} = {
|
|
78
|
-
|
|
79
|
+
} = {
|
|
80
|
+
forceNew: null,
|
|
81
|
+
targetManager: null,
|
|
82
|
+
workspace: null,
|
|
83
|
+
debuggerWorkspaceBinding: null,
|
|
84
|
+
settings: null,
|
|
85
|
+
}): BreakpointManager {
|
|
86
|
+
const {forceNew, targetManager, workspace, debuggerWorkspaceBinding, settings, restoreInitialBreakpointCount} =
|
|
87
|
+
opts;
|
|
79
88
|
if (!breakpointManagerInstance || forceNew) {
|
|
80
|
-
if (!targetManager || !workspace || !debuggerWorkspaceBinding) {
|
|
89
|
+
if (!targetManager || !workspace || !debuggerWorkspaceBinding || !settings) {
|
|
81
90
|
throw new Error(
|
|
82
|
-
`Unable to create settings: targetManager, workspace, and
|
|
91
|
+
`Unable to create settings: targetManager, workspace, debuggerWorkspaceBinding, and settings must be provided: ${
|
|
83
92
|
new Error().stack}`);
|
|
84
93
|
}
|
|
85
94
|
|
|
86
|
-
breakpointManagerInstance =
|
|
87
|
-
|
|
95
|
+
breakpointManagerInstance = new BreakpointManager(
|
|
96
|
+
targetManager, workspace, debuggerWorkspaceBinding, settings, restoreInitialBreakpointCount);
|
|
88
97
|
}
|
|
89
98
|
|
|
90
99
|
return breakpointManagerInstance;
|
|
@@ -986,8 +995,7 @@ export class ModelBreakpoint {
|
|
|
986
995
|
const {lineNumber: uiLineNumber, columnNumber: uiColumnNumber} =
|
|
987
996
|
BreakpointManager.uiLocationFromBreakpointLocation(uiSourceCode, lineNumber, columnNumber);
|
|
988
997
|
const locations =
|
|
989
|
-
await
|
|
990
|
-
uiSourceCode, uiLineNumber, uiColumnNumber);
|
|
998
|
+
await this.#debuggerWorkspaceBinding.uiLocationToRawLocations(uiSourceCode, uiLineNumber, uiColumnNumber);
|
|
991
999
|
debuggerLocations = locations.filter(location => location.debuggerModel === this.#debuggerModel);
|
|
992
1000
|
if (debuggerLocations.length) {
|
|
993
1001
|
break;
|
|
@@ -1248,8 +1256,8 @@ class Storage {
|
|
|
1248
1256
|
readonly breakpoints: Map<string, BreakpointStorageState>;
|
|
1249
1257
|
#muted: boolean;
|
|
1250
1258
|
|
|
1251
|
-
constructor() {
|
|
1252
|
-
this.setting =
|
|
1259
|
+
constructor(settings: Common.Settings.Settings) {
|
|
1260
|
+
this.setting = settings.createLocalSetting('breakpoints', []);
|
|
1253
1261
|
this.breakpoints = new Map();
|
|
1254
1262
|
this.#muted = false;
|
|
1255
1263
|
for (const breakpoint of this.setting.get()) {
|
|
@@ -680,7 +680,11 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
|
|
|
680
680
|
}
|
|
681
681
|
|
|
682
682
|
private applyUserAgent(userAgent: string, userAgentMetadata: Protocol.Emulation.UserAgentMetadata|null): void {
|
|
683
|
-
|
|
683
|
+
// When the user agent string is empty (e.g. custom desktop device without
|
|
684
|
+
// a UA override), metadata must also be cleared. The backend rejects
|
|
685
|
+
// setUserAgentOverride calls that provide metadata without a UA string.
|
|
686
|
+
SDK.NetworkManager.MultitargetNetworkManager.instance().setUserAgentOverride(
|
|
687
|
+
userAgent, userAgent ? userAgentMetadata : null);
|
|
684
688
|
}
|
|
685
689
|
|
|
686
690
|
private applyDeviceMetrics(
|
|
@@ -201,7 +201,8 @@ export class EmulatedDevice {
|
|
|
201
201
|
const rawUserAgent = (parseValue(json, 'user-agent', 'string') as string);
|
|
202
202
|
result.userAgent = SDK.NetworkManager.MultitargetNetworkManager.patchUserAgentWithChromeVersion(rawUserAgent);
|
|
203
203
|
|
|
204
|
-
|
|
204
|
+
const userAgentMetadata = parseValue(json, 'user-agent-metadata', 'object', null);
|
|
205
|
+
result.userAgentMetadata = result.userAgent ? userAgentMetadata : null;
|
|
205
206
|
|
|
206
207
|
const capabilities = parseValue(json, 'capabilities', 'object', []);
|
|
207
208
|
if (!Array.isArray(capabilities)) {
|
|
@@ -366,7 +367,7 @@ export class EmulatedDevice {
|
|
|
366
367
|
json['foldable-screen'] = this.isFoldableScreen;
|
|
367
368
|
json['show'] = this.#show;
|
|
368
369
|
|
|
369
|
-
if (this.userAgentMetadata) {
|
|
370
|
+
if (this.userAgent && this.userAgentMetadata) {
|
|
370
371
|
json['user-agent-metadata'] = this.userAgentMetadata;
|
|
371
372
|
}
|
|
372
373
|
|