chrome-devtools-frontend 1.0.1642845 → 1.0.1643099

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 (128) hide show
  1. package/SECURITY.md +1 -0
  2. package/front_end/core/host/UserMetrics.ts +2 -1
  3. package/front_end/core/protocol_client/InspectorBackend.ts +4 -0
  4. package/front_end/core/sdk/CSSMatchedStyles.ts +55 -26
  5. package/front_end/core/sdk/CSSRule.ts +1 -0
  6. package/front_end/core/sdk/DebuggerModel.ts +5 -0
  7. package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +4 -3
  8. package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +4 -3
  9. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +4 -5
  10. package/front_end/generated/InspectorBackendCommands.ts +1 -1
  11. package/front_end/generated/protocol.ts +7 -0
  12. package/front_end/models/ai_assistance/AiAgent2.ts +100 -18
  13. package/front_end/models/ai_assistance/AiConversation.ts +18 -14
  14. package/front_end/models/ai_assistance/AiUtils.ts +71 -0
  15. package/front_end/models/ai_assistance/ChangeManager.ts +2 -5
  16. package/front_end/models/ai_assistance/{agents/ConversationSummaryAgent.ts → ConversationSummary.ts} +29 -66
  17. package/front_end/models/ai_assistance/ExtensionScope.ts +1 -4
  18. package/front_end/models/ai_assistance/{agents/PerformanceAnnotationsAgent.ts → PerformanceAnnotations.ts} +47 -89
  19. package/front_end/models/ai_assistance/README.md +8 -0
  20. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +65 -40
  21. package/front_end/models/ai_assistance/agents/AiAgent.ts +37 -6
  22. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +11 -0
  23. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +55 -5
  24. package/front_end/models/ai_assistance/agents/ExecuteJavascript.ts +2 -0
  25. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +119 -78
  26. package/front_end/models/ai_assistance/agents/StorageAgent.ts +47 -38
  27. package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +0 -25
  28. package/front_end/models/ai_assistance/agents/StylingAgent.ts +46 -326
  29. package/front_end/models/ai_assistance/ai_assistance.ts +14 -4
  30. package/front_end/models/ai_assistance/contexts/DOMNodeContext.snapshot.txt +51 -0
  31. package/front_end/models/ai_assistance/contexts/DOMNodeContext.ts +200 -0
  32. package/front_end/models/ai_assistance/skills/styling.md +44 -2
  33. package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +140 -0
  34. package/front_end/models/ai_assistance/tools/GetStyles.ts +141 -0
  35. package/front_end/models/ai_assistance/tools/Tool.ts +64 -0
  36. package/front_end/models/ai_assistance/tools/ToolRegistry.ts +36 -0
  37. package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +5 -7
  38. package/front_end/models/lighthouse/LighthouseReporterTypes.ts +5 -0
  39. package/front_end/models/live-metrics/LiveMetrics.ts +24 -13
  40. package/front_end/models/stack_trace/DetailedErrorStackParser.ts +2 -2
  41. package/front_end/models/stack_trace/StackTrace.ts +4 -1
  42. package/front_end/models/stack_trace/StackTraceImpl.ts +9 -2
  43. package/front_end/models/stack_trace/StackTraceModel.ts +17 -4
  44. package/front_end/models/stack_trace/Trie.ts +1 -1
  45. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +25 -22
  46. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +16 -0
  47. package/front_end/panels/ai_assistance/components/ChatInput.ts +2 -2
  48. package/front_end/panels/ai_assistance/components/ChatMessage.ts +96 -4
  49. package/front_end/panels/ai_assistance/components/chatMessage.css +6 -0
  50. package/front_end/panels/application/DOMStorageItemsView.ts +4 -0
  51. package/front_end/panels/application/KeyValueStorageItemsView.ts +39 -7
  52. package/front_end/panels/application/components/AdsView.ts +219 -0
  53. package/front_end/panels/application/components/adsView.css +54 -0
  54. package/front_end/panels/application/components/components.ts +2 -0
  55. package/front_end/panels/common/ExtensionServer.ts +26 -15
  56. package/front_end/panels/console/SymbolizedErrorWidget.ts +73 -22
  57. package/front_end/panels/elements/StandaloneStylesContainer.ts +1 -1
  58. package/front_end/panels/elements/StylePropertiesSection.ts +8 -0
  59. package/front_end/panels/elements/StylePropertyHighlighter.ts +4 -2
  60. package/front_end/panels/elements/StylePropertyTreeElement.ts +6 -5
  61. package/front_end/panels/elements/StylesContainer.ts +1 -1
  62. package/front_end/panels/elements/StylesSidebarPane.ts +4 -4
  63. package/front_end/panels/layer_viewer/PaintProfilerView.ts +106 -132
  64. package/front_end/panels/lighthouse/LighthousePanel.ts +4 -3
  65. package/front_end/panels/network/NetworkLogView.ts +8 -1
  66. package/front_end/panels/network/networkLogView.css +0 -15
  67. package/front_end/panels/timeline/overlays/components/EntryLabelOverlay.ts +5 -4
  68. package/front_end/third_party/chromium/README.chromium +1 -1
  69. package/front_end/third_party/lighthouse/README.chromium +2 -2
  70. package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +1607 -5733
  71. package/front_end/third_party/lighthouse/locales/ar-XB.json +290 -65
  72. package/front_end/third_party/lighthouse/locales/ar.json +290 -65
  73. package/front_end/third_party/lighthouse/locales/bg.json +290 -65
  74. package/front_end/third_party/lighthouse/locales/ca.json +295 -70
  75. package/front_end/third_party/lighthouse/locales/cs.json +290 -65
  76. package/front_end/third_party/lighthouse/locales/da.json +294 -69
  77. package/front_end/third_party/lighthouse/locales/de.json +295 -70
  78. package/front_end/third_party/lighthouse/locales/el.json +290 -65
  79. package/front_end/third_party/lighthouse/locales/en-GB.json +290 -65
  80. package/front_end/third_party/lighthouse/locales/en-US.json +79 -67
  81. package/front_end/third_party/lighthouse/locales/en-XA.json +253 -64
  82. package/front_end/third_party/lighthouse/locales/en-XL.json +79 -67
  83. package/front_end/third_party/lighthouse/locales/es-419.json +290 -65
  84. package/front_end/third_party/lighthouse/locales/es.json +298 -73
  85. package/front_end/third_party/lighthouse/locales/fi.json +290 -65
  86. package/front_end/third_party/lighthouse/locales/fil.json +290 -65
  87. package/front_end/third_party/lighthouse/locales/fr.json +294 -69
  88. package/front_end/third_party/lighthouse/locales/he.json +293 -68
  89. package/front_end/third_party/lighthouse/locales/hi.json +291 -66
  90. package/front_end/third_party/lighthouse/locales/hr.json +290 -65
  91. package/front_end/third_party/lighthouse/locales/hu.json +290 -65
  92. package/front_end/third_party/lighthouse/locales/id.json +290 -65
  93. package/front_end/third_party/lighthouse/locales/it.json +294 -69
  94. package/front_end/third_party/lighthouse/locales/ja.json +290 -65
  95. package/front_end/third_party/lighthouse/locales/ko.json +290 -65
  96. package/front_end/third_party/lighthouse/locales/lt.json +290 -65
  97. package/front_end/third_party/lighthouse/locales/lv.json +290 -65
  98. package/front_end/third_party/lighthouse/locales/nl.json +290 -65
  99. package/front_end/third_party/lighthouse/locales/no.json +290 -65
  100. package/front_end/third_party/lighthouse/locales/pl.json +290 -65
  101. package/front_end/third_party/lighthouse/locales/pt-PT.json +291 -66
  102. package/front_end/third_party/lighthouse/locales/pt.json +290 -65
  103. package/front_end/third_party/lighthouse/locales/ro.json +290 -65
  104. package/front_end/third_party/lighthouse/locales/ru.json +301 -76
  105. package/front_end/third_party/lighthouse/locales/sk.json +291 -66
  106. package/front_end/third_party/lighthouse/locales/sl.json +290 -65
  107. package/front_end/third_party/lighthouse/locales/sr-Latn.json +290 -65
  108. package/front_end/third_party/lighthouse/locales/sr.json +290 -65
  109. package/front_end/third_party/lighthouse/locales/sv.json +297 -72
  110. package/front_end/third_party/lighthouse/locales/ta.json +291 -66
  111. package/front_end/third_party/lighthouse/locales/te.json +293 -68
  112. package/front_end/third_party/lighthouse/locales/th.json +291 -66
  113. package/front_end/third_party/lighthouse/locales/tr.json +290 -65
  114. package/front_end/third_party/lighthouse/locales/uk.json +290 -65
  115. package/front_end/third_party/lighthouse/locales/vi.json +291 -66
  116. package/front_end/third_party/lighthouse/locales/zh-HK.json +292 -67
  117. package/front_end/third_party/lighthouse/locales/zh-TW.json +291 -66
  118. package/front_end/third_party/lighthouse/locales/zh.json +291 -66
  119. package/front_end/third_party/lighthouse/report/bundle.d.ts +6 -6
  120. package/front_end/third_party/lighthouse/report/bundle.js +4 -7
  121. package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +2 -2
  122. package/front_end/ui/legacy/Widget.ts +32 -8
  123. package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +36 -3
  124. package/front_end/ui/legacy/components/data_grid/dataGridAiButton.css +20 -0
  125. package/front_end/ui/legacy/components/utils/Linkifier.ts +19 -4
  126. package/front_end/ui/visual_logging/KnownContextValues.ts +3 -0
  127. package/mcp/mcp.ts +1 -0
  128. package/package.json +1 -1
