chrome-devtools-frontend 1.0.1625854 → 1.0.1626840

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 (62) hide show
  1. package/front_end/core/host/AidaClient.ts +1 -1
  2. package/front_end/core/host/AidaClientTypes.ts +2 -0
  3. package/front_end/core/host/AidaGcaTranslation.ts +2 -2
  4. package/front_end/core/host/UserMetrics.ts +11 -6
  5. package/front_end/core/root/ExperimentNames.ts +1 -1
  6. package/front_end/core/sdk/CSSMetadata.ts +60 -55
  7. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +11 -2
  8. package/front_end/core/sdk/HeapProfilerModel.ts +1 -11
  9. package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +0 -1
  10. package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +0 -1
  11. package/front_end/entrypoints/main/MainImpl.ts +4 -29
  12. package/front_end/generated/InspectorBackendCommands.ts +3 -2
  13. package/front_end/generated/protocol-mapping.d.ts +5 -0
  14. package/front_end/generated/protocol-proxy-api.d.ts +4 -0
  15. package/front_end/generated/protocol.ts +21 -0
  16. package/front_end/models/ai_assistance/StorageItem.ts +16 -0
  17. package/front_end/models/ai_assistance/agents/AiAgent.ts +2 -1
  18. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +11 -5
  19. package/front_end/models/ai_assistance/agents/StorageAgent.ts +82 -0
  20. package/front_end/models/ai_assistance/ai_assistance.ts +4 -0
  21. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +9 -37
  22. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +26 -3
  23. package/front_end/models/javascript_metadata/NativeFunctions.js +0 -4
  24. package/front_end/models/lighthouse/RunTypes.ts +1 -1
  25. package/front_end/models/web_mcp/WebMCPModel.ts +11 -2
  26. package/front_end/models/workspace/UISourceCode.ts +0 -1
  27. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +6 -1
  28. package/front_end/panels/ai_assistance/components/ChatMessage.ts +4 -3
  29. package/front_end/panels/application/WebMCPView.ts +74 -16
  30. package/front_end/panels/application/webMCPView.css +13 -2
  31. package/front_end/panels/common/AiCodeCompletionTeaser.ts +9 -0
  32. package/front_end/panels/elements/StandaloneStylesContainer.ts +3 -0
  33. package/front_end/panels/elements/StylePropertyTreeElement.ts +35 -2
  34. package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +1 -1
  35. package/front_end/panels/elements/StylesContainer.ts +1 -0
  36. package/front_end/panels/elements/StylesSidebarPane.ts +10 -4
  37. package/front_end/panels/emulation/DeviceModeToolbar.ts +7 -3
  38. package/front_end/panels/lighthouse/LighthouseController.ts +18 -0
  39. package/front_end/panels/profiler/profiler-meta.ts +0 -71
  40. package/front_end/panels/profiler/profiler.ts +0 -2
  41. package/front_end/panels/sources/ProfilePlugin.ts +12 -65
  42. package/front_end/panels/sources/ScopeChainSidebarPane.ts +5 -1
  43. package/front_end/panels/sources/UISourceCodeFrame.ts +1 -2
  44. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +179 -145
  45. package/front_end/panels/timeline/timelineTreeView.css +2 -2
  46. package/front_end/third_party/chromium/README.chromium +1 -1
  47. package/front_end/third_party/lighthouse/README.chromium +2 -2
  48. package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +4213 -4208
  49. package/front_end/third_party/lighthouse/locales/en-US.json +26 -8
  50. package/front_end/third_party/lighthouse/locales/en-XL.json +26 -8
  51. package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +1 -1
  52. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +7 -1
  53. package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +8 -1
  54. package/front_end/ui/components/tooltips/Tooltip.ts +3 -3
  55. package/front_end/ui/legacy/components/perf_ui/LineLevelProfile.ts +0 -56
  56. package/front_end/ui/legacy/components/perf_ui/perf_ui-meta.ts +0 -35
  57. package/front_end/ui/legacy/components/perf_ui/perf_ui.ts +0 -2
  58. package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
  59. package/package.json +1 -1
  60. package/front_end/panels/profiler/LiveHeapProfileView.ts +0 -405
  61. package/front_end/panels/profiler/liveHeapProfile.css +0 -22
  62. package/front_end/ui/legacy/components/perf_ui/LiveHeapProfile.ts +0 -113
@@ -250,7 +250,7 @@ export class AidaClient {
250
250
  } else if ('error' in result) {
251
251
  throw new Error(`Server responded: ${JSON.stringify(result)}`);
252
252
  } else {
253
- throw new Error('Unknown chunk result');
253
+ throw new Error(`Unknown chunk result ${JSON.stringify(result)}`);
254
254
  }
255
255
  }
256
256
  if (textUpdated) {
@@ -133,6 +133,8 @@ export enum ClientFeature {
133
133
  CHROME_ACCESSIBILITY_AGENT = 26,
134
134
  // Chrome AI Assistance Conversation Summary Agent.
135
135
  CHROME_CONVERSATION_SUMMARY_AGENT = 27,
136
+ // Chrome AI Assistance Storage Agent.
137
+ CHROME_STORAGE_AGENT = 28,
136
138
  }
137
139
 
138
140
  export enum UserTier {
@@ -468,9 +468,9 @@ export function gcaChunkResponseToAidaChunkResponse(response: GCA.GenerateConten
468
468
  })),
469
469
  };
470
470
  }
471
- const chunks: AIDA.AidaChunkResponse[] = (parts).map(part => {
471
+ const chunks: AIDA.AidaChunkResponse[] = parts.map(part => {
472
472
  const aidaChunkResponse: AIDA.AidaChunkResponse = {metadata};
473
- if (part.text) {
473
+ if (part.text !== undefined) {
474
474
  aidaChunkResponse.textChunk = {
475
475
  text: extractTextFromGcaParts(parts),
476
476
  };
@@ -489,7 +489,14 @@ export enum Action {
489
489
  InsightTeaserModelDownloadCompleted = 198,
490
490
  AiCodeGenerationError = 199,
491
491
  AiCodeGenerationRequestTriggered = 200,
492
- MAX_VALUE = 201,
492
+ AiCodeCompletionRequestTriggeredFromConsole = 201,
493
+ AiCodeCompletionRequestTriggeredFromSources = 202,
494
+ AiCodeCompletionRequestTriggeredFromStyles = 203,
495
+ AiCodeGenerationRequestTriggeredFromConsole = 204,
496
+ AiCodeGenerationRequestTriggeredFromSources = 205,
497
+ AiCodeCompletionFreCompletedFromConsole = 206,
498
+ AiCodeCompletionFreCompletedFromSources = 207,
499
+ MAX_VALUE = 208,
493
500
  /* eslint-enable @typescript-eslint/naming-convention */
494
501
  }
495
502
 
@@ -519,7 +526,7 @@ export enum PanelCodes {
519
526
  'changes.changes' = 23,
520
527
  'performance.monitor' = 24,
521
528
  'release-note' = 25,
522
- 'live-heap-profile' = 26,
529
+
523
530
  'sources.quick' = 27,
524
531
  'network.blocked-urls' = 28,
525
532
  'settings-preferences' = 29,
@@ -669,8 +676,6 @@ export enum KeyboardShortcutAction {
669
676
  'inspector-main.focus-debuggee' = 47,
670
677
  'inspector-main.hard-reload' = 48,
671
678
  'inspector-main.reload' = 49,
672
- 'live-heap-profile.start-with-reload' = 50,
673
- 'live-heap-profile.toggle-recording' = 51,
674
679
  'main.debug-reload' = 52,
675
680
  'main.next-tab' = 53,
676
681
  'main.previous-tab' = 54,
@@ -758,7 +763,6 @@ export const enum IssueOpener {
758
763
  export enum DevtoolsExperiments {
759
764
  /* eslint-disable @typescript-eslint/naming-convention */
760
765
  'capture-node-creation-stacks' = 1,
761
- 'live-heap-profile' = 11,
762
766
  'protocol-monitor' = 13,
763
767
  'timeline-invalidation-tracking' = 26,
764
768
  'instrumentation-breakpoints' = 61,
@@ -1142,7 +1146,8 @@ export const enum LighthouseCategoryUsed {
1142
1146
  SEO = 3,
1143
1147
  PWA = 4,
1144
1148
  PUB_ADS = 5,
1145
- MAX_VALUE = 6,
1149
+ AGENTIC_BROWSING = 6,
1150
+ MAX_VALUE = 7,
1146
1151
  }
1147
1152
 
1148
1153
  export const enum SwatchType {
@@ -5,7 +5,7 @@
5
5
  export enum ExperimentName {
6
6
  ALL = '*',
7
7
  CAPTURE_NODE_CREATION_STACKS = 'capture-node-creation-stacks',
8
- LIVE_HEAP_PROFILE = 'live-heap-profile',
8
+
9
9
  PROTOCOL_MONITOR = 'protocol-monitor',
10
10
  TIMELINE_INVALIDATION_TRACKING = 'timeline-invalidation-tracking',
11
11
  INSTRUMENTATION_BREAKPOINTS = 'instrumentation-breakpoints',
@@ -634,6 +634,64 @@ const textEmphasisStyle = new Set([
634
634
  '"❤️"', // <string>
635
635
  ]);
636
636
 
637
+ const listStyleTypeValues = new Set([
638
+ 'disc',
639
+ 'circle',
640
+ 'square',
641
+ 'decimal',
642
+ 'decimal-leading-zero',
643
+ 'arabic-indic',
644
+ 'bengali',
645
+ 'cambodian',
646
+ 'khmer',
647
+ 'devanagari',
648
+ 'gujarati',
649
+ 'gurmukhi',
650
+ 'kannada',
651
+ 'lao',
652
+ 'malayalam',
653
+ 'mongolian',
654
+ 'myanmar',
655
+ 'oriya',
656
+ 'persian',
657
+ 'urdu',
658
+ 'telugu',
659
+ 'tibetan',
660
+ 'thai',
661
+ 'lower-roman',
662
+ 'upper-roman',
663
+ 'lower-greek',
664
+ 'lower-alpha',
665
+ 'lower-latin',
666
+ 'upper-alpha',
667
+ 'upper-latin',
668
+ 'cjk-earthly-branch',
669
+ 'cjk-heavenly-stem',
670
+ 'ethiopic-halehame',
671
+ 'ethiopic-halehame-am',
672
+ 'ethiopic-halehame-ti-er',
673
+ 'ethiopic-halehame-ti-et',
674
+ 'hangul',
675
+ 'hangul-consonant',
676
+ 'korean-hangul-formal',
677
+ 'korean-hanja-formal',
678
+ 'korean-hanja-informal',
679
+ 'hebrew',
680
+ 'armenian',
681
+ 'lower-armenian',
682
+ 'upper-armenian',
683
+ 'georgian',
684
+ 'cjk-ideographic',
685
+ 'simp-chinese-formal',
686
+ 'simp-chinese-informal',
687
+ 'trad-chinese-formal',
688
+ 'trad-chinese-informal',
689
+ 'hiragana',
690
+ 'katakana',
691
+ 'hiragana-iroha',
692
+ 'katakana-iroha',
693
+ ]);
694
+
637
695
  // manually maintained list of property #values to add into autocomplete list
638
696
  const extraPropertyValues = new Map<string, Set<string>>([
639
697
  ['background-repeat', new Set(['repeat', 'repeat-x', 'repeat-y', 'no-repeat', 'space', 'round'])],
@@ -1111,63 +1169,10 @@ const extraPropertyValues = new Map<string, Set<string>>([
1111
1169
  new Set([
1112
1170
  'outside',
1113
1171
  'inside',
1114
- 'disc',
1115
- 'circle',
1116
- 'square',
1117
- 'decimal',
1118
- 'decimal-leading-zero',
1119
- 'arabic-indic',
1120
- 'bengali',
1121
- 'cambodian',
1122
- 'khmer',
1123
- 'devanagari',
1124
- 'gujarati',
1125
- 'gurmukhi',
1126
- 'kannada',
1127
- 'lao',
1128
- 'malayalam',
1129
- 'mongolian',
1130
- 'myanmar',
1131
- 'oriya',
1132
- 'persian',
1133
- 'urdu',
1134
- 'telugu',
1135
- 'tibetan',
1136
- 'thai',
1137
- 'lower-roman',
1138
- 'upper-roman',
1139
- 'lower-greek',
1140
- 'lower-alpha',
1141
- 'lower-latin',
1142
- 'upper-alpha',
1143
- 'upper-latin',
1144
- 'cjk-earthly-branch',
1145
- 'cjk-heavenly-stem',
1146
- 'ethiopic-halehame',
1147
- 'ethiopic-halehame-am',
1148
- 'ethiopic-halehame-ti-er',
1149
- 'ethiopic-halehame-ti-et',
1150
- 'hangul',
1151
- 'hangul-consonant',
1152
- 'korean-hangul-formal',
1153
- 'korean-hanja-formal',
1154
- 'korean-hanja-informal',
1155
- 'hebrew',
1156
- 'armenian',
1157
- 'lower-armenian',
1158
- 'upper-armenian',
1159
- 'georgian',
1160
- 'cjk-ideographic',
1161
- 'simp-chinese-formal',
1162
- 'simp-chinese-informal',
1163
- 'trad-chinese-formal',
1164
- 'trad-chinese-informal',
1165
- 'hiragana',
1166
- 'katakana',
1167
- 'hiragana-iroha',
1168
- 'katakana-iroha',
1172
+ ...listStyleTypeValues,
1169
1173
  ]),
1170
1174
  ],
1175
+ ['list-style-type', listStyleTypeValues],
1171
1176
  ['max-block-size', new Set(['-webkit-fill-available', 'min-content', 'max-content', 'fit-content'])],
1172
1177
  ['max-inline-size', new Set(['-webkit-fill-available', 'min-content', 'max-content', 'fit-content'])],
1173
1178
  ['min-block-size', new Set(['-webkit-fill-available', 'min-content', 'max-content', 'fit-content'])],
@@ -739,8 +739,10 @@ export const enum LinkableNameProperties {
739
739
  ANIMATION = 'animation',
740
740
  ANIMATION_NAME = 'animation-name',
741
741
  FONT_PALETTE = 'font-palette',
742
- POSITION_TRY_FALLBACKS = 'position-try-fallbacks',
742
+ LIST_STYLE = 'list-style',
743
+ LIST_STYLE_TYPE = 'list-style-type',
743
744
  POSITION_TRY = 'position-try',
745
+ POSITION_TRY_FALLBACKS = 'position-try-fallbacks',
744
746
  }
745
747
 
746
748
  const enum AnimationLonghandPart {
@@ -765,8 +767,10 @@ export class LinkableNameMatcher extends matcherBase(LinkableNameMatch) {
765
767
  LinkableNameProperties.ANIMATION,
766
768
  LinkableNameProperties.ANIMATION_NAME,
767
769
  LinkableNameProperties.FONT_PALETTE,
768
- LinkableNameProperties.POSITION_TRY_FALLBACKS,
770
+ LinkableNameProperties.LIST_STYLE,
771
+ LinkableNameProperties.LIST_STYLE_TYPE,
769
772
  LinkableNameProperties.POSITION_TRY,
773
+ LinkableNameProperties.POSITION_TRY_FALLBACKS,
770
774
  ];
771
775
  return names.includes(propertyName);
772
776
  }
@@ -867,6 +871,11 @@ export class LinkableNameMatcher extends matcherBase(LinkableNameMatch) {
867
871
  return null;
868
872
  }
869
873
 
874
+ // If it is a builtin keyword value, it is not linkable.
875
+ if (cssMetadata().getPropertyValues(propertyName).includes(text)) {
876
+ return null;
877
+ }
878
+
870
879
  if (propertyName === 'animation') {
871
880
  return this.matchAnimationNameInShorthand(node, matching);
872
881
  }
@@ -16,7 +16,6 @@ export class HeapProfilerModel extends SDKModel<EventTypes> {
16
16
  #enabled = false;
17
17
  readonly #heapProfilerAgent: ProtocolProxyApi.HeapProfilerApi;
18
18
  readonly #runtimeModel: RuntimeModel;
19
- #samplingProfilerDepth = 0;
20
19
 
21
20
  constructor(target: Target) {
22
21
  super(target);
@@ -43,9 +42,6 @@ export class HeapProfilerModel extends SDKModel<EventTypes> {
43
42
  }
44
43
 
45
44
  async startSampling(samplingRateInBytes?: number): Promise<boolean> {
46
- if (this.#samplingProfilerDepth++) {
47
- return false;
48
- }
49
45
  const defaultSamplingIntervalInBytes = 16384;
50
46
  const response = await this.#heapProfilerAgent.invoke_startSampling(
51
47
  {samplingInterval: samplingRateInBytes || defaultSamplingIntervalInBytes});
@@ -53,15 +49,9 @@ export class HeapProfilerModel extends SDKModel<EventTypes> {
53
49
  }
54
50
 
55
51
  async stopSampling(): Promise<Protocol.HeapProfiler.SamplingHeapProfile|null> {
56
- if (!this.#samplingProfilerDepth) {
57
- throw new Error('Sampling profiler is not running.');
58
- }
59
- if (--this.#samplingProfilerDepth) {
60
- return await this.getSamplingProfile();
61
- }
62
52
  const response = await this.#heapProfilerAgent.invoke_stopSampling();
63
53
  if (response.getError()) {
64
- return null;
54
+ throw new Error('Sampling profiler is not running.');
65
55
  }
66
56
  return response.profile;
67
57
  }
@@ -534,7 +534,6 @@ async function init(): Promise<void> {
534
534
  Root.ExperimentNames.ExperimentName.INSTRUMENTATION_BREAKPOINTS, 'Enable instrumentation breakpoints');
535
535
  safeRegisterExperiment(
536
536
  Root.ExperimentNames.ExperimentName.USE_SOURCE_MAP_SCOPES, 'Use scope information from source maps');
537
- safeRegisterExperiment(Root.ExperimentNames.ExperimentName.LIVE_HEAP_PROFILE, 'Live heap profile');
538
537
  safeRegisterExperiment(Root.ExperimentNames.ExperimentName.PROTOCOL_MONITOR, 'Protocol Monitor');
539
538
 
540
539
  const hostUnsyncedStorage: Common.Settings.SettingsBackingStore = {
@@ -250,7 +250,6 @@ async function init(): Promise<void> {
250
250
  Root.ExperimentNames.ExperimentName.INSTRUMENTATION_BREAKPOINTS, 'Enable instrumentation breakpoints');
251
251
  Root.Runtime.experiments.register(
252
252
  Root.ExperimentNames.ExperimentName.USE_SOURCE_MAP_SCOPES, 'Use scope information from source maps');
253
- Root.Runtime.experiments.register(Root.ExperimentNames.ExperimentName.LIVE_HEAP_PROFILE, 'Live heap profile');
254
253
  Root.Runtime.experiments.register(Root.ExperimentNames.ExperimentName.PROTOCOL_MONITOR, 'Protocol Monitor');
255
254
 
256
255
  const WINDOW_LOCAL_STORAGE: Common.Settings.SettingsBackingStore = {
@@ -350,7 +350,6 @@ export class MainImpl {
350
350
  #initializeExperiments(): void {
351
351
  Root.Runtime.experiments.register(
352
352
  Root.ExperimentNames.ExperimentName.CAPTURE_NODE_CREATION_STACKS, 'Capture node creation stacks');
353
- Root.Runtime.experiments.register(Root.ExperimentNames.ExperimentName.LIVE_HEAP_PROFILE, 'Live heap profile');
354
353
 
355
354
  const enableProtocolMonitor = (Root.Runtime.hostConfig.devToolsProtocolMonitor?.enabled ?? false) ||
356
355
  Boolean(Root.Runtime.Runtime.queryParam('isChromeForTesting'));
@@ -404,13 +403,6 @@ export class MainImpl {
404
403
  Root.Runtime.experiments.setServerEnabledExperiments(enabledExperiments.split(';'));
405
404
  }
406
405
 
407
- if (Host.InspectorFrontendHost.isUnderTest()) {
408
- const testParam = Root.Runtime.Runtime.queryParam('test');
409
- if (testParam?.includes('live-line-level-heap-profile.js')) {
410
- Root.Runtime.experiments.enableForTest(Root.ExperimentNames.ExperimentName.LIVE_HEAP_PROFILE);
411
- }
412
- }
413
-
414
406
  for (const experiment of Root.Runtime.experiments.allConfigurableExperiments()) {
415
407
  if (experiment.isEnabled()) {
416
408
  Host.userMetrics.experimentEnabledAtLaunch(experiment.name);
@@ -667,27 +659,10 @@ export class MainImpl {
667
659
  async #lateInitialization(): Promise<void> {
668
660
  MainImpl.time('Main._lateInitialization');
669
661
  PanelCommon.ExtensionServer.ExtensionServer.instance().initializeExtensions();
670
- const promises: Array<Promise<void>> =
671
- Common.Runnable.lateInitializationRunnables().map(async lateInitializationLoader => {
672
- const runnable = await lateInitializationLoader();
673
- return await runnable.run();
674
- });
675
- if (Root.Runtime.experiments.isEnabled(Root.ExperimentNames.ExperimentName.LIVE_HEAP_PROFILE)) {
676
- const PerfUI = await import('../../ui/legacy/components/perf_ui/perf_ui.js');
677
- const setting = 'memory-live-heap-profile';
678
- if (Common.Settings.Settings.instance().moduleSetting(setting).get()) {
679
- promises.push(PerfUI.LiveHeapProfile.LiveHeapProfile.instance().run());
680
- } else {
681
- const changeListener = async(event: Common.EventTarget.EventTargetEvent<unknown>): Promise<void> => {
682
- if (!event.data) {
683
- return;
684
- }
685
- Common.Settings.Settings.instance().moduleSetting(setting).removeChangeListener(changeListener);
686
- void PerfUI.LiveHeapProfile.LiveHeapProfile.instance().run();
687
- };
688
- Common.Settings.Settings.instance().moduleSetting(setting).addChangeListener(changeListener);
689
- }
690
- }
662
+ void Promise.all(Common.Runnable.lateInitializationRunnables().map(async lateInitializationLoader => {
663
+ const runnable = await lateInitializationLoader();
664
+ return await runnable.run();
665
+ }));
691
666
 
692
667
  MainImpl.timeEnd('Main._lateInitialization');
693
668
  }
@@ -266,7 +266,8 @@ inspectorBackend.registerCommand("CSS.setEffectivePropertyValueForNode", [{"name
266
266
  inspectorBackend.registerCommand("CSS.setPropertyRulePropertyName", [{"name": "styleSheetId", "type": "string", "optional": false, "description": "", "typeRef": "DOM.StyleSheetId"}, {"name": "range", "type": "object", "optional": false, "description": "", "typeRef": "CSS.SourceRange"}, {"name": "propertyName", "type": "string", "optional": false, "description": "", "typeRef": null}], ["propertyName"], "Modifies the property rule property name.");
267
267
  inspectorBackend.registerCommand("CSS.setKeyframeKey", [{"name": "styleSheetId", "type": "string", "optional": false, "description": "", "typeRef": "DOM.StyleSheetId"}, {"name": "range", "type": "object", "optional": false, "description": "", "typeRef": "CSS.SourceRange"}, {"name": "keyText", "type": "string", "optional": false, "description": "", "typeRef": null}], ["keyText"], "Modifies the keyframe rule key text.");
268
268
  inspectorBackend.registerCommand("CSS.setMediaText", [{"name": "styleSheetId", "type": "string", "optional": false, "description": "", "typeRef": "DOM.StyleSheetId"}, {"name": "range", "type": "object", "optional": false, "description": "", "typeRef": "CSS.SourceRange"}, {"name": "text", "type": "string", "optional": false, "description": "", "typeRef": null}], ["media"], "Modifies the rule selector.");
269
- inspectorBackend.registerCommand("CSS.setContainerQueryText", [{"name": "styleSheetId", "type": "string", "optional": false, "description": "", "typeRef": "DOM.StyleSheetId"}, {"name": "range", "type": "object", "optional": false, "description": "", "typeRef": "CSS.SourceRange"}, {"name": "text", "type": "string", "optional": false, "description": "", "typeRef": null}], ["containerQuery"], "Modifies the expression of a container query.");
269
+ inspectorBackend.registerCommand("CSS.setContainerQueryText", [{"name": "styleSheetId", "type": "string", "optional": false, "description": "", "typeRef": "DOM.StyleSheetId"}, {"name": "range", "type": "object", "optional": false, "description": "", "typeRef": "CSS.SourceRange"}, {"name": "text", "type": "string", "optional": false, "description": "", "typeRef": null}], ["containerQuery"], "Modifies the expression of a container query. Deprecated. Use setContainerQueryConditionText instead.");
270
+ inspectorBackend.registerCommand("CSS.setContainerQueryConditionText", [{"name": "styleSheetId", "type": "string", "optional": false, "description": "", "typeRef": "DOM.StyleSheetId"}, {"name": "range", "type": "object", "optional": false, "description": "", "typeRef": "CSS.SourceRange"}, {"name": "text", "type": "string", "optional": false, "description": "", "typeRef": null}], ["containerQuery"], "");
270
271
  inspectorBackend.registerCommand("CSS.setSupportsText", [{"name": "styleSheetId", "type": "string", "optional": false, "description": "", "typeRef": "DOM.StyleSheetId"}, {"name": "range", "type": "object", "optional": false, "description": "", "typeRef": "CSS.SourceRange"}, {"name": "text", "type": "string", "optional": false, "description": "", "typeRef": null}], ["supports"], "Modifies the expression of a supports at-rule.");
271
272
  inspectorBackend.registerCommand("CSS.setNavigationText", [{"name": "styleSheetId", "type": "string", "optional": false, "description": "", "typeRef": "DOM.StyleSheetId"}, {"name": "range", "type": "object", "optional": false, "description": "", "typeRef": "CSS.SourceRange"}, {"name": "text", "type": "string", "optional": false, "description": "", "typeRef": null}], ["navigation"], "Modifies the expression of a navigation at-rule.");
272
273
  inspectorBackend.registerCommand("CSS.setScopeText", [{"name": "styleSheetId", "type": "string", "optional": false, "description": "", "typeRef": "DOM.StyleSheetId"}, {"name": "range", "type": "object", "optional": false, "description": "", "typeRef": "CSS.SourceRange"}, {"name": "text", "type": "string", "optional": false, "description": "", "typeRef": null}], ["scope"], "Modifies the expression of a scope at-rule.");
@@ -298,7 +299,7 @@ inspectorBackend.registerType("CSS.CSSProperty", [{"name": "name", "type": "stri
298
299
  inspectorBackend.registerType("CSS.CSSMedia", [{"name": "text", "type": "string", "optional": false, "description": "Media query text.", "typeRef": null}, {"name": "source", "type": "string", "optional": false, "description": "Source of the media query: \\\"mediaRule\\\" if specified by a @media rule, \\\"importRule\\\" if specified by an @import rule, \\\"linkedSheet\\\" if specified by a \\\"media\\\" attribute in a linked stylesheet's LINK tag, \\\"inlineSheet\\\" if specified by a \\\"media\\\" attribute in an inline stylesheet's STYLE tag.", "typeRef": null}, {"name": "sourceURL", "type": "string", "optional": true, "description": "URL of the document containing the media query description.", "typeRef": null}, {"name": "range", "type": "object", "optional": true, "description": "The associated rule (@media or @import) header range in the enclosing stylesheet (if available).", "typeRef": "CSS.SourceRange"}, {"name": "styleSheetId", "type": "string", "optional": true, "description": "Identifier of the stylesheet containing this object (if exists).", "typeRef": "DOM.StyleSheetId"}, {"name": "mediaList", "type": "array", "optional": true, "description": "Array of media queries.", "typeRef": "CSS.MediaQuery"}]);
299
300
  inspectorBackend.registerType("CSS.MediaQuery", [{"name": "expressions", "type": "array", "optional": false, "description": "Array of media query expressions.", "typeRef": "CSS.MediaQueryExpression"}, {"name": "active", "type": "boolean", "optional": false, "description": "Whether the media query condition is satisfied.", "typeRef": null}]);
300
301
  inspectorBackend.registerType("CSS.MediaQueryExpression", [{"name": "value", "type": "number", "optional": false, "description": "Media query expression value.", "typeRef": null}, {"name": "unit", "type": "string", "optional": false, "description": "Media query expression units.", "typeRef": null}, {"name": "feature", "type": "string", "optional": false, "description": "Media query expression feature.", "typeRef": null}, {"name": "valueRange", "type": "object", "optional": true, "description": "The associated range of the value text in the enclosing stylesheet (if available).", "typeRef": "CSS.SourceRange"}, {"name": "computedLength", "type": "number", "optional": true, "description": "Computed length of media query expression (if applicable).", "typeRef": null}]);
301
- inspectorBackend.registerType("CSS.CSSContainerQuery", [{"name": "text", "type": "string", "optional": false, "description": "Container query text.", "typeRef": null}, {"name": "range", "type": "object", "optional": true, "description": "The associated rule header range in the enclosing stylesheet (if available).", "typeRef": "CSS.SourceRange"}, {"name": "styleSheetId", "type": "string", "optional": true, "description": "Identifier of the stylesheet containing this object (if exists).", "typeRef": "DOM.StyleSheetId"}, {"name": "name", "type": "string", "optional": true, "description": "Optional name for the container.", "typeRef": null}, {"name": "physicalAxes", "type": "string", "optional": true, "description": "Optional physical axes queried for the container.", "typeRef": "DOM.PhysicalAxes"}, {"name": "logicalAxes", "type": "string", "optional": true, "description": "Optional logical axes queried for the container.", "typeRef": "DOM.LogicalAxes"}, {"name": "queriesScrollState", "type": "boolean", "optional": true, "description": "true if the query contains scroll-state() queries.", "typeRef": null}, {"name": "queriesAnchored", "type": "boolean", "optional": true, "description": "true if the query contains anchored() queries.", "typeRef": null}]);
302
+ inspectorBackend.registerType("CSS.CSSContainerQuery", [{"name": "text", "type": "string", "optional": false, "description": "Container query text. Contains the query part without the container name for a single query. Deprecated in favor of conditionText which contains the full prelude after @container.", "typeRef": null}, {"name": "range", "type": "object", "optional": true, "description": "The associated rule header range in the enclosing stylesheet (if available).", "typeRef": "CSS.SourceRange"}, {"name": "styleSheetId", "type": "string", "optional": true, "description": "Identifier of the stylesheet containing this object (if exists).", "typeRef": "DOM.StyleSheetId"}, {"name": "name", "type": "string", "optional": true, "description": "Optional name for the container.", "typeRef": null}, {"name": "physicalAxes", "type": "string", "optional": true, "description": "Optional physical axes queried for the container.", "typeRef": "DOM.PhysicalAxes"}, {"name": "logicalAxes", "type": "string", "optional": true, "description": "Optional logical axes queried for the container.", "typeRef": "DOM.LogicalAxes"}, {"name": "queriesScrollState", "type": "boolean", "optional": true, "description": "true if the query contains scroll-state() queries.", "typeRef": null}, {"name": "queriesAnchored", "type": "boolean", "optional": true, "description": "true if the query contains anchored() queries.", "typeRef": null}, {"name": "conditionText", "type": "string", "optional": false, "description": "CSSContainerRule.conditionText", "typeRef": null}]);
302
303
  inspectorBackend.registerType("CSS.CSSSupports", [{"name": "text", "type": "string", "optional": false, "description": "Supports rule text.", "typeRef": null}, {"name": "active", "type": "boolean", "optional": false, "description": "Whether the supports condition is satisfied.", "typeRef": null}, {"name": "range", "type": "object", "optional": true, "description": "The associated rule header range in the enclosing stylesheet (if available).", "typeRef": "CSS.SourceRange"}, {"name": "styleSheetId", "type": "string", "optional": true, "description": "Identifier of the stylesheet containing this object (if exists).", "typeRef": "DOM.StyleSheetId"}]);
303
304
  inspectorBackend.registerType("CSS.CSSNavigation", [{"name": "text", "type": "string", "optional": false, "description": "Navigation rule text.", "typeRef": null}, {"name": "active", "type": "boolean", "optional": true, "description": "Whether the navigation condition is satisfied.", "typeRef": null}, {"name": "range", "type": "object", "optional": true, "description": "The associated rule header range in the enclosing stylesheet (if available).", "typeRef": "CSS.SourceRange"}, {"name": "styleSheetId", "type": "string", "optional": true, "description": "Identifier of the stylesheet containing this object (if exists).", "typeRef": "DOM.StyleSheetId"}]);
304
305
  inspectorBackend.registerType("CSS.CSSScope", [{"name": "text", "type": "string", "optional": false, "description": "Scope rule text.", "typeRef": null}, {"name": "range", "type": "object", "optional": true, "description": "The associated rule header range in the enclosing stylesheet (if available).", "typeRef": "CSS.SourceRange"}, {"name": "styleSheetId", "type": "string", "optional": true, "description": "Identifier of the stylesheet containing this object (if exists).", "typeRef": "DOM.StyleSheetId"}]);
@@ -1729,11 +1729,16 @@ export namespace ProtocolMapping {
1729
1729
  };
1730
1730
  /**
1731
1731
  * Modifies the expression of a container query.
1732
+ * Deprecated. Use setContainerQueryConditionText instead.
1732
1733
  */
1733
1734
  'CSS.setContainerQueryText': {
1734
1735
  paramsType: [Protocol.CSS.SetContainerQueryTextRequest];
1735
1736
  returnType: Protocol.CSS.SetContainerQueryTextResponse;
1736
1737
  };
1738
+ 'CSS.setContainerQueryConditionText': {
1739
+ paramsType: [Protocol.CSS.SetContainerQueryConditionTextRequest];
1740
+ returnType: Protocol.CSS.SetContainerQueryConditionTextResponse;
1741
+ };
1737
1742
  /**
1738
1743
  * Modifies the expression of a supports at-rule.
1739
1744
  */
@@ -880,9 +880,13 @@ declare namespace ProtocolProxyApi {
880
880
 
881
881
  /**
882
882
  * Modifies the expression of a container query.
883
+ * Deprecated. Use setContainerQueryConditionText instead.
884
+ * @deprecated
883
885
  */
884
886
  invoke_setContainerQueryText(params: Protocol.CSS.SetContainerQueryTextRequest): Promise<Protocol.CSS.SetContainerQueryTextResponse>;
885
887
 
888
+ invoke_setContainerQueryConditionText(params: Protocol.CSS.SetContainerQueryConditionTextRequest): Promise<Protocol.CSS.SetContainerQueryConditionTextResponse>;
889
+
886
890
  /**
887
891
  * Modifies the expression of a supports at-rule.
888
892
  */
@@ -3240,6 +3240,10 @@ export namespace CSS {
3240
3240
  export interface CSSContainerQuery {
3241
3241
  /**
3242
3242
  * Container query text.
3243
+ * Contains the query part without the container name for a single query.
3244
+ * Deprecated in favor of conditionText which contains the full prelude
3245
+ * after @container.
3246
+ * @deprecated
3243
3247
  */
3244
3248
  text: string;
3245
3249
  /**
@@ -3271,6 +3275,10 @@ export namespace CSS {
3271
3275
  * true if the query contains anchored() queries.
3272
3276
  */
3273
3277
  queriesAnchored?: boolean;
3278
+ /**
3279
+ * CSSContainerRule.conditionText
3280
+ */
3281
+ conditionText: string;
3274
3282
  }
3275
3283
 
3276
3284
  /**
@@ -4138,6 +4146,19 @@ export namespace CSS {
4138
4146
  containerQuery: CSSContainerQuery;
4139
4147
  }
4140
4148
 
4149
+ export interface SetContainerQueryConditionTextRequest {
4150
+ styleSheetId: DOM.StyleSheetId;
4151
+ range: SourceRange;
4152
+ text: string;
4153
+ }
4154
+
4155
+ export interface SetContainerQueryConditionTextResponse extends ProtocolResponseWithError {
4156
+ /**
4157
+ * The resulting CSS container query rule after modification.
4158
+ */
4159
+ containerQuery: CSSContainerQuery;
4160
+ }
4161
+
4141
4162
  export interface SetSupportsTextRequest {
4142
4163
  styleSheetId: DOM.StyleSheetId;
4143
4164
  range: SourceRange;
@@ -0,0 +1,16 @@
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
+ // The StorageItem is used as context for the Ai Assistance.
6
+ // If the user selects a row in e.g. the cookies table, the storageType and key
7
+ // will be populated. An empty {} StorageItem is used if the user asks general questions.
8
+ export type StorageItem = {
9
+ origin: string,
10
+ }&({
11
+ storageType?: never,
12
+ key?: never,
13
+ }|{
14
+ storageType: 'cookie' | 'localStorage' | 'sessionStorage',
15
+ key: string,
16
+ });
@@ -8,6 +8,7 @@ import type * as SDK from '../../../core/sdk/sdk.js';
8
8
  import type * as Protocol from '../../../generated/protocol.js';
9
9
  import * as Greendev from '../../greendev/greendev.js';
10
10
  import type * as LHModel from '../../lighthouse/lighthouse.js';
11
+ import type * as TextUtils from '../../text_utils/text_utils.js';
11
12
  import type * as Trace from '../../trace/trace.js';
12
13
  import {debugLog, isStructuredLogEnabled} from '../debug.js';
13
14
 
@@ -236,7 +237,7 @@ export interface DomTreeAiWidget {
236
237
  size: number,
237
238
  resourceType: Protocol.Network.ResourceType,
238
239
  mimeType: string,
239
- imageUrl?: string,
240
+ imageContent?: TextUtils.ContentData.ContentData,
240
241
  },
241
242
  };
242
243
  }
@@ -985,9 +985,14 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
985
985
  const nodeMap = await domModel.pushNodesByBackendIdsToFrontend(new Set([nodeId]));
986
986
  const node = nodeMap?.get(nodeId);
987
987
  if (node) {
988
- const snapshot = await node.takeSnapshot();
989
- let networkRequest;
990
988
  const lcpSyntheticRequest = insight.lcpRequest;
989
+ const [snapshot, imageContent] = await Promise.all([
990
+ node.takeSnapshot(),
991
+ lcpSyntheticRequest ? this.#getNetworkRequestImageData(lcpSyntheticRequest) :
992
+ Promise.resolve(undefined),
993
+ ]);
994
+
995
+ let networkRequest;
991
996
  if (lcpSyntheticRequest) {
992
997
  networkRequest = {
993
998
  url: lcpSyntheticRequest.args.data.url,
@@ -995,7 +1000,7 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
995
1000
  lcpSyntheticRequest.args.data.encodedDataLength ?? 0,
996
1001
  resourceType: lcpSyntheticRequest.args.data.resourceType,
997
1002
  mimeType: lcpSyntheticRequest.args.data.mimeType ?? '',
998
- imageUrl: await this.#getNetworkRequestImageData(lcpSyntheticRequest),
1003
+ imageContent,
999
1004
  };
1000
1005
  }
1001
1006
  widgets.push({
@@ -1567,7 +1572,8 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
1567
1572
  return {result: {success: true}};
1568
1573
  }
1569
1574
 
1570
- async #getNetworkRequestImageData(lcpRequest: Trace.Types.Events.SyntheticNetworkRequest): Promise<string|undefined> {
1575
+ async #getNetworkRequestImageData(lcpRequest: Trace.Types.Events.SyntheticNetworkRequest):
1576
+ Promise<TextUtils.ContentData.ContentData|undefined> {
1571
1577
  const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
1572
1578
  const networkManager = target?.model(SDK.NetworkManager.NetworkManager);
1573
1579
  if (!target || !networkManager) {
@@ -1581,7 +1587,7 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
1581
1587
  if (sdkRequest?.contentType().isImage()) {
1582
1588
  const contentData = await sdkRequest.requestContentData();
1583
1589
  if (!TextUtils.ContentData.ContentData.isError(contentData)) {
1584
- return contentData.asDataUrl() ?? undefined;
1590
+ return contentData;
1585
1591
  }
1586
1592
  }
1587
1593
  return undefined;
@@ -0,0 +1,82 @@
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 {StorageItem} from '../StorageItem.js';
8
+
9
+ import {
10
+ AiAgent,
11
+ ConversationContext,
12
+ type RequestOptions,
13
+ } from './AiAgent.js';
14
+
15
+ // TODO(kimanh): Replace temporary preamble as soon as functions are implemented
16
+ const preamble =
17
+ `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 Cookies, LocalStorage, and SessionStorage and connecting it to the application logic in the source code.
18
+
19
+ # Considerations
20
+
21
+ - **Raw Evidence**: Treat storage data as "raw evidence". Do not make assumptions without verifying code references.
22
+ - **Brevity**: Use the precision of Strunk & White, the brevity of Hemingway, and the simple clarity of Vonnegut. Keep answers short and actionable.
23
+
24
+ **CRITICAL** You are a debugging assistant in DevTools. 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.
25
+ `;
26
+
27
+ export class StorageContext extends ConversationContext<StorageItem> {
28
+ #item: StorageItem;
29
+
30
+ constructor(item: StorageItem) {
31
+ super();
32
+ this.#item = item;
33
+ }
34
+
35
+ override getOrigin(): string {
36
+ return this.#item.origin;
37
+ }
38
+
39
+ override getItem(): StorageItem {
40
+ return this.#item;
41
+ }
42
+
43
+ override getTitle(): string {
44
+ if (this.#item.key) {
45
+ return `${this.#item.storageType}: ${this.#item.key}`;
46
+ }
47
+ return `Storage for ${this.#item.origin}`;
48
+ }
49
+ }
50
+
51
+ export class StorageAgent extends AiAgent<StorageItem> {
52
+ readonly preamble = preamble;
53
+ readonly clientFeature = Host.AidaClient.ClientFeature.CHROME_STORAGE_AGENT;
54
+
55
+ get userTier(): string|undefined {
56
+ return Root.Runtime.hostConfig.devToolsFreestyler?.userTier;
57
+ }
58
+
59
+ get options(): RequestOptions {
60
+ const temperature = Root.Runtime.hostConfig.devToolsFreestyler?.temperature;
61
+ const modelId = Root.Runtime.hostConfig.devToolsFreestyler?.modelId;
62
+
63
+ return {
64
+ temperature,
65
+ modelId,
66
+ };
67
+ }
68
+
69
+ constructor(opts: {sessionId?: string, aidaClient?: Host.AidaClient.AidaClient} = {}) {
70
+ super({
71
+ aidaClient: opts.aidaClient ?? new Host.AidaClient.AidaClient(),
72
+ sessionId: opts.sessionId,
73
+ });
74
+ }
75
+
76
+ async * handleContextDetails(_context: ConversationContext<StorageItem>|null): AsyncGenerator<never, void, void> {
77
+ }
78
+
79
+ override async enhanceQuery(query: string, _context: ConversationContext<StorageItem>|null): Promise<string> {
80
+ return query;
81
+ }
82
+ }