chrome-devtools-frontend 1.0.1642899 → 1.0.1643855

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 (125) hide show
  1. package/eslint.config.mjs +3 -1
  2. package/extension-api/ExtensionAPI.d.ts +83 -12
  3. package/front_end/core/host/UserMetrics.ts +0 -1
  4. package/front_end/core/protocol_client/InspectorBackend.ts +4 -0
  5. package/front_end/core/root/ExperimentNames.ts +0 -1
  6. package/front_end/core/sdk/ConsoleModel.ts +4 -0
  7. package/front_end/core/sdk/NetworkRequest.ts +12 -0
  8. package/front_end/core/sdk/SourceMap.ts +15 -18
  9. package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +0 -2
  10. package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +0 -2
  11. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +4 -5
  12. package/front_end/entrypoints/main/MainImpl.ts +0 -6
  13. package/front_end/generated/InspectorBackendCommands.ts +1 -1
  14. package/front_end/generated/protocol.ts +7 -0
  15. package/front_end/models/ai_assistance/AiAgent2.ts +24 -5
  16. package/front_end/models/ai_assistance/AiConversation.ts +15 -12
  17. package/front_end/models/ai_assistance/AiUtils.ts +71 -0
  18. package/front_end/models/ai_assistance/ChangeManager.ts +2 -5
  19. package/front_end/models/ai_assistance/{agents/ConversationSummaryAgent.ts → ConversationSummary.ts} +29 -66
  20. package/front_end/models/ai_assistance/ExtensionScope.ts +1 -4
  21. package/front_end/models/ai_assistance/{agents/PerformanceAnnotationsAgent.ts → PerformanceAnnotations.ts} +47 -89
  22. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +47 -31
  23. package/front_end/models/ai_assistance/agents/AiAgent.ts +40 -12
  24. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +11 -0
  25. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +58 -8
  26. package/front_end/models/ai_assistance/agents/ExecuteJavascript.ts +1 -92
  27. package/front_end/models/ai_assistance/agents/NetworkAgent.ts +25 -0
  28. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +94 -79
  29. package/front_end/models/ai_assistance/agents/StorageAgent.ts +101 -39
  30. package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +1 -2
  31. package/front_end/models/ai_assistance/agents/StylingAgent.ts +27 -21
  32. package/front_end/models/ai_assistance/ai_assistance.ts +6 -4
  33. package/front_end/models/ai_assistance/skills/styling.md +12 -4
  34. package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +134 -0
  35. package/front_end/models/ai_assistance/tools/GetStyles.ts +6 -2
  36. package/front_end/models/ai_assistance/tools/Tool.ts +16 -1
  37. package/front_end/models/ai_assistance/tools/ToolRegistry.ts +2 -0
  38. package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +6 -9
  39. package/front_end/models/bindings/DefaultScriptMapping.ts +2 -1
  40. package/front_end/models/bindings/SymbolizedError.ts +45 -35
  41. package/front_end/models/extensions/ExtensionAPI.ts +138 -47
  42. package/front_end/models/har/Importer.ts +1 -0
  43. package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +5 -7
  44. package/front_end/models/source_map_scopes/FunctionCodeResolver.ts +12 -2
  45. package/front_end/models/stack_trace/DetailedErrorStackParser.ts +44 -51
  46. package/front_end/models/stack_trace/StackTrace.ts +7 -0
  47. package/front_end/models/stack_trace/StackTraceImpl.ts +13 -4
  48. package/front_end/models/stack_trace/StackTraceModel.ts +9 -8
  49. package/front_end/panels/accessibility/AccessibilitySidebarView.ts +2 -1
  50. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +8 -8
  51. package/front_end/panels/ai_assistance/components/ChatMessage.ts +96 -4
  52. package/front_end/panels/ai_assistance/components/chatMessage.css +6 -0
  53. package/front_end/panels/application/ApplicationPanelSidebar.ts +39 -0
  54. package/front_end/panels/application/ApplicationPanelTreeElement.ts +39 -0
  55. package/front_end/panels/application/CookieItemsView.ts +2 -2
  56. package/front_end/panels/application/components/AdsView.ts +219 -0
  57. package/front_end/panels/application/components/adsView.css +54 -0
  58. package/front_end/panels/application/components/components.ts +2 -0
  59. package/front_end/panels/application/resourcesSidebar.css +11 -0
  60. package/front_end/panels/console/SymbolizedErrorWidget.ts +79 -25
  61. package/front_end/panels/network/NetworkLogView.ts +5 -1
  62. package/front_end/panels/settings/emulation/DevicesSettingsTab.ts +1 -0
  63. package/front_end/panels/sources/SourcesPanel.ts +2 -1
  64. package/front_end/panels/timeline/overlays/components/EntryLabelOverlay.ts +5 -4
  65. package/front_end/third_party/chromium/README.chromium +1 -1
  66. package/front_end/third_party/lighthouse/README.chromium +2 -2
  67. package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +1607 -5733
  68. package/front_end/third_party/lighthouse/locales/ar-XB.json +290 -65
  69. package/front_end/third_party/lighthouse/locales/ar.json +290 -65
  70. package/front_end/third_party/lighthouse/locales/bg.json +290 -65
  71. package/front_end/third_party/lighthouse/locales/ca.json +295 -70
  72. package/front_end/third_party/lighthouse/locales/cs.json +290 -65
  73. package/front_end/third_party/lighthouse/locales/da.json +294 -69
  74. package/front_end/third_party/lighthouse/locales/de.json +295 -70
  75. package/front_end/third_party/lighthouse/locales/el.json +290 -65
  76. package/front_end/third_party/lighthouse/locales/en-GB.json +290 -65
  77. package/front_end/third_party/lighthouse/locales/en-US.json +79 -67
  78. package/front_end/third_party/lighthouse/locales/en-XA.json +253 -64
  79. package/front_end/third_party/lighthouse/locales/en-XL.json +79 -67
  80. package/front_end/third_party/lighthouse/locales/es-419.json +290 -65
  81. package/front_end/third_party/lighthouse/locales/es.json +298 -73
  82. package/front_end/third_party/lighthouse/locales/fi.json +290 -65
  83. package/front_end/third_party/lighthouse/locales/fil.json +290 -65
  84. package/front_end/third_party/lighthouse/locales/fr.json +294 -69
  85. package/front_end/third_party/lighthouse/locales/he.json +293 -68
  86. package/front_end/third_party/lighthouse/locales/hi.json +291 -66
  87. package/front_end/third_party/lighthouse/locales/hr.json +290 -65
  88. package/front_end/third_party/lighthouse/locales/hu.json +290 -65
  89. package/front_end/third_party/lighthouse/locales/id.json +290 -65
  90. package/front_end/third_party/lighthouse/locales/it.json +294 -69
  91. package/front_end/third_party/lighthouse/locales/ja.json +290 -65
  92. package/front_end/third_party/lighthouse/locales/ko.json +290 -65
  93. package/front_end/third_party/lighthouse/locales/lt.json +290 -65
  94. package/front_end/third_party/lighthouse/locales/lv.json +290 -65
  95. package/front_end/third_party/lighthouse/locales/nl.json +290 -65
  96. package/front_end/third_party/lighthouse/locales/no.json +290 -65
  97. package/front_end/third_party/lighthouse/locales/pl.json +290 -65
  98. package/front_end/third_party/lighthouse/locales/pt-PT.json +291 -66
  99. package/front_end/third_party/lighthouse/locales/pt.json +290 -65
  100. package/front_end/third_party/lighthouse/locales/ro.json +290 -65
  101. package/front_end/third_party/lighthouse/locales/ru.json +301 -76
  102. package/front_end/third_party/lighthouse/locales/sk.json +291 -66
  103. package/front_end/third_party/lighthouse/locales/sl.json +290 -65
  104. package/front_end/third_party/lighthouse/locales/sr-Latn.json +290 -65
  105. package/front_end/third_party/lighthouse/locales/sr.json +290 -65
  106. package/front_end/third_party/lighthouse/locales/sv.json +297 -72
  107. package/front_end/third_party/lighthouse/locales/ta.json +291 -66
  108. package/front_end/third_party/lighthouse/locales/te.json +293 -68
  109. package/front_end/third_party/lighthouse/locales/th.json +291 -66
  110. package/front_end/third_party/lighthouse/locales/tr.json +290 -65
  111. package/front_end/third_party/lighthouse/locales/uk.json +290 -65
  112. package/front_end/third_party/lighthouse/locales/vi.json +291 -66
  113. package/front_end/third_party/lighthouse/locales/zh-HK.json +292 -67
  114. package/front_end/third_party/lighthouse/locales/zh-TW.json +291 -66
  115. package/front_end/third_party/lighthouse/locales/zh.json +291 -66
  116. package/front_end/third_party/lighthouse/report/bundle.d.ts +6 -6
  117. package/front_end/third_party/lighthouse/report/bundle.js +4 -7
  118. package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +2 -2
  119. package/front_end/ui/legacy/StackedPane.ts +229 -0
  120. package/front_end/ui/legacy/ViewManager.ts +59 -169
  121. package/front_end/ui/legacy/Widget.ts +32 -8
  122. package/front_end/ui/legacy/legacy.ts +3 -1
  123. package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
  124. package/mcp/mcp.ts +1 -0
  125. package/package.json +1 -1