@@ -6,6 +6,7 @@ import * as Common from '../../../core/common/common.js';
6
6
  import * as Host from '../../../core/host/host.js';
7
7
  import * as i18n from '../../../core/i18n/i18n.js';
8
8
  import * as Root from '../../../core/root/root.js';
9
+ import type {NetworkRequest} from '../../../core/sdk/NetworkRequest.js';
9
10
  import type * as SDK from '../../../core/sdk/sdk.js';
10
11
  import type * as LHModel from '../../lighthouse/lighthouse.js';
11
12
  import * as Logs from '../../logs/logs.js';
@@ -13,7 +14,9 @@ import * as NetworkTimeCalculator from '../../network_time_calculator/network_ti
13
14
  import type * as Trace from '../../trace/trace.js';
14
15
  import * as Workspace from '../../workspace/workspace.js';
15
16
  import {isOpaqueOrigin} from '../AiOrigins.js';
17
+ import {DOMNodeContext} from '../contexts/DOMNodeContext.js';
16
18
  import {debugLog} from '../debug.js';
19
+ import {StorageItem} from '../StorageItem.js';
17
20
 
18
21
  import {AccessibilityContext} from './AccessibilityAgent.js';
19
22
  import {
@@ -26,7 +29,7 @@ import {
26
29
  import {FileContext} from './FileAgent.js';
27
30
  import {RequestContext} from './NetworkAgent.js';
28
31
  import {PerformanceTraceContext} from './PerformanceAgent.js';
29
- import {NodeContext} from './StylingAgent.js';
32
+ import {StorageContext} from './StorageAgent.js';
30
33
 
31
34
  const lockedString = i18n.i18n.lockedString;
32
35
  /**
@@ -41,12 +44,12 @@ Your role is to understand the user's query, identify the appropriate specialize
41
44
 
42
45
  # Workflow
43
46
  1. **Analyze**: Understand the user's intent and what they are trying to achieve.
44
- 2. **Classify**: Determine which specialized agent is best suited for the task (e.g., StylingAgent for CSS/styling issues, NetworkAgent for network requests, FileAgent for source files, PerformanceAgent for performance details, AccessibilityAgent for accessibility reports, or StorageAgent for storage issues).
45
- 3. **Gather Context**: Identify what information the specialized agent will need. Proactively use your tools to find and select this context (e.g., finding the relevant DOM node, network request, file, or performance trace). Always try to select a single specific context before answering the question.
47
+ 2. **Classify**: Determine which specialized agent is best suited for the task (e.g., StylingAgent for CSS/styling issues, NetworkAgent for network requests, FileAgent for source files, PerformanceAgent for performance details, AccessibilityAgent for accessibility reports, or StorageAgent for analyzing and explaining storage but not editing).
48
+ 3. **Gather Context**: Identify what information the specialized agent will need. Proactively use your tools to find and select this context (e.g., finding the relevant DOM node, network request, file, performance trace, or storage). Always try to select a single specific context before answering the question.
46
49
  4. **Delegate**: Once context is selected, hand over to the specialized agent. If you are unable to delegate or gather more information, provide a comprehensive guide on how to fix the issue using Chrome DevTools, explaining how and why, or suggest any panel/flow that may help.
47
50
 
48
51
  # Considerations
49
- * Determine what is the domain of the question - styling, network, sources, performance or other part of DevTools.
52
+ * Determine what is the domain of the question - styling, network, sources, performance, storage, or other part of DevTools.
50
53
  * For questions about performance (e.g., general performance issues, page speed, performance metrics like LCP, INP, CLS), use performanceRecordAndReload to record a performance trace.
51
54
  * Proactively try to gather additional data. If a specific piece of data can be selected, select it.
52
55
  * Always try to select a single specific context before answering the question.
@@ -141,6 +144,7 @@ export class ContextSelectionAgent extends AiAgent<never> {
141
144
  }
142
145
 
143
146
  let hasCrossOriginRequest = false;
147
+ const requestsToShow: NetworkRequest[] = [];
144
148
  for (const request of Logs.NetworkLog.NetworkLog.instance().requests()) {
145
149
  const documentOrigin = Common.ParsedURL.ParsedURL.extractOrigin(request.documentURL);
146
150
  /**
@@ -163,6 +167,7 @@ export class ContextSelectionAgent extends AiAgent<never> {
163
167
  duration: i18n.TimeUtilities.secondsToString(request.duration),
164
168
  transferSize: i18n.ByteUtilities.formatBytesToKb(request.transferSize),
165
169
  });
170
+ requestsToShow.push(request);
166
171
  }
167
172
 
168
173
  if (requests.length === 0) {
@@ -175,6 +180,12 @@ export class ContextSelectionAgent extends AiAgent<never> {
175
180
 
176
181
  return {
177
182
  result: requests,
183
+ widgets: [{
184
+ name: 'NETWORK_REQUESTS_LIST',
185
+ data: {
186
+ requests: requestsToShow,
187
+ },
188
+ }],
178
189
  };
179
190
  },
180
191
  });
@@ -469,7 +480,7 @@ export class ContextSelectionAgent extends AiAgent<never> {
469
480
  const node = await this.#onInspectElement();
470
481
  if (node) {
471
482
  return {
472
- context: new NodeContext(node),
483
+ context: new DOMNodeContext(node),
473
484
  description: 'User selected an element',
474
485
  };
475
486
  }
@@ -478,6 +489,45 @@ export class ContextSelectionAgent extends AiAgent<never> {
478
489
  };
479
490
  },
480
491
  });
492
+
493
+ if (Root.Runtime.hostConfig.devToolsAiAssistanceStorageAgent?.enabled) {
494
+ this.declareFunction<Record<string, never>>('analyzeStorage', {
495
+ description:
496
+ 'Selects the page storage. Use this when asked about browser storage (localStorage, sessionStorage, cookies) and issues related to these.',
497
+ parameters: {
498
+ type: Host.AidaClient.ParametersTypes.OBJECT,
499
+ description: '',
500
+ nullable: true,
501
+ required: [],
502
+ properties: {},
503
+ },
504
+ displayInfoFromArgs: () => {
505
+ return {
506
+ title: lockedString('Prepare storage analysis'),
507
+ action: 'analyzeStorage()',
508
+ };
509
+ },
510
+ handler: async () => {
511
+ const allowedOriginResult = this.#allowedOrigin();
512
+ if ('blocked' in allowedOriginResult) {
513
+ return {
514
+ error: 'Cross-origin access blocked due to navigation. Please start a new chat.',
515
+ };
516
+ }
517
+ const origin = allowedOriginResult.origin;
518
+ if (!origin) {
519
+ return {
520
+ error: 'Unable to find page storage.',
521
+ };
522
+ }
523
+
524
+ return {
525
+ context: new StorageContext(new StorageItem(origin, origin)),
526
+ description: 'User selected page storage',
527
+ };
528
+ },
529
+ });
530
+ }
481
531
  }
482
532
 
483
533
  async * handleContextDetails(): AsyncGenerator<ContextResponse, void, void> {
@@ -28,6 +28,8 @@ export interface ExecuteJsAgentOptions extends BaseAgentOptions {
28
28
  execJs?: typeof executeJsCode;
29
29
  }
30
30
 
31
+ // TODO(crbug.com/510206549): De-duplicate this function by migrating AccessibilityAgent to use
32
+ // the registry-based ExecuteJavaScriptTool in tools/ExecuteJavaScript.ts.
31
33
  export function executeJavaScriptFunction(executor: JavascriptExecutor): FunctionDeclaration<
32
34
  {
33
35
  title: string,
@@ -239,7 +239,6 @@ export class PerformanceTraceContext extends ConversationContext<AgentFocus> {
239
239
  }
240
240
 
241
241
  #focus: AgentFocus;
242
- external = false;
243
242
 
244
243
  constructor(focus: AgentFocus) {
245
244
  super();
@@ -456,7 +455,7 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
456
455
  * so we can show it in the disclosure UI. This is cleared and then populated
457
456
  * on each prompt.
458
457
  */
459
- #additionalSelectionsForQuery: string[] = [];
458
+ #additionalSelectionsForDisclosure: string[] = [];
460
459
 
461
460
  get clientFeature(): Host.AidaClient.ClientFeature {
462
461
  return Host.AidaClient.ClientFeature.CHROME_PERFORMANCE_FULL_AGENT;
@@ -490,7 +489,7 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
490
489
  }
491
490
  contextDisclosure.push(fact.text);
492
491
  }
493
- contextDisclosure.push(...this.#additionalSelectionsForQuery);
492
+ contextDisclosure.push(...this.#additionalSelectionsForDisclosure);
494
493
 
495
494
  const focus = context.getItem();
496
495
  const widgets = this.#getWidgetsForFocus(focus);
@@ -705,12 +704,13 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
705
704
  }
706
705
  }
707
706
 
708
- this.#additionalSelectionsForQuery = selected;
709
707
  if (!selected.length) {
708
+ this.#additionalSelectionsForDisclosure = [];
710
709
  return query;
711
710
  }
712
711
 
713
712
  selected.push(`# User query\n\n${query}`);
713
+ this.#additionalSelectionsForDisclosure = [...selected];
714
714
  return selected.join('');
715
715
  }
