chrome-devtools-frontend 1.0.1717709 → 1.0.1721762

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 (291) hide show
  1. package/.agents/rules/models-and-core/core-ai-agent-context-and-prompt-discipline.md +29 -0
  2. package/.agents/rules/models-and-core/core-cdp-and-extension-error-handling.md +34 -0
  3. package/.agents/rules/models-and-core/core-gn-build-and-module-layering.md +23 -0
  4. package/.agents/rules/models-and-core/core-runtime-neutrality-and-platform-utils.md +28 -0
  5. package/.agents/rules/models-and-core/core-sdk-model-and-target-lifecycle.md +35 -0
  6. package/.agents/rules/models-and-core/core-security-origin-and-capability-guards.md +33 -0
  7. package/.agents/rules/models-and-core/core-settings-and-storage-migration.md +31 -0
  8. package/.agents/rules/models-and-core/core-sourcemap-and-workspace-mapping.md +28 -0
  9. package/.agents/rules/models-and-core/core-trace-engine-handler-invariants.md +32 -0
  10. package/.agents/rules/models-and-core/core-trace-insight-models-and-timing-types.md +28 -0
  11. package/.agents/rules/tests/test-cleanup-mutated-globals-and-widgets.md +40 -0
  12. package/.agents/rules/tests/test-deterministic-async-synchronization.md +30 -0
  13. package/.agents/rules/tests/test-modular-hooks-and-test-universe.md +38 -0
  14. package/.agents/rules/tests/test-public-api-and-encapsulation.md +30 -0
  15. package/.agents/rules/tests/test-shared-fixture-and-helper-reuse.md +29 -0
  16. package/.agents/rules/tests/test-single-responsibility-and-conciseness.md +37 -0
  17. package/.agents/rules/tests/test-strict-assertions-and-literal-expectations.md +31 -0
  18. package/.agents/rules/tests/test-type-safe-mocks-and-events.md +30 -0
  19. package/.agents/rules/tests/test-view-and-presenter-isolation.md +32 -0
  20. package/.agents/rules/ui-and-widgets/ui-accessibility-and-semantic-html.md +32 -0
  21. package/.agents/rules/ui-and-widgets/ui-await-update-complete-post-render.md +30 -0
  22. package/.agents/rules/ui-and-widgets/ui-css-scoping-and-flex-layout.md +27 -0
  23. package/.agents/rules/ui-and-widgets/ui-declarative-child-widget-composition.md +29 -0
  24. package/.agents/rules/ui-and-widgets/ui-lit-declarative-templates-and-directives.md +33 -0
  25. package/.agents/rules/ui-and-widgets/ui-localization-and-uistrings-hygiene.md +36 -0
  26. package/.agents/rules/ui-and-widgets/ui-modern-component-and-encapsulation-standards.md +32 -0
  27. package/.agents/rules/ui-and-widgets/ui-panel-and-meta-registration.md +35 -0
  28. package/.agents/rules/ui-and-widgets/ui-performance-and-flamechart-rendering.md +34 -0
  29. package/.agents/rules/ui-and-widgets/ui-pure-view-and-presenter-separation.md +31 -0
  30. package/.agents/rules/ui-and-widgets/ui-reactive-widget-update-lifecycle.md +34 -0
  31. package/.agents/rules/ui-and-widgets/ui-security-and-output-sanitization.md +28 -0
  32. package/.agents/rules/ui-and-widgets/ui-type-safety-and-exhaustiveness.md +37 -0
  33. package/.agents/rules/ui-and-widgets/ui-view-output-and-callback-contracts.md +35 -0
  34. package/.agents/rules/ui-and-widgets/ui-visual-logging-instrumentation.md +29 -0
  35. package/.agents/rules/ui-and-widgets/ui-weak-dom-references-and-observer-cleanup.md +29 -0
  36. package/.agents/rules/ui-and-widgets/ui-widget-dom-and-listener-lifecycle.md +38 -0
  37. package/.agents/skills/code-review/SKILL.md +3 -0
  38. package/.agents/skills/devtools-testing-guidance/SKILL.md +1 -0
  39. package/.agents/skills/review-models-core/SKILL.md +73 -0
  40. package/.agents/skills/review-tests/SKILL.md +67 -0
  41. package/.agents/skills/review-ui-widgets/SKILL.md +115 -0
  42. package/.agents/skills/ui-eng-vision-local-lit-renderer/SKILL.md +19 -3
  43. package/.agents/skills/ui-eng-vision-widget-promoter/SKILL.md +2 -1
  44. package/.agents/skills/ui-widgets/SKILL.md +3 -1
  45. package/AUTHORS +3 -0
  46. package/DIR_METADATA +51 -1
  47. package/eslint.config.mjs +63 -21
  48. package/front_end/core/platform/api/HostRuntime.ts +1 -0
  49. package/front_end/core/platform/browser/HostRuntime.ts +10 -0
  50. package/front_end/core/platform/node/HostRuntime.ts +1 -0
  51. package/front_end/core/sdk/CSSMatchedStyles.ts +60 -20
  52. package/front_end/core/sdk/CSSProperty.ts +2 -2
  53. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +28 -9
  54. package/front_end/core/sdk/NetworkManager.ts +9 -3
  55. package/front_end/core/sdk/OverlayModel.ts +2 -8
  56. package/front_end/core/sdk/PrivateVerificationTokensModel.ts +79 -0
  57. package/front_end/core/sdk/SecurityOrigin.ts +1 -1
  58. package/front_end/core/sdk/SourceMapCache.ts +20 -15
  59. package/front_end/core/sdk/SourceMapManager.ts +28 -9
  60. package/front_end/core/sdk/TargetManager.ts +7 -4
  61. package/front_end/core/sdk/WebAuthnModel.ts +11 -2
  62. package/front_end/core/sdk/sdk.ts +2 -0
  63. package/front_end/entrypoints/inspector_main/InspectorMain.ts +0 -2
  64. package/front_end/entrypoints/inspector_main/inspector_main-meta.ts +10 -0
  65. package/front_end/entrypoints/main/GlobalAiButton.ts +1 -1
  66. package/front_end/entrypoints/main/MainImpl.ts +5 -2
  67. package/front_end/foundation/Universe.ts +1 -1
  68. package/front_end/generated/Deprecation.ts +4 -0
  69. package/front_end/generated/InspectorBackendCommands.ts +3 -3
  70. package/front_end/generated/SupportedCSSProperties.ts +89 -17
  71. package/front_end/generated/protocol-mapping.d.ts +1 -0
  72. package/front_end/generated/protocol-proxy-api.d.ts +1 -0
  73. package/front_end/generated/protocol.ts +5 -3
  74. package/front_end/models/{ai_assistance → ai-utils}/AiHistoryStorage.ts +6 -5
  75. package/front_end/models/{ai_assistance → ai-utils}/AiUtils.ts +9 -0
  76. package/front_end/models/{ai_assistance → ai-utils}/BuiltInAi.ts +1 -1
  77. package/front_end/models/ai-utils/ai-utils.ts +17 -0
  78. package/front_end/models/ai_assistance/AiAgent2.ts +3 -1
  79. package/front_end/models/ai_assistance/AiConversation.ts +34 -22
  80. package/front_end/models/ai_assistance/AlwaysAllowedTools.ts +107 -0
  81. package/front_end/models/ai_assistance/ConversationSummary.ts +2 -1
  82. package/front_end/models/ai_assistance/PerformanceAnnotations.ts +3 -1
  83. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +3 -1
  84. package/front_end/models/ai_assistance/agents/AiAgent.ts +15 -7
  85. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +3 -1
  86. package/front_end/models/ai_assistance/agents/ExecuteJavascript.ts +3 -1
  87. package/front_end/models/ai_assistance/agents/PerformanceAgent.snapshot.txt +1 -1
  88. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +3 -1
  89. package/front_end/models/ai_assistance/ai_assistance.ts +9 -10
  90. package/front_end/models/ai_assistance/data_formatters/FileFormatter.ts +27 -6
  91. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +3 -3
  92. package/front_end/models/ai_assistance/skills/sources.md +3 -1
  93. package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +1 -0
  94. package/front_end/models/ai_assistance/tools/GetCookieValues.ts +1 -0
  95. package/front_end/models/ai_assistance/tools/GetInsightDetails.ts +3 -1
  96. package/front_end/models/ai_assistance/tools/GetSourceContent.ts +46 -4
  97. package/front_end/models/ai_assistance/tools/GetStorageValues.ts +1 -0
  98. package/front_end/models/ai_assistance/tools/Tool.ts +6 -0
  99. package/front_end/models/breakpoints/BreakpointManager.ts +0 -4
  100. package/front_end/models/change_tracker/ChangeTracker.ts +2 -0
  101. package/front_end/models/comment_manager/CommentManager.ts +12 -0
  102. package/front_end/models/comment_manager/CommentThread.ts +21 -1
  103. package/front_end/models/elements/ChangeTrackingUtils.ts +37 -0
  104. package/front_end/models/elements/DOMChanges.ts +24 -36
  105. package/front_end/models/elements/StyleChanges.ts +97 -0
  106. package/front_end/models/elements/elements.ts +4 -0
  107. package/front_end/models/emulation/DeviceModeModel.ts +19 -0
  108. package/front_end/models/javascript_metadata/NativeFunctions.ts +11 -1
  109. package/front_end/models/trace/EventsSerializer.ts +35 -2
  110. package/front_end/models/trace/handlers/LayoutShiftsHandler.ts +17 -21
  111. package/front_end/models/trace/helpers/SyntheticEvents.ts +4 -2
  112. package/front_end/models/trace/lantern/core/NetworkAnalyzer.ts +12 -8
  113. package/front_end/models/trace/types/File.ts +20 -3
  114. package/front_end/models/trace/types/TraceEvents.ts +8 -3
  115. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +14 -0
  116. package/front_end/panels/ai_assistance/README.md +1 -1
  117. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +1 -1
  118. package/front_end/panels/ai_assistance/ai_assistance.ts +2 -0
  119. package/front_end/panels/ai_assistance/components/ChatInput.ts +5 -43
  120. package/front_end/panels/ai_assistance/components/ChatMessage.ts +52 -147
  121. package/front_end/panels/ai_assistance/components/ChatView.ts +28 -3
  122. package/front_end/panels/ai_assistance/components/PermissionPrompt.ts +151 -0
  123. package/front_end/panels/ai_assistance/components/RelevantDataDisclaimer.ts +73 -0
  124. package/front_end/panels/ai_assistance/components/chatInput.css +0 -59
  125. package/front_end/panels/ai_assistance/components/chatMessage.css +0 -47
  126. package/front_end/panels/ai_assistance/components/chatView.css +5 -30
  127. package/front_end/panels/ai_assistance/components/permissionPrompt.css +55 -0
  128. package/front_end/panels/ai_assistance/components/relevantDataDisclaimer.css +35 -0
  129. package/front_end/panels/application/ApplicationPanelSidebar.ts +3 -7
  130. package/front_end/panels/application/BackgroundServiceView.ts +8 -8
  131. package/front_end/panels/application/IndexedDBViews.ts +102 -73
  132. package/front_end/panels/application/OpenedWindowDetailsView.ts +167 -130
  133. package/front_end/panels/application/ServiceWorkerCacheViews.ts +288 -346
  134. package/front_end/panels/application/StorageBucketsTreeElement.ts +22 -27
  135. package/front_end/panels/application/StorageItemsToolbar.ts +2 -2
  136. package/front_end/panels/application/components/StorageMetadataView.ts +207 -160
  137. package/front_end/panels/application/openedWindowDetailsView.css +7 -30
  138. package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +1 -1
  139. package/front_end/panels/changes/changesView.css +0 -6
  140. package/front_end/panels/console/ConsoleInsightTeaser.ts +5 -1
  141. package/front_end/panels/console/ConsolePinPane.ts +1 -1
  142. package/front_end/panels/console/ConsoleView.ts +1 -0
  143. package/front_end/panels/elements/CSSValueTraceView.ts +5 -5
  144. package/front_end/panels/elements/ColorSwatchPopoverIcon.ts +14 -6
  145. package/front_end/panels/elements/ComputedStyleWidget.ts +14 -5
  146. package/front_end/panels/elements/DOMTreeElementWidget.ts +2 -2
  147. package/front_end/panels/elements/DOMTreeWidget.ts +7 -3
  148. package/front_end/panels/elements/EventListenersWidget.ts +1 -1
  149. package/front_end/panels/elements/LayersWidget.ts +1 -1
  150. package/front_end/panels/elements/PropertyRenderer.ts +91 -16
  151. package/front_end/panels/elements/StandaloneStylesContainer.ts +33 -6
  152. package/front_end/panels/elements/StylePropertiesSection.ts +1 -0
  153. package/front_end/panels/elements/StylePropertyTreeElement.ts +211 -121
  154. package/front_end/panels/elements/StylesContainer.ts +2 -0
  155. package/front_end/panels/elements/StylesSidebarPane.ts +34 -16
  156. package/front_end/panels/elements/components/QueryContainer.ts +1 -1
  157. package/front_end/panels/elements/elementStatePaneWidget.css +1 -1
  158. package/front_end/panels/elements/stylePropertiesTreeOutline.css +1 -1
  159. package/front_end/panels/elements/stylesSidebarPane.css +4 -0
  160. package/front_end/panels/emulation/DeviceModeToolbar.ts +57 -25
  161. package/front_end/panels/emulation/DeviceModeView.ts +27 -1
  162. package/front_end/panels/emulation/InspectedPagePlaceholder.ts +6 -0
  163. package/front_end/panels/emulation/MediaQueryInspector.ts +14 -4
  164. package/front_end/panels/explain/components/ConsoleInsight.ts +2 -3
  165. package/front_end/panels/explain/explain-meta.ts +1 -1
  166. package/front_end/panels/issues/AffectedMetadataAllowedSitesView.ts +67 -34
  167. package/front_end/panels/issues/issues.ts +2 -0
  168. package/front_end/panels/layer_viewer/LayerTreeOutline.ts +7 -3
  169. package/front_end/panels/lighthouse/LighthouseController.ts +1 -1
  170. package/front_end/panels/media/PlayerMessagesView.ts +1 -1
  171. package/front_end/panels/mobile_throttling/CPUThrottlingSelector.ts +1 -1
  172. package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +45 -15
  173. package/front_end/panels/mobile_throttling/ThrottlingManager.ts +3 -3
  174. package/front_end/panels/network/BinaryResourceView.ts +54 -50
  175. package/front_end/panels/network/RequestHeadersView.ts +6 -2
  176. package/front_end/panels/network/RequestPreviewView.ts +28 -5
  177. package/front_end/panels/network/ResourceWebSocketFrameView.ts +1 -0
  178. package/front_end/panels/network/components/EditableSpan.ts +11 -30
  179. package/front_end/panels/network/components/HeaderSectionRow.ts +2 -2
  180. package/front_end/panels/performance_monitor/PerformanceMonitor.ts +10 -6
  181. package/front_end/panels/profiler/HeapDetachedElementsView.ts +112 -22
  182. package/front_end/panels/profiler/HeapProfileView.ts +3 -3
  183. package/front_end/panels/profiler/HeapSnapshotView.ts +12 -2
  184. package/front_end/panels/profiler/HeapTimelineOverview.ts +16 -2
  185. package/front_end/panels/profiler/profiler.ts +0 -2
  186. package/front_end/panels/protocol_monitor/JSONEditor.ts +1 -1
  187. package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +1 -1
  188. package/front_end/panels/recorder/CreateRecordingView.ts +1 -1
  189. package/front_end/panels/recorder/RecordingView.ts +3 -3
  190. package/front_end/panels/recorder/ReplaySection.ts +1 -1
  191. package/front_end/panels/screencast/ScreencastApp.ts +83 -57
  192. package/front_end/panels/screencast/screencastView.css +1 -1
  193. package/front_end/panels/settings/AISettingsTab.ts +107 -4
  194. package/front_end/panels/settings/aiSettingsTab.css +53 -0
  195. package/front_end/panels/settings/settings-meta.ts +1 -1
  196. package/front_end/panels/settings/settingsScreen.css +0 -4
  197. package/front_end/panels/sources/BreakpointsView.ts +2 -2
  198. package/front_end/panels/sources/DebuggerPlugin.ts +7 -0
  199. package/front_end/panels/sources/NavigatorView.ts +61 -18
  200. package/front_end/panels/sources/SourcesNavigator.ts +22 -7
  201. package/front_end/panels/sources/SourcesPanel.ts +1 -0
  202. package/front_end/panels/timeline/README.md +12 -0
  203. package/front_end/panels/timeline/StatusDialog.ts +1 -1
  204. package/front_end/panels/timeline/ThirdPartyTreeView.ts +1 -3
  205. package/front_end/panels/timeline/TimelineCommentController.ts +346 -0
  206. package/front_end/panels/timeline/TimelineDetailsView.ts +24 -1
  207. package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +34 -30
  208. package/front_end/panels/timeline/TimelineFlameChartView.ts +22 -1
  209. package/front_end/panels/timeline/TimelinePanel.ts +12 -5
  210. package/front_end/panels/timeline/TimelineTreeView.ts +28 -6
  211. package/front_end/panels/timeline/components/LiveMetricsView.ts +1 -1
  212. package/front_end/panels/timeline/components/fieldSettingsDialog.css +2 -2
  213. package/front_end/panels/timeline/components/insights/baseInsightComponent.css +1 -1
  214. package/front_end/panels/timeline/overlays/components/entriesLinkOverlay.css +2 -2
  215. package/front_end/panels/timeline/overlays/components/entryLabelOverlay.css +9 -9
  216. package/front_end/panels/timeline/timeline-meta.ts +2 -2
  217. package/front_end/panels/timeline/timeline.ts +4 -0
  218. package/front_end/panels/timeline/timelineFlamechartPopover.css +2 -2
  219. package/front_end/panels/timeline/timelinePanel.css +2 -2
  220. package/front_end/panels/web_audio/WebAudioView.ts +7 -4
  221. package/front_end/third_party/chromium/README.chromium +1 -1
  222. package/front_end/third_party/codemirror.next/chunk/angular.js +1 -1
  223. package/front_end/third_party/codemirror.next/chunk/angular.js.map +1 -1
  224. package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
  225. package/front_end/third_party/codemirror.next/chunk/codemirror.js.map +1 -1
  226. package/front_end/third_party/codemirror.next/chunk/cpp.js +1 -1
  227. package/front_end/third_party/codemirror.next/chunk/cpp.js.map +1 -1
  228. package/front_end/third_party/codemirror.next/chunk/java.js +1 -1
  229. package/front_end/third_party/codemirror.next/chunk/java.js.map +1 -1
  230. package/front_end/third_party/codemirror.next/chunk/less.js +1 -1
  231. package/front_end/third_party/codemirror.next/chunk/less.js.map +1 -1
  232. package/front_end/third_party/codemirror.next/chunk/markdown.js +1 -1
  233. package/front_end/third_party/codemirror.next/chunk/markdown.js.map +1 -1
  234. package/front_end/third_party/codemirror.next/chunk/php.js +1 -1
  235. package/front_end/third_party/codemirror.next/chunk/php.js.map +1 -1
  236. package/front_end/third_party/codemirror.next/chunk/python.js +1 -1
  237. package/front_end/third_party/codemirror.next/chunk/python.js.map +1 -1
  238. package/front_end/third_party/codemirror.next/chunk/sass.js +1 -1
  239. package/front_end/third_party/codemirror.next/chunk/sass.js.map +1 -1
  240. package/front_end/third_party/codemirror.next/chunk/svelte.js +1 -1
  241. package/front_end/third_party/codemirror.next/chunk/svelte.js.map +1 -1
  242. package/front_end/third_party/codemirror.next/chunk/vue.js +1 -1
  243. package/front_end/third_party/codemirror.next/chunk/vue.js.map +1 -1
  244. package/front_end/third_party/codemirror.next/chunk/wast.js +1 -1
  245. package/front_end/third_party/codemirror.next/chunk/wast.js.map +1 -1
  246. package/front_end/third_party/codemirror.next/chunk/xml.js +1 -1
  247. package/front_end/third_party/codemirror.next/chunk/xml.js.map +1 -1
  248. package/front_end/third_party/codemirror.next/codemirror.next.js +1 -1
  249. package/front_end/third_party/codemirror.next/rollup.config.mjs +1 -1
  250. package/front_end/tsconfig.json +1 -1
  251. package/front_end/ui/comments/CommentAnchorResolver.ts +1 -1
  252. package/front_end/ui/components/buttons/Button.ts +29 -18
  253. package/front_end/ui/components/code_highlighter/CodeHighlighter.ts +1 -1
  254. package/front_end/ui/components/dialogs/TypeToAllowDialog.ts +94 -39
  255. package/front_end/ui/components/dialogs/dialog.css +1 -1
  256. package/front_end/ui/components/menus/menuItem.css +11 -0
  257. package/front_end/ui/components/text_editor/AccessiblePlaceholder.ts +1 -1
  258. package/front_end/ui/components/text_editor/AiCodeCompletionTeaser.ts +1 -1
  259. package/front_end/ui/components/text_editor/config.ts +2 -1
  260. package/front_end/ui/components/text_editor/javascript.ts +2 -1
  261. package/front_end/ui/legacy/InspectorView.ts +4 -2
  262. package/front_end/ui/legacy/SplitWidget.ts +14 -16
  263. package/front_end/ui/legacy/TabbedPane.ts +9 -1
  264. package/front_end/ui/legacy/UIUtils.ts +60 -40
  265. package/front_end/ui/legacy/components/color_picker/spectrum.css +2 -2
  266. package/front_end/ui/legacy/components/data_grid/dataGrid.css +9 -0
  267. package/front_end/ui/legacy/components/inline_editor/CSSAngle.ts +0 -1
  268. package/front_end/ui/legacy/components/inline_editor/cssShadowEditor.css +5 -7
  269. package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +1 -1
  270. package/front_end/ui/legacy/components/perf_ui/PieChart.ts +11 -0
  271. package/front_end/ui/legacy/components/perf_ui/chartViewport.css +4 -4
  272. package/front_end/ui/legacy/components/quick_open/filteredListWidget.css +6 -0
  273. package/front_end/ui/legacy/components/settings_ui/SettingsUI.ts +1 -1
  274. package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +38 -13
  275. package/front_end/ui/legacy/dropTarget.css +1 -1
  276. package/front_end/ui/legacy/statusBar.css +7 -0
  277. package/front_end/ui/legacy/tabbedPane.css +0 -7
  278. package/front_end/ui/visual_logging/KnownContextValues.ts +13 -0
  279. package/inspector_overlay/main.ts +2 -15
  280. package/inspector_overlay/tool_persistent.ts +0 -14
  281. package/mcp/mcp.ts +3 -0
  282. package/package.json +1 -1
  283. package/front_end/panels/ai_assistance/components/StylingAgentMarkdownRenderer.ts +0 -178
  284. package/front_end/panels/profiler/HeapDetachedElementsDataGrid.ts +0 -147
  285. package/front_end/panels/profiler/heapDetachedElementsDataGrid.css +0 -14
  286. package/front_end/ui/components/legacy_wrapper/LegacyWrapper.ts +0 -62
  287. package/front_end/ui/components/legacy_wrapper/legacy_wrapper.ts +0 -8
  288. package/inspector_overlay/tool_green_dev_anchors.css +0 -54
  289. package/inspector_overlay/tool_green_dev_anchors.ts +0 -164
  290. /package/front_end/models/{ai_assistance → ai-utils}/AiSetting.ts +0 -0
  291. /package/front_end/models/{ai_assistance → ai-utils}/debug.ts +0 -0