@@ -23,7 +23,7 @@ const lockedString = i18n.i18n.lockedString;
23
23
  const preamble =
24
24
  `You are a Senior Software Engineer specializing in state audit and storage analysis within Chrome DevTools. Your mission is to help developers debug storage-related issues faster by analyzing the evidence in LocalStorage, SessionStorage, and Cookies.
25
25
 
26
- You have access to the site's storage using tools like \`listPageOrigins\`, \`listStorageKeys\`, \`getStorageValues\`, \`listCookies\`, and \`getCookieValues\`.
26
+ You have access to the site's storage using tools like \`getStorageBreakdown\`, \`listPageOrigins\`, \`listStorageKeys\`, \`getStorageValues\`, \`listCookies\`, and \`getCookieValues\`.
27
27
 
28
28
  # Goals
29
29
 
@@ -34,6 +34,7 @@ const preamble =
34
34
  # Tools & Workflow
35
35
 
36
36
  - **Prioritize Top-Level Context**: Always initiate your investigation from the top-level page's storage. Explicitly state if you are analyzing storage from a different context (e.g., an iframe).
37
+ - **Storage Breakdown**: Calling \`getStorageBreakdown\` gives you the total usage and quota per storage for the top-level page.
37
38
  - **Address Specific Selections**: The user can select individual storage items in the DevTools UI (provided in the '# Active Context' section of the prompt). If the query is about a selected item (e.g., "Why is this cookie set?"), focus your response on that specific item.
38
39
  - **Expand Scope When Necessary**: For general questions or those implying a wider scope (e.g., "Check all storages," "Are there related cookies on subdomains?"), proactively use your tools to explore other relevant storage contexts, including iframes and different origins.
39
40
  - **Discovery**: Start by calling \`listPageOrigins\` to discover all active, non-empty frame origins loaded by the page.
@@ -173,18 +174,17 @@ export class StorageAgent extends AiAgent<StorageItem> {
173
174
  },
174
175
  });
175
176
 
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', {
177
+ this.declareFunction<{
178
+ type: 'localStorage' | 'sessionStorage',
179
+ origin: string,
180
+ storageKey?: string,
181
+ },
182
+ {
183
+ partitions: Array<{
184
+ storageKey: string,
185
+ keys: string[],
186
+ }>,
187
+ }>('listStorageKeys', {
188
188
  description:
189
189
  'Lists all keys for a given storage type for the requested origin. Returns keys grouped by storage partition.',
190
190
  parameters: {
@@ -218,6 +218,7 @@ export class StorageAgent extends AiAgent<StorageItem> {
218
218
  },
219
219
 
220
220
  handler: async args => {
221
+ this.disableServerSideLogging();
221
222
  if (!isSamePrimaryPageOrigin(this.context)) {
222
223
  return {error: 'No origin available or not allowed.'};
223
224
  }
@@ -244,19 +245,18 @@ export class StorageAgent extends AiAgent<StorageItem> {
244
245
  },
245
246
  });
246
247
 
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', {
248
+ this.declareFunction<{
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', {
260
260
  description: 'Retrieve specific string values from storage partitions for requested keys.',
261
261
  parameters: {
262
262
  type: Host.AidaClient.ParametersTypes.OBJECT,
@@ -296,6 +296,7 @@ export class StorageAgent extends AiAgent<StorageItem> {
296
296
  },
297
297
 
298
298
  handler: async (args, options) => {
299
+ this.disableServerSideLogging();
299
300
  if (!isSamePrimaryPageOrigin(this.context)) {
300
301
  return {error: 'No origin available or not allowed.'};
301
302
  }
@@ -353,11 +354,10 @@ export class StorageAgent extends AiAgent<StorageItem> {
353
354
  },
354
355
  });
355
356
 
356
- this.declareFunction<
357
- {
358
- origin: string,
359
- },
360
- {cookies: string[]}>('listCookies', {
357
+ this.declareFunction<{
358
+ origin: string,
359
+ },
360
+ {cookies: string[]}>('listCookies', {
361
361
  description: 'Lists all cookies for the requested origin, strictly excluding their values.',
362
362
  parameters: {
363
363
  type: Host.AidaClient.ParametersTypes.OBJECT,
@@ -379,6 +379,7 @@ export class StorageAgent extends AiAgent<StorageItem> {
379
379
  };
380
380
  },
381
381
  handler: async args => {
382
+ this.disableServerSideLogging();
382
383
  if (!isSamePrimaryPageOrigin(this.context)) {
383
384
  return {error: 'No origin available or not allowed.'};
384
385
  }
@@ -396,14 +397,13 @@ export class StorageAgent extends AiAgent<StorageItem> {
396
397
  },
397
398
  });
398
399
 
399
- this.declareFunction<
400
- {
401
- cookieNames: string[],
402
- origin: string,
403
- },
404
- {
405
- cookies: CookieDetails[],
406
- }>('getCookieValues', {
400
+ this.declareFunction<{
401
+ cookieNames: string[],
402
+ origin: string,
403
+ },
404
+ {
405
+ cookies: CookieDetails[],
406
+ }>('getCookieValues', {
407
407
  description: 'Retrieve the values and detailed metadata of specific cookies by their names.',
408
408
  parameters: {
409
409
  type: Host.AidaClient.ParametersTypes.OBJECT,
@@ -431,6 +431,7 @@ export class StorageAgent extends AiAgent<StorageItem> {
431
431
  };
432
432
  },
433
433
  handler: async (args, options) => {
434
+ this.disableServerSideLogging();
434
435
  if (!isSamePrimaryPageOrigin(this.context)) {
435
436
  return {error: 'No origin available or not allowed.'};
436
437
  }
@@ -479,6 +480,58 @@ export class StorageAgent extends AiAgent<StorageItem> {
479
480
  return {result: {cookies: cookieData}};
480
481
  },
481
482
  });
483
+
484
+ this.declareFunction<Record<string, never>, {
485
+ totalUsage: string,
486
+ totalQuota: string,
487
+ usageBreakdown: Array<{
488
+ storageType: string,
489
+ usage: string,
490
+ }>,
491
+ }>('getStorageBreakdown', {
492
+ description:
493
+ 'Retrieves the total storage usage, total storage quota, and a breakdown of active storage usage per storage type for the top-level page.',
494
+ parameters: {
495
+ type: Host.AidaClient.ParametersTypes.OBJECT,
496
+ description: '',
497
+ nullable: false,
498
+ properties: {},
499
+ required: [],
500
+ },
501
+ displayInfoFromArgs: () => {
502
+ return {
503
+ title: lockedString('Retrieving storage breakdown'),
504
+ action: 'getStorageBreakdown()',
505
+ };
506
+ },
507
+ handler: async () => {
508
+ const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
509
+ if (!target || !this.context || !isSamePageOrigin(target, this.context)) {
510
+ return {error: 'No origin available or not allowed.'};
511
+ }
512
+
513
+ const origin = this.context.getOrigin();
514
+ const response = await target.storageAgent().invoke_getUsageAndQuota({origin});
515
+ if (response.getError()) {
516
+ return {error: response.getError() || 'Unknown CDP error'};
517
+ }
518
+
519
+ const usageBreakdown = response.usageBreakdown.filter(entry => entry.usage > 0)
520
+ .sort((a, b) => b.usage - a.usage)
521
+ .map(entry => ({
522
+ storageType: entry.storageType as string,
523
+ usage: i18n.ByteUtilities.bytesToString(entry.usage),
524
+ }));
525
+
526
+ return {
527
+ result: {
528
+ totalUsage: i18n.ByteUtilities.bytesToString(response.usage),
529
+ totalQuota: i18n.ByteUtilities.bytesToString(response.quota),
530
+ usageBreakdown,
531
+ },
532
+ };
533
+ },
534
+ });
482
535
  }
483
536
 
484
537
  static #formatContext(item: StorageItem): string {
@@ -498,6 +551,15 @@ export class StorageAgent extends AiAgent<StorageItem> {
498
551
  return primaryTargetOrigin;
499
552
  }
500
553
 
554
+ protected override async preRun(): Promise<void> {
555
+ const item = this.context?.getItem();
556
+ if (item instanceof CookieItem && Boolean(item.name)) {
557
+ this.disableServerSideLogging();
558
+ } else if (item instanceof DOMStorageItem && Boolean(item.key)) {
559
+ this.disableServerSideLogging();
560
+ }
561
+ }
562
+
501
563
  async *
502
564
  handleContextDetails(context: ConversationContext<StorageItem>|null):
503
565
  AsyncGenerator<ContextResponse, void, void> {
@@ -1,4 +1,3 @@
1
-
2
1
  Title: StylingAgent buildRequest structure matches the snapshot
3
2
  Content:
4
3
  {
@@ -129,7 +128,7 @@ Content:
129
128
  "disable_user_content_logging": false,
130
129
  "string_session_id": "sessionId",
131
130
  "user_tier": 3,
132
- "client_version": "unit_test"
131
+ "client_version": "unit_test+function_calling"
133
132
  },
134
133
  "functionality_type": 5,
135
134
  "client_feature": 2
@@ -27,10 +27,8 @@ import {
27
27
  } from './AiAgent.js';
28
28
  import {
29
29
  type CreateExtensionScopeFunction,
30
- executeJavaScriptFunction,
31
30
  type ExecuteJsAgentOptions,
32
31
  executeJsCode,
33
- JavascriptExecutor
34
32
  } from './ExecuteJavascript.js';
35
33
 
36
34
  const preamble = `You are the most advanced CSS/DOM/HTML debugging assistant integrated into Chrome DevTools.