716
716
 
@@ -818,9 +818,7 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
818
818
  async #addFacts(context: PerformanceTraceContext): Promise<void> {
819
819
  const focus = context.getItem();
820
820
 
821
- if (!context.external) {
822
- this.addFact(this.#notExternalExtraPreambleFact);
823
- }
821
+ this.addFact(this.#notExternalExtraPreambleFact);
824
822
 
825
823
  const annotationsEnabled = Annotations.AnnotationRepository.annotationsEnabled();
826
824
  if (annotationsEnabled) {
@@ -847,7 +845,7 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
847
845
  this.#formatter = new PerformanceTraceFormatter(focus);
848
846
  this.#formatter.resolveFunctionCode =
849
847
  async (url: Platform.DevToolsPath.UrlString, line: number, column: number) => {
850
- if (!target) {
848
+ if (!target || !isFresh) {
851
849
  return null;
852
850
  }
853
851
 
@@ -932,6 +930,7 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
932
930
  #declareFunctions(context: PerformanceTraceContext): void {
933
931
  const focus = context.getItem();
934
932
  const {parsedTrace} = focus;
933
+ const isFresh = Tracing.FreshRecording.Tracker.instance().recordingIsFresh(parsedTrace);
935
934
 
936
935
  this.declareFunction<{insightSetId: string, insightName: string}, {details: string}>('getInsightDetails', {
937
936
  description:
@@ -1070,35 +1069,7 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
1070
1069
  }
1071
1070
 
1072
1071
  // 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
- }
1072
+ const details = formatEventForAI(event);
1102
1073
 
1103
1074
  const key = `getEventByKey('${params.eventKey}')`;
1104
1075
  this.#cacheFunctionResult(focus, key, details);
@@ -1393,6 +1364,11 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
1393
1364
  },
1394
1365
  handler: async args => {
1395
1366
  debugLog('Function call: getFunctionCode');
1367
+ if (!isFresh) {
1368
+ return {
1369
+ error: 'Cannot use this tool on an imported file.',
1370
+ };
1371
+ }
1396
1372
 
1397
1373
  if (args.line === undefined) {
1398
1374
  return {error: 'Missing arg: line'};
@@ -1436,7 +1412,6 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
1436
1412
  },
1437
1413
  });
1438
1414
 
1439
- const isFresh = Tracing.FreshRecording.Tracker.instance().recordingIsFresh(parsedTrace);
1440
1415
  const isTraceApp = Root.Runtime.Runtime.isTraceApp();
1441
1416
 
1442
1417
  this.declareFunction<{url: UrlString}, {content: string}>('getResourceContent', {
@@ -1502,48 +1477,46 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
1502
1477
  },
1503
1478
  });
1504
1479
 
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'};
1480
+ this.declareFunction<{eventKey: string}, {success: boolean}>('selectEventByKey', {
1481
+ description:
1482
+ '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.',
1483
+ parameters: {
1484
+ type: Host.AidaClient.ParametersTypes.OBJECT,
1485
+ description: '',
1486
+ nullable: false,
1487
+ properties: {
1488
+ eventKey: {
1489
+ type: Host.AidaClient.ParametersTypes.STRING,
1490
+ description: 'The key for the event.',
1491
+ nullable: false,
1530
1492
  }
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
1493
  },
1545
- });
1546
- }
1494
+ required: ['eventKey']
1495
+ },
1496
+ displayInfoFromArgs: params => {
1497
+ return {title: lockedString('Selecting event'), action: `selectEventByKey('${params.eventKey}')`};
1498
+ },
1499
+ handler: async params => {
1500
+ debugLog('Function call: selectEventByKey', params);
1501
+ const event = focus.lookupEvent(params.eventKey);
1502
+ if (!event) {
1503
+ return {error: 'Invalid eventKey'};
1504
+ }
1505
+
1506
+ const revealable = new SDK.TraceObject.RevealableEvent(event);
1507
+ await Common.Revealer.reveal(revealable);
1508
+ return {
1509
+ result: {success: true},
1510
+ widgets: [{
1511
+ name: 'TIMELINE_EVENT_SUMMARY',
1512
+ data: {
1513
+ event,
1514
+ parsedTrace,
1515
+ },
1516
+ }],
1517
+ };
1518
+ },
1519
+ });
1547
1520
  }