@@ -362,26 +362,23 @@ async function buildLayoutShiftsClusters(): Promise<void> {
362
362
  navigationId = Types.Events.NO_NAVIGATION;
363
363
  }
364
364
 
365
- clusters.push(Helpers.SyntheticEvents.SyntheticEventsManager
366
- .registerSyntheticEvent<Types.Events.SyntheticLayoutShiftCluster>({
367
- name: 'SyntheticLayoutShiftCluster',
368
- // Will be replaced by the worst layout shift in the next for loop.
369
- rawSourceEvent: event,
370
- events: [],
371
- clusterWindow: traceWindowFromTime(clusterStartTime),
372
- clusterCumulativeScore: 0,
373
- scoreWindows: {
374
- good: traceWindowFromTime(clusterStartTime),
375
- },
376
- navigationId,
377
- // Set default Event so that this event is treated accordingly for the track appender.
378
- ts: event.ts,
379
- pid: event.pid,
380
- tid: event.tid,
381
- ph: Types.Events.Phase.COMPLETE,
382
- cat: '',
383
- dur: Types.Timing.Micro(-1), // This `cluster.dur` is updated below.
384
- }));
365
+ clusters.push({
366
+ name: 'SyntheticLayoutShiftCluster',
367
+ events: [],
368
+ clusterWindow: traceWindowFromTime(clusterStartTime),
369
+ clusterCumulativeScore: 0,
370
+ scoreWindows: {
371
+ good: traceWindowFromTime(clusterStartTime),
372
+ },
373
+ navigationId,
374
+ // Set default Event so that this event is treated accordingly for the track appender.
375
+ ts: event.ts,
376
+ pid: event.pid,
377
+ tid: event.tid,
378
+ ph: Types.Events.Phase.COMPLETE,
379
+ cat: '',
380
+ dur: Types.Timing.Micro(-1), // This `cluster.dur` is updated below.
381
+ });
385
382
 
