chrome-devtools-frontend 1.0.1642845 → 1.0.1642899

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 (51) hide show
  1. package/SECURITY.md +1 -0
  2. package/front_end/core/host/UserMetrics.ts +2 -1
  3. package/front_end/core/sdk/CSSMatchedStyles.ts +55 -26
  4. package/front_end/core/sdk/CSSRule.ts +1 -0
  5. package/front_end/core/sdk/DebuggerModel.ts +5 -0
  6. package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +4 -3
  7. package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +4 -3
  8. package/front_end/models/ai_assistance/AiAgent2.ts +80 -16
  9. package/front_end/models/ai_assistance/AiConversation.ts +3 -2
  10. package/front_end/models/ai_assistance/README.md +8 -0
  11. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +50 -35
  12. package/front_end/models/ai_assistance/agents/AiAgent.ts +16 -0
  13. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +2 -2
  14. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +195 -147
  15. package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +0 -25
  16. package/front_end/models/ai_assistance/agents/StylingAgent.ts +24 -305
  17. package/front_end/models/ai_assistance/ai_assistance.ts +8 -0
  18. package/front_end/models/ai_assistance/contexts/DOMNodeContext.snapshot.txt +51 -0
  19. package/front_end/models/ai_assistance/contexts/DOMNodeContext.ts +200 -0
  20. package/front_end/models/ai_assistance/skills/styling.md +36 -2
  21. package/front_end/models/ai_assistance/tools/GetStyles.ts +137 -0
  22. package/front_end/models/ai_assistance/tools/Tool.ts +55 -0
  23. package/front_end/models/ai_assistance/tools/ToolRegistry.ts +34 -0
  24. package/front_end/models/lighthouse/LighthouseReporterTypes.ts +5 -0
  25. package/front_end/models/live-metrics/LiveMetrics.ts +24 -13
  26. package/front_end/models/stack_trace/DetailedErrorStackParser.ts +2 -2
  27. package/front_end/models/stack_trace/StackTrace.ts +4 -1
  28. package/front_end/models/stack_trace/StackTraceImpl.ts +9 -2
  29. package/front_end/models/stack_trace/StackTraceModel.ts +17 -4
  30. package/front_end/models/stack_trace/Trie.ts +1 -1
  31. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +19 -15
  32. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +16 -0
  33. package/front_end/panels/ai_assistance/components/ChatInput.ts +2 -2
  34. package/front_end/panels/application/DOMStorageItemsView.ts +4 -0
  35. package/front_end/panels/application/KeyValueStorageItemsView.ts +39 -7
  36. package/front_end/panels/common/ExtensionServer.ts +26 -15
  37. package/front_end/panels/elements/StandaloneStylesContainer.ts +1 -1
  38. package/front_end/panels/elements/StylePropertiesSection.ts +8 -0
  39. package/front_end/panels/elements/StylePropertyHighlighter.ts +4 -2
  40. package/front_end/panels/elements/StylePropertyTreeElement.ts +6 -5
  41. package/front_end/panels/elements/StylesContainer.ts +1 -1
  42. package/front_end/panels/elements/StylesSidebarPane.ts +4 -4
  43. package/front_end/panels/layer_viewer/PaintProfilerView.ts +106 -132
  44. package/front_end/panels/lighthouse/LighthousePanel.ts +4 -3
  45. package/front_end/panels/network/NetworkLogView.ts +3 -0
  46. package/front_end/panels/network/networkLogView.css +0 -15
  47. package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +36 -3
  48. package/front_end/ui/legacy/components/data_grid/dataGridAiButton.css +20 -0
  49. package/front_end/ui/legacy/components/utils/Linkifier.ts +19 -4
  50. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  51. package/package.json +1 -1
@@ -63,6 +63,12 @@ export type MainThreadSectionLabel = 'nav-to-lcp'|'lcp-ttfb'|'lcp-render-delay'|
63
63
  * chrome_preambles.gcl). Sync local changes with the server-side.