1548
1521
 
1549
1522
  #getBoundsForLabel(label: MainThreadSectionLabel, focus: AgentFocus): Trace.Types.Timing.TraceWindowMicro|null {
@@ -1669,3 +1642,71 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
1669
1642
  return undefined;
1670
1643
  }
1671
1644
  }
1645
+
1646
+ /**
1647
+ * Serializes a trace event to a JSON string for AI consumption,
1648
+ * ensuring sensitive data (like headers and raw script source code)
1649
+ * is sanitized or redacted.
1650
+ */
1651
+ function formatEventForAI(event: Trace.Types.Events.Event): string {
1652
+ if (Trace.Types.Events.isSyntheticNetworkRequest(event)) {
1653
+ return JSON.stringify({
1654
+ ...event,
1655
+ args: {
1656
+ ...event.args,
1657
+ data: {
1658
+ ...event.args.data,
1659
+ responseHeaders: event.args.data.responseHeaders ? sanitizeHeaders(event.args.data.responseHeaders) : null,
1660
+ },
1661
+ },
1662
+ });
1663
+ }
1664
+
1665
+ if (Trace.Types.Events.isResourceReceiveResponse(event)) {
1666
+ return JSON.stringify({
1667
+ ...event,
1668
+ args: {
1669
+ ...event.args,
1670
+ data: {
1671
+ ...event.args.data,
1672
+ headers: event.args.data.headers ? sanitizeHeaders(event.args.data.headers) : undefined,
1673
+ },
1674
+ },
1675
+ });
1676
+ }
1677
+
1678
+ if (Trace.Types.Events.isRundownScriptSource(event)) {
1679
+ // Redact sensitive cross-origin script source text.
1680
+ const safeData: Omit<Trace.Types.Events.RundownScriptSource['args']['data'], 'sourceText'> = {
1681
+ isolate: event.args.data.isolate,
1682
+ scriptId: event.args.data.scriptId,
1683
+ length: event.args.data.length,
1684
+ };
1685
+ return JSON.stringify({
1686
+ ...event,
1687
+ args: {
1688
+ ...event.args,
1689
+ data: safeData,
1690
+ },
1691
+ });
1692
+ }
1693
+
1694
+ if (Trace.Types.Events.isRundownScriptSourceLarge(event)) {
1695
+ // Redact sensitive cross-origin script source text.
1696
+ const safeData: Omit<Trace.Types.Events.RundownScriptSourceLarge['args']['data'], 'sourceText'> = {
1697
+ isolate: event.args.data.isolate,
1698
+ scriptId: event.args.data.scriptId,
1699
+ splitIndex: event.args.data.splitIndex,
1700
+ splitCount: event.args.data.splitCount,
1701
+ };
1702
+ return JSON.stringify({
1703
+ ...event,
1704
+ args: {
1705
+ ...event.args,
1706
+ data: safeData,
1707
+ },
1708
+ });
1709
+ }
1710
+
1711
+ return JSON.stringify(event);
1712
+ }
@@ -173,18 +173,17 @@ export class StorageAgent extends AiAgent<StorageItem> {
173
173
  },