@@ -169,32 +167,21 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
169
167
  }
170
168
 
171
169
  #execJs: typeof executeJsCode;
172
- #javascriptExecutor: JavascriptExecutor;
173
170
 
174
171
  #changes: ChangeManager;
175
172
  #createExtensionScope: CreateExtensionScopeFunction;
176
173
  #greenDevEmulationScreenshot: string|null = null;
177
174
  #greenDevEmulationAxTree: string|null = null;
178
175
  #hasAddedEmulationInstructions = false;
179
- #currentTurnId = 0;
180
176
 
181
177
  constructor(opts: ExecuteJsAgentOptions) {
182
178
  super(opts);
183
179
 
184
180
  this.#changes = opts.changeManager || new ChangeManager();
185
181
  this.#execJs = opts.execJs ?? executeJsCode;
186
- this.#createExtensionScope =
187
- opts.createExtensionScope ?? ((changes: ChangeManager) => {
188
- return new ExtensionScope(changes, this.sessionId, this.context?.getItem() ?? null, this.#currentTurnId);
189
- });
190
- this.#javascriptExecutor = new JavascriptExecutor(
191
- {
192
- executionMode: this.executionMode,
193
- getContextNode: () => this.#getSelectedNode(),
194
- createExtensionScope: this.#createExtensionScope.bind(this),
195
- changes: this.#changes,
196
- },
197
- this.#execJs);
182
+ this.#createExtensionScope = opts.createExtensionScope ?? ((changes: ChangeManager) => {
183
+ return new ExtensionScope(changes, this.sessionId, this.context?.getItem() ?? null);
184
+ });
198
185
 