64
64
  */
65
65
 
66
+ const SECURITY_WARNING = `**CRITICAL CONSTRAINT**: This performance trace was loaded from a file and is static.
67
+ You do NOT have access to the live page.
68
+ The tool \`getFunctionCode\` is disabled.
69
+ Do NOT attempt to use it or instruct the user that you will use it.
70
+ Rely only on the trace data and other available tools.`;
71
+
66
72
  const GREEN_DEV_ANNOTATIONS_INSTRUCTIONS = `
67
73
  - CRITICAL: You also have access to functions called addElementAnnotation and addNeworkRequestAnnotation,
68
74
  which should be used to highlight elements and network requests (respectively).
@@ -239,7 +245,6 @@ export class PerformanceTraceContext extends ConversationContext<AgentFocus> {
239
245
  }
240
246
 
241
247
  #focus: AgentFocus;
242
- external = false;
243
248
 
244
249
  constructor(focus: AgentFocus) {
245
250
  super();
@@ -456,7 +461,7 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
456
461
  * so we can show it in the disclosure UI. This is cleared and then populated
457
462
  * on each prompt.
458
463
  */
459
- #additionalSelectionsForQuery: string[] = [];
464
+ #additionalSelectionsForDisclosure: string[] = [];
460
465
 
461
466
  get clientFeature(): Host.AidaClient.ClientFeature {
462
467
  return Host.AidaClient.ClientFeature.CHROME_PERFORMANCE_FULL_AGENT;
@@ -490,7 +495,7 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
490
495
  }
491
496
  contextDisclosure.push(fact.text);
492
497
  }
493
- contextDisclosure.push(...this.#additionalSelectionsForQuery);
498
+ contextDisclosure.push(...this.#additionalSelectionsForDisclosure);
494
499
 
495
500
  const focus = context.getItem();
496
501
  const widgets = this.#getWidgetsForFocus(focus);
@@ -705,13 +710,18 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
705
710
  }
706
711
  }
707
712
 
708
- this.#additionalSelectionsForQuery = selected;
713
+ const isFresh = Tracing.FreshRecording.Tracker.instance().recordingIsFresh(focus.parsedTrace);
714
+
709
715
  if (!selected.length) {
710
- return query;
716
+ this.#additionalSelectionsForDisclosure = [];
717
+ const finalQuery = query;
718
+ return isFresh ? finalQuery : `${SECURITY_WARNING}\n\n${finalQuery}`;
711
719
  }
712
720
 
713
721
  selected.push(`# User query\n\n${query}`);
714
- return selected.join('');
722
+ this.#additionalSelectionsForDisclosure = [...selected];
723
+ const finalQuery = selected.join('');
724
+ return isFresh ? finalQuery : `${SECURITY_WARNING}\n\n${finalQuery}`;
715
725
  }
716
726
 
