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
package/eslint.config.mjs CHANGED
@@ -721,7 +721,8 @@ export default defineConfig([
721
721
  'test/**/*.ts',
722
722
  '**/testing/*.ts',
723
723
  'scripts/eslint_rules/test/**/*',
724
- 'extensions/cxx_debugging/e2e/**',
724
+ 'extensions/cxx_debugging/e2e/**/*.ts',
725
+ 'extensions/cxx_debugging/tests/**/*.ts',
725
726
  ],
726
727
 
727
728
  rules: {
@@ -750,6 +751,7 @@ export default defineConfig([
750
751
  ],
751
752
 
752
753
  '@devtools/check-test-definitions': 'error',
754
+ '@devtools/prefer-chai-assert': 'error',
753
755
  '@devtools/no-assert-strict-equal-for-arrays-and-objects': 'error',
754
756
  '@devtools/no-assert-deep-strict-equal': 'error',
755
757
  '@devtools/no-assert-equal': 'error',
@@ -19,8 +19,35 @@ export namespace Chrome {
19
19
  */
20
20
  readonly buildId?: string;
21
21
 
22
+ /**
23
+ * Returns the `content` and `encoding` of the resource. If a `callback`
24
+ * is provided, it is invoked with the `content` and `encoding` and the
25
+ * method returns `void`. If no `callback` is provided, the method returns
26
+ * a `Promise`.
27
+ *
28
+ * @param callback Optional callback to be invoked with the content and
29
+ * encoding.
30
+ * @returns A Promise that resolves to an object containing the content
31
+ * and encoding if no callback is provided, otherwise void. Rejects with
32
+ * an error object on failure.
33
+ */
34
+ getContent(): Promise<{content: string, encoding: string}>;
22
35
  getContent(callback: (content: string, encoding: string) => unknown): void;
23
- setContent(content: string, commit: boolean, callback?: (error?: Object) => unknown): void;
36
+
37
+ /**
38
+ * Sets the content of the resource. If a `callback` is provided, it is
39
+ * invoked when the content is set and the method returns `void`. If no
40
+ * `callback` is provided, the method returns a `Promise`.
41
+ *
42
+ * @param content The new content of the resource.
43
+ * @param commit Whether to commit the changes.
44
+ * @param callback Optional callback to be invoked when the content is
45
+ * set.
46
+ * @returns A Promise that resolves when the content is set if no callback
47
+ * is provided, otherwise void. Rejects with an error object on failure.
48
+ */
49
+ setContent(content: string, commit: boolean): Promise<void>;
50
+ setContent(content: string, commit: boolean, callback: (error?: object) => unknown): void;
24
51
  /**
25
52
  * Augments this resource's scopes information based on the list of {@link NamedFunctionRange}s
26
53
  * for improved debuggability and function naming.
@@ -40,18 +67,62 @@ export namespace Chrome {
40
67
  onResourceAdded: EventSink<(resource: Resource) => unknown>;
41
68
  onResourceContentCommitted: EventSink<(resource: Resource, content: string) => unknown>;
42
69
 
43
- eval(
44
- expression: string,
45
- options?: {scriptExecutionContext?: string, frameURL?: string, useContentScriptContext?: boolean},
46
- callback?: (result: unknown, exceptioninfo: {
47
- code: string,
48
- description: string,
49
- details: unknown[],
50
- isError: boolean,
51
- isException: boolean,
52
- value: string,
53
- }) => unknown): void;
70
+ /**
71
+ * Evaluates a JavaScript expression in the context of the inspected page.
72
+ *
73
+ * If a `callback` is provided, it is invoked with the result and
74
+ * exception information and the method returns `void`. If no `callback`
75
+ * is provided, the method returns a `Promise`.
76
+ *
77
+ * @template E The type of the value that the Promise resolves to.
78
+ * @param expression The JavaScript expression to evaluate.
79
+ * @param optionsOrCallback Optional options for evaluation, or a callback
80
+ * function.
81
+ * @param callback Optional callback to be invoked with the evaluation
82
+ * result and exception information.
83
+ * @returns A Promise that resolves to the result if no callback is
84
+ * provided, otherwise void. Rejects with an error object on failure.
85
+ */
86
+ eval<E = unknown>(expression: string, options?: {
87
+ scriptExecutionContext?: string,
88
+ frameURL?: string,
89
+ useContentScriptContext?: boolean,
90
+ }): Promise<E>;
91
+ eval(expression: string,
92
+ optionsOrCallback: {scriptExecutionContext?: string, frameURL?: string, useContentScriptContext?: boolean}|
93
+ undefined|((result: unknown, exceptioninfo: {
94
+ code: string,
95
+ description: string,
96
+ details: unknown[],
97
+ isError: boolean,
98
+ isException: boolean,
99
+ value: string,
100
+ }) => unknown),
101
+ callback?: (result: unknown, exceptioninfo: {
102
+ code: string,
103
+ description: string,
104
+ details: unknown[],
105
+ isError: boolean,
106
+ isException: boolean,
107
+ value: string,
108
+ }) => unknown): void;
109
+
110
+ /**
111
+ * Retrieves all resources within the inspected window.
112
+ *
113
+ * If a `callback` is provided, it is invoked with the array of resources
114
+ * and the method returns `void`. If no `callback` is provided, the method
115
+ * returns a `Promise`.
116
+ *
117
+ * @param callback Optional callback to be invoked with the array of
118
+ * resources.
119
+ * @returns A Promise that resolves to an array of resources if no
120
+ * callback is provided, otherwise void. Rejects with an error object on
121
+ * failure.
122
+ */
123
+ getResources(): Promise<Resource[]>;
54
124
  getResources(callback: (resources: Resource[]) => unknown): void;
125
+
55
126
  reload(reloadOptions?: {ignoreCache?: boolean, injectedScript?: string, userAgent?: string}): void;
56
127
  }
57
128
 
@@ -767,7 +767,6 @@ export enum DevtoolsExperiments {
767
767
  /* eslint-disable @typescript-eslint/naming-convention */
768
768
  'protocol-monitor' = 13,
769
769
  'instrumentation-breakpoints' = 61,
770
- 'use-source-map-scopes' = 76,
771
770
  'durable-messages' = 110,
772
771
  'jpeg-xl' = 111,
773
772
  'plus-button' = 112,
@@ -339,6 +339,10 @@ export class TargetBase {
339
339
  return this.getAgent('Autofill');
340
340
  }
341
341
 
342
+ adsAgent(): ProtocolProxyApi.AdsApi {
343
+ return this.getAgent('Ads');
344
+ }
345
+
342
346
  browserAgent(): ProtocolProxyApi.BrowserApi {
343
347
  return this.getAgent('Browser');
344
348
  }
@@ -6,7 +6,6 @@ export enum ExperimentName {
6
6
  ALL = '*',
7
7
  PROTOCOL_MONITOR = 'protocol-monitor',
8
8
  INSTRUMENTATION_BREAKPOINTS = 'instrumentation-breakpoints',
9
- USE_SOURCE_MAP_SCOPES = 'use-source-map-scopes',
10
9
  DURABLE_MESSAGES = 'durable-messages',
11
10
  JPEG_XL = 'jpeg-xl',
12
11
  PLUS_BUTTON = 'plus-button',
@@ -547,6 +547,7 @@ export interface ConsoleMessageDetails {
547
547
  context?: string;
548
548
  affectedResources?: AffectedResources;
549
549
  category?: Protocol.Log.LogEntryCategory;
550
+ exceptionDetails?: Protocol.Runtime.ExceptionDetails;
550
551
  }
551
552
 
552
553
  export class ConsoleMessage {
@@ -570,6 +571,7 @@ export class ConsoleMessage {
570
571
  #exceptionId?: number = undefined;
571
572
  #affectedResources?: AffectedResources;
572
573
  category?: Protocol.Log.LogEntryCategory;
574
+ readonly exceptionDetails?: Protocol.Runtime.ExceptionDetails;
573
575
 
574
576
  /**
575
577
  * The parent frame of the `console.log` call of logpoints or conditional breakpoints
@@ -600,6 +602,7 @@ export class ConsoleMessage {
600
602
  this.workerId = details?.workerId;
601
603
  this.#affectedResources = details?.affectedResources;
602
604
  this.category = details?.category;
605
+ this.exceptionDetails = details?.exceptionDetails;
603
606
 
604
607
  if (!this.#executionContextId && this.#runtimeModel) {
605
608
  if (this.scriptId) {
@@ -646,6 +649,7 @@ export class ConsoleMessage {
646
649
  executionContextId: exceptionDetails.executionContextId,
647
650
  scriptId: exceptionDetails.scriptId,
648
651
  affectedResources,
652
+ exceptionDetails,
649
653
  };
650
654
  return new ConsoleMessage(
651
655
  runtimeModel, Protocol.Log.LogEntrySource.Javascript, Protocol.Log.LogEntryLevel.Error,
@@ -299,6 +299,10 @@ export class NetworkRequest extends Common.ObjectWrapper.ObjectWrapper<EventType
299
299
  #contentDataProvider?: () => Promise<TextUtils.ContentData.ContentDataOrError>;
300
300
  #isSameSite: boolean|null = null;
301
301
  #wasIntercepted = false;
302
+ /**
303
+ * Whether this request was imported from a HAR file.
304
+ */
305
+ #isImportedHar = false;
302
306
  #associatedData = new Map<string, object>();
303
307
  #hasOverriddenContent = false;
304
308
  #hasThirdPartyCookiePhaseoutIssue = false;
@@ -1148,6 +1152,14 @@ export class NetworkRequest extends Common.ObjectWrapper.ObjectWrapper<EventType
1148
1152
  this.#wasIntercepted = wasIntercepted;
1149
1153
  }
1150
1154
 
1155
+ isImportedHar(): boolean {
1156
+ return this.#isImportedHar;
1157
+ }
1158
+
1159
+ setIsImportedHar(isImportedHar: boolean): void {
1160
+ this.#isImportedHar = isImportedHar;
1161
+ }
1162
+
1151
1163
  setEarlyHintsHeaders(headers: NameValue[]): void {
1152
1164
  this.earlyHintsHeaders = headers;
1153
1165
  }
@@ -6,7 +6,6 @@ import * as TextUtils from '../../models/text_utils/text_utils.js';
6
6
  import * as ScopesCodec from '../../third_party/source-map-scopes-codec/source-map-scopes-codec.js';
7
7
  import * as Common from '../common/common.js';
8
8
  import * as Platform from '../platform/platform.js';
9
- import * as Root from '../root/root.js';
10
9
 
11
10
  import type {CallFrame, ScopeChainEntry} from './DebuggerModel.js';
12
11
  import {scopeTreeForScript} from './ScopeTreeCache.js';
@@ -584,23 +583,21 @@ export class SourceMap {
584
583
  lineNumber, columnNumber, sourceIndex, sourceURL, sourceLineNumber, sourceColumnNumber, names[nameIndex]));
585
584
  }
586
585
 
587
- if (Root.Runtime.experiments.isEnabled(Root.ExperimentNames.ExperimentName.USE_SOURCE_MAP_SCOPES)) {
588
- if (!this.#scopesInfo) {
589
- this.#scopesInfo = new SourceMapScopesInfo(this, {scopes: [], ranges: []});
590
- }
591
- if (map.scopes) {
592
- const {scopes, ranges} = ScopesCodec.decode(
593
- map as ScopesCodec.SourceMapJson,
594
- {mode: ScopesCodec.DecodeMode.LAX, generatedOffset: {line: baseLineNumber, column: baseColumnNumber}});
595
- this.#scopesInfo.addOriginalScopes(scopes);
596
- this.#scopesInfo.addGeneratedRanges(ranges);
597
- } else if (map.x_com_bloomberg_sourcesFunctionMappings) {
598
- const originalScopes = this.parseBloombergScopes(map);
599
- this.#scopesInfo.addOriginalScopes(originalScopes);
600
- } else {
601
- // Keep the OriginalScope[] tree array consistent with sources.
602
- this.#scopesInfo.addOriginalScopes(new Array(map.sources.length).fill(null));
603
- }
586
+ if (!this.#scopesInfo) {
587
+ this.#scopesInfo = new SourceMapScopesInfo(this, {scopes: [], ranges: []});
588
+ }
589
+ if (map.scopes) {
590
+ const {scopes, ranges} = ScopesCodec.decode(
591
+ map as ScopesCodec.SourceMapJson,
592
+ {mode: ScopesCodec.DecodeMode.LAX, generatedOffset: {line: baseLineNumber, column: baseColumnNumber}});
593
+ this.#scopesInfo.addOriginalScopes(scopes);
594
+ this.#scopesInfo.addGeneratedRanges(ranges);
595
+ } else if (map.x_com_bloomberg_sourcesFunctionMappings) {
596
+ const originalScopes = this.parseBloombergScopes(map);
597
+ this.#scopesInfo.addOriginalScopes(originalScopes);
598
+ } else {
599
+ // Keep the OriginalScope[] tree array consistent with sources.
600
+ this.#scopesInfo.addOriginalScopes(new Array(map.sources.length).fill(null));
604
601
  }
605
602
  }
606
603
 
@@ -593,8 +593,6 @@ async function init(): Promise<void> {
593
593
 
594
594
  safeRegisterExperiment(
595
595
  Root.ExperimentNames.ExperimentName.INSTRUMENTATION_BREAKPOINTS, 'Enable instrumentation breakpoints');
596
- safeRegisterExperiment(
597
- Root.ExperimentNames.ExperimentName.USE_SOURCE_MAP_SCOPES, 'Use scope information from source maps');
598
596
  safeRegisterExperiment(Root.ExperimentNames.ExperimentName.PROTOCOL_MONITOR, 'Protocol Monitor');
599
597
 
600
598
  const hostUnsyncedStorage: Common.Settings.SettingsBackingStore = {
@@ -247,8 +247,6 @@ async function init(): Promise<void> {
247
247
  // Register necessary experiments to avoid "Unknown experiment" errors.
248
248
  Root.Runtime.experiments.register(
249
249
  Root.ExperimentNames.ExperimentName.INSTRUMENTATION_BREAKPOINTS, 'Enable instrumentation breakpoints');
250
- Root.Runtime.experiments.register(
251
- Root.ExperimentNames.ExperimentName.USE_SOURCE_MAP_SCOPES, 'Use scope information from source maps');
252
250
  Root.Runtime.experiments.register(Root.ExperimentNames.ExperimentName.PROTOCOL_MONITOR, 'Protocol Monitor');
253
251
 
254
252
  const WINDOW_LOCAL_STORAGE: Common.Settings.SettingsBackingStore = {
@@ -876,7 +876,7 @@ export abstract class HeapSnapshot {
876
876
  readonly #progress: HeapSnapshotProgress;
877
877
  readonly #noDistance = -5;
878
878
  rootNodeIndexInternal = 0;
879
- #snapshotDiffs: Record<string, Record<string, HeapSnapshotModel.HeapSnapshotModel.Diff>> = {};
879
+ #snapshotDiffs: Record<number, Record<string, HeapSnapshotModel.HeapSnapshotModel.Diff>> = {};
880
880
  #aggregatesForDiff?: {
881
881
  interfaceDefinitions: string,
882
882
  aggregates: Record<string, HeapSnapshotModel.HeapSnapshotModel.AggregateForDiff>,
@@ -2688,9 +2688,8 @@ export abstract class HeapSnapshot {
2688
2688
  throw new Error('Not implemented');
2689
2689
  }
2690
2690
 
2691
- calculateSnapshotDiff(
2692
- baseSnapshotId: string,
2693
- baseSnapshotAggregates: Record<string, HeapSnapshotModel.HeapSnapshotModel.AggregateForDiff>):
2691
+ calculateSnapshotDiff(baseSnapshotId: number,
2692
+ baseSnapshotAggregates: Record<string, HeapSnapshotModel.HeapSnapshotModel.AggregateForDiff>):
2694
2693
  Record<string, HeapSnapshotModel.HeapSnapshotModel.Diff> {
2695
2694
  let snapshotDiff: Record<string, HeapSnapshotModel.HeapSnapshotModel.Diff> = this.#snapshotDiffs[baseSnapshotId];
2696
2695
  if (snapshotDiff) {
@@ -2976,7 +2975,7 @@ export abstract class HeapSnapshot {
2976
2975
  return {paths, limitsReached};
2977
2976
  }
2978
2977
 
2979
- createAddedNodesProvider(baseSnapshotId: string, classKey: string): HeapSnapshotNodesProvider {
2978
+ createAddedNodesProvider(baseSnapshotId: number, classKey: string): HeapSnapshotNodesProvider {
2980
2979
  const snapshotDiff = this.#snapshotDiffs[baseSnapshotId];
2981
2980
  const diffForClass = snapshotDiff[classKey];
2982
2981
  return new HeapSnapshotNodesProvider(this, diffForClass.addedIndexes);
@@ -365,8 +365,6 @@ export class MainImpl {
365
365
  // Debugging
366
366
  Root.Runtime.experiments.register(
367
367
  Root.ExperimentNames.ExperimentName.INSTRUMENTATION_BREAKPOINTS, 'Instrumentation breakpoints');
368
- Root.Runtime.experiments.register(
369
- Root.ExperimentNames.ExperimentName.USE_SOURCE_MAP_SCOPES, 'Use scope information from source maps');
370
368
 
371
369
  Root.Runtime.experiments.registerHostExperiment({
372
370
  name: Root.ExperimentNames.ExperimentName.DURABLE_MESSAGES,
@@ -392,10 +390,6 @@ export class MainImpl {
392
390
  requiresChromeRestart: false,
393
391
  });
394
392
 
395
- Root.Runtime.experiments.enableExperimentsByDefault([
396
- Root.ExperimentNames.ExperimentName.USE_SOURCE_MAP_SCOPES,
397
- ]);
398
-
399
393
  const enabledExperiments = Root.Runtime.Runtime.queryParam('enabledExperiments');
400
394
  if (enabledExperiments) {
401
395
  Root.Runtime.experiments.setServerEnabledExperiments(enabledExperiments.split(';'));
@@ -435,7 +435,7 @@ inspectorBackend.registerCommand("DOM.getFrameOwner", [{"name": "frameId", "type
435
435
  inspectorBackend.registerCommand("DOM.getContainerForNode", [{"name": "nodeId", "type": "number", "optional": false, "description": "", "typeRef": "DOM.NodeId"}, {"name": "containerName", "type": "string", "optional": true, "description": "", "typeRef": null}, {"name": "physicalAxes", "type": "string", "optional": true, "description": "", "typeRef": "DOM.PhysicalAxes"}, {"name": "logicalAxes", "type": "string", "optional": true, "description": "", "typeRef": "DOM.LogicalAxes"}, {"name": "queriesScrollState", "type": "boolean", "optional": true, "description": "", "typeRef": null}, {"name": "queriesAnchored", "type": "boolean", "optional": true, "description": "", "typeRef": null}], ["nodeId"], "Returns the query container of the given node based on container query conditions: containerName, physical and logical axes, and whether it queries scroll-state or anchored elements. If no axes are provided and queriesScrollState is false, the style container is returned, which is the direct parent or the closest element with a matching container-name.");
436
436
  inspectorBackend.registerCommand("DOM.getQueryingDescendantsForContainer", [{"name": "nodeId", "type": "number", "optional": false, "description": "Id of the container node to find querying descendants from.", "typeRef": "DOM.NodeId"}], ["nodeIds"], "Returns the descendants of a container query container that have container queries against this container.");
437
437
  inspectorBackend.registerCommand("DOM.getAnchorElement", [{"name": "nodeId", "type": "number", "optional": false, "description": "Id of the positioned element from which to find the anchor.", "typeRef": "DOM.NodeId"}, {"name": "anchorSpecifier", "type": "string", "optional": true, "description": "An optional anchor specifier, as defined in https://www.w3.org/TR/css-anchor-position-1/#anchor-specifier. If not provided, it will return the implicit anchor element for the given positioned element.", "typeRef": null}], ["nodeId"], "Returns the target anchor element of the given anchor query according to https://www.w3.org/TR/css-anchor-position-1/#target.");
438
- inspectorBackend.registerCommand("DOM.forceShowPopover", [{"name": "nodeId", "type": "number", "optional": false, "description": "Id of the popover HTMLElement", "typeRef": "DOM.NodeId"}, {"name": "enable", "type": "boolean", "optional": false, "description": "If true, opens the popover and keeps it open. If false, closes the popover if it was previously force-opened.", "typeRef": null}], ["nodeIds"], "When enabling, this API force-opens the popover identified by nodeId and keeps it open until disabled.");
438
+ inspectorBackend.registerCommand("DOM.forceShowPopover", [{"name": "nodeId", "type": "number", "optional": false, "description": "Id of the popover HTMLElement", "typeRef": "DOM.NodeId"}, {"name": "enable", "type": "boolean", "optional": false, "description": "If true, opens the popover and keeps it open. If false, closes the popover if it was previously force-opened.", "typeRef": null}, {"name": "invokerNodeId", "type": "number", "optional": true, "description": "Optional ID of the element invoking this popover, used to establish the implicit anchor. If not provided, it will fall back to the first invoker in the document, preferring elements with a popovertarget attribute over those with a commandfor attribute. Note that if there are multiple invokers, this is just an estimate.", "typeRef": "DOM.BackendNodeId"}], ["nodeIds"], "When enabling, this API force-opens the popover identified by nodeId and keeps it open until disabled.");
439
439
  inspectorBackend.registerType("DOM.BackendNode", [{"name": "nodeType", "type": "number", "optional": false, "description": "`Node`'s nodeType.", "typeRef": null}, {"name": "nodeName", "type": "string", "optional": false, "description": "`Node`'s nodeName.", "typeRef": null}, {"name": "backendNodeId", "type": "number", "optional": false, "description": "", "typeRef": "DOM.BackendNodeId"}]);
440
440
  inspectorBackend.registerType("DOM.Node", [{"name": "nodeId", "type": "number", "optional": false, "description": "Node identifier that is passed into the rest of the DOM messages as the `nodeId`. Backend will only push node with given `id` once. It is aware of all requested nodes and will only fire DOM events for nodes known to the client.", "typeRef": "DOM.NodeId"}, {"name": "parentId", "type": "number", "optional": true, "description": "The id of the parent node if any.", "typeRef": "DOM.NodeId"}, {"name": "backendNodeId", "type": "number", "optional": false, "description": "The BackendNodeId for this node.", "typeRef": "DOM.BackendNodeId"}, {"name": "nodeType", "type": "number", "optional": false, "description": "`Node`'s nodeType.", "typeRef": null}, {"name": "nodeName", "type": "string", "optional": false, "description": "`Node`'s nodeName.", "typeRef": null}, {"name": "localName", "type": "string", "optional": false, "description": "`Node`'s localName.", "typeRef": null}, {"name": "nodeValue", "type": "string", "optional": false, "description": "`Node`'s nodeValue.", "typeRef": null}, {"name": "childNodeCount", "type": "number", "optional": true, "description": "Child count for `Container` nodes.", "typeRef": null}, {"name": "children", "type": "array", "optional": true, "description": "Child nodes of this node when requested with children.", "typeRef": "DOM.Node"}, {"name": "attributes", "type": "array", "optional": true, "description": "Attributes of the `Element` node in the form of flat array `[name1, value1, name2, value2]`.", "typeRef": "string"}, {"name": "documentURL", "type": "string", "optional": true, "description": "Document URL that `Document` or `FrameOwner` node points to.", "typeRef": null}, {"name": "baseURL", "type": "string", "optional": true, "description": "Base URL that `Document` or `FrameOwner` node uses for URL completion.", "typeRef": null}, {"name": "publicId", "type": "string", "optional": true, "description": "`DocumentType`'s publicId.", "typeRef": null}, {"name": "systemId", "type": "string", "optional": true, "description": "`DocumentType`'s systemId.", "typeRef": null}, {"name": "internalSubset", "type": "string", "optional": true, "description": "`DocumentType`'s internalSubset.", "typeRef": null}, {"name": "xmlVersion", "type": "string", "optional": true, "description": "`Document`'s XML version in case of XML documents.", "typeRef": null}, {"name": "name", "type": "string", "optional": true, "description": "`Attr`'s name.", "typeRef": null}, {"name": "value", "type": "string", "optional": true, "description": "`Attr`'s value.", "typeRef": null}, {"name": "pseudoType", "type": "string", "optional": true, "description": "Pseudo element type for this node.", "typeRef": "DOM.PseudoType"}, {"name": "pseudoIdentifier", "type": "string", "optional": true, "description": "Pseudo element identifier for this node. Only present if there is a valid pseudoType.", "typeRef": null}, {"name": "shadowRootType", "type": "string", "optional": true, "description": "Shadow root type.", "typeRef": "DOM.ShadowRootType"}, {"name": "frameId", "type": "string", "optional": true, "description": "Frame ID for frame owner elements.", "typeRef": "Page.FrameId"}, {"name": "contentDocument", "type": "object", "optional": true, "description": "Content document for frame owner elements.", "typeRef": "DOM.Node"}, {"name": "shadowRoots", "type": "array", "optional": true, "description": "Shadow root list for given element host.", "typeRef": "DOM.Node"}, {"name": "templateContent", "type": "object", "optional": true, "description": "Content document fragment for template elements.", "typeRef": "DOM.Node"}, {"name": "pseudoElements", "type": "array", "optional": true, "description": "Pseudo elements associated with this node.", "typeRef": "DOM.Node"}, {"name": "importedDocument", "type": "object", "optional": true, "description": "Deprecated, as the HTML Imports API has been removed (crbug.com/937746). This property used to return the imported document for the HTMLImport links. The property is always undefined now.", "typeRef": "DOM.Node"}, {"name": "distributedNodes", "type": "array", "optional": true, "description": "Distributed nodes for given insertion point.", "typeRef": "DOM.BackendNode"}, {"name": "isSVG", "type": "boolean", "optional": true, "description": "Whether the node is SVG.", "typeRef": null}, {"name": "compatibilityMode", "type": "string", "optional": true, "description": "", "typeRef": "DOM.CompatibilityMode"}, {"name": "assignedSlot", "type": "object", "optional": true, "description": "", "typeRef": "DOM.BackendNode"}, {"name": "isScrollable", "type": "boolean", "optional": true, "description": "", "typeRef": null}, {"name": "affectedByStartingStyles", "type": "boolean", "optional": true, "description": "", "typeRef": null}, {"name": "adoptedStyleSheets", "type": "array", "optional": true, "description": "", "typeRef": "DOM.StyleSheetId"}, {"name": "adProvenance", "type": "object", "optional": true, "description": "", "typeRef": "Network.AdProvenance"}]);
441
441
  inspectorBackend.registerType("DOM.DetachedElementInfo", [{"name": "treeNode", "type": "object", "optional": false, "description": "", "typeRef": "DOM.Node"}, {"name": "retainedNodeIds", "type": "array", "optional": false, "description": "", "typeRef": "DOM.NodeId"}]);
@@ -5849,6 +5849,13 @@ export namespace DOM {
5849
5849
  * popover if it was previously force-opened.
5850
5850
  */
5851
5851
  enable: boolean;
5852
+ /**
5853
+ * Optional ID of the element invoking this popover, used to establish the implicit anchor.
5854
+ * If not provided, it will fall back to the first invoker in the document, preferring
5855
+ * elements with a popovertarget attribute over those with a commandfor attribute. Note that
5856
+ * if there are multiple invokers, this is just an estimate.
5857
+ */
5858
+ invokerNodeId?: BackendNodeId;
5852
5859
  }
5853
5860
 
5854
5861
  export interface ForceShowPopoverResponse extends ProtocolResponseWithError {
@@ -5,7 +5,6 @@
5
5
  import * as Host from '../../core/host/host.js';
6
6
 
7
7
  import {
8
- type AgentOptions,
9
8
  AiAgent,
10
9
  type ContextResponse,
11
10
  type ConversationContext,
@@ -13,7 +12,11 @@ import {
13
12
  type RequestOptions,
14
13
  ResponseType
15
14
  } from './agents/AiAgent.js';
15
+ import {type ExecuteJsAgentOptions, executeJsCode} from './agents/ExecuteJavascript.js';
16
+ import {ChangeManager} from './ChangeManager.js';
17
+ import {DOMNodeContext} from './contexts/DOMNodeContext.js';
16
18
  import {debugLog} from './debug.js';
19
+ import {ExtensionScope} from './ExtensionScope.js';
17
20
  import type {Skill, SkillName} from './skills/Skill.js';
18
21
  import {SKILLS} from './skills/SkillRegistry.js';
19
22
  import type {Tool} from './tools/Tool.js';
@@ -30,6 +33,8 @@ export class AiAgent2 extends AiAgent<unknown> {
30
33
  readonly userTier = 'TESTERS';
31
34
 
32
35
  #skillsInjected = false;
36
+ #changes = new ChangeManager();
37
+ #execJs: typeof executeJsCode;
33
38
 
34
39
  get options(): RequestOptions {
35
40
  return {};
@@ -38,8 +43,9 @@ export class AiAgent2 extends AiAgent<unknown> {
38
43
  readonly #activeSkills = new Set<SkillName>();
39
44
  readonly #declaredTools = new Set<string>();
40
45
 
41
- constructor(opts: AgentOptions) {
46
+ constructor(opts: ExecuteJsAgentOptions) {
42
47
  super(opts);
48
+ this.#execJs = opts.execJs ?? executeJsCode;
43
49
  this.#declaredTools.add('learnSkills');
44
50
  const skillsList = Object.keys(SKILLS).join(', ');
45
51
  this.declareFunction<{skills: SkillName[]}>('learnSkills', {
@@ -154,6 +160,11 @@ User query: ${enhancedQuery}`;
154
160
  return response.trim();
155
161
  }
156
162
 
163
+ #createExtensionScope(changes: ChangeManager): {install(): Promise<void>, uninstall(): Promise<void>} {
164
+ const selectedNode = this.context && this.context instanceof DOMNodeContext ? this.context.getItem() : null;
165
+ return new ExtensionScope(changes, this.sessionId, selectedNode);
166
+ }
167
+
157
168
  /**
158
169
  * Declares a tool to be available to the agent model, verifying first that
159
170
  * it hasn't already been declared to prevent duplicate declaration errors.
@@ -168,9 +179,17 @@ User query: ${enhancedQuery}`;
168
179
  description: tool.description,
169
180
  parameters: tool.parameters,
170
181
  displayInfoFromArgs: tool.displayInfoFromArgs,
171
- handler: args => tool.handler(args, {
172
- conversationContext: this.context ?? null,
173
- }),
182
+ handler: (args, options) => tool.handler(
183
+ args,
184
+ {
185
+ conversationContext: this.context ?? null,
186
+ changeManager: this.#changes,
187
+ createExtensionScope: this.#createExtensionScope.bind(this),
188
+ execJs: this.#execJs,
189
+ getExecutionContextNode: () => this.context instanceof DOMNodeContext ? this.context.getItem() : null,
190
+ },
191
+ options,
192
+ ),
174
193
  });
175
194
  }
176
195
 
@@ -328,24 +328,27 @@ export class AiConversation {
328
328
  };
329
329
  }
330
330
 
331
+ #filterHistoryForNewAgent(): Host.AidaClient.Content[] {
332
+ return this.#agent?.history
333
+ .map(content => {
334
+ return {
335
+ ...content,
336
+ parts: content.parts.filter(part => !('functionCall' in part) && !('functionResponse' in part)),
337
+ };
338
+ })
339
+ .filter(content => content.parts.length > 0) ??
340
+ [];
341
+ }
342
+
331
343
  #updateAgent(type: ConversationType): void {
332
344
  if (this.#type === type) {
333
345
  return;
334
346
  }
335
347
 
336
- this.#type = type;
348
+ const isTransitioningFromStorage = this.#type === ConversationType.STORAGE && type !== ConversationType.STORAGE;
349
+ const history = isTransitioningFromStorage ? [] : this.#filterHistoryForNewAgent();
337
350
 
338
- // We need to filter out the function calls
339
- // as the LLM tries to call the existing ones.
340
- const history =
341
- this.#agent?.history
342
- .map(content => {
343
- return {
344
- ...content,
345
- parts: content.parts.filter(part => !('functionCall' in part) && !('functionResponse' in part)),
346
- };
347
- })
348
- .filter(content => content.parts.length > 0);
351
+ this.#type = type;
349
352
 
350
353
  const options = {
351
354
  aidaClient: this.#aidaClient,
@@ -8,6 +8,8 @@ import * as i18n from '../../core/i18n/i18n.js';
8
8
  import type * as Platform from '../../core/platform/platform.js';
9
9
  import * as Root from '../../core/root/root.js';
10
10
 
11
+ import {debugLog} from './debug.js';
12
+
11
13
  const UIStrings = {
12
14
  /**
13
15
  * @description Message shown to the user if the age check is not successful.
@@ -71,3 +73,72 @@ export function isSameOrigin(url1: Platform.DevToolsPath.UrlString, url2: Platfo
71
73
  const origin2 = Common.ParsedURL.ParsedURL.extractOrigin(url2);
72
74
  return origin1 !== '' && origin1 === origin2;
73
75
  }
76
+
77
+ export interface OneShotPromptRequest {
78
+ aidaClient: Host.AidaClient.AidaClient;
79
+ preamble: string;
80
+ query: string;
81
+ clientFeature: Host.AidaClient.ClientFeature;
82
+ temperature?: number;
83
+ modelId?: string;
84
+ userTier?: string;
85
+ serverSideLoggingEnabled?: boolean;
86
+ signal?: AbortSignal;
87
+ }
88
+
89
+ export async function runOneShotPrompt({
90
+ aidaClient,
91
+ preamble,
92
+ query,
93
+ clientFeature,
94
+ temperature,
95
+ modelId,
96
+ userTier,
97
+ serverSideLoggingEnabled,
98
+ signal,
99
+ }: OneShotPromptRequest): Promise<string> {
100
+ const chromeVersion = Root.Runtime.getChromeVersion();
101
+ if (!chromeVersion) {
102
+ throw new Error('Cannot determine Chrome version');
103
+ }
104
+ const disallowLogging = !serverSideLoggingEnabled;
105
+ const sessionId = crypto.randomUUID();
106
+
107
+ const userTierEnum = Host.AidaClient.convertToUserTierEnum(userTier);
108
+ const finalPreamble = userTierEnum === Host.AidaClient.UserTier.TESTERS ? preamble : undefined;
109
+
110
+ const request: Host.AidaClient.DoConversationRequest = {
111
+ client: Host.AidaClient.CLIENT_NAME,
112
+ current_message: {
113
+ parts: [{text: query}],
114
+ role: Host.AidaClient.Role.USER,
115
+ },
116
+ preamble: finalPreamble,
117
+ options: {
118
+ temperature: typeof temperature === 'number' && temperature >= 0 ? temperature : undefined,
119
+ model_id: modelId || undefined,
120
+ },
121
+ metadata: {
122
+ disable_user_content_logging: disallowLogging,
123
+ string_session_id: sessionId,
124
+ user_tier: userTierEnum,
125
+ client_version: chromeVersion,
126
+ },
127
+ functionality_type: Host.AidaClient.FunctionalityType.CHAT,
128
+ client_feature: clientFeature,
129
+ };
130
+
131
+ let textResponse = '';
132
+ try {
133
+ for await (const response of aidaClient.doConversation(request, {signal})) {
134
+ if (response.explanation) {
135
+ textResponse = response.explanation;
136
+ }
137
+ }
138
+ } catch (err) {
139
+ debugLog('Error calling AIDA for one-shot prompt', err);
140
+ throw err;
141
+ }
142
+
143
+ return textResponse;
144
+ }
@@ -9,8 +9,6 @@ import type * as Protocol from '../../generated/protocol.js';
9
9
 
10
10
  export interface Change {
11
11
  groupId: string;
12
- // Optional turn ID to group changes from the same turn.
13
- turnId?: number;
14
12
  // Optional about where in the source the selector was defined.
15
13
  sourceLocation?: string;
16
14
  // Selector used by the page or a simple selector as the fallback.
@@ -104,7 +102,6 @@ export class ChangeManager {
104
102
  // it currently causes crashes in the Styles tab when duplicate selectors exist (crbug.com/393515428).
105
103
  // This workaround avoids that crash.
106
104
  existingChange.groupId = change.groupId;
107
- existingChange.turnId = change.turnId;
108
105
  } else {
109
106
  changes.push({
110
107
  ...change,
@@ -126,11 +123,11 @@ export class ChangeManager {
126
123
  .join('\n\n');
127
124
  }
128
125
 
129
- getChangedNodesForGroupId(groupId: string, turnId?: number): Protocol.DOM.BackendNodeId[] {
126
+ getChangedNodesForGroupId(groupId: string): Protocol.DOM.BackendNodeId[] {
130
127
  const nodes = new Set<Protocol.DOM.BackendNodeId>();
131
128
  for (const changes of this.#stylesheetChanges.values()) {
132
129
  for (const change of changes) {
133
- if (change.groupId === groupId && change.backendNodeId && (turnId === undefined || change.turnId === turnId)) {
130
+ if (change.groupId === groupId && change.backendNodeId) {
134
131
  nodes.add(change.backendNodeId);
135
132
  }
136
133
  }