199
186
  const getStylesTool = ToolRegistry.get(ToolName.GET_STYLES);
200
187
  if (!getStylesTool) {
@@ -209,7 +196,26 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
209
196
  }),
210
197
  });
211
198
 
212
- this.declareFunction('executeJavaScript', executeJavaScriptFunction(this.#javascriptExecutor));
199
+ const executeJsTool = ToolRegistry.get(ToolName.EXECUTE_JAVASCRIPT);
200
+ if (!executeJsTool) {
201
+ throw new Error('Required tool "executeJavaScript" not found');
202
+ }
203
+ this.declareFunction(ToolName.EXECUTE_JAVASCRIPT, {
204
+ description: executeJsTool.description,
205
+ parameters: executeJsTool.parameters,
206
+ displayInfoFromArgs: executeJsTool.displayInfoFromArgs,
207
+ handler: (args, options) => executeJsTool.handler(
208
+ args,
209
+ {
210
+ conversationContext: this.context ?? null,
211
+ changeManager: this.#changes,
212
+ createExtensionScope: this.#createExtensionScope.bind(this),
213
+ execJs: this.#execJs,
214
+ getExecutionContextNode: () => this.context?.getItem() ?? null,
215
+ },
216
+ options,
217
+ ),
218
+ });
213
219
 
214
220
  if (Annotations.AnnotationRepository.annotationsEnabled()) {
215
221
  this.declareFunction<{
@@ -275,6 +281,10 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
275
281
  });
276
282
  }
277
283
 
284
+ override preambleFeatures(): string[] {
285
+ return ['function_calling'];
286
+ }
287
+
278
288
  #getSelectedNode(): SDK.DOMModel.DOMNode|null {
279
289
  return this.context?.getItem() ?? null;
280
290
  }