174
174
  });
175
175
 
176
- this.declareFunction<
177
- {
178
- type: 'localStorage' | 'sessionStorage',
179
- origin: string,
180
- storageKey?: string,
181
- },
182
- {
183
- partitions: Array<{
184
- storageKey: string,
185
- keys: string[],
186
- }>,
187
- }>('listStorageKeys', {
176
+ this.declareFunction<{
177
+ type: 'localStorage' | 'sessionStorage',
178
+ origin: string,
179
+ storageKey?: string,
180
+ },
181
+ {
182
+ partitions: Array<{
183
+ storageKey: string,
184
+ keys: string[],
185
+ }>,
186
+ }>('listStorageKeys', {
188
187
  description:
189
188
  'Lists all keys for a given storage type for the requested origin. Returns keys grouped by storage partition.',
190
189
  parameters: {
@@ -218,6 +217,7 @@ export class StorageAgent extends AiAgent<StorageItem> {
218
217
  },
219
218
 
220
219
  handler: async args => {
220
+ this.disableServerSideLogging();
221
221
  if (!isSamePrimaryPageOrigin(this.context)) {
222
222
  return {error: 'No origin available or not allowed.'};
223
223
  }
@@ -244,19 +244,18 @@ export class StorageAgent extends AiAgent<StorageItem> {
244
244
  },
245
245
  });
246
246
 
247
- this.declareFunction<
248
- {
249
- type: 'localStorage' | 'sessionStorage',
250
- keys: string[],
251
- origin: string,
252
- storageKey?: string,
253
- },
254
- {
255
- items: Array<{
256
- storageKey: string,
257
- values: Record<string, string>,
258
- }>,
259
- }>('getStorageValues', {
247
+ this.declareFunction<{
248
+ type: 'localStorage' | 'sessionStorage',
249
+ keys: string[],
250
+ origin: string,
251
+ storageKey?: string,
252
+ },
253
+ {
254
+ items: Array<{
255
+ storageKey: string,
256
+ values: Record<string, string>,
257
+ }>,
258
+ }>('getStorageValues', {
260
259
  description: 'Retrieve specific string values from storage partitions for requested keys.',
261
260
  parameters: {
262
261
  type: Host.AidaClient.ParametersTypes.OBJECT,
@@ -296,6 +295,7 @@ export class StorageAgent extends AiAgent<StorageItem> {
296
295
  },
297
296
 
298
297
  handler: async (args, options) => {
298
+ this.disableServerSideLogging();
299
299
  if (!isSamePrimaryPageOrigin(this.context)) {
300
300
  return {error: 'No origin available or not allowed.'};
301
301
  }
@@ -353,11 +353,10 @@ export class StorageAgent extends AiAgent<StorageItem> {
353
353
  },
354
354
  });
355
355
 
356
- this.declareFunction<
357
- {
358
- origin: string,
359
- },
360
- {cookies: string[]}>('listCookies', {
356
+ this.declareFunction<{
357
+ origin: string,
358
+ },
359
+ {cookies: string[]}>('listCookies', {
361
360
  description: 'Lists all cookies for the requested origin, strictly excluding their values.',
362
361
  parameters: {
363
362
  type: Host.AidaClient.ParametersTypes.OBJECT,
@@ -379,6 +378,7 @@ export class StorageAgent extends AiAgent<StorageItem> {
379
378
  };
380
379
  },
381
380
  handler: async args => {
381
+ this.disableServerSideLogging();
382
382
  if (!isSamePrimaryPageOrigin(this.context)) {
383
383
  return {error: 'No origin available or not allowed.'};
384
384
  }
@@ -396,14 +396,13 @@ export class StorageAgent extends AiAgent<StorageItem> {
396
396
  },
397
397
  });
398
398
 
399
- this.declareFunction<
400
- {
401
- cookieNames: string[],
402
- origin: string,
403
- },
404
- {
405
- cookies: CookieDetails[],
406
- }>('getCookieValues', {
399
+ this.declareFunction<{
400
+ cookieNames: string[],
401
+ origin: string,
402
+ },
403
+ {
404
+ cookies: CookieDetails[],
405
+ }>('getCookieValues', {
407
406
  description: 'Retrieve the values and detailed metadata of specific cookies by their names.',
408
407
  parameters: {
409
408
  type: Host.AidaClient.ParametersTypes.OBJECT,
@@ -431,6 +430,7 @@ export class StorageAgent extends AiAgent<StorageItem> {
431
430
  };
432
431
  },
433
432
  handler: async (args, options) => {
433
+ this.disableServerSideLogging();
434
434
  if (!isSamePrimaryPageOrigin(this.context)) {
435
435
  return {error: 'No origin available or not allowed.'};
436
436
  }
@@ -498,6 +498,15 @@ export class StorageAgent extends AiAgent<StorageItem> {
498
498
  return primaryTargetOrigin;
499
499
  }
500
500
 
501
+ protected override async preRun(): Promise<void> {
502
+ const item = this.context?.getItem();
503
+ if (item instanceof CookieItem && Boolean(item.name)) {
504
+ this.disableServerSideLogging();
505
+ } else if (item instanceof DOMStorageItem && Boolean(item.key)) {
506
+ this.disableServerSideLogging();
507
+ }
508
+ }
509
+
501
510
  async *
502
511
  handleContextDetails(context: ConversationContext<StorageItem>|null):
503
512
  AsyncGenerator<ContextResponse, void, void> {
@@ -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: