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
@@ -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 * as SDK from '../../../core/sdk/sdk.js';
9
8
  import * as Protocol from '../../../generated/protocol.js';
@@ -11,16 +10,15 @@ import * as Greendev from '../../../models/greendev/greendev.js';
11
10
  import * as Annotations from '../../annotations/annotations.js';
12
11
  import * as Emulation from '../../emulation/emulation.js';
13
12
  import {ChangeManager} from '../ChangeManager.js';
14
- import {debugLog} from '../debug.js';
15
13
  import {ExtensionScope} from '../ExtensionScope.js';
16
14
  import {AI_ASSISTANCE_CSS_CLASS_NAME} from '../injected.js';
15
+ import {ToolName} from '../tools/Tool.js';
16
+ import {ToolRegistry} from '../tools/ToolRegistry.js';
17
17
 
18
18
  import {
19
19
  AiAgent,
20
- type ComputedStyleAiWidget,
21
20
  type ContextResponse,
22
- ConversationContext,
23
- type ConversationSuggestions,
21
+ type ConversationContext,
24
22
  type FunctionCallHandlerResult,
25
23
  type MultimodalInput,
26
24
  MultimodalInputType,
@@ -29,24 +27,10 @@ import {
29
27
  } from './AiAgent.js';
30
28
  import {
31
29
  type CreateExtensionScopeFunction,
32
- executeJavaScriptFunction,
33
30
  type ExecuteJsAgentOptions,
34
31
  executeJsCode,
35
- JavascriptExecutor
36
32
  } from './ExecuteJavascript.js';
37
33
 
38
- /*
39
- * Strings that don't need to be translated at this time.
40
- */
41
- const UIStringsNotTranslate = {
42
- /**
43
- * @description Heading text for context details of Freestyler agent.
44
- */
45
- dataUsed: 'Data used',
46
- } as const;
47
-
48
- const lockedString = i18n.i18n.lockedString;
49
-
50
34
  const preamble = `You are the most advanced CSS/DOM/HTML debugging assistant integrated into Chrome DevTools.
51
35
  You always suggest considering the best web development practices and the newest platform features such as view transitions.
52
36
  The user selected a DOM element in the browser's DevTools and sends a query about the page or the selected DOM element.
@@ -152,78 +136,6 @@ const MULTIMODAL_ENHANCEMENT_PROMPTS: Record<MultimodalInputType, string> = {
152
136
 
153
137
  export const AI_ASSISTANCE_FILTER_REGEX = `\\.${AI_ASSISTANCE_CSS_CLASS_NAME}-.*&`;
154
138
 
155
- export class NodeContext extends ConversationContext<SDK.DOMModel.DOMNode> {
156
- #node: SDK.DOMModel.DOMNode;
157
-
158
- constructor(node: SDK.DOMModel.DOMNode) {
159
- super();
160
- this.#node = node;
161
- }
162
-
163
- override getURL(): string {
164
- const ownerDocument = this.#node.ownerDocument;
165
- if (!ownerDocument) {
166
- // The node is detached from a document.
167
- return 'detached';
168
- }
169
- return ownerDocument.documentURL;
170
- }
171
-
172
- getItem(): SDK.DOMModel.DOMNode {
173
- return this.#node;
174
- }
175
-
176
- override getTitle(): string {
177
- throw new Error('Not implemented');
178
- }
179
-
180
- override async getSuggestions(): Promise<ConversationSuggestions|undefined> {
181
- const layoutProps = await this.#node.domModel().cssModel().getLayoutPropertiesFromComputedStyle(this.#node.id);
182
-
183
- if (!layoutProps) {
184
- return;
185
- }
186
-
187
- if (layoutProps.isFlex) {
188
- return [
189
- {title: 'How can I make flex items wrap?', jslogContext: 'flex-wrap'},
190
- {title: 'How do I distribute flex items evenly?', jslogContext: 'flex-distribute'},
191
- {title: 'What is flexbox?', jslogContext: 'flex-what'},
192
- ];
193
- }
194
- if (layoutProps.isSubgrid) {
195
- return [
196
- {title: 'Where is this grid defined?', jslogContext: 'subgrid-where'},
197
- {title: 'How to overwrite parent grid properties?', jslogContext: 'subgrid-override'},
198
- {title: 'How do subgrids work? ', jslogContext: 'subgrid-how'},
199
- ];
200
- }
201
- if (layoutProps.isGrid) {
202
- return [
203
- {title: 'How do I align items in a grid?', jslogContext: 'grid-align'},
204
- {title: 'How to add spacing between grid items?', jslogContext: 'grid-gap'},
205
- {title: 'How does grid layout work?', jslogContext: 'grid-how'},
206
- ];
207
- }
208
- if (layoutProps.hasScroll) {
209
- return [
210
- {title: 'How do I remove scrollbars for this element?', jslogContext: 'scroll-remove'},
211
- {title: 'How can I style a scrollbar?', jslogContext: 'scroll-style'},
212
- {title: 'Why does this element scroll?', jslogContext: 'scroll-why'},
213
- ];
214
- }
215
- if (layoutProps.containerType) {
216
- return [
217
- {title: 'What are container queries?', jslogContext: 'container-what'},
218
- {title: 'How do I use container-type?', jslogContext: 'container-how'},
219
- {title: 'What\'s the container context for this element?', jslogContext: 'container-context'},
220
- ];
221
- }
222
-
223
- return;
224
- }
225
- }
226
-
227
139
  /**
228
140
  * One agent instance handles one conversation. Create a new agent
229
141
  * instance for a new conversation.
@@ -255,88 +167,55 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
255
167
  }
256
168
 
257
169
  #execJs: typeof executeJsCode;
258
- #javascriptExecutor: JavascriptExecutor;
259
170
 
260
171
  #changes: ChangeManager;
261
172
  #createExtensionScope: CreateExtensionScopeFunction;
262
173
  #greenDevEmulationScreenshot: string|null = null;
263
174
  #greenDevEmulationAxTree: string|null = null;
264
175
  #hasAddedEmulationInstructions = false;
265
- #currentTurnId = 0;
266
176
 
267
177
  constructor(opts: ExecuteJsAgentOptions) {
268
178
  super(opts);
269
179
 
270
180
  this.#changes = opts.changeManager || new ChangeManager();
271
181
  this.#execJs = opts.execJs ?? executeJsCode;
272
- this.#createExtensionScope =
273
- opts.createExtensionScope ?? ((changes: ChangeManager) => {
274
- return new ExtensionScope(changes, this.sessionId, this.context?.getItem() ?? null, this.#currentTurnId);
275
- });
276
- this.#javascriptExecutor = new JavascriptExecutor(
277
- {
278
- executionMode: this.executionMode,
279
- getContextNode: () => this.#getSelectedNode(),
280
- createExtensionScope: this.#createExtensionScope.bind(this),
281
- changes: this.#changes,
282
- },
283
- this.#execJs);
284
-
285
- this.declareFunction<{
286
- elements: number[],
287
- styleProperties: string[],
288
- explanation: string,
289
- }>('getStyles', {
290
- description:
291
- `Get computed and source styles for one or multiple elements on the inspected page for multiple elements at once by uid.
182
+ this.#createExtensionScope = opts.createExtensionScope ?? ((changes: ChangeManager) => {
183
+ return new ExtensionScope(changes, this.sessionId, this.context?.getItem() ?? null);
184
+ });
185
+
186
+ const getStylesTool = ToolRegistry.get(ToolName.GET_STYLES);
187
+ if (!getStylesTool) {
188
+ throw new Error('Required tool "getStyles" not found');
189
+ }
190
+ this.declareFunction(ToolName.GET_STYLES, {
191
+ description: getStylesTool.description,
192
+ parameters: getStylesTool.parameters,
193
+ displayInfoFromArgs: getStylesTool.displayInfoFromArgs,
194
+ handler: args => getStylesTool.handler(args, {
195
+ conversationContext: this.context ?? null,
196
+ }),
197
+ });
292
198
 
293
- **CRITICAL** An element uid is a number, not a selector.
294
- **CRITICAL** Use selectors to refer to elements in the text output. Do not use uids.
295
- **CRITICAL** Always provide the explanation argument to explain what and why you query.
296
- **CRITICAL** You MUST provide a specific list of CSS property names. Do not use generic values like "all" or "*".`,
297
- parameters: {
298
- type: Host.AidaClient.ParametersTypes.OBJECT,
299
- description: '',
300
- nullable: false,
301
- properties: {
302
- explanation: {
303
- type: Host.AidaClient.ParametersTypes.STRING,
304
- description: 'Explain why you want to get styles',
305
- nullable: false,
306
- },
307
- elements: {
308
- type: Host.AidaClient.ParametersTypes.ARRAY,
309
- description: 'A list of element uids to get data for. These are numbers, not selectors.',
310
- items: {type: Host.AidaClient.ParametersTypes.INTEGER, description: `An element uid.`},
311
- nullable: false,
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,
312
214
  },
313
- styleProperties: {
314
- type: Host.AidaClient.ParametersTypes.ARRAY,
315
- description:
316
- 'One or more specific CSS style property names to fetch. Generic values like "all" or "*" are not supported.',
317
- nullable: false,
318
- items: {
319
- type: Host.AidaClient.ParametersTypes.STRING,
320
- description: 'A CSS style property name to retrieve. For example, \'background-color\'.'
321
- }
322
- },
323
- },
324
- required: ['explanation', 'elements', 'styleProperties']
325
- },
326
- displayInfoFromArgs: params => {
327
- return {
328
- title: 'Reading computed and source styles',
329
- thought: params.explanation,
330
- action: `getStyles(${JSON.stringify(params.elements)}, ${JSON.stringify(params.styleProperties)})`,
331
- };
332
- },
333
- handler: async params => {
334
- return await this.#getStyles(params.elements, params.styleProperties);
335
- },
215
+ options,
216
+ ),
336
217
  });
337
218
 
338
- this.declareFunction('executeJavaScript', executeJavaScriptFunction(this.#javascriptExecutor));
339
-
340
219
  if (Annotations.AnnotationRepository.annotationsEnabled()) {
341
220
  this.declareFunction<{
342
221
  elementId: string,
@@ -401,162 +280,10 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
401
280
  });
402
281
  }
403
282
 
404
- static async describeElement(element: SDK.DOMModel.DOMNode): Promise<string> {
405
- let output = `* Element's uid is ${element.backendNodeId()}.
406
- * Its selector is \`${element.simpleSelector()}\``;
407
- const childNodes = await element.getChildNodesPromise();
408
- if (childNodes) {
409
- const textChildNodes = childNodes.filter(childNode => childNode.nodeType() === Node.TEXT_NODE);
410
- const elementChildNodes = childNodes.filter(childNode => childNode.nodeType() === Node.ELEMENT_NODE);
411
- switch (elementChildNodes.length) {
412
- case 0:
413
- output += '\n* It doesn\'t have any child element nodes';
414
- break;
415
- case 1:
416
- output += `\n* It only has 1 child element node: \`${elementChildNodes[0].simpleSelector()}\``;
417
- break;
418
- default:
419
- output += `\n* It has ${elementChildNodes.length} child element nodes: ${
420
- elementChildNodes.map(node => `\`${node.simpleSelector()}\` (uid=${node.backendNodeId()})`).join(', ')}`;
421
- }
422
-
423
- switch (textChildNodes.length) {
424
- case 0:
425
- output += '\n* It doesn\'t have any child text nodes';
426
- break;
427
- case 1:
428
- output += '\n* It only has 1 child text node';
429
- break;
430
- default:
431
- output += `\n* It has ${textChildNodes.length} child text nodes`;
432
- }
433
- }
434
-
435
- if (element.nextSibling) {
436
- const elementOrNodeElementNodeText = element.nextSibling.nodeType() === Node.ELEMENT_NODE ?
437
- `an element (uid=${element.nextSibling.backendNodeId()})` :
438
- 'a non element';
439
- output += `\n* It has a next sibling and it is ${elementOrNodeElementNodeText} node`;
440
- }
441
-
442
- if (element.previousSibling) {
443
- const elementOrNodeElementNodeText = element.previousSibling.nodeType() === Node.ELEMENT_NODE ?
444
- `an element (uid=${element.previousSibling.backendNodeId()})` :
445
- 'a non element';
446
- output += `\n* It has a previous sibling and it is ${elementOrNodeElementNodeText} node`;
447
- }
448
-
449
- if (element.isInShadowTree()) {
450
- output += '\n* It is in a shadow DOM tree.';
451
- }
452
-
453
- const parentNode = element.parentNode;
454
- if (parentNode) {
455
- const parentChildrenNodes = await parentNode.getChildNodesPromise();
456
- output += `\n* Its parent's selector is \`${parentNode.simpleSelector()}\` (uid=${parentNode.backendNodeId()})`;
457
- const elementOrNodeElementNodeText = parentNode.nodeType() === Node.ELEMENT_NODE ? 'an element' : 'a non element';
458
- output += `\n* Its parent is ${elementOrNodeElementNodeText} node`;
459
- if (parentNode.isShadowRoot()) {
460
- output += '\n* Its parent is a shadow root.';
461
- }
462
- if (parentChildrenNodes) {
463
- const childElementNodes =
464
- parentChildrenNodes.filter(siblingNode => siblingNode.nodeType() === Node.ELEMENT_NODE);
465
- switch (childElementNodes.length) {
466
- case 0:
467
- break;
468
- case 1:
469
- output += '\n* Its parent has only 1 child element node';
470
- break;
471
- default:
472
- output += `\n* Its parent has ${childElementNodes.length} child element nodes: ${
473
- childElementNodes.map(node => `\`${node.simpleSelector()}\` (uid=${node.backendNodeId()})`)
474
- .join(', ')}`;
475
- break;
476
- }
477
-
478
- const siblingTextNodes = parentChildrenNodes.filter(siblingNode => siblingNode.nodeType() === Node.TEXT_NODE);
479
- switch (siblingTextNodes.length) {
480
- case 0:
481
- break;
482
- case 1:
483
- output += '\n* Its parent has only 1 child text node';
484
- break;
485
- default:
486
- output += `\n* Its parent has ${siblingTextNodes.length} child text nodes: ${
487
- siblingTextNodes.map(node => `\`${node.simpleSelector()}\``).join(', ')}`;
488
- break;
489
- }
490
- }
491
- }
492
-
493
- return output.trim();
494
- }
495
-
496
283
  #getSelectedNode(): SDK.DOMModel.DOMNode|null {
497
284
  return this.context?.getItem() ?? null;
498
285
  }
499
286
 
500
- async #getStyles(elements: number[], properties: string[]): Promise<FunctionCallHandlerResult<unknown>> {
501
- const widgets: ComputedStyleAiWidget[] = [];
502
-
503
- const result:
504
- Record<string, {computed: Record<string, string|undefined>, authored: Record<string, string|undefined>}> = {};
505
- for (const uid of elements) {
506
- result[uid] = {computed: {}, authored: {}};
507
- debugLog(`Action to execute: uid=${uid}`);
508
- const selectedNode = this.#getSelectedNode();
509
- if (!selectedNode) {
510
- return {error: 'Error: Could not find the currently selected element.'};
511
- }
512
- const node = new SDK.DOMModel.DeferredDOMNode(
513
- selectedNode.domModel().target(), Number(uid) as unknown as Protocol.DOM.BackendNodeId);
514
- const resolved = await node.resolvePromise();
515
- if (!resolved) {
516
- return {error: 'Error: Could not find the element with uid=' + uid};
517
- }
518
- const newContext = new NodeContext(resolved);
519
- if (this.context?.getOrigin() !== newContext.getOrigin()) {
520
- return {error: 'Error: Node does not belong to the current origin.'};
521
- }
522
- const styles = await resolved.domModel().cssModel().getComputedStyle(resolved.id);
523
- if (!styles) {
524
- return {error: 'Error: Could not get computed styles.'};
525
- }
526
- const matchedStyles = await resolved.domModel().cssModel().getMatchedStyles(resolved.id);
527
- if (!matchedStyles) {
528
- return {error: 'Error: Could not get authored styles.'};
529
- }
530
- widgets.push({
531
- name: 'COMPUTED_STYLES',
532
- data: {
533
- computedStyles: styles,
534
- backendNodeId: node.backendNodeId(),
535
- matchedCascade: matchedStyles,
536
- properties,
537
- }
538
- });
539
- for (const prop of properties) {
540
- result[uid].computed[prop] = styles.get(prop);
541
- }
542
- for (const style of matchedStyles.nodeStyles()) {
543
- for (const property of style.allProperties()) {
544
- if (!properties.includes(property.name)) {
545
- continue;
546
- }
547
- const state = matchedStyles.propertyState(property);
548
- if (state === SDK.CSSMatchedStyles.PropertyState.ACTIVE) {
549
- result[uid].authored[property.name] = property.value;
550
- }
551
- }
552
- }
553
- }
554
- return {
555
- result: JSON.stringify(result, null, 2),
556
- widgets,
557
- };
558
- }
559
-
560
287
  async addElementAnnotation(elementId: string, annotationMessage: string):
561
288
  Promise<FunctionCallHandlerResult<unknown>> {
562
289
  if (!Annotations.AnnotationRepository.annotationsEnabled()) {
@@ -782,20 +509,15 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
782
509
  override async *
783
510
  handleContextDetails(selectedElement: ConversationContext<SDK.DOMModel.DOMNode>|null):
784
511
  AsyncGenerator<ContextResponse, void, void> {
785
- if (!selectedElement) {
786
- return;
512
+ if (selectedElement) {
513
+ const details = await selectedElement.getUserFacingDetails();
514
+ if (details) {
515
+ yield {
516
+ type: ResponseType.CONTEXT,
517
+ details,
518
+ };
519
+ }
787
520
  }
788
- yield {
789
- type: ResponseType.CONTEXT,
790
- details: [{
791
- title: lockedString(UIStringsNotTranslate.dataUsed),
792
- text: await StylingAgent.describeElement(selectedElement.getItem()),
793
- }],
794
- };
795
- }
796
-
797
- protected override async preRun(): Promise<void> {
798
- this.#currentTurnId++;
799
521
  }
800
522
 
801
523
  override async enhanceQuery(
@@ -814,10 +536,8 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
814
536
  this.#hasAddedEmulationInstructions = true;
815
537
  }
816
538
 
817
- const elementEnchancementQuery = selectedElement ?
818
- `# Inspected element\n\n${
819
- await StylingAgent.describeElement(selectedElement.getItem())}\n\n# User request\n\n` :
820
- '';
539
+ const promptDetails = selectedElement ? await selectedElement.getPromptDetails() : null;
540
+ const elementEnchancementQuery = promptDetails ? `${promptDetails}\n\n# User request\n\n` : '';
821
541
  return `${multimodalInputEnhancementQuery}${elementEnchancementQuery}QUERY: ${query}`;