@@ -515,10 +525,6 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
515
525
  }
516
526
  }
517
527
 
518
- protected override async preRun(): Promise<void> {
519
- this.#currentTurnId++;
520
- }
521
-
522
528
  override async enhanceQuery(
523
529
  query: string, selectedElement: ConversationContext<SDK.DOMModel.DOMNode>|null,
524
530
  multimodalInputType?: MultimodalInputType): Promise<string> {
@@ -6,7 +6,6 @@ import * as AgentProject from './AgentProject.js';
6
6
  import * as AccessibilityAgent from './agents/AccessibilityAgent.js';
7
7
  import * as AiAgent from './agents/AiAgent.js';
8
8
  import * as ContextSelectionAgent from './agents/ContextSelectionAgent.js';
9
- import * as ConversationSummaryAgent from './agents/ConversationSummaryAgent.js';
10
9
  import * as FileAgent from './agents/FileAgent.js';
11
10
  import * as GreenDevAgent from './agents/GreenDevAgent.js';
12
11
  import * as GreenDevAgentAntigravityCliSocketClient from './agents/GreenDevAgentAntigravityCliSocketClient.js';
@@ -14,7 +13,6 @@ import * as GreenDevAgentGeminiCliSocketClient from './agents/GreenDevAgentGemin
14
13
  import * as NetworkAgent from './agents/NetworkAgent.js';
15
14
  import * as PatchAgent from './agents/PatchAgent.js';
16
15
  import * as PerformanceAgent from './agents/PerformanceAgent.js';
17
- import * as PerformanceAnnotationsAgent from './agents/PerformanceAnnotationsAgent.js';
18
16
  import * as StorageAgent from './agents/StorageAgent.js';
19
17
  import * as StylingAgent from './agents/StylingAgent.js';
20
18
  import * as AiAgent2 from './AiAgent2.js';
@@ -25,6 +23,7 @@ import * as AiUtils from './AiUtils.js';
25
23
  import * as BuiltInAi from './BuiltInAi.js';
26
24
  import * as ChangeManager from './ChangeManager.js';
27
25
  import * as DOMNodeContext from './contexts/DOMNodeContext.js';
26
+ import * as ConversationSummary from './ConversationSummary.js';
28
27
  import * as FileFormatter from './data_formatters/FileFormatter.js';
29
28
  import * as LighthouseFormatter from './data_formatters/LighthouseFormatter.js';
30
29
  import * as NetworkRequestFormatter from './data_formatters/NetworkRequestFormatter.js';
@@ -38,7 +37,9 @@ import * as Injected from './injected.js';
38
37
  import * as AICallTree from './performance/AICallTree.js';
39
38
  import * as AIContext from './performance/AIContext.js';
40
39
  import * as AIQueries from './performance/AIQueries.js';
40
+ import * as PerformanceAnnotations from './PerformanceAnnotations.js';
41
41
  import * as StorageItem from './StorageItem.js';
42
+ import * as ExecuteJavaScript from './tools/ExecuteJavaScript.js';
42
43
  import * as GetStyles from './tools/GetStyles.js';
43
44
  import * as Tool from './tools/Tool.js';
44
45
  import * as ToolRegistry from './tools/ToolRegistry.js';
@@ -58,10 +59,11 @@ export {
58
59
  BuiltInAi,
59
60
  ChangeManager,
60
61
  ContextSelectionAgent,
61
- ConversationSummaryAgent,
62
+ ConversationSummary,
62
63
  Debug,
63
64
  DOMNodeContext,
64
65
  EvaluateAction,
66
+ ExecuteJavaScript,
65
67
  ExtensionScope,
66
68
  FileAgent,
67
69
  FileFormatter,
@@ -75,7 +77,7 @@ export {
75
77
  NetworkRequestFormatter,
76
78
  PatchAgent,
77
79
  PerformanceAgent,
78
- PerformanceAnnotationsAgent,
80
+ PerformanceAnnotations,
79
81
  PerformanceInsightFormatter,
80
82
  PerformanceTraceFormatter,
81
83
  StorageAgent,
@@ -2,12 +2,13 @@
2
2
  name: styling
3
3
  description: Helping with CSS and styling
4
4
  allowed-tools:
5
+ - executeJavaScript
5
6
  - getStyles
6
7
  ---
7
- You are a CSS/DOM/HTML debugging assistant.
8
+ You are the most advanced CSS/DOM/HTML debugging assistant integrated into Chrome DevTools.
8
9
  You always suggest considering the best web development practices and the newest platform features such as view transitions.
9
10
  The user selected a DOM element in the browser's DevTools and sends a query about the page or the selected DOM element.
10
- First, examine the provided context, then use the getStyles function to gather additional context and resolve the user request.
11
+ First, examine the provided context, then use the getStyles and executeJavaScript functions to gather additional context and resolve the user request.
11
12
 
12
13
  # Considerations
13
14
 
@@ -19,10 +20,17 @@ First, examine the provided context, then use the getStyles function to gather a
19
20
  * Please answer only if you are sure about the answer. Otherwise, explain why you're not able to answer.
20
21
  * When answering, always consider MULTIPLE possible solutions.
21
22
  * When answering, remember to consider CSS concepts such as the CSS cascade, explicit and implicit stacking contexts and various CSS layout types.
22
- * Use the getStyles function available to you to investigate and fulfill the user request.
23
- * ALWAYS OUTPUT a list of follow-up queries at the end of your text response. The format is SUGGESTIONS: ["suggestion1", "suggestion2", "suggestion3"]. Make sure that the array and the `SUGGESTIONS: ` text is in the same line.
23
+ * Use the functions available to you to investigate and fulfill the user request.
24
+ * After applying a fix, please ask the user to confirm if the fix worked or not.
25
+ * ALWAYS OUTPUT a list of follow-up queries at the end of your text response. The format is SUGGESTIONS: ["suggestion1", "suggestion2", "suggestion3"]. Make sure that the array and the `SUGGESTIONS: ` text is in the same line. You're also capable of executing the fix for the issue user mentioned. Reflect this in your suggestions.
24
26
  * Use the precision of Strunk & White, the brevity of Hemingway, and the simple clarity of Vonnegut. Don't add repeated information, and keep the whole answer short.
27
+ * **CRITICAL** NEVER output text before a function call. Always do a function call first.
25
28
  * **CRITICAL** When answering questions about positioning or layout, ALWAYS inspect `position`, `display` and all other related properties. You MUST provide a specific list of CSS property names when calling getStyles. Do not use generic values like "all" or "*".
29
+ * **CRITICAL** When writing JavaScript via the `executeJavaScript` tool:
30
+ - To return data, define a top-level `data` variable and populate it with a JSON-serializable object.
31
+ - If you modify styles on an element, ALWAYS call the pre-defined global `async setElementStyles(el: Element, styles: object)` function. This function is an internal mechanism and should never be presented to the user.
32
+ - Never assume a selector for the elements unless you verified your knowledge.
33
+ - Consider that `data` variables from previous function calls are not available in a new function call.
26
34
  * **CRITICAL** You are a CSS/DOM/HTML debugging assistant. NEVER provide answers to questions of unrelated topics such as legal advice, financial advice, personal opinions, medical advice, religion, race, politics, sexuality, gender, or any other non web-development topics. Answer "Sorry, I can't answer that. I'm best at questions about debugging web pages." to such questions.
27
35
 
28
36
  ## Response Structure
@@ -0,0 +1,134 @@
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 * as Host from '../../../core/host/host.js';
6
+ import * as Root from '../../../core/root/root.js';
7
+ import type {FunctionCallHandlerResult, FunctionHandlerOptions,} from '../agents/AiAgent.js';
8
+ import {JavascriptExecutor} from '../agents/ExecuteJavascript.js';
9
+
10
+ import {
11
+ type Tool,
12
+ type ToolArgs,
13
+ type ToolContext,
14
+ ToolName,
15
+ } from './Tool.js';
16
+
17
+ export interface ExecuteJavaScriptArgs extends ToolArgs {
18
+ code: string;
19
+ explanation: string;
20
+ title: string;
21
+ }
22
+
23
+ export class ExecuteJavaScriptTool implements Tool<ExecuteJavaScriptArgs, unknown> {
24
+ readonly name = ToolName.EXECUTE_JAVASCRIPT;
25
+
26
+ readonly description =
27
+ 'This function allows you to run JavaScript code on the inspected page to access the element styles and page content.\nCall this function to gather additional information or modify the page state. Call this function enough times to investigate the user request.';
28
+
29
+ readonly parameters: Host.AidaClient.FunctionObjectParam<keyof ExecuteJavaScriptArgs> = {
30
+ type: Host.AidaClient.ParametersTypes.OBJECT,
31
+ description: '',
32
+ nullable: false,
33
+ properties: {
34
+ code: {
35
+ type: Host.AidaClient.ParametersTypes.STRING,
36
+ description:
37
+ `JavaScript code snippet to run on the inspected page. Make sure the code is formatted for readability.
38
+
39
+ # Instructions
40
+
41
+ * To return data, define a top-level \`data\` variable and populate it with data you want to get. Only JSON-serializable objects can be assigned to \`data\`.
42
+ * If you modify styles on an element, ALWAYS call the pre-defined global \`async setElementStyles(el: Element, styles: object)\` function. This function is an internal mechanism for you and should never be presented as a command/advice to the user.
43
+ * **CRITICAL** Only get styles that might be relevant to the user request.
44
+ * **CRITICAL** Never assume a selector for the elements unless you verified your knowledge.
45
+ * **CRITICAL** Consider that \`data\` variable from the previous function calls are not available in a new function call.
46
+
47
+ For example, the code to change element styles:
48
+
49
+ \`\`\`
50
+ await setElementStyles($0, {
51
+ color: 'blue',
52
+ });
53
+ \`\`\`
54
+
55
+ For example, the code to get overlapping elements:
56
+
57
+ \`\`\`
58
+ const data = {
59
+ overlappingElements: Array.from(document.querySelectorAll('*'))
60
+ .filter(el => {
61
+ const rect = el.getBoundingClientRect();
62
+ const popupRect = $0.getBoundingClientRect();
63
+ return (
64
+ el !== $0 &&
65
+ rect.left < popupRect.right &&
66
+ rect.right > popupRect.left &&
67
+ rect.top < popupRect.bottom &&
68
+ rect.bottom > popupRect.top
69
+ );
70
+ })
71
+ .map(el => ({
72
+ tagName: el.tagName,
73
+ id: el.id,
74
+ className: el.className,
75
+ zIndex: window.getComputedStyle(el)['z-index']
76
+ }))
77
+ };
78
+ \`\`\`
79
+ `,
80
+ },
81
+ explanation: {
82
+ type: Host.AidaClient.ParametersTypes.STRING,
83
+ description: 'Explain why you want to run this code',
84
+ },
85
+ title: {
86
+ type: Host.AidaClient.ParametersTypes.STRING,
87
+ description: 'Provide a summary of what the code does. For example, "Checking related element styles".',
88
+ },
89
+ },
90
+ required: ['code', 'explanation', 'title'],
91
+ };
92
+
93
+ displayInfoFromArgs(params: ExecuteJavaScriptArgs): {
94
+ title: string,
95
+ thought: string,
96
+ action: string,
97
+ } {
98
+ return {
99
+ title: params.title,
100
+ thought: params.explanation,
101
+ action: params.code,
102
+ };
103
+ }
104
+
105
+ async handler(
106
+ params: ExecuteJavaScriptArgs,
107
+ context: ToolContext,
108
+ options?: FunctionHandlerOptions,
109
+ ): Promise<FunctionCallHandlerResult<unknown>> {
110
+ const executionNode = context.getExecutionContextNode?.() ?? null;
111
+ if (!executionNode) {
112
+ return {error: 'Error: Could not find the context node for execution.'};
113
+ }
114
+
115
+ const executionMode = Root.Runtime.hostConfig.devToolsFreestyler?.executionMode ??
116
+ Root.Runtime.HostConfigFreestylerExecutionMode.ALL_SCRIPTS;
117
+
118
+ const changes = context.changeManager;
119
+ const createExtensionScope = context.createExtensionScope;
120
+ if (!changes || !createExtensionScope) {
121
+ return {error: 'Internal Error: Required change manager or extension scope creator is missing.'};
122
+ }
123
+
124
+ const executor = new JavascriptExecutor({
125
+ executionMode,
126
+ getContextNode: () => executionNode,
127
+ createExtensionScope,
128
+ changes,
129
+ },
130
+ context.execJs);
131
+
132
+ return await executor.executeAction(params.code, options);
133
+ }
134
+ }
@@ -5,7 +5,7 @@
5
5
  import * as Host from '../../../core/host/host.js';
6
6
  import * as SDK from '../../../core/sdk/sdk.js';
7
7
  import type * as Protocol from '../../../generated/protocol.js';
8
- import type {ComputedStyleAiWidget, FunctionCallHandlerResult} from '../agents/AiAgent.js';
8
+ import type {ComputedStyleAiWidget, FunctionCallHandlerResult, FunctionHandlerOptions} from '../agents/AiAgent.js';
9
9
  import {DOMNodeContext} from '../contexts/DOMNodeContext.js';
10
10
  import {debugLog} from '../debug.js';
11
11
 
@@ -69,7 +69,11 @@ export class GetStylesTool implements Tool<GetStylesArgs, unknown> {
69
69
  };
70
70
  }
71
71
 
72
- async handler(params: GetStylesArgs, context: ToolContext): Promise<FunctionCallHandlerResult<unknown>> {
72
+ async handler(
73
+ params: GetStylesArgs,
74
+ context: ToolContext,
75
+ _options?: FunctionHandlerOptions,
76
+ ): Promise<FunctionCallHandlerResult<unknown>> {
73
77
  const widgets: ComputedStyleAiWidget[] = [];
74
78
  const result:
75
79
  Record<string, {computed: Record<string, string|undefined>, authored: Record<string, string|undefined>}> = {};
@@ -3,13 +3,26 @@
3
3
  // found in the LICENSE file.
4
4
 
5
5
  import type * as Host from '../../../core/host/host.js';
6
- import type {ConversationContext, FunctionCallHandlerResult,} from '../agents/AiAgent.js';
6
+ import type * as SDK from '../../../core/sdk/sdk.js';
7
+ import type {ConversationContext, FunctionCallHandlerResult, FunctionHandlerOptions} from '../agents/AiAgent.js';
8
+ import type {executeJsCode} from '../agents/ExecuteJavascript.js';
9
+ import type {ChangeManager} from '../ChangeManager.js';
7
10
 
8
11
  /**
9
12
  * Context provided to the tool's handler execution.
10
13
  */
11
14
  export interface ToolContext {
12
15
  conversationContext: ConversationContext<unknown>|null;
16
+ changeManager?: ChangeManager;
17
+ createExtensionScope?: (changes: ChangeManager) => {
18
+ install(): Promise<void>, uninstall(): Promise<void>,
19
+ };
20
+ execJs?: typeof executeJsCode;
21
+ /**
22
+ * Returns the DOM node that acts as the execution context (i.e. `$0` inside the execution context)
23
+ * for running JavaScript.
24
+ */
25
+ getExecutionContextNode?: () => SDK.DOMModel.DOMNode | null;
13
26
  }
14
27
 
15
28
  /**
@@ -18,6 +31,7 @@ export interface ToolContext {
18
31
  export type ToolArgs = Record<string, unknown>;
19
32
 
20
33
  export const enum ToolName {
34
+ EXECUTE_JAVASCRIPT = 'executeJavaScript',
21
35
  GET_STYLES = 'getStyles',
22
36
  }
23
37
 
@@ -51,5 +65,6 @@ export interface Tool<Args extends ToolArgs = ToolArgs, ReturnType = unknown, >
51
65
  handler(
52
66
  args: Args,
53
67
  context: ToolContext,
68
+ options?: FunctionHandlerOptions,
54
69
  ): Promise<FunctionCallHandlerResult<ReturnType>>;
55
70
  }
@@ -2,6 +2,7 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
 
5
+ import {ExecuteJavaScriptTool} from './ExecuteJavaScript.js';
5
6
  import {GetStylesTool} from './GetStyles.js';
6
7
  import {type Tool, ToolName} from './Tool.js';
7
8
 
@@ -10,6 +11,7 @@ import {type Tool, ToolName} from './Tool.js';
10
11
  * Keep this type concrete (no type-erasure) to preserve exact tool types.
11
12
  */
12
13
  export const TOOLS = {
14
+ [ToolName.EXECUTE_JAVASCRIPT]: new ExecuteJavaScriptTool(),
13
15
  [ToolName.GET_STYLES]: new GetStylesTool(),
14
16
  };
15
17