386
383
  firstShiftTime = clusterStartTime;
387
384
  }
@@ -510,7 +507,6 @@ async function buildLayoutShiftsClusters(): Promise<void> {
510
507
  // Update the cluster's worst layout shift.
511
508
  if (worstShiftEvent) {
512
509
  cluster.worstShiftEvent = worstShiftEvent;
513
- cluster.rawSourceEvent = worstShiftEvent.rawSourceEvent;
514
510
  }
515
511
 
516
512
  // layout shifts are already sorted by time ascending.
@@ -8,8 +8,10 @@ let activeManager: SyntheticEventsManager|null = null;
8
8
 
9
9
  export class SyntheticEventsManager {
10
10
  /**
11
- * All synthetic entries created in a trace from a corresponding trace events.
12
- * (ProfileCalls are excluded because they are not based on a real trace event)
11
+ * All synthetic entries created in a trace from
12
+ * corresponding trace events.
13
+ * (ProfileCalls and layout shift clusters are excluded
14
+ * because they are not based on a real trace event.)
13
15
  */
14
16
  #syntheticTraces: Types.Events.SyntheticBased[] = [];
15
17
  /**
@@ -589,16 +589,20 @@ class NetworkAnalyzer {
589
589
  return exactMatch;
590
590
  }
591
591
 
592
- // Cross-origin redirects in renderer trace events have their pre-redirect URL path scrubbed to the origin.
593
- try {
594
- const originUrl = `${new URL(resourceUrl).origin}/`;
595
- return records.find(
596
- request => Boolean(request.redirectDestination) && originUrl.startsWith(request.url) &&
597
- UrlUtils.equalWithExcludedFragments(request.url, originUrl),
598
- );
599
- } catch {
592
+ // Cross-origin document redirects in renderer trace events have their pre-redirect URL scrubbed to the origin.
593
+ const origin = URL.parse(resourceUrl)?.origin;
594
+ if (!origin) {
600
595
  return undefined;
601
596
  }
597
+
598
+ return records.find(request => {
599
+ if (!request.redirectDestination || request.url !== `${origin}/`) {
600
+ return false;
601
+ }
602
+ const finalRequest = NetworkAnalyzer.resolveRedirects(request);
603
+ return finalRequest.resourceType === 'Document' && !finalRequest.failed &&
604
+ URL.parse(finalRequest.url)?.origin !== origin;
605
+ });
602
606
  }
603
607
 
604
608
  static findLastDocumentForUrl<T extends Lantern.NetworkRequest>(records: T[], resourceUrl: string): T|undefined {
@@ -48,6 +48,7 @@ export enum EventKeyType {
48
48
  SYNTHETIC_EVENT = 's',
49
49
  PROFILE_CALL = 'p',
50
50
  LEGACY_TIMELINE_FRAME = 'l',
51
+ LAYOUT_SHIFT_CLUSTER = 'c',
51
52
  }
52
53
 
53
54
  /**
@@ -141,7 +142,8 @@ export type RawEventKey = `${EventKeyType.RAW_EVENT}-${number}`;
141
142
  export type SyntheticEventKey = `${EventKeyType.SYNTHETIC_EVENT}-${number}`;
142
143
  export type ProfileCallKey = `${EventKeyType.PROFILE_CALL}-${ProcessID}-${ThreadID}-${SampleIndex}-${Protocol.integer}`;
143
144
  export type LegacyTimelineFrameKey = `${EventKeyType.LEGACY_TIMELINE_FRAME}-${number}`;
144
- export type SerializableKey = RawEventKey|ProfileCallKey|SyntheticEventKey|LegacyTimelineFrameKey;
145
+ export type LayoutShiftClusterKey = `${EventKeyType.LAYOUT_SHIFT_CLUSTER}-${number}`;
146
+ export type SerializableKey = RawEventKey|ProfileCallKey|SyntheticEventKey|LegacyTimelineFrameKey|LayoutShiftClusterKey;
145
147
 
146
148
  /** Serializable keys values objects contain data that maps the keys to original Trace Events **/
147
149
  export interface RawEventKeyValues {
@@ -167,8 +169,14 @@ export interface LegacyTimelineFrameKeyValues {
167
169
  rawIndex: number;
168
170
  }
169
171
 
170
- export type SerializableKeyValues =
171
- RawEventKeyValues|ProfileCallKeyValues|SyntheticEventKeyValues|LegacyTimelineFrameKeyValues;
172
+ export interface LayoutShiftClusterKeyValues {
173
+ type: EventKeyType.LAYOUT_SHIFT_CLUSTER;
174
+ // The raw event index of the first layout shift in the cluster.
175
+ rawIndex: number;
176
+ }
177
+
178
+ export type SerializableKeyValues = RawEventKeyValues|ProfileCallKeyValues|SyntheticEventKeyValues|
179
+ LegacyTimelineFrameKeyValues|LayoutShiftClusterKeyValues;
172
180
 
173
181
  export interface Modifications {
174
182
  entriesModifications: {
@@ -291,6 +299,15 @@ export function traceEventKeyToValues(key: SerializableKey): SerializableKeyValu
291
299
  rawIndex: parseInt(parts[1], 10),
292
300
  };
293
301
  }
302
+ case EventKeyType.LAYOUT_SHIFT_CLUSTER: {
303
+ if (parts.length !== 2 || Number.isNaN(parseInt(parts[1], 10))) {
304
+ throw new Error(`Invalid LayoutShiftCluster Key: ${key}`);
305
+ }
306
+ return {
307
+ type,
308
+ rawIndex: parseInt(parts[1], 10),
309
+ };
310
+ }
294
311
 
295
312
  default:
296
313
  throw new Error(`Unknown trace event key: ${key}`);
@@ -1080,10 +1080,15 @@ export const NO_NAVIGATION = 'NO_NAVIGATION';
1080
1080
  export type NavigationId = string;
1081
1081
 
1082
1082
  /**
1083
- * This is a synthetic Layout shift cluster. The rawSourceEvent is the worst layout shift event
1084
- * in the cluster.
1083
+ * This is a synthetic Layout shift cluster: a session window of layout shifts.
1084
+ *
1085
+ * Do not extend the SyntheticBased interface because a cluster is built from
1086
+ * many layout shifts and doesn't have a raw trace event of its own. For the
1087
+ * same reason, clusters are not registered with SyntheticEventsManager. Use
1088
+ * `worstShiftEvent` to find the layout shift with the highest score in the
1089
+ * cluster.
1085
1090
  */
1086
- export interface SyntheticLayoutShiftCluster extends SyntheticBased<Phase.COMPLETE> {
1091
+ export interface SyntheticLayoutShiftCluster extends Event {
1087
1092
  name: 'SyntheticLayoutShiftCluster';
1088
1093
  clusterWindow: TraceWindowMicro;
1089
1094
  clusterCumulativeScore: number;
@@ -62,6 +62,10 @@ const AI_ASSISTANCE_HELP =
62
62
  'https://developer.chrome.com/docs/devtools/ai-assistance' as Platform.DevToolsPath.UrlString;
63
63
  const WALKTHROUGH_SIDEBAR_BREAKPOINT = 700;
64
64
  const WALKTHROUGH_SIDEBAR_INITIAL_WIDTH = 400;
65
+ // Ignores approvals that arrive within this window after a permission prompt appears, so input meant for something
66
+ // else (such as the second click of a double-click on the previous prompt) cannot approve it. The value matches the
67
+ // 500 ms double-click interval that Chromium's InputEventActivationProtector uses for dialog buttons.
68
+ const PERMISSION_PROMPT_INPUT_PROTECTION_MS = 500;
65
69
 
66
70
  const UIStrings = {
67
71
  /**
@@ -594,6 +598,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
594
598
  #serverSideLoggingEnabled = isAiAssistanceServerSideLoggingEnabled();
595
599
  #aiAssistanceEnabledSetting: AiAssistanceModel.AiSetting.AiSetting<boolean>;
596
600
  #changeManager = new AiAssistanceModel.ChangeManager.ChangeManager();
601
+ #alwaysAllowedTools =
602
+ new AiAssistanceModel.AlwaysAllowedTools.AlwaysAllowedTools(Common.Settings.Settings.instance());
597
603
  #mutex = new Common.Mutex.Mutex();
598
604
 
599
605
  #conversation?: AiAssistanceModel.AiConversation.AiConversation;
@@ -982,6 +988,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
982
988
  isReadOnly: false,
983
989
  aidaClient: this.#aidaClient,
984
990
  changeManager: this.#changeManager,
991
+ alwaysAllowedTools: this.#alwaysAllowedTools,
985
992
  performanceRecordAndReload: this.#handlePerformanceRecordAndReload.bind(this),
986
993
  onInspectElement: this.#handleInspectElement.bind(this),
987
994
  networkTimeCalculator: NetworkPanel.NetworkPanel.NetworkPanel.instance().networkLogView.timeCalculator(),
@@ -1012,6 +1019,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1012
1019
  isReadOnly: false,
1013
1020
  aidaClient: this.#aidaClient,
1014
1021
  changeManager: this.#changeManager,
1022
+ alwaysAllowedTools: this.#alwaysAllowedTools,
1015
1023
  performanceRecordAndReload: this.#handlePerformanceRecordAndReload.bind(this),
1016
1024
  onInspectElement: this.#handleInspectElement.bind(this),
1017
1025
  networkTimeCalculator: NetworkPanel.NetworkPanel.NetworkPanel.instance().networkLogView.timeCalculator(),
@@ -1519,6 +1527,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1519
1527
  isReadOnly: false,
1520
1528
  aidaClient: this.#aidaClient,
1521
1529
  changeManager: this.#changeManager,
1530
+ alwaysAllowedTools: this.#alwaysAllowedTools,
1522
1531
  performanceRecordAndReload: this.#handlePerformanceRecordAndReload.bind(this),
1523
1532
  onInspectElement: this.#handleInspectElement.bind(this),
1524
1533
  networkTimeCalculator: NetworkPanel.NetworkPanel.NetworkPanel.instance().networkLogView.timeCalculator(),
@@ -1914,6 +1923,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1914
1923
  step = stepForCall(data.callId);
1915
1924
  const approvalStep = step;
1916
1925
  approvalStep.code ??= data.code;
1926
+ const promptShownAt = performance.now();
1917
1927
  approvalStep.state = {
1918
1928
  type: 'needs_approval',
1919
1929
  sideEffectDialog: {
@@ -1921,6 +1931,10 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1921
1931
  permissionPrompt: data.permissionPrompt,
1922
1932
  permissionTitle: data.permissionTitle,
1923
1933
  onAnswer: (decision: AiAssistanceModel.Tool.PermissionDecision) => {
1934
+ if (decision !== AiAssistanceModel.Tool.PermissionDecision.REJECT &&
1935
+ performance.now() - promptShownAt < PERMISSION_PROMPT_INPUT_PROTECTION_MS) {
1936
+ return;
1937
+ }
1924
1938
  data.confirm(decision);
1925
1939
  approvalStep.state = {type: 'completed'};
1926
1940
  this.requestUpdate();
@@ -117,7 +117,7 @@ Each `Step` has a `state` (`StepState` in `components/ChatMessage.ts`):
117
117
  | State | Set when | Badge |
118
118
  | :--- | :--- | :--- |
119
119
  | `in_progress` | `QUERYING` creates the step. | A spinner if the step is the last step. Otherwise, a checkmark. |
120
- | `needs_approval` | A `SIDE_EFFECT` event asks the user to approve a tool call. The state holds the approval dialog. | A pause icon, with the approval prompt in the step. Only the last step can be in this state. |
120
+ | `needs_approval` | A `SIDE_EFFECT` event asks the user to approve a tool call. The state holds the approval dialog. The panel ignores allow decisions that arrive within 500 ms of the prompt appearing; rejections always go through. | A pause icon, with the approval prompt in the step. Only the last step can be in this state. |
121
121
  | `canceled` | An `ACTION` with `canceled: true` arrives because the user denied the tool call, or the user aborts the run while this is the last step. | A cross. |
122
122
  | `completed` | A `CONTEXT`, `THOUGHT`, `ACTION`, `CONTEXT_CHANGE` or `ANSWER` event arrives, or the user answers the approval prompt. | A checkmark. |
123
123
 
@@ -5,7 +5,7 @@
5
5
  import * as Common from '../../core/common/common.js';
6
6
  import * as i18n from '../../core/i18n/i18n.js';
7
7
  import * as Root from '../../core/root/root.js';
8
- import * as AiAssistanceModel from '../../models/ai_assistance/ai_assistance.js';
8
+ import * as AiAssistanceModel from '../../models/ai-utils/ai-utils.js';
9
9
  import * as UI from '../../ui/legacy/legacy.js';
10
10
  import * as SettingUIRegistration from '../../ui/settings/settings.js';
11
11
 
@@ -12,6 +12,8 @@ export * as ChatMessage from './components/ChatMessage.js';
12
12
  export * as ExploreWidget from './components/ExploreWidget.js';
13
13
  export * as ExportForAgentsDialog from './components/ExportForAgentsDialog.js';
14
14
  export * as OptInChangeDialog from './components/OptInChangeDialog.js';
15
+ export * as PermissionPrompt from './components/PermissionPrompt.js';
16
+ export * as RelevantDataDisclaimer from './components/RelevantDataDisclaimer.js';
15
17
  export * as DisabledWidget from './components/DisabledWidget.js';
16
18
  export * as WalkthroughUtils from './components/WalkthroughUtils.js';
17
19
  export * as WalkthroughView from './components/WalkthroughView.js';
@@ -2,8 +2,6 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
 
5
- import '../../../ui/components/tooltips/tooltips.js';
6
-
7
5
  import type * as Host from '../../../core/host/host.js';
8
6
  import * as i18n from '../../../core/i18n/i18n.js';
9
7
  import type * as Platform from '../../../core/platform/platform.js';
@@ -21,6 +19,7 @@ import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
21
19
 
22
20
  import chatInputStyles from './chatInput.css.js';
23
21
  import * as ImageResize from './ImageResize.js';
22
+ import {renderRelevantDataDisclaimer} from './RelevantDataDisclaimer.js';
24
23
 
25
24
  const {html, Directives: {createRef, ref}} = Lit;
26
25
  const {widget} = UI.Widget;
@@ -34,10 +33,6 @@ const UIStrings = {
34
33
  * @description Label added to the button that reveals the selected context item in DevTools.
35
34
  */
36
35
  revealContextDescription: 'Reveal the selected context item in DevTools',
37
- /**
38
- * @description The footer disclaimer that links to more information about the AI feature.
39
- */
40
- learnAbout: 'Learn about AI in DevTools',
41
36
  } as const;
42
37
 
43
38
  /*
@@ -207,45 +202,12 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTML
207
202
  disabled: input.isTextInputDisabled,
208
203
  });
209
204
 
210
- const renderRelevantDataDisclaimer = (tooltipId: string): Lit.LitTemplate => {
205
+ const renderDisclaimer = (tooltipId: string): Lit.LitTemplate => {
211
206
  const classes = Lit.Directives.classMap({
212
207
  'chat-input-disclaimer': true,
213
208
  'hide-divider': !input.isLoading && input.blockedByCrossOrigin,
214
209
  });
215
- // clang-format off
216
- return html`
217
- <div class=${classes}>
218
- <button
219
- class="link"
220
- role="link"
221
- aria-details=${tooltipId}
222
- jslog=${VisualLogging.link('open-ai-settings').track({
223
- click: true,
224
- })}
225
- @click=${(ev: Event) => {
226
- ev.preventDefault();
227
- void UI.ViewManager.ViewManager.instance().showView('chrome-ai');
228
- }}
229
- >${lockedString('Relevant data')}</button>&nbsp;${lockedString('is sent to Google')}
230
- <devtools-tooltip
231
- id=${tooltipId}
232
- variant="rich"
233
- ><div class="info-tooltip-container">
234
- ${input.disclaimerText}
235
- <button
236
- class="link tooltip-link"
237
- role="link"
238
- jslog=${VisualLogging.link('open-ai-settings').track({
239
- click: true,
240
- })}
241
- @click=${() => {
242
- void UI.ViewManager.ViewManager.instance().showView('chrome-ai');
243
- }}>${i18nString(UIStrings.learnAbout)}
244
- </button>
245
- </div></devtools-tooltip>
246
- </div>
247
- `;
248
- // clang-format on
210
+ return html`<div class=${classes}>${renderRelevantDataDisclaimer(tooltipId, input.disclaimerText)}</div>`;
249
211
  };
250
212
 
251
213
  // clang-format off
@@ -413,7 +375,7 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTML
413
375
  </div>
414
376
  <div class="chat-input-actions-right">
415
377
  <div class="chat-input-disclaimer-container">
416
- ${renderRelevantDataDisclaimer(RELEVANT_DATA_LINK_CHAT_ID)}
378
+ ${renderDisclaimer(RELEVANT_DATA_LINK_CHAT_ID)}
417
379
  </div>
418
380
  ${(input.multimodalInputEnabled && !input.blockedByCrossOrigin) ?
419
381
  html`
@@ -503,7 +465,7 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTML
503
465
  })}
504
466
  jslog=${VisualLogging.section('footer')}
505
467
  >
506
- ${renderRelevantDataDisclaimer(RELEVANT_DATA_LINK_FOOTER_ID)}
468
+ ${renderDisclaimer(RELEVANT_DATA_LINK_FOOTER_ID)}
507
469
  </footer>
508
470
  `, target);
509
471
  // clang-format on
@@ -47,7 +47,6 @@ const {html, Directives: {ref, ifDefined}} = Lit;
47
47
  const lockedString = i18n.i18n.lockedString;
48
48
  const {widget} = UI.Widget;
49
49
 
50
- const REPORT_URL = 'https://crbug.com/508304827' as Platform.DevToolsPath.UrlString;
51
50
  const SCROLL_ROUNDING_OFFSET = 1;
52
51
 
53
52
  /*
@@ -131,26 +130,6 @@ const UIStringsNotTranslate = {
131
130
  * @description Button text that cancels code execution that may affect the page.
132
131
  */
133
132
  declineActionRequestApproval: 'Cancel',
134
- /**
135
- * @description Button text in the permission prompt that skips the tool call.
136
- */
137
- skipToolCall: 'Skip',
138
- /**
139
- * @description Button text in the permission prompt that allows the tool call once.
140
- */
141
- allowThisTime: 'Yes, allow this time',
142
- /**
143
- * @description Button text in the permission prompt that allows the tool call now and in the future.
144
- */
145
- allowAlways: 'Yes, always allow',
146
- /**
147
- * @description Fallback title of the permission prompt when the tool has no title.
148
- */
149
- allowThisAction: 'Allow this action?',
150
- /**
151
- * @description Footer of the permission prompt.
152
- */
153
- relevantDataIsSentToGoogle: 'Relevant data is sent to Google. Change permissions in settings at any time.',
154
133
  /**
155
134
  * @description The fallback text when a step has no title yet
156
135
  */
@@ -895,105 +874,32 @@ function renderWalkthroughUI(input: ChatMessageViewInput, steps: Step[]): Lit.Li
895
874
  }
896
875
 
897
876
  function renderSideEffectStepsUI(input: ChatMessageViewInput, steps: Step[]): Lit.LitTemplate {
898
- const sideEffectSteps = steps.filter(s => s.state.type === 'needs_approval');
877
+ // With the natural language interface a step that needs approval is
878
+ // rendered by ChatView as a permission prompt in place of the chat input
879
+ // (see `renderPermissionPrompt`), so it is skipped here.
880
+ const sideEffectSteps = steps.filter(
881
+ s => (s.state.type === 'needs_approval' && !AiAssistanceModel.AiUtils.isNaturalLanguageInterfaceEnabled()));
899
882
  if (sideEffectSteps.length === 0) {
900
883
  return Lit.nothing;
901
884
  }
902
- // With the natural language interface the approval is rendered as a
903
- // dedicated permission prompt instead of the side-effect confirmation UI.
904
- const showPermissionPrompt = AiAssistanceModel.AiUtils.isNaturalLanguageInterfaceEnabled();
885
+ // Key each prompt by its step so that a new prompt always gets new DOM.
886
+ // Without the key, Lit reuses the previous prompt's buttons when one prompt
887
+ // replaces another in a single render, and keyboard focus on the previous
888
+ // approve button would carry over to the new prompt.
905
889
  // clang-format off
906
890
  return html`
907
- ${sideEffectSteps.map(step => html`
891
+ ${Lit.Directives.repeat(sideEffectSteps, step => step, step => html`
908
892
  <div class="side-effect-container">
909
- ${showPermissionPrompt ?
910
- renderPermissionPrompt(step) :
911
- renderStep({
912
- step,
913
- markdownRenderer: input.markdownRenderer,
914
- isLast: true,
915
- })}
893
+ ${renderStep({
894
+ step,
895
+ markdownRenderer: input.markdownRenderer,
896
+ isLast: true,
897
+ })}
916
898
  </div> `)}
917
899
  `;
918
900
  // clang-format on
919
901
  }
920
902
 
921
- /**
922
- * Renders the permission prompt for a step that needs approval. Used when
923
- * `AiUtils.isNaturalLanguageInterfaceEnabled()` is on; otherwise
924
- * `renderSideEffectStepsUI` falls back to `renderStep`, which shows the
925
- * legacy Allow / Deny buttons inside the `renderSideEffectConfirmationUi`.
926
- *
927
- * A separate UI is needed because the natural language interface runs tools
928
- * that need richer consent than "run this code?": a tool-specific title and
929
- * description, and an "Allow always" option (`sideEffectDialog.permissionPrompt`).
930
- * It is a standalone card rather than a collapsible step so the user sees the
931
- * question without expanding anything.
932
- *
933
- * TODO(b/516828269): Remove `renderSideEffectConfirmationUi` once the natural
934
- * language interface launches.
935
- */
936
- function renderPermissionPrompt(step: Step): Lit.LitTemplate {
937
- if (step.state.type !== 'needs_approval') {
938
- return Lit.nothing;
939
- }
940
- const dialog = step.state.sideEffectDialog;
941
- const title = dialog.permissionTitle ?? lockedString(UIStringsNotTranslate.allowThisAction);
942
-
943
- const description =
944
- dialog.description ? html`<p class="permission-prompt-description">${dialog.description}</p>` : Lit.nothing;
945
-
946
- const code = step.code ? html`<devtools-code-block
947
- class="permission-prompt-code"
948
- .code=${step.code.trim()}
949
- .codeLang=${'js'}
950
- .displayNotice=${true}
951
- .header=${lockedString(UIStringsNotTranslate.codeToExecute)}
952
- ></devtools-code-block>` :
953
- Lit.nothing;
954
-
955
- const allowAlwaysButton = dialog.permissionPrompt === AiAssistanceModel.Tool.PermissionPrompt.ALLOW_ONCE_OR_ALWAYS ?
956
- html`<devtools-button
957
- .data=${{
958
- variant: Buttons.Button.Variant.OUTLINED,
959
- jslogContext: 'always-allow-execute-code',
960
- } as Buttons.Button.ButtonData}
961
- @click=${() => dialog.onAnswer(AiAssistanceModel.Tool.PermissionDecision.ALLOW_ALWAYS)}
962
- >${lockedString(UIStringsNotTranslate.allowAlways)}</devtools-button>` :
963
- Lit.nothing;
964
-
965
- // clang-format off
966
- return html`
967
- <div class="permission-prompt"
968
- jslog=${VisualLogging.section('side-effect-confirmation')}>
969
- <div class="permission-prompt-header">
970
- <devtools-icon name="lock"></devtools-icon>
971
- <h3 class="permission-prompt-title">${title}</h3>
972
- </div>
973
- ${description}
974
- ${code}
975
- <p class="permission-prompt-footer">${lockedString(UIStringsNotTranslate.relevantDataIsSentToGoogle)}</p>
976
- <div class="permission-prompt-buttons">
977
- <devtools-button
978
- .data=${{
979
- variant: Buttons.Button.Variant.TEXT,
980
- jslogContext: 'decline-execute-code',
981
- } as Buttons.Button.ButtonData}
982
- @click=${() => dialog.onAnswer(AiAssistanceModel.Tool.PermissionDecision.REJECT)}
983
- >${lockedString(UIStringsNotTranslate.skipToolCall)}</devtools-button>
984
- ${allowAlwaysButton}
985
- <devtools-button
986
- .data=${{
987
- variant: Buttons.Button.Variant.PRIMARY,
988
- jslogContext: 'accept-execute-code',
989
- } as Buttons.Button.ButtonData}
990
- @click=${() => dialog.onAnswer(AiAssistanceModel.Tool.PermissionDecision.ALLOW_ONCE)}
991
- >${lockedString(UIStringsNotTranslate.allowThisTime)}</devtools-button>
992
- </div>
993
- </div>`;
994
- // clang-format on
995
- }
996
-
997
903
  function renderStepBadge({step, isLast}: {
998
904
  step: Step,
999
905
  isLast: boolean,
@@ -2251,44 +2157,43 @@ export class ChatMessage extends UI.Widget.Widget {
2251
2157
  override performUpdate(): Promise<void>|void {
2252
2158
  const message =
2253
2159
  this.message.entity === ChatMessageEntity.MODEL ? getDeduplicatedWidgetsMessage(this.message) : this.message;
2254
- this.#view(
2255
- {
2256
- message,
2257
- isLoading: this.isLoading,
2258
- isReadOnly: this.isReadOnly,
2259
- canShowFeedbackForm: this.canShowFeedbackForm,
2260
- markdownRenderer: this.markdownRenderer,
2261
- isLastMessage: this.isLastMessage,
2262
- isFirstMessage: this.isFirstMessage,
2263
- prompt: this.prompt,
2264
- onSuggestionClick: this.onSuggestionClick,
2265
- onRatingClick: this.#handleRateClick.bind(this),
2266
- onReportClick: () => UIHelpers.openInNewTab(REPORT_URL),
2267
- onCopyResponseClick: () => {
2268
- if (this.message.entity === ChatMessageEntity.MODEL) {
2269
- this.onCopyResponseClick(this.message);
2270
- }
2271
- },
2272
- onExportClick: this.onExportClick,
2273
- scrollSuggestionsScrollContainer: this.#scrollSuggestionsScrollContainer.bind(this),
2274
- onSuggestionsScrollOrResize: this.#handleSuggestionsScrollOrResize.bind(this),
2275
- onSubmit: this.#handleSubmit.bind(this),
2276
- onClose: this.#handleClose.bind(this),
2277
- onInputChange: this.#handleInputChange.bind(this),
2278
- isSubmitButtonDisabled: this.#isSubmitButtonDisabled,
2279
- // Props for actions logic
2280
- showActions: !(this.isLastMessage && this.isLoading),
2281
- showRateButtons: this.message.entity === ChatMessageEntity.MODEL && !!this.message.rpcId,
2282
- suggestions: (this.isLastMessage && this.message.entity === ChatMessageEntity.MODEL && !this.isReadOnly &&
2283
- this.message.parts.at(-1)?.type === 'answer') ?
2284
- (this.message.parts.at(-1) as AnswerPart).suggestions :
2285
- undefined,
2286
- currentRating: this.#currentRating,
2287
- isShowingFeedbackForm: this.#isShowingFeedbackForm,
2288
- onFeedbackSubmit: this.onFeedbackSubmit,
2289
- walkthrough: this.walkthrough,
2290
- },
2291
- this.#viewOutput, this.contentElement);
2160
+ this.#view({
2161
+ message,
2162
+ isLoading: this.isLoading,
2163
+ isReadOnly: this.isReadOnly,
2164
+ canShowFeedbackForm: this.canShowFeedbackForm,
2165
+ markdownRenderer: this.markdownRenderer,
2166
+ isLastMessage: this.isLastMessage,
2167
+ isFirstMessage: this.isFirstMessage,
2168
+ prompt: this.prompt,
2169
+ onSuggestionClick: this.onSuggestionClick,
2170
+ onRatingClick: this.#handleRateClick.bind(this),
2171
+ onReportClick: () => UIHelpers.openInNewTab(AiAssistanceModel.AiUtils.REPORT_LEGAL_ISSUE_URL),
2172
+ onCopyResponseClick: () => {
2173
+ if (this.message.entity === ChatMessageEntity.MODEL) {
2174
+ this.onCopyResponseClick(this.message);
2175
+ }
2176
+ },
2177
+ onExportClick: this.onExportClick,
2178
+ scrollSuggestionsScrollContainer: this.#scrollSuggestionsScrollContainer.bind(this),
2179
+ onSuggestionsScrollOrResize: this.#handleSuggestionsScrollOrResize.bind(this),
2180
+ onSubmit: this.#handleSubmit.bind(this),
2181
+ onClose: this.#handleClose.bind(this),
2182
+ onInputChange: this.#handleInputChange.bind(this),
2183
+ isSubmitButtonDisabled: this.#isSubmitButtonDisabled,
2184
+ // Props for actions logic
2185
+ showActions: !(this.isLastMessage && this.isLoading),
2186
+ showRateButtons: this.message.entity === ChatMessageEntity.MODEL && !!this.message.rpcId,
2187
+ suggestions: (this.isLastMessage && this.message.entity === ChatMessageEntity.MODEL && !this.isReadOnly &&
2188
+ this.message.parts.at(-1)?.type === 'answer') ?
2189
+ (this.message.parts.at(-1) as AnswerPart).suggestions :
2190
+ undefined,
2191
+ currentRating: this.#currentRating,
2192
+ isShowingFeedbackForm: this.#isShowingFeedbackForm,
2193
+ onFeedbackSubmit: this.onFeedbackSubmit,
2194
+ walkthrough: this.walkthrough,
2195
+ },
2196
+ this.#viewOutput, this.contentElement);
2292
2197
 
2293
2198
  if (this.#viewOutput.suggestionsScrollContainer && !this.#isObservingSuggestions) {
2294
2199
  this.#suggestionsResizeObserver.observe(this.#viewOutput.suggestionsScrollContainer);