822
542
  }
823
543
  }
@@ -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';
@@ -24,6 +22,8 @@ import * as AiOrigins from './AiOrigins.js';
24
22
  import * as AiUtils from './AiUtils.js';
25
23
  import * as BuiltInAi from './BuiltInAi.js';
26
24
  import * as ChangeManager from './ChangeManager.js';
25
+ import * as DOMNodeContext from './contexts/DOMNodeContext.js';
26
+ import * as ConversationSummary from './ConversationSummary.js';
27
27
  import * as FileFormatter from './data_formatters/FileFormatter.js';
28
28
  import * as LighthouseFormatter from './data_formatters/LighthouseFormatter.js';
29
29
  import * as NetworkRequestFormatter from './data_formatters/NetworkRequestFormatter.js';
@@ -37,7 +37,12 @@ import * as Injected from './injected.js';
37
37
  import * as AICallTree from './performance/AICallTree.js';
38
38
  import * as AIContext from './performance/AIContext.js';
39
39
  import * as AIQueries from './performance/AIQueries.js';
40
+ import * as PerformanceAnnotations from './PerformanceAnnotations.js';
40
41
  import * as StorageItem from './StorageItem.js';
42
+ import * as ExecuteJavaScript from './tools/ExecuteJavaScript.js';
43
+ import * as GetStyles from './tools/GetStyles.js';
44
+ import * as Tool from './tools/Tool.js';
45
+ import * as ToolRegistry from './tools/ToolRegistry.js';
41
46
 