717
727
  override async * run(initialQuery: string, options: {
@@ -818,9 +828,7 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
818
828
  async #addFacts(context: PerformanceTraceContext): Promise<void> {
819
829
  const focus = context.getItem();
820
830
 
821
- if (!context.external) {
822
- this.addFact(this.#notExternalExtraPreambleFact);
823
- }
831
+ this.addFact(this.#notExternalExtraPreambleFact);
824
832
 
825
833
  const annotationsEnabled = Annotations.AnnotationRepository.annotationsEnabled();
826
834
  if (annotationsEnabled) {
@@ -847,7 +855,7 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
847
855
  this.#formatter = new PerformanceTraceFormatter(focus);
848
856
  this.#formatter.resolveFunctionCode =
849
857
  async (url: Platform.DevToolsPath.UrlString, line: number, column: number) => {
850
- if (!target) {
858
+ if (!target || !isFresh) {
851
859
  return null;
852
860
  }
853
861
 
@@ -932,6 +940,7 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
932
940
  #declareFunctions(context: PerformanceTraceContext): void {
933
941
  const focus = context.getItem();
934
942
  const {parsedTrace} = focus;
943
+ const isFresh = Tracing.FreshRecording.Tracker.instance().recordingIsFresh(parsedTrace);
935
944
 
936
945
  this.declareFunction<{insightSetId: string, insightName: string}, {details: string}>('getInsightDetails', {
937
946
  description:
@@ -1070,35 +1079,7 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
1070
1079
  }
1071
1080
 
1072
1081
  // TODO(b/425270067): Format in the same way that "Summary" detail tab does.
1073
- let details;
1074
- if (Trace.Types.Events.isSyntheticNetworkRequest(event)) {
1075
- const eventToSerialize = {
1076
- ...event,
1077
- args: {
1078
- ...event.args,
1079
- data: {
1080
- ...event.args.data,
1081
- responseHeaders: event.args.data.responseHeaders ? sanitizeHeaders(event.args.data.responseHeaders) :
1082
- null,
1083
- },
1084
- },
1085
- };
1086
- details = JSON.stringify(eventToSerialize);
1087
- } else if (Trace.Types.Events.isResourceReceiveResponse(event)) {
1088
- const eventToSerialize = {
1089
- ...event,
1090
- args: {
1091
- ...event.args,
1092
- data: {
1093
- ...event.args.data,
1094
- headers: event.args.data.headers ? sanitizeHeaders(event.args.data.headers) : undefined,
1095
- },
1096
- },
1097
- };
1098
- details = JSON.stringify(eventToSerialize);
1099
- } else {
1100
- details = JSON.stringify(event);
1101
- }
1082
+ const details = formatEventForAI(event);
1102
1083
 
1103
1084
  const key = `getEventByKey('${params.eventKey}')`;
1104
1085
  this.#cacheFunctionResult(focus, key, details);
@@ -1359,84 +1340,85 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
1359
1340
  });
1360
1341
  }
1361
1342
 
1362
- this.declareFunction<{scriptUrl: UrlString, line: number, column: number}, {result: string}>('getFunctionCode', {
1363
- description:
1364
- 'Returns the code for a function defined at the given location. The result is annotated with the runtime performance of each line of code.',
1365
- parameters: {
1366
- type: Host.AidaClient.ParametersTypes.OBJECT,
1367
- description: '',
1368
- nullable: false,
1369
- properties: {
1370
- scriptUrl: {
1371
- type: Host.AidaClient.ParametersTypes.STRING,
1372
- description: 'The url of the function.',
1373
- nullable: false,
1374
- },
1375
- line: {
1376
- type: Host.AidaClient.ParametersTypes.INTEGER,
1377
- description: 'The line number where the function is defined.',
1378
- nullable: false,
1379
- },
1380
- column: {
1381
- type: Host.AidaClient.ParametersTypes.INTEGER,
1382
- description: 'The column number where the function is defined.',
1383
- nullable: false,
1343
+ if (isFresh) {
1344
+ this.declareFunction<{scriptUrl: UrlString, line: number, column: number}, {result: string}>('getFunctionCode', {
1345
+ description:
1346
+ 'Returns the code for a function defined at the given location. The result is annotated with the runtime performance of each line of code.',
1347
+ parameters: {
1348
+ type: Host.AidaClient.ParametersTypes.OBJECT,
1349
+ description: '',
1350
+ nullable: false,
1351
+ properties: {
1352
+ scriptUrl: {
1353
+ type: Host.AidaClient.ParametersTypes.STRING,
1354
+ description: 'The url of the function.',
1355
+ nullable: false,
1356
+ },
1357
+ line: {
1358
+ type: Host.AidaClient.ParametersTypes.INTEGER,
1359
+ description: 'The line number where the function is defined.',
1360
+ nullable: false,
1361
+ },
1362
+ column: {
1363
+ type: Host.AidaClient.ParametersTypes.INTEGER,
1364
+ description: 'The column number where the function is defined.',
1365
+ nullable: false,
1366
+ },
1384
1367
  },
1368
+ required: ['scriptUrl', 'line', 'column']
1385
1369
  },
1386
- required: ['scriptUrl', 'line', 'column']
1387
- },
1388
- displayInfoFromArgs: args => {
1389
- return {
1390
- title: lockedString('Looking up function code'),
1391
- action: `getFunctionCode('${args.scriptUrl}', ${args.line}, ${args.column})`
1392
- };
1393
- },
1394
- handler: async args => {
1395
- debugLog('Function call: getFunctionCode');
1370
+ displayInfoFromArgs: args => {
1371
+ return {
1372
+ title: lockedString('Looking up function code'),
1373
+ action: `getFunctionCode('${args.scriptUrl}', ${args.line}, ${args.column})`
1374
+ };
1375
+ },
1376
+ handler: async args => {
1377
+ debugLog('Function call: getFunctionCode');
1396
1378
 
1397
- if (args.line === undefined) {
1398
- return {error: 'Missing arg: line'};
1399
- }
1379
+ if (args.line === undefined) {
1380
+ return {error: 'Missing arg: line'};
1381
+ }
1400
1382
 
1401
- if (args.column === undefined) {
1402
- return {error: 'Missing arg: column'};
1403
- }
1383
+ if (args.column === undefined) {
1384
+ return {error: 'Missing arg: column'};
1385
+ }
1404
1386
 
1405
- if (!this.#formatter) {
1406
- throw new Error('missing formatter');
1407
- }
1387
+ if (!this.#formatter) {
1388
+ throw new Error('missing formatter');
1389
+ }
1408
1390
 
1409
- const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
1410
- if (!target) {
1411
- throw new Error('missing target');
1412
- }
1391
+ const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
1392
+ if (!target) {
1393
+ throw new Error('missing target');
1394
+ }
1413
1395
 
1414
- const url = args.scriptUrl as Platform.DevToolsPath.UrlString;
1415
- const code = await this.#formatter.resolveFunctionCodeAtLocation(url, args.line, args.column);
1416
- if (!code) {
1417
- return {error: 'Could not find code'};
1418
- }
1396
+ const url = args.scriptUrl as Platform.DevToolsPath.UrlString;
1397
+ const code = await this.#formatter.resolveFunctionCodeAtLocation(url, args.line, args.column);
1398
+ if (!code) {
1399
+ return {error: 'Could not find code'};
1400
+ }
1419
1401
 
1420
- const result = this.#formatter.formatFunctionCode(code);
1402
+ const result = this.#formatter.formatFunctionCode(code);
1421
1403
 
1422
- const key = `getFunctionCode('${args.scriptUrl}', ${args.line}, ${args.column})`;
1423
- this.#cacheFunctionResult(focus, key, result);
1424
- return {
1425
- result: {result},
1426
- widgets: [{
1427
- name: 'SOURCE_CODE',
1428
- data: {
1429
- url: args.scriptUrl,
1430
- line: args.line,
1431
- column: args.column,
1432
- code: code.code,
1433
- },
1434
- }],
1435
- };
1436
- },
1437
- });
1404
+ const key = `getFunctionCode('${args.scriptUrl}', ${args.line}, ${args.column})`;
1405
+ this.#cacheFunctionResult(focus, key, result);
1406
+ return {
1407
+ result: {result},
1408
+ widgets: [{
1409
+ name: 'SOURCE_CODE',
1410
+ data: {
1411
+ url: args.scriptUrl,
1412
+ line: args.line,
1413
+ column: args.column,
1414
+ code: code.code,
1415
+ },
1416
+ }],
1417
+ };
1418
+ },
1419
+ });
1420
+ }
1438
1421
 
1439
- const isFresh = Tracing.FreshRecording.Tracker.instance().recordingIsFresh(parsedTrace);
1440
1422
  const isTraceApp = Root.Runtime.Runtime.isTraceApp();
1441
1423
 
1442
1424
  this.declareFunction<{url: UrlString}, {content: string}>('getResourceContent', {
@@ -1502,48 +1484,46 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
1502
1484
  },
1503
1485
  });
1504
1486
 
1505
- if (!context.external) {
1506
- this.declareFunction<{eventKey: string}, {success: boolean}>('selectEventByKey', {
1507
- description:
1508
- 'Selects the event in the flamechart for the user. If the user asks to show them something, it\'s likely a good idea to call this function.',
1509
- parameters: {
1510
- type: Host.AidaClient.ParametersTypes.OBJECT,
1511
- description: '',
1512
- nullable: false,
1513
- properties: {
1514
- eventKey: {
1515
- type: Host.AidaClient.ParametersTypes.STRING,
1516
- description: 'The key for the event.',
1517
- nullable: false,
1518
- }
1519
- },
1520
- required: ['eventKey']
1521
- },
1522
- displayInfoFromArgs: params => {
1523
- return {title: lockedString('Selecting event'), action: `selectEventByKey('${params.eventKey}')`};
1524
- },
1525
- handler: async params => {
1526
- debugLog('Function call: selectEventByKey', params);
1527
- const event = focus.lookupEvent(params.eventKey);
1528
- if (!event) {
1529
- return {error: 'Invalid eventKey'};
1487
+ this.declareFunction<{eventKey: string}, {success: boolean}>('selectEventByKey', {
1488
+ description:
1489
+ 'Selects the event in the flamechart for the user. If the user asks to show them something, it\'s likely a good idea to call this function.',
1490
+ parameters: {
1491
+ type: Host.AidaClient.ParametersTypes.OBJECT,
1492
+ description: '',
1493
+ nullable: false,
1494
+ properties: {
1495
+ eventKey: {
1496
+ type: Host.AidaClient.ParametersTypes.STRING,
1497
+ description: 'The key for the event.',
1498
+ nullable: false,
1530
1499
  }
1531
-
1532
- const revealable = new SDK.TraceObject.RevealableEvent(event);
1533
- await Common.Revealer.reveal(revealable);
1534
- return {
1535
- result: {success: true},
1536
- widgets: [{
1537
- name: 'TIMELINE_EVENT_SUMMARY',
1538
- data: {
1539
- event,
1540
- parsedTrace,
1541
- },
1542
- }],
1543
- };
1544
1500
  },
1545
- });
1546
- }
1501
+ required: ['eventKey']
1502
+ },
1503
+ displayInfoFromArgs: params => {
1504
+ return {title: lockedString('Selecting event'), action: `selectEventByKey('${params.eventKey}')`};
1505
+ },
1506
+ handler: async params => {
1507
+ debugLog('Function call: selectEventByKey', params);
1508
+ const event = focus.lookupEvent(params.eventKey);
1509
+ if (!event) {
1510
+ return {error: 'Invalid eventKey'};
1511
+ }
1512
+
1513
+ const revealable = new SDK.TraceObject.RevealableEvent(event);
1514
+ await Common.Revealer.reveal(revealable);
1515
+ return {
1516
+ result: {success: true},
1517
+ widgets: [{
1518
+ name: 'TIMELINE_EVENT_SUMMARY',
1519
+ data: {
1520
+ event,
1521
+ parsedTrace,
1522
+ },
1523
+ }],
1524
+ };
1525
+ },
1526
+ });
1547
1527
  }
1548
1528
 
1549
1529
  #getBoundsForLabel(label: MainThreadSectionLabel, focus: AgentFocus): Trace.Types.Timing.TraceWindowMicro|null {
@@ -1669,3 +1649,71 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
1669
1649
  return undefined;
1670
1650
  }
1671
1651
  }
1652
+
1653
+ /**
1654
+ * Serializes a trace event to a JSON string for AI consumption,
1655
+ * ensuring sensitive data (like headers and raw script source code)
1656
+ * is sanitized or redacted.
1657
+ */
1658
+ function formatEventForAI(event: Trace.Types.Events.Event): string {
1659
+ if (Trace.Types.Events.isSyntheticNetworkRequest(event)) {
1660
+ return JSON.stringify({
1661
+ ...event,
1662
+ args: {
1663
+ ...event.args,
1664
+ data: {
1665
+ ...event.args.data,
1666
+ responseHeaders: event.args.data.responseHeaders ? sanitizeHeaders(event.args.data.responseHeaders) : null,
1667
+ },
1668
+ },
1669
+ });
1670
+ }
1671
+
1672
+ if (Trace.Types.Events.isResourceReceiveResponse(event)) {
1673
+ return JSON.stringify({
1674
+ ...event,
1675
+ args: {
1676
+ ...event.args,
1677
+ data: {
1678
+ ...event.args.data,
1679
+ headers: event.args.data.headers ? sanitizeHeaders(event.args.data.headers) : undefined,
1680
+ },
1681
+ },
1682
+ });
1683
+ }
1684
+
1685
+ if (Trace.Types.Events.isRundownScriptSource(event)) {
1686
+ // Redact sensitive cross-origin script source text.
1687
+ const safeData: Omit<Trace.Types.Events.RundownScriptSource['args']['data'], 'sourceText'> = {
1688
+ isolate: event.args.data.isolate,
1689
+ scriptId: event.args.data.scriptId,
1690
+ length: event.args.data.length,
1691
+ };
1692
+ return JSON.stringify({
1693
+ ...event,
1694
+ args: {
1695
+ ...event.args,
1696
+ data: safeData,
1697
+ },
1698
+ });
1699
+ }
1700
+
1701
+ if (Trace.Types.Events.isRundownScriptSourceLarge(event)) {
1702
+ // Redact sensitive cross-origin script source text.
1703
+ const safeData: Omit<Trace.Types.Events.RundownScriptSourceLarge['args']['data'], 'sourceText'> = {
1704
+ isolate: event.args.data.isolate,
1705
+ scriptId: event.args.data.scriptId,
1706
+ splitIndex: event.args.data.splitIndex,
1707
+ splitCount: event.args.data.splitCount,
1708
+ };
1709
+ return JSON.stringify({
1710
+ ...event,
1711
+ args: {
1712
+ ...event.args,
1713
+ data: safeData,
1714
+ },
1715
+ });
1716
+ }
1717
+
1718
+ return JSON.stringify(event);
1719
+ }
@@ -1,28 +1,3 @@
1
- Title: StylingAgent describeElement should describe an element with no children, siblings, or parent
2
- Content:
3
- * Element's uid is 99.
4
- * Its selector is `div#myElement`
5
- === end content
6
-
7
- Title: StylingAgent describeElement should describe an element with child element and text nodes
8
- Content:
9
- * Element's uid is 99.
10
- * Its selector is `div#parentElement`
11
- * It has 2 child element nodes: `span.child1` (uid=undefined), `span.child2` (uid=undefined)
12
- * It only has 1 child text node
13
- === end content
14
-
15
- Title: StylingAgent describeElement should describe an element with siblings and a parent
16
- Content:
17
- * Element's uid is 99.
18
- * Its selector is `div#parentElement`
19
- * It has a next sibling and it is an element (uid=undefined) node
20
- * It has a previous sibling and it is a non element node
21
- * Its parent's selector is `div#grandparentElement` (uid=undefined)
22
- * Its parent is a non element node
23
- * Its parent has only 1 child element node
24
- * Its parent has only 1 child text node
25
- === end content
26
1
 
27
2
  Title: StylingAgent buildRequest structure matches the snapshot
28
3
  Content: