chrome-devtools-frontend 1.0.1604514 → 1.0.1605219

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 (54) hide show
  1. package/AUTHORS +1 -0
  2. package/front_end/Tests.js +23 -7
  3. package/front_end/core/host/AidaClient.ts +114 -63
  4. package/front_end/core/host/AidaGcaTranslation.ts +6 -0
  5. package/front_end/core/host/GcaClient.ts +112 -0
  6. package/front_end/core/host/UserMetrics.ts +0 -1
  7. package/front_end/core/host/host.ts +2 -0
  8. package/front_end/core/root/ExperimentNames.ts +0 -1
  9. package/front_end/core/root/Runtime.ts +5 -0
  10. package/front_end/core/sdk/AutofillModel.ts +3 -2
  11. package/front_end/core/sdk/CSSModel.ts +3 -4
  12. package/front_end/core/sdk/CSSProperty.ts +1 -1
  13. package/front_end/core/sdk/ConsoleModel.ts +15 -13
  14. package/front_end/core/sdk/CookieModel.ts +5 -4
  15. package/front_end/core/sdk/DOMDebuggerModel.ts +20 -14
  16. package/front_end/core/sdk/DebuggerModel.ts +21 -36
  17. package/front_end/core/sdk/EventBreakpointsModel.ts +16 -6
  18. package/front_end/core/sdk/IsolateManager.ts +12 -7
  19. package/front_end/entrypoints/main/MainImpl.ts +0 -4
  20. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +31 -17
  21. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +1 -1
  22. package/front_end/models/emulation/DeviceModeModel.ts +21 -26
  23. package/front_end/models/trace/insights/LCPDiscovery.ts +14 -6
  24. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +2 -17
  25. package/front_end/panels/ai_assistance/components/ChatMessage.ts +36 -20
  26. package/front_end/panels/ai_assistance/components/chatMessage.css +5 -1
  27. package/front_end/panels/application/ApplicationPanelSidebar.ts +6 -0
  28. package/front_end/panels/application/IndexedDBViews.ts +0 -9
  29. package/front_end/panels/application/WebMCPTreeElement.ts +35 -0
  30. package/front_end/panels/application/WebMCPView.ts +118 -0
  31. package/front_end/panels/application/application.ts +4 -0
  32. package/front_end/panels/application/webMCPView.css +65 -0
  33. package/front_end/panels/common/aiCodeCompletionSummaryToolbar.css +1 -1
  34. package/front_end/panels/console/consoleView.css +4 -0
  35. package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +23 -2
  36. package/front_end/panels/elements/StylesSidebarPane.ts +85 -20
  37. package/front_end/panels/elements/elementsPanel.css +14 -0
  38. package/front_end/panels/network/NetworkLogViewColumns.ts +3 -3
  39. package/front_end/panels/recorder/components/recordingView.css +0 -6
  40. package/front_end/panels/sensors/SensorsView.ts +28 -59
  41. package/front_end/panels/timeline/EventsTimelineTreeView.ts +2 -2
  42. package/front_end/panels/timeline/ThirdPartyTreeView.ts +35 -36
  43. package/front_end/panels/timeline/TimelineDetailsView.ts +47 -41
  44. package/front_end/panels/timeline/TimelineTreeView.ts +13 -13
  45. package/front_end/panels/timeline/components/LiveMetricsView.ts +839 -783
  46. package/front_end/panels/timeline/thirdPartyTreeView.css +2 -2
  47. package/front_end/ui/components/buttons/button.css +2 -2
  48. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +0 -11
  49. package/front_end/ui/legacy/InspectorDrawerView.ts +206 -0
  50. package/front_end/ui/legacy/InspectorView.ts +41 -91
  51. package/front_end/ui/legacy/ViewManager.ts +14 -5
  52. package/front_end/ui/legacy/inspectorDrawerTabbedPane.css +5 -0
  53. package/front_end/ui/visual_logging/KnownContextValues.ts +2 -1
  54. package/package.json +1 -1
@@ -342,12 +342,13 @@ export const DEFAULT_VIEW = (input: ChatMessageViewInput, output: ViewOutput, ta
342
342
  class="chat-message answer ${input.isLastMessage ? 'is-last-message' : ''}"
343
343
  jslog=${VisualLogging.section('answer')}
344
344
  >
345
- <div class="message-info">
346
- <devtools-icon name=${icon}></devtools-icon>
347
- <div class="message-name">
348
- <h2>${AiAssistanceModel.AiUtils.isGeminiBranding() ? lockedString(UIStringsNotTranslate.gemini) : lockedString(UIStringsNotTranslate.ai)}</h2>
349
- </div>
350
- </div>
345
+ ${aiAssistanceV2 ? Lit.nothing : html`
346
+ <div class="message-info">
347
+ <devtools-icon name=${icon}></devtools-icon>
348
+ <div class="message-name">
349
+ <h2>${AiAssistanceModel.AiUtils.isGeminiBranding() ? lockedString(UIStringsNotTranslate.gemini) : lockedString(UIStringsNotTranslate.ai)}</h2>
350
+ </div>
351
+ </div>`}
351
352
  ${aiAssistanceV2 ? renderWalkthroughUI(input, steps) : Lit.nothing}
352
353
  ${Lit.Directives.repeat(
353
354
  message.parts,
@@ -519,11 +520,14 @@ function renderWalkthroughSidebarButton(
519
520
  // want to change it visually at the end once everything has stopped
520
521
  // loading.
521
522
  const variant = hasOneStepWithWidget && !input.isLoading ? Buttons.Button.Variant.TONAL : Buttons.Button.Variant.TEXT;
523
+ const icon = AiAssistanceModel.AiUtils.getIconName();
522
524
 
523
525
  // clang-format off
524
526
  return html`
525
- <div class="walkthrough-toggle-container">
526
- ${input.isLoading ? html`<devtools-spinner></devtools-spinner>` : Lit.nothing}
527
+ <div class="walkthrough-toggle-container ${hasOneStepWithWidget ? 'has-widgets' : ''}">
528
+ ${input.isLoading ?
529
+ html`<devtools-spinner></devtools-spinner>` :
530
+ html`<devtools-icon name=${icon}></devtools-icon>`}
527
531
  <devtools-button
528
532
  .variant=${variant}
529
533
  .size=${Buttons.Button.Size.SMALL}
@@ -540,8 +544,8 @@ function renderWalkthroughSidebarButton(
540
544
  walkthrough.onOpen(message as ModelChatMessage);
541
545
  }
542
546
  }}
543
- >
544
- ${title}<devtools-icon class="chevron" .name=${'chevron-right'}></devtools-icon>
547
+ >
548
+ ${title}<devtools-icon class="chevron" .name=${isExpanded ? 'cross' : 'chevron-right'}></devtools-icon>
545
549
  </devtools-button>
546
550
  </div>
547
551
  `;
@@ -1236,7 +1240,7 @@ export class ChatMessage extends UI.Widget.Widget {
1236
1240
  };
1237
1241
 
1238
1242
  #suggestionsResizeObserver = new ResizeObserver(() => this.#handleSuggestionsScrollOrResize());
1239
- #suggestionsEvaluateLayoutThrottler = new Common.Throttler.Throttler(50);
1243
+ #suggestionsEvaluateLayoutThrottler = new Common.Throttler.Throttler(100);
1240
1244
 
1241
1245
  #feedbackValue = '';
1242
1246
  #currentRating: Host.AidaClient.Rating|undefined;
@@ -1246,6 +1250,8 @@ export class ChatMessage extends UI.Widget.Widget {
1246
1250
  #view: View;
1247
1251
  #viewOutput: ViewOutput = {};
1248
1252
 
1253
+ #isObservingSuggestions = false;
1254
+
1249
1255
  constructor(element?: HTMLElement, view?: View) {
1250
1256
  super(element);
1251
1257
  this.#view = view ?? DEFAULT_VIEW;
@@ -1255,10 +1261,6 @@ export class ChatMessage extends UI.Widget.Widget {
1255
1261
  super.wasShown();
1256
1262
  void this.performUpdate();
1257
1263
  this.#evaluateSuggestionsLayout();
1258
-
1259
- if (this.#viewOutput.suggestionsScrollContainer) {
1260
- this.#suggestionsResizeObserver.observe(this.#viewOutput.suggestionsScrollContainer);
1261
- }
1262
1264
  }
1263
1265
 
1264
1266
  override performUpdate(): Promise<void>|void {
@@ -1297,6 +1299,11 @@ export class ChatMessage extends UI.Widget.Widget {
1297
1299
  walkthrough: this.walkthrough,
1298
1300
  },
1299
1301
  this.#viewOutput, this.contentElement);
1302
+
1303
+ if (this.#viewOutput.suggestionsScrollContainer && !this.#isObservingSuggestions) {
1304
+ this.#suggestionsResizeObserver.observe(this.#viewOutput.suggestionsScrollContainer);
1305
+ this.#isObservingSuggestions = true;
1306
+ }
1300
1307
  }
1301
1308
 
1302
1309
  #handleInputChange(value: string): void {
@@ -1320,6 +1327,7 @@ export class ChatMessage extends UI.Widget.Widget {
1320
1327
  const shouldShowRightButton = suggestionsScrollContainer.scrollLeft +
1321
1328
  (suggestionsScrollContainer as HTMLElement).offsetWidth + SCROLL_ROUNDING_OFFSET <
1322
1329
  suggestionsScrollContainer.scrollWidth;
1330
+
1323
1331
  leftScrollButtonContainer.classList.toggle('hidden', !shouldShowLeftButton);
1324
1332
  rightScrollButtonContainer.classList.toggle('hidden', !shouldShowRightButton);
1325
1333
  };
@@ -1327,6 +1335,7 @@ export class ChatMessage extends UI.Widget.Widget {
1327
1335
  override willHide(): void {
1328
1336
  super.willHide();
1329
1337
  this.#suggestionsResizeObserver.disconnect();
1338
+ this.#isObservingSuggestions = false;
1330
1339
  }
1331
1340
 
1332
1341
  #handleSuggestionsScrollOrResize(): void {
@@ -1410,8 +1419,8 @@ async function makeTimelineRangeSummaryWidget(widgetData: TimelineRangeSummaryAi
1410
1419
 
1411
1420
  const thirdPartyTree = new Timeline.ThirdPartyTreeView.ThirdPartyTreeViewWidget();
1412
1421
  const mapper = new Trace.EntityMapper.EntityMapper(parsedTrace);
1413
- thirdPartyTree.setModelWithEvents(eventsArray, parsedTrace, mapper);
1414
- thirdPartyTree.updateContents(Timeline.TimelineSelection.selectionFromRangeMicroSeconds(bounds.min, bounds.max));
1422
+ thirdPartyTree.model = {selectedEvents: eventsArray, parsedTrace, entityMapper: mapper};
1423
+ thirdPartyTree.activeSelection = Timeline.TimelineSelection.selectionFromRangeMicroSeconds(bounds.min, bounds.max);
1415
1424
  thirdPartyTree.refreshTree(true);
1416
1425
 
1417
1426
  // clang-format off
@@ -1423,9 +1432,16 @@ async function makeTimelineRangeSummaryWidget(widgetData: TimelineRangeSummaryAi
1423
1432
  events,
1424
1433
  startTime: Trace.Helpers.Timing.microToMilli(bounds.min),
1425
1434
  endTime: Trace.Helpers.Timing.microToMilli(bounds.max),
1426
- thirdPartyTreeTemplate: html`<devtools-performance-third-party-tree-view
1427
- max-rows="10"
1428
- .treeView=${thirdPartyTree}></devtools-performance-third-party-tree-view>`,
1435
+ thirdPartyTreeTemplate: html`${
1436
+ widget(Timeline.ThirdPartyTreeView.ThirdPartyTreeViewWidget, {
1437
+ maxRows: 10,
1438
+ model: {
1439
+ selectedEvents: thirdPartyTree.selectedEvents() ?? null,
1440
+ parsedTrace,
1441
+ entityMapper: thirdPartyTree.entityMapper(),
1442
+ },
1443
+ activeSelection: { bounds },
1444
+ })}`,
1429
1445
  } as TimelineComponents.TimelineRangeSummaryView.TimelineRangeSummaryViewData,
1430
1446
  })}
1431
1447
  ></devtools-widget>`;
@@ -344,9 +344,13 @@
344
344
 
345
345
  .walkthrough-toggle-container {
346
346
  display: flex;
347
- gap: var(--sys-size-4);
347
+ gap: var(--sys-size-2);
348
348
  align-items: center;
349
349
 
350
+ &.has-widgets {
351
+ gap: var(--sys-size-6);
352
+ }
353
+
350
354
  .chevron {
351
355
  color: var(--sys-color-primary);
352
356
  width: var(--sys-size-8);
@@ -92,6 +92,7 @@ import {SharedStorageTreeElement} from './SharedStorageTreeElement.js';
92
92
  import {StorageBucketsTreeParentElement} from './StorageBucketsTreeElement.js';
93
93
  import {StorageView} from './StorageView.js';
94
94
  import {TrustTokensTreeElement} from './TrustTokensTreeElement.js';
95
+ import {WebMCPTreeElement} from './WebMCPTreeElement.js';
95
96
 
96
97
  const UIStrings = {
97
98
  /**
@@ -346,6 +347,7 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
346
347
  periodicBackgroundSyncTreeElement: BackgroundServiceTreeElement;
347
348
  pushMessagingTreeElement: BackgroundServiceTreeElement;
348
349
  reportingApiTreeElement: ReportingApiTreeElement;
350
+ webMcpTreeElement?: WebMCPTreeElement;
349
351
  deviceBoundSessionsRootTreeElement: DeviceBoundSessionsRootTreeElement|undefined;
350
352
  deviceBoundSessionsModel: DeviceBoundSessionsModel|undefined;
351
353
  preloadingSummaryTreeElement: PreloadingSummaryTreeElement|undefined;
@@ -390,6 +392,10 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
390
392
  this.applicationTreeElement.appendChild(this.serviceWorkersTreeElement);
391
393
  const clearStorageTreeElement = new ClearStorageTreeElement(panel);
392
394
  this.applicationTreeElement.appendChild(clearStorageTreeElement);
395
+ if (Root.Runtime.hostConfig.devToolsWebMCPSupport?.enabled) {
396
+ this.webMcpTreeElement = new WebMCPTreeElement(panel);
397
+ this.applicationTreeElement.appendChild(this.webMcpTreeElement);
398
+ }
393
399
 
394
400
  const storageSectionTitle = i18nString(UIStrings.storage);
395
401
  const storageTreeElement = this.addSidebarSection(storageSectionTitle, 'storage');
@@ -321,27 +321,19 @@ export class IDBDataView extends UI.View.SimpleView {
321
321
  const keyPath = this.isIndex && this.index ? this.index.keyPath : this.objectStore.keyPath;
322
322
 
323
323
  const columns: DataGrid.DataGrid.ColumnDescriptor[] = [];
324
-
325
- // Create column defaults so that we avoid repetition below.
326
- const columnDefaults: Partial<DataGrid.DataGrid.ColumnDescriptor> = {
327
- sortable: false,
328
- };
329
324
  columns.push({
330
- ...columnDefaults,
331
325
  id: 'number',
332
326
  title: '#' as Platform.UIString.LocalizedString,
333
327
  sortable: false,
334
328
  width: '50px',
335
329
  });
336
330
  columns.push({
337
- ...columnDefaults,
338
331
  id: 'key',
339
332
  titleDOMFragment: this.keyColumnHeaderFragment(i18nString(UIStrings.keyString), keyPath),
340
333
  sortable: false,
341
334
  });
342
335
  if (this.isIndex) {
343
336
  columns.push({
344
- ...columnDefaults,
345
337
  id: 'primary-key',
346
338
  titleDOMFragment: this.keyColumnHeaderFragment(i18nString(UIStrings.primaryKey), this.objectStore.keyPath),
347
339
  sortable: false,
@@ -349,7 +341,6 @@ export class IDBDataView extends UI.View.SimpleView {
349
341
  }
350
342
  const title = i18nString(UIStrings.valueString);
351
343
  columns.push({
352
- ...columnDefaults,
353
344
  id: 'value',
354
345
  title,
355
346
  sortable: false,
@@ -0,0 +1,35 @@
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 type * as Platform from '../../core/platform/platform.js';
7
+ import {createIcon} from '../../ui/kit/kit.js';
8
+
9
+ import {ApplicationPanelTreeElement} from './ApplicationPanelTreeElement.js';
10
+ import type {ResourcesPanel} from './ResourcesPanel.js';
11
+ import {WebMCPView} from './WebMCPView.js';
12
+
13
+ export class WebMCPTreeElement extends ApplicationPanelTreeElement {
14
+ #view?: WebMCPView;
15
+
16
+ constructor(storagePanel: ResourcesPanel) {
17
+ super(storagePanel, 'WebMCP', false, 'web-mcp');
18
+ const icon = createIcon('document');
19
+ this.setLeadingIcons([icon]);
20
+ }
21
+
22
+ override get itemURL(): Platform.DevToolsPath.UrlString {
23
+ return 'webMcp://' as Platform.DevToolsPath.UrlString;
24
+ }
25
+
26
+ override onselect(selectedByUser?: boolean): boolean {
27
+ super.onselect(selectedByUser);
28
+ if (!this.#view) {
29
+ this.#view = new WebMCPView();
30
+ }
31
+ this.showView(this.#view);
32
+ Host.userMetrics.panelShown('web-mcp');
33
+ return false;
34
+ }
35
+ }
@@ -0,0 +1,118 @@
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 '../../ui/components/icon_button/icon_button.js';
6
+ import '../../ui/components/lists/lists.js';
7
+ import '../../ui/legacy/legacy.js';
8
+
9
+ import * as i18n from '../../core/i18n/i18n.js';
10
+ import * as SDK from '../../core/sdk/sdk.js';
11
+ import type * as Protocol from '../../generated/protocol.js';
12
+ import * as UI from '../../ui/legacy/legacy.js';
13
+ import {
14
+ html,
15
+ render,
16
+ } from '../../ui/lit/lit.js';
17
+
18
+ import webMCPViewStyles from './webMCPView.css.js';
19
+
20
+ const UIStrings = {
21
+ /**
22
+ * @description Text for the header of the tool registry section
23
+ */
24
+ toolRegistry: 'Available Tools',
25
+ /**
26
+ * @description Title of text to display when no tools are registered
27
+ */
28
+ noToolsPlaceholderTitle: 'Available `WebMCP` Tools',
29
+ /**
30
+ * @description Text to display when no tools are registered
31
+ */
32
+ noToolsPlaceholder:
33
+ 'Registered `WebMCP` tools for this page will appear here. No tools have been registered or detected yet.',
34
+ /**
35
+ * @description Title of text to display when no calls have been made
36
+ */
37
+ noCallsPlaceholderTitle: 'Tool Activity',
38
+ /**
39
+ * @description Text to display when no calls have been made
40
+ */
41
+ noCallsPlaceholder: 'Start interacting with your `WebMCP` agent to see real-time tool calls and executions here.'
42
+ } as const;
43
+ const str_ = i18n.i18n.registerUIStrings('panels/application/WebMCPView.ts', UIStrings);
44
+ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
45
+
46
+ export interface ViewInput {
47
+ tools: Protocol.WebMCP.Tool[];
48
+ }
49
+
50
+ export type View = (input: ViewInput, output: object, target: HTMLElement) => void;
51
+ export const DEFAULT_VIEW: View = (input, output, target) => {
52
+ const tools = input.tools;
53
+ // clang-format off
54
+ render(html`
55
+ <style>${webMCPViewStyles}</style>
56
+ <devtools-split-view class="webmcp-view" direction="row" sidebar-position="second" name="webmcp-split-view">
57
+ <div slot="main" class="call-log">
58
+ ${UI.Widget.widget(UI.EmptyWidget.EmptyWidget, {header: i18nString(UIStrings.noCallsPlaceholderTitle),
59
+ text: i18nString(UIStrings.noCallsPlaceholder)})}
60
+ </div>
61
+ <div slot="sidebar" class="tool-list">
62
+ <div class="section-title">${i18nString(UIStrings.toolRegistry)}</div>
63
+ ${tools.length === 0 ? html`
64
+ ${UI.Widget.widget(UI.EmptyWidget.EmptyWidget, {header: i18nString(UIStrings.noToolsPlaceholderTitle),
65
+ text: i18nString(UIStrings.noToolsPlaceholder)})}
66
+ ` : html`
67
+ <devtools-list>
68
+ ${tools.map(tool => html`
69
+ <div class="tool-item">
70
+ <div class="tool-name-container">
71
+ <div class="tool-name source-code">${tool.name}</div>
72
+ </div>
73
+ <div class="tool-description">${tool.description}</div>
74
+ </div>
75
+ `)}
76
+ </devtools-list>
77
+ `}
78
+ </div>
79
+ </devtools-split-view>
80
+ `, target);
81
+ // clang-format on
82
+ };
83
+
84
+ export class WebMCPView extends UI.Widget.VBox {
85
+ readonly #view: View;
86
+
87
+ constructor(target?: HTMLElement, view: View = DEFAULT_VIEW) {
88
+ super();
89
+ this.#view = view;
90
+ SDK.TargetManager.TargetManager.instance().observeModels(SDK.WebMCPModel.WebMCPModel, {
91
+ modelAdded: (model: SDK.WebMCPModel.WebMCPModel) => this.#webMCPModelAdded(model),
92
+ modelRemoved: (model: SDK.WebMCPModel.WebMCPModel) => this.#webMCPModelRemoved(model),
93
+ });
94
+ this.requestUpdate();
95
+ }
96
+
97
+ #webMCPModelAdded(model: SDK.WebMCPModel.WebMCPModel): void {
98
+ model.addEventListener(SDK.WebMCPModel.Events.TOOLS_ADDED, this.requestUpdate, this);
99
+ model.addEventListener(SDK.WebMCPModel.Events.TOOLS_REMOVED, this.requestUpdate, this);
100
+ }
101
+
102
+ #webMCPModelRemoved(model: SDK.WebMCPModel.WebMCPModel): void {
103
+ model.removeEventListener(SDK.WebMCPModel.Events.TOOLS_ADDED, this.requestUpdate, this);
104
+ model.removeEventListener(SDK.WebMCPModel.Events.TOOLS_REMOVED, this.requestUpdate, this);
105
+ }
106
+
107
+ override performUpdate(): void {
108
+ const tools = SDK.TargetManager.TargetManager.instance()
109
+ .models(SDK.WebMCPModel.WebMCPModel)
110
+ .flatMap(m => m.tools.toArray())
111
+ .sort((a, b) => a.name.localeCompare(b.name));
112
+ this.#view(
113
+ {
114
+ tools,
115
+ },
116
+ {}, this.contentElement);
117
+ }
118
+ }
@@ -40,6 +40,8 @@ import * as StorageBucketsTreeElement from './StorageBucketsTreeElement.js';
40
40
  import * as StorageItemsToolbar from './StorageItemsToolbar.js';
41
41
  import * as StorageView from './StorageView.js';
42
42
  import * as TrustTokensTreeElement from './TrustTokensTreeElement.js';
43
+ import * as WebMCPTreeElement from './WebMCPTreeElement.js';
44
+ import * as WebMCPView from './WebMCPView.js';
43
45
 
44
46
  export {
45
47
  ApplicationPanelSidebar,
@@ -80,4 +82,6 @@ export {
80
82
  StorageItemsToolbar,
81
83
  StorageView,
82
84
  TrustTokensTreeElement,
85
+ WebMCPTreeElement,
86
+ WebMCPView,
83
87
  };
@@ -0,0 +1,65 @@
1
+ /*
2
+ * Copyright 2026 The Chromium Authors
3
+ * Use of this source code is governed by a BSD-style license that can be
4
+ * found in the LICENSE file.
5
+ */
6
+
7
+ @scope to (devtools-widget > *) {
8
+ .webmcp-view {
9
+ height: 100%;
10
+ width: 100%;
11
+ }
12
+
13
+ .call-log,
14
+ .tool-list {
15
+ height: 100%;
16
+ display: flex;
17
+ flex-direction: column;
18
+ overflow: auto;
19
+ padding: 0;
20
+ }
21
+
22
+ .empty-view-scroller {
23
+ flex: auto;
24
+ }
25
+
26
+ .section-title {
27
+ background-color: var(--sys-color-surface1);
28
+ padding: 0 5px;
29
+ line-height: 22px;
30
+ overflow: hidden;
31
+ align-items: center;
32
+ flex: none;
33
+ color: var(--sys-color-on-surface);
34
+ }
35
+
36
+ devtools-list {
37
+ flex: 1 1 auto;
38
+ margin: var(--sys-size-4);
39
+ }
40
+
41
+ .tool-item {
42
+ display: flex;
43
+ flex-direction: column;
44
+ padding: 8px 0;
45
+ gap: 4px;
46
+ width: 100%;
47
+ border-bottom: 1px solid var(--sys-color-divider);
48
+ }
49
+
50
+ .tool-name-container {
51
+ display: flex;
52
+ justify-content: space-between;
53
+ align-items: center;
54
+ }
55
+
56
+ .tool-name.source-code {
57
+ color: var(--sys-color-token-string);
58
+ }
59
+
60
+ .tool-description {
61
+ color: var(--sys-color-on-surface);
62
+ }
63
+
64
+
65
+ }
@@ -49,7 +49,7 @@
49
49
  border-left: var(--sys-size-1) solid var(--sys-color-divider);
50
50
  }
51
51
 
52
- @media (width < 545px) {
52
+ @container (width < 545px) {
53
53
  &.has-disclaimer.has-recitation-notice {
54
54
  height: 46px;
55
55
  flex-direction: column;
@@ -633,6 +633,10 @@
633
633
  }
634
634
  }
635
635
 
636
+ .ai-code-completion-summary-toolbar-container {
637
+ container-type: inline-size;
638
+ }
639
+
636
640
  @media (forced-colors: active) {
637
641
  .console-message-expand-icon,
638
642
  .console-warning-level .expand-group-icon {
@@ -16,6 +16,18 @@ export class StylesAiCodeCompletionProvider {
16
16
  #aiCodeCompletion?: AiCodeCompletion.AiCodeCompletion.AiCodeCompletion;
17
17
  #aiCodeCompletionConfig?: TextEditor.AiCodeCompletionProvider.AiCodeCompletionConfig;
18
18
 
19
+ getCompletionHint?: () => string | null;
20
+ setAiAutoCompletion?: (args: {
21
+ text: string,
22
+ from: number,
23
+ startTime: number,
24
+ onImpression: (rpcGlobalId: Host.AidaClient.RpcGlobalId, latency: number, sampleId?: number) => void,
25
+ clearCachedRequest: () => void,
26
+ citations: Host.AidaClient.Citation[],
27
+ rpcGlobalId?: Host.AidaClient.RpcGlobalId,
28
+ sampleId?: number,
29
+ }|null) => void;
30
+
19
31
  #boundOnUpdateAiCodeCompletionState = this.#updateAiCodeCompletionState.bind(this);
20
32
 
21
33
  private constructor(aiCodeCompletionConfig: TextEditor.AiCodeCompletionProvider.AiCodeCompletionConfig) {
@@ -123,7 +135,7 @@ export class StylesAiCodeCompletionProvider {
123
135
  return;
124
136
  }
125
137
 
126
- this.#aiCodeCompletionConfig?.setAiAutoCompletion?.({
138
+ this.setAiAutoCompletion?.({
127
139
  text: currentPropertyString + aidaSuggestion.suggestionText,
128
140
  from: cursorPosition,
129
141
  rpcGlobalId: aidaSuggestion.rpcGlobalId,
@@ -131,6 +143,7 @@ export class StylesAiCodeCompletionProvider {
131
143
  startTime,
132
144
  clearCachedRequest: this.clearCache.bind(this),
133
145
  onImpression: this.#aiCodeCompletion.registerUserImpression.bind(this.#aiCodeCompletion),
146
+ citations: aidaSuggestion.citations,
134
147
  });
135
148
  }
136
149
 
@@ -206,7 +219,7 @@ export class StylesAiCodeCompletionProvider {
206
219
  return null;
207
220
  }
208
221
 
209
- const completionHint = this.#aiCodeCompletionConfig?.getCompletionHint?.();
222
+ const completionHint = this.getCompletionHint?.();
210
223
  if (!completionHint) {
211
224
  return response.generatedSamples[0];
212
225
  }
@@ -216,4 +229,12 @@ export class StylesAiCodeCompletionProvider {
216
229
  clearCache(): void {
217
230
  this.#aiCodeCompletion?.clearCachedRequest();
218
231
  }
232
+
233
+ onSuggestionAccepted(
234
+ citations: Host.AidaClient.Citation[], rpcGlobalId?: Host.AidaClient.RpcGlobalId, sampleId?: number): void {
235
+ this.#aiCodeCompletionConfig?.onSuggestionAccepted(citations);
236
+ if (rpcGlobalId) {
237
+ this.#aiCodeCompletion?.registerUserAcceptance(rpcGlobalId, sampleId);
238
+ }
239
+ }
219
240
  }