42
47
  export {
43
48
  AccessibilityAgent,
@@ -54,12 +59,15 @@ export {
54
59
  BuiltInAi,
55
60
  ChangeManager,
56
61
  ContextSelectionAgent,
57
- ConversationSummaryAgent,
62
+ ConversationSummary,
58
63
  Debug,
64
+ DOMNodeContext,
59
65
  EvaluateAction,
66
+ ExecuteJavaScript,
60
67
  ExtensionScope,
61
68
  FileAgent,
62
69
  FileFormatter,
70
+ GetStyles,
63
71
  GreenDevAgent,
64
72
  GreenDevAgentAntigravityCliSocketClient,
65
73
  GreenDevAgentGeminiCliSocketClient,
@@ -69,11 +77,13 @@ export {
69
77
  NetworkRequestFormatter,
70
78
  PatchAgent,
71
79
  PerformanceAgent,
72
- PerformanceAnnotationsAgent,
80
+ PerformanceAnnotations,
73
81
  PerformanceInsightFormatter,
74
82
  PerformanceTraceFormatter,
75
83
  StorageAgent,
76
84
  StorageItem,
77
85
  StylingAgent,
86
+ Tool,
87
+ ToolRegistry,
78
88
  UnitFormatters,
79
89
  };
@@ -0,0 +1,51 @@
1
+ Title: DOMNodeContext getPromptDetails describes the node correctly
2
+ Content:
3
+ # Inspected element
4
+
5
+ * Element's uid is 99.
6
+ * Its selector is `div#myElement`
7
+ === end content
8
+
9
+ Title: DOMNodeContext getUserFacingDetails returns details with Data Used title
10
+ Content:
11
+ [
12
+ {
13
+ "title": "Data used",
14
+ "text": "* Element's uid is 99.\n* Its selector is `div#myElement`"
15
+ }
16
+ ]
17
+ === end content
18
+
19
+ Title: DOMNodeContext describes an element with child nodes not loaded
20
+ Content:
21
+ * Element's uid is 99.
22
+ * Its selector is `div#myElement`
23
+ === end content
24
+
25
+ Title: DOMNodeContext describes an element with no children, siblings, or parent
26
+ Content:
27
+ * Element's uid is 99.
28
+ * Its selector is `div#myElement`
29
+ * It doesn't have any child element nodes
30
+ * It doesn't have any child text nodes
31
+ === end content
32
+
33
+ Title: DOMNodeContext describes an element with child element and text nodes
34
+ Content:
35
+ * Element's uid is 99.
36
+ * Its selector is `div#parentElement`
37
+ * It has 2 child element nodes: `span.child1` (uid=undefined), `span.child2` (uid=undefined)
38
+ * It only has 1 child text node
39
+ === end content
40
+
41
+ Title: DOMNodeContext describes an element with siblings and a parent
42
+ Content:
43
+ * Element's uid is 99.
44
+ * Its selector is `div#parentElement`
45
+ * It has a next sibling and it is an element (uid=undefined) node
46
+ * It has a previous sibling and it is a non element node
47
+ * Its parent's selector is `div#grandparentElement` (uid=undefined)
48
+ * Its parent is a non element node
49
+ * Its parent has only 1 child element node
50
+ * Its parent has only 1 child text node
51
+ === end content