chrome-devtools-frontend 1.0.1597624 → 1.0.1598808
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.
- package/docs/ui_engineering.md +6 -6
- package/front_end/core/host/AidaClient.ts +2 -0
- package/front_end/models/ai_assistance/AiConversation.ts +16 -14
- package/front_end/models/ai_assistance/agents/AiAgent.ts +14 -4
- package/front_end/models/ai_assistance/agents/ConversationSummaryAgent.ts +109 -0
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +30 -1
- package/front_end/models/ai_assistance/ai_assistance.ts +2 -0
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +6 -9
- package/front_end/panels/ai_assistance/PatchWidget.ts +1 -1
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +53 -29
- package/front_end/panels/ai_assistance/components/ChatView.ts +1 -1
- package/front_end/panels/application/AppManifestView.ts +2 -2
- package/front_end/panels/application/CookieItemsView.ts +9 -15
- package/front_end/panels/application/DeviceBoundSessionsView.ts +3 -5
- package/front_end/panels/application/FrameDetailsView.ts +2 -2
- package/front_end/panels/application/ReportingApiView.ts +2 -2
- package/front_end/panels/application/preloading/PreloadingView.ts +18 -3
- package/front_end/panels/changes/ChangesView.ts +7 -11
- package/front_end/panels/coverage/CoverageView.ts +4 -4
- package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +3 -3
- package/front_end/panels/elements/ElementsTreeOutline.ts +34 -8
- package/front_end/panels/elements/StylePropertiesSection.ts +129 -1
- package/front_end/panels/elements/StylePropertyHighlighter.ts +3 -0
- package/front_end/panels/elements/stylesSidebarPane.css +34 -0
- package/front_end/panels/issues/AffectedSelectivePermissionsInterventionView.ts +3 -5
- package/front_end/panels/layer_viewer/LayerDetailsView.ts +2 -1
- package/front_end/panels/network/RequestConditionsDrawer.ts +4 -4
- package/front_end/panels/network/RequestCookiesView.ts +2 -2
- package/front_end/panels/network/RequestHeadersView.ts +4 -4
- package/front_end/panels/network/RequestResponseView.ts +2 -2
- package/front_end/panels/performance_monitor/PerformanceMonitor.ts +2 -2
- package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +3 -3
- package/front_end/panels/recorder/components/StepView.ts +2 -1
- package/front_end/panels/search/SearchView.ts +2 -2
- package/front_end/panels/timeline/TimelineDetailsView.ts +8 -6
- package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +2 -7
- package/front_end/panels/timeline/components/insights/CharacterSet.ts +2 -6
- package/front_end/panels/timeline/components/insights/EventRef.ts +2 -2
- package/front_end/panels/webauthn/WebauthnPane.ts +2 -2
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/puppeteer/README.chromium +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Realm.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Realm.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/util.d.ts +4 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/util.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/util.js +13 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/util.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/third_party/mitt/mitt.js +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/third_party/parsel-js/parsel-js.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/third_party/rxjs/rxjs.js +446 -446
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +166 -167
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Realm.js +2 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Realm.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/util.d.ts +4 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/util.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/util.js +12 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/util.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/third_party/mitt/mitt.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/third_party/parsel-js/parsel-js.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/third_party/rxjs/rxjs.js +97 -97
- package/front_end/third_party/puppeteer/package/package.json +1 -1
- package/front_end/third_party/puppeteer/package/src/bidi/Realm.ts +2 -2
- package/front_end/third_party/puppeteer/package/src/bidi/util.ts +17 -0
- package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
- package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
- package/front_end/ui/legacy/Widget.ts +42 -6
- package/package.json +1 -1
package/docs/ui_engineering.md
CHANGED
|
@@ -44,7 +44,7 @@ To embed another presenter (`UI.Widget`) in the lit-html template, use `widget(<
|
|
|
44
44
|
|
|
45
45
|
This will instantiate a `Widget` class with the web component as its `element` and, optionally, will set the properties provided in the second parameter. The widget won’t be re-instantiated on the subsequent template renders, but the properties would be updated. For this to work, the widget needs to accept `HTMLElement` as a sole constructor parameter and properties need to be public members or setters.
|
|
46
46
|
|
|
47
|
-
For backwards compatibility, the first argument to `
|
|
47
|
+
For backwards compatibility, the first argument to `widget` can also be a factory function: `widget(element => new MyWidget(foo, bar, element))`. Similar to the class constructor version, `element` is the actual `<devtools-widget>` so the following two invocations of `widget` are equivalent: `widget(MyWidget)` and `widget(element => new MyWidget(element))`.
|
|
48
48
|
|
|
49
49
|
## Styling
|
|
50
50
|
To prevent style conflicts in widgets without relying on shadow DOM, we use the CSS [`@scope`](https://developer.mozilla.org/en-US/docs/Web/CSS/@scope) at-rule for style encapsulation. This ensures that styles defined for a widget do not leak out and affect other components.
|
|
@@ -93,9 +93,9 @@ In this example, the `.title` style will apply within the parent widget but will
|
|
|
93
93
|
## Examples
|
|
94
94
|
|
|
95
95
|
```html
|
|
96
|
-
<devtools-widget
|
|
96
|
+
<devtools-widget ${widget(ElementsPanel)}>
|
|
97
97
|
<devtools-split-view>
|
|
98
|
-
<devtools-widget slot="main"
|
|
98
|
+
<devtools-widget slot="main" ${widget(ElementsTree)}></devtools-widget>
|
|
99
99
|
<devtools-tab-pane slot="sidebar">
|
|
100
100
|
${widget(StylesPane, {element: input.element})}
|
|
101
101
|
${widget(ComputedPane, {element: input.element})}
|
|
@@ -1169,12 +1169,12 @@ export const DEFAULT_VIEW = (input, _output, target) => {
|
|
|
1169
1169
|
<div>
|
|
1170
1170
|
<devtools-split-view direction=${this.vertical ? 'column' : 'row'} sidebar-position="first"
|
|
1171
1171
|
sidebar-initial-size="200">
|
|
1172
|
-
<devtools-widget slot="sidebar"
|
|
1172
|
+
<devtools-widget slot="sidebar" ${widget(SidebarPanel,
|
|
1173
1173
|
{minimumSize: {width: 100, height: 25}})}></devtools-widget>
|
|
1174
1174
|
<devtools-split-view direction="column" sidebar-position="second" slot="main"
|
|
1175
1175
|
direction="row" sidebar-position="$this.dockedLeft ? 'second' : 'first'}">
|
|
1176
|
-
<devtools-widget slot="main"
|
|
1177
|
-
<devtools-widget slot="sidebar"
|
|
1176
|
+
<devtools-widget slot="main" ${widget(UI.Widget.EmptyWidget)}></devtools-widget>
|
|
1177
|
+
<devtools-widget slot="sidebar" ${widget(DetailsView)}></devtools-widget>
|
|
1178
1178
|
</devtools-split-view>
|
|
1179
1179
|
</devtools-split-view>
|
|
1180
1180
|
</div>`,
|
|
@@ -137,6 +137,8 @@ export enum ClientFeature {
|
|
|
137
137
|
CHROME_CONTEXT_SELECTION_AGENT = 25,
|
|
138
138
|
// Chrome Accessibility Agent
|
|
139
139
|
CHROME_ACCESSIBILITY_AGENT = 26,
|
|
140
|
+
// Chrome AI Assistance Conversation Summary Agent.
|
|
141
|
+
CHROME_CONVERSATION_SUMMARY_AGENT = 27,
|
|
140
142
|
|
|
141
143
|
// Removed features (for reference).
|
|
142
144
|
// Chrome AI Assistance Performance Insights Agent.
|
|
@@ -265,21 +265,23 @@ export class AiConversation {
|
|
|
265
265
|
id: this.id,
|
|
266
266
|
history: this.history
|
|
267
267
|
.map(item => {
|
|
268
|
-
|
|
269
|
-
|
|
268
|
+
switch (item.type) {
|
|
269
|
+
case ResponseType.CONTEXT_CHANGE: {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
case ResponseType.USER_QUERY: {
|
|
273
|
+
return {...item, imageInput: undefined};
|
|
274
|
+
}
|
|
275
|
+
case ResponseType.SIDE_EFFECT: {
|
|
276
|
+
return {...item, confirm: undefined};
|
|
277
|
+
}
|
|
278
|
+
case ResponseType.CONTEXT:
|
|
279
|
+
case ResponseType.ACTION: {
|
|
280
|
+
return {...item, widgets: undefined};
|
|
281
|
+
}
|
|
282
|
+
default:
|
|
283
|
+
return item;
|
|
270
284
|
}
|
|
271
|
-
|
|
272
|
-
if (item.type === ResponseType.USER_QUERY) {
|
|
273
|
-
return {...item, imageInput: undefined};
|
|
274
|
-
}
|
|
275
|
-
// Remove the `confirm()`-function because `structuredClone()` throws on functions
|
|
276
|
-
if (item.type === ResponseType.SIDE_EFFECT) {
|
|
277
|
-
return {...item, confirm: undefined};
|
|
278
|
-
}
|
|
279
|
-
if (item.type === ResponseType.CONTEXT && item.widgets) {
|
|
280
|
-
return {...item, widgets: undefined};
|
|
281
|
-
}
|
|
282
|
-
return item;
|
|
283
285
|
})
|
|
284
286
|
.filter(history => !!history),
|
|
285
287
|
type: this.#type,
|
|
@@ -249,8 +249,15 @@ export interface StylePropertiesAiWidget {
|
|
|
249
249
|
};
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
+
export interface DomTreeAiWidget {
|
|
253
|
+
name: 'DOM_TREE';
|
|
254
|
+
data: {
|
|
255
|
+
root: SDK.DOMModel.DOMNodeSnapshot,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
252
259
|
// This type will grow as we add more widgets.
|
|
253
|
-
export type AiWidget = ComputedStyleAiWidget|CoreVitalsAiWidget|StylePropertiesAiWidget;
|
|
260
|
+
export type AiWidget = ComputedStyleAiWidget|CoreVitalsAiWidget|StylePropertiesAiWidget|DomTreeAiWidget;
|
|
254
261
|
|
|
255
262
|
export type FunctionCallHandlerResult<Result> = {
|
|
256
263
|
requiresApproval: true,
|
|
@@ -689,10 +696,12 @@ export abstract class AiAgent<T> {
|
|
|
689
696
|
|
|
690
697
|
return;
|
|
691
698
|
}
|
|
699
|
+
|
|
692
700
|
query = {
|
|
693
701
|
functionResponse: {
|
|
694
702
|
name: functionCall.name,
|
|
695
|
-
|
|
703
|
+
// Widgets are not sent back to the LLM
|
|
704
|
+
response: {...result, widgets: undefined},
|
|
696
705
|
},
|
|
697
706
|
};
|
|
698
707
|
request = this.buildRequest(query, Host.AidaClient.Role.ROLE_UNSPECIFIED);
|
|
@@ -720,7 +729,8 @@ export abstract class AiAgent<T> {
|
|
|
720
729
|
options?: FunctionHandlerOptions&{explanation?: string},
|
|
721
730
|
): AsyncGenerator<FunctionCallResponseData, {
|
|
722
731
|
result: unknown,
|
|
723
|
-
|
|
732
|
+
widgets?: AiWidget[],
|
|
733
|
+
}|{context: ConversationContext<unknown>, description: string, widgets?: AiWidget[]}> {
|
|
724
734
|
const call = this.#functionDeclarations.get(name);
|
|
725
735
|
if (!call) {
|
|
726
736
|
throw new Error(`Function ${name} is not found.`);
|
|
@@ -837,7 +847,7 @@ export abstract class AiAgent<T> {
|
|
|
837
847
|
return result;
|
|
838
848
|
}
|
|
839
849
|
|
|
840
|
-
return result as {result: unknown};
|
|
850
|
+
return result as {result: unknown, widgets?: AiWidget[]};
|
|
841
851
|
}
|
|
842
852
|
|
|
843
853
|
async *
|
|
@@ -0,0 +1,109 @@
|
|
|
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
|
+
|
|
8
|
+
import {AiAgent, type ContextResponse, ConversationContext, type RequestOptions, ResponseType} from './AiAgent.js';
|
|
9
|
+
|
|
10
|
+
const preamble =
|
|
11
|
+
`You are an expert technical assistant specializing in summarizing debugging conversations from Chrome DevTools.
|
|
12
|
+
You will receive a markdown-formatted transcript of a conversation between a user and a DevTools AI assistant.
|
|
13
|
+
Your goal is to produce a succinct, structured summary that a local AI agent in the user's IDE can use to apply code fixes.
|
|
14
|
+
|
|
15
|
+
Focus on extracting:
|
|
16
|
+
1. **Core Issue:** The primary problem or question the user was investigating.
|
|
17
|
+
2. **Diagnostic Findings:** Key technical details discovered (e.g., specific functions, bottlenecks, error messages, URLs, or CSS properties).
|
|
18
|
+
3. **Proposed Solution:** The specific changes or optimizations recommended by the DevTools assistant.
|
|
19
|
+
4. **Actionable Steps:** A clear, step-by-step list of instructions for the IDE agent to implement the fix.
|
|
20
|
+
|
|
21
|
+
Maintain a professional, technical, and extremely concise tone. Avoid conversational filler or introductory/concluding remarks.
|
|
22
|
+
The output must be structured markdown.`;
|
|
23
|
+
|
|
24
|
+
export class ConversationSummaryContext extends ConversationContext<string> {
|
|
25
|
+
#conversation: string;
|
|
26
|
+
constructor(conversation: string) {
|
|
27
|
+
super();
|
|
28
|
+
this.#conversation = conversation;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
getOrigin(): string {
|
|
32
|
+
return 'devtools://ai-assistance';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
getItem(): string {
|
|
36
|
+
return this.#conversation;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override getTitle(): string {
|
|
40
|
+
return 'Conversation';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* An agent that takes a full conversation between a user and an agent in markdown
|
|
46
|
+
* format and produces a succinct summary of the conversation.
|
|
47
|
+
*
|
|
48
|
+
* This summary is designed to be read by a local agent in the user's IDE and it
|
|
49
|
+
* will be used to help apply fixes to the user's local codebase based on the
|
|
50
|
+
* debugging information the devtools agent found.
|
|
51
|
+
*
|
|
52
|
+
* This agent is not intended to be used directly by users in the AI Assistance
|
|
53
|
+
* panel when chatting with DevTools AI.
|
|
54
|
+
*/
|
|
55
|
+
export class ConversationSummaryAgent extends AiAgent<string> {
|
|
56
|
+
override preamble = preamble;
|
|
57
|
+
|
|
58
|
+
get clientFeature(): Host.AidaClient.ClientFeature {
|
|
59
|
+
return Host.AidaClient.ClientFeature.CHROME_CONVERSATION_SUMMARY_AGENT;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
get userTier(): string|undefined {
|
|
63
|
+
// TODO(b/491772868): tidy up userTier & feature flags in the backend.
|
|
64
|
+
return Root.Runtime.hostConfig.devToolsFreestyler?.userTier;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
get options(): RequestOptions {
|
|
68
|
+
// TODO(b/491772868): tidy up userTier & feature flags in the backend.
|
|
69
|
+
const temperature = Root.Runtime.hostConfig.devToolsFreestyler?.temperature;
|
|
70
|
+
const modelId = Root.Runtime.hostConfig.devToolsFreestyler?.modelId;
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
temperature,
|
|
74
|
+
modelId,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async * handleContextDetails(context: ConversationContext<string>|null): AsyncGenerator<ContextResponse, void, void> {
|
|
79
|
+
if (!context) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
yield {
|
|
84
|
+
type: ResponseType.CONTEXT,
|
|
85
|
+
title: 'Summarizing conversation',
|
|
86
|
+
details: [
|
|
87
|
+
{
|
|
88
|
+
title: 'Conversation transcript',
|
|
89
|
+
text: context.getItem(),
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
override async enhanceQuery(query: string, context: ConversationContext<string>|null): Promise<string> {
|
|
96
|
+
const conversation = context ? context.getItem() : query;
|
|
97
|
+
return `Summarize the following conversation:\n\n${conversation}`;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async summarizeConversation(conversation: string): Promise<string> {
|
|
101
|
+
const context = new ConversationSummaryContext(conversation);
|
|
102
|
+
const response = await Array.fromAsync(this.run('', {selected: context}));
|
|
103
|
+
const lastResponse = response.at(-1);
|
|
104
|
+
if (lastResponse && lastResponse.type === ResponseType.ANSWER && lastResponse.complete === true) {
|
|
105
|
+
return lastResponse.text.trim();
|
|
106
|
+
}
|
|
107
|
+
throw new Error('Failed to summarize conversation');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -8,6 +8,7 @@ import * as i18n from '../../../core/i18n/i18n.js';
|
|
|
8
8
|
import * as Platform from '../../../core/platform/platform.js';
|
|
9
9
|
import * as Root from '../../../core/root/root.js';
|
|
10
10
|
import * as SDK from '../../../core/sdk/sdk.js';
|
|
11
|
+
import type * as Protocol from '../../../generated/protocol.js';
|
|
11
12
|
import * as Tracing from '../../../services/tracing/tracing.js';
|
|
12
13
|
import * as Annotations from '../../annotations/annotations.js';
|
|
13
14
|
import * as SourceMapScopes from '../../source_map_scopes/source_map_scopes.js';
|
|
@@ -700,6 +701,7 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
700
701
|
#declareFunctions(context: PerformanceTraceContext): void {
|
|
701
702
|
const focus = context.getItem();
|
|
702
703
|
const {parsedTrace} = focus;
|
|
704
|
+
const processedNodeIds = new Set<Protocol.DOM.BackendNodeId>();
|
|
703
705
|
|
|
704
706
|
this.declareFunction<{insightSetId: string, insightName: string}, {details: string}>('getInsightDetails', {
|
|
705
707
|
description:
|
|
@@ -749,9 +751,36 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
749
751
|
|
|
750
752
|
const details = new PerformanceInsightFormatter(focus, insight).formatInsight();
|
|
751
753
|
|
|
754
|
+
const widgets: AiWidget[] = [];
|
|
755
|
+
if (params.insightName === 'LCPDiscovery' || params.insightName === 'LCPBreakdown') {
|
|
756
|
+
const lcpMetric = Trace.Insights.Common.getLCP(insightSet);
|
|
757
|
+
const lcpEvent = lcpMetric?.event;
|
|
758
|
+
if (lcpEvent && Trace.Types.Events.isAnyLargestContentfulPaintCandidate(lcpEvent)) {
|
|
759
|
+
const nodeId = lcpEvent.args.data?.nodeId;
|
|
760
|
+
// We want to show only one DOM tree widget per walkthrough per node.
|
|
761
|
+
// We do want to show the widget for the same node again, if it's within a new walkthrough.
|
|
762
|
+
if (nodeId && !processedNodeIds.has(nodeId)) {
|
|
763
|
+
const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
|
|
764
|
+
const domModel = target?.model(SDK.DOMModel.DOMModel);
|
|
765
|
+
if (domModel) {
|
|
766
|
+
const nodeMap = await domModel.pushNodesByBackendIdsToFrontend(new Set([nodeId]));
|
|
767
|
+
const node = nodeMap?.get(nodeId);
|
|
768
|
+
if (node) {
|
|
769
|
+
const snapshot = await node.takeSnapshot();
|
|
770
|
+
widgets.push({
|
|
771
|
+
name: 'DOM_TREE',
|
|
772
|
+
data: {root: snapshot},
|
|
773
|
+
});
|
|
774
|
+
processedNodeIds.add(nodeId);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
|
|
752
781
|
const key = `getInsightDetails('${params.insightSetId}', '${params.insightName}')`;
|
|
753
782
|
this.#cacheFunctionResult(focus, key, details);
|
|
754
|
-
return {result: {details}};
|
|
783
|
+
return {result: {details}, widgets};
|
|
755
784
|
},
|
|
756
785
|
});
|
|
757
786
|
|
|
@@ -7,6 +7,7 @@ import * as AccessibilityAgent from './agents/AccessibilityAgent.js';
|
|
|
7
7
|
import * as AiAgent from './agents/AiAgent.js';
|
|
8
8
|
import * as BreakpointDebuggerAgent from './agents/BreakpointDebuggerAgent.js';
|
|
9
9
|
import * as ContextSelectionAgent from './agents/ContextSelectionAgent.js';
|
|
10
|
+
import * as ConversationSummaryAgent from './agents/ConversationSummaryAgent.js';
|
|
10
11
|
import * as FileAgent from './agents/FileAgent.js';
|
|
11
12
|
import * as NetworkAgent from './agents/NetworkAgent.js';
|
|
12
13
|
import * as PatchAgent from './agents/PatchAgent.js';
|
|
@@ -47,6 +48,7 @@ export {
|
|
|
47
48
|
ChangeManager,
|
|
48
49
|
ContextSelectionAgent,
|
|
49
50
|
ConversationHandler,
|
|
51
|
+
ConversationSummaryAgent,
|
|
50
52
|
Debug,
|
|
51
53
|
EvaluateAction,
|
|
52
54
|
ExtensionScope,
|
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
import {isAiAssistancePatchingEnabled} from './PatchWidget.js';
|
|
51
51
|
|
|
52
52
|
const {html} = Lit;
|
|
53
|
+
const {widget} = UI.Widget;
|
|
53
54
|
|
|
54
55
|
const AI_ASSISTANCE_SEND_FEEDBACK = 'https://crbug.com/364805393' as Platform.DevToolsPath.UrlString;
|
|
55
56
|
const AI_ASSISTANCE_HELP =
|
|
@@ -465,16 +466,12 @@ function defaultView(input: ViewInput, output: PanelViewOutput, target: HTMLElem
|
|
|
465
466
|
></devtools-ai-chat-view>`;
|
|
466
467
|
}
|
|
467
468
|
case ViewState.EXPLORE_VIEW:
|
|
468
|
-
return html`<devtools-widget
|
|
469
|
-
|
|
470
|
-
.widgetConfig=${UI.Widget.widgetConfig(ExploreWidget)}
|
|
471
|
-
></devtools-widget>`;
|
|
469
|
+
return html`<devtools-widget class="fill-panel" ${widget(ExploreWidget)}>
|
|
470
|
+
</devtools-widget>`;
|
|
472
471
|
|
|
473
472
|
case ViewState.DISABLED_VIEW:
|
|
474
|
-
return html`<devtools-widget
|
|
475
|
-
|
|
476
|
-
.widgetConfig=${UI.Widget.widgetConfig(DisabledWidget, input.props)}
|
|
477
|
-
></devtools-widget>`;
|
|
473
|
+
return html`<devtools-widget class="fill-panel" ${widget(DisabledWidget, input.props)}>
|
|
474
|
+
</devtools-widget>`;
|
|
478
475
|
}
|
|
479
476
|
}
|
|
480
477
|
|
|
@@ -510,7 +507,7 @@ function defaultView(input: ViewInput, output: PanelViewOutput, target: HTMLElem
|
|
|
510
507
|
</div>
|
|
511
508
|
<div slot="sidebar" class="sidebar-view">
|
|
512
509
|
${shouldShowWalkthrough ? html`
|
|
513
|
-
<devtools-widget
|
|
510
|
+
<devtools-widget ${widget(WalkthroughView, {
|
|
514
511
|
message: input.props.walkthrough.activeMessage,
|
|
515
512
|
isLoading: input.props.isLoading && walkthroughIsForLastMessage,
|
|
516
513
|
markdownRenderer: input.props.markdownRenderer,
|
|
@@ -280,7 +280,7 @@ const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
280
280
|
|
|
281
281
|
// clang-format off
|
|
282
282
|
return html`<devtools-widget class="copy-to-prompt"
|
|
283
|
-
|
|
283
|
+
${widget(PanelCommon.CopyChangesToPrompt, {
|
|
284
284
|
workspaceDiff: input.workspaceDiff,
|
|
285
285
|
patchAgentCSSChange: changedCode,
|
|
286
286
|
})}></devtools-widget>`;
|
|
@@ -13,7 +13,7 @@ import * as Root from '../../../core/root/root.js';
|
|
|
13
13
|
import * as SDK from '../../../core/sdk/sdk.js';
|
|
14
14
|
import type * as Protocol from '../../../generated/protocol.js';
|
|
15
15
|
import type {
|
|
16
|
-
AiWidget, ComputedStyleAiWidget, CoreVitalsAiWidget, StylePropertiesAiWidget} from
|
|
16
|
+
AiWidget, ComputedStyleAiWidget, CoreVitalsAiWidget, DomTreeAiWidget, StylePropertiesAiWidget} from
|
|
17
17
|
'../../../models/ai_assistance/agents/AiAgent.js';
|
|
18
18
|
import * as AiAssistanceModel from '../../../models/ai_assistance/ai_assistance.js';
|
|
19
19
|
import * as ComputedStyle from '../../../models/computed_style/computed_style.js';
|
|
@@ -676,33 +676,29 @@ async function makeComputedStyleWidget(widgetData: ComputedStyleAiWidget): Promi
|
|
|
676
676
|
}
|
|
677
677
|
const styles = new ComputedStyle.ComputedStyleModel.ComputedStyle(domNodeForId, widgetData.data.computedStyles);
|
|
678
678
|
|
|
679
|
-
const widgetConfig = UI.Widget.widgetConfig(Elements.ComputedStyleWidget.ComputedStyleWidget, {
|
|
680
|
-
nodeStyle: styles,
|
|
681
|
-
matchedStyles: widgetData.data.matchedCascade,
|
|
682
|
-
// This disables showing the nested traces and detailed information in the widget.
|
|
683
|
-
propertyTraces: null,
|
|
684
|
-
allowUserControl: false,
|
|
685
|
-
filterText: new RegExp(widgetData.data.properties.join('|'), 'i')
|
|
686
|
-
});
|
|
687
|
-
|
|
688
679
|
// clang-format off
|
|
689
|
-
const
|
|
680
|
+
const renderedWidget = html`<devtools-widget
|
|
681
|
+
class="computed-styles-widget" ${widget(Elements.ComputedStyleWidget.ComputedStyleWidget, {
|
|
682
|
+
nodeStyle: styles,
|
|
683
|
+
matchedStyles: widgetData.data.matchedCascade,
|
|
684
|
+
// This disables showing the nested traces and detailed information in the widget.
|
|
685
|
+
propertyTraces: null,
|
|
686
|
+
allowUserControl: false,
|
|
687
|
+
filterText: new RegExp(widgetData.data.properties.join('|'), 'i')
|
|
688
|
+
})}></devtools-widget>`;
|
|
690
689
|
// clang-format on
|
|
691
690
|
|
|
692
|
-
return {renderedWidget
|
|
691
|
+
return {renderedWidget, revealable: new Elements.ElementsPanel.NodeComputedStyles(domNodeForId)};
|
|
693
692
|
}
|
|
694
693
|
|
|
695
694
|
async function makeCoreVitalsWidget(widgetData: CoreVitalsAiWidget): Promise<WidgetMakerResponse|null> {
|
|
696
|
-
const widgetConfig = UI.Widget.widgetConfig(TimelineComponents.CWVMetrics.CWVMetrics, {data: widgetData.data});
|
|
697
|
-
|
|
698
695
|
// clang-format off
|
|
699
|
-
const
|
|
696
|
+
const renderedWidget = html`<devtools-widget
|
|
697
|
+
class="core-vitals-widget" ${widget(TimelineComponents.CWVMetrics.CWVMetrics, {data: widgetData.data})}>
|
|
698
|
+
</devtools-widget>`;
|
|
700
699
|
// clang-format on
|
|
701
700
|
|
|
702
|
-
return {
|
|
703
|
-
renderedWidget: widget,
|
|
704
|
-
revealable: new TimelineUtils.Helpers.RevealableCoreVitals(widgetData.data.insightSetKey)
|
|
705
|
-
};
|
|
701
|
+
return {renderedWidget, revealable: new TimelineUtils.Helpers.RevealableCoreVitals(widgetData.data.insightSetKey)};
|
|
706
702
|
}
|
|
707
703
|
|
|
708
704
|
async function makeStylePropertiesWidget(widgetData: StylePropertiesAiWidget): Promise<WidgetMakerResponse|null> {
|
|
@@ -711,19 +707,17 @@ async function makeStylePropertiesWidget(widgetData: StylePropertiesAiWidget): P
|
|
|
711
707
|
return null;
|
|
712
708
|
}
|
|
713
709
|
|
|
714
|
-
const widgetConfig = UI.Widget.widgetConfig(Elements.StandaloneStylesContainer.StandaloneStylesContainer, {
|
|
715
|
-
domNode: domNodeForId,
|
|
716
|
-
filter: widgetData.data.selector ? new RegExp(widgetData.data.selector) : null,
|
|
717
|
-
});
|
|
718
|
-
|
|
719
710
|
// clang-format off
|
|
720
|
-
const
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
711
|
+
const renderedWidget = html`<devtools-widget
|
|
712
|
+
class="styling-preview-widget"
|
|
713
|
+
${widget(Elements.StandaloneStylesContainer.StandaloneStylesContainer, {
|
|
714
|
+
domNode: domNodeForId,
|
|
715
|
+
filter: widgetData.data.selector ? new RegExp(widgetData.data.selector) : null,
|
|
716
|
+
})}>
|
|
717
|
+
</devtools-widget>`;
|
|
724
718
|
// clang-format on
|
|
725
719
|
|
|
726
|
-
return {renderedWidget
|
|
720
|
+
return {renderedWidget, revealable: domNodeForId};
|
|
727
721
|
}
|
|
728
722
|
|
|
729
723
|
function renderWidgetResponse(response: WidgetMakerResponse|null): Lit.LitTemplate {
|
|
@@ -756,6 +750,34 @@ function renderWidgetResponse(response: WidgetMakerResponse|null): Lit.LitTempla
|
|
|
756
750
|
// clang-format on
|
|
757
751
|
}
|
|
758
752
|
|
|
753
|
+
async function makeDomTreeWidget(widgetData: DomTreeAiWidget): Promise<WidgetMakerResponse|null> {
|
|
754
|
+
const root = widgetData.data.root;
|
|
755
|
+
if (!(root instanceof SDK.DOMModel.DOMNodeSnapshot)) {
|
|
756
|
+
return null;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
const widgetConfig = UI.Widget.widgetConfig(Elements.ElementsTreeOutline.DOMTreeWidget, {
|
|
760
|
+
maxTreeDepth: 2,
|
|
761
|
+
enableContextMenu: false,
|
|
762
|
+
showComments: false,
|
|
763
|
+
showAIButton: false,
|
|
764
|
+
disableEdits: true,
|
|
765
|
+
expandRoot: true,
|
|
766
|
+
rootDOMNode: root,
|
|
767
|
+
visibleWidth: 400,
|
|
768
|
+
wrap: true,
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
// clang-format off
|
|
772
|
+
const widget = html`<devtools-widget class="dom-tree-widget" .widgetConfig=${widgetConfig}></devtools-widget>`;
|
|
773
|
+
// clang-format on
|
|
774
|
+
|
|
775
|
+
return {
|
|
776
|
+
renderedWidget: widget,
|
|
777
|
+
revealable: new SDK.DOMModel.DeferredDOMNode(root.domModel().target(), root.backendNodeId()),
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
|
|
759
781
|
/**
|
|
760
782
|
* Renders AI-defined UI widgets.
|
|
761
783
|
* When a ModelChatMessage contains a WidgetPart, or a Step has widgets,
|
|
@@ -786,6 +808,8 @@ async function renderWidgets(
|
|
|
786
808
|
response = await makeCoreVitalsWidget(widgetData);
|
|
787
809
|
} else if (widgetData.name === 'STYLE_PROPERTIES') {
|
|
788
810
|
response = await makeStylePropertiesWidget(widgetData);
|
|
811
|
+
} else if (widgetData.name === 'DOM_TREE') {
|
|
812
|
+
response = await makeDomTreeWidget(widgetData);
|
|
789
813
|
}
|
|
790
814
|
return renderWidgetResponse(response);
|
|
791
815
|
}));
|
|
@@ -169,7 +169,7 @@ const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
169
169
|
</div>
|
|
170
170
|
</div>
|
|
171
171
|
`}
|
|
172
|
-
<devtools-widget class=${inputWidgetClasses}
|
|
172
|
+
<devtools-widget class=${inputWidgetClasses} ${widget(ChatInput, {
|
|
173
173
|
isLoading: input.isLoading,
|
|
174
174
|
blockedByCrossOrigin: input.blockedByCrossOrigin,
|
|
175
175
|
isTextInputDisabled: input.isTextInputDisabled,
|
|
@@ -22,7 +22,7 @@ import * as ApplicationComponents from './components/components.js';
|
|
|
22
22
|
|
|
23
23
|
const {styleMap, classMap, ref} = Directives;
|
|
24
24
|
const {linkifyURL} = Components.Linkifier.Linkifier;
|
|
25
|
-
const {widget
|
|
25
|
+
const {widget} = UI.Widget;
|
|
26
26
|
|
|
27
27
|
const UIStrings = {
|
|
28
28
|
/**
|
|
@@ -719,7 +719,7 @@ function renderProtocolHandlers(data: ProtocolHandlersSectionData, output: ViewO
|
|
|
719
719
|
// clang-format off
|
|
720
720
|
return html`${renderSectionHeader(i18nString(UIStrings.protocolHandlers), output)}
|
|
721
721
|
<div class="report-row">
|
|
722
|
-
<devtools-widget
|
|
722
|
+
<devtools-widget ${widget(
|
|
723
723
|
ApplicationComponents.ProtocolHandlersView.ProtocolHandlersView,
|
|
724
724
|
{protocolHandlers: data.protocolHandlers, manifestLink: data.manifestLink})}
|
|
725
725
|
${ref(setFocusOnSection(i18nString(UIStrings.protocolHandlers), output))}>
|
|
@@ -82,6 +82,7 @@ const UIStrings = {
|
|
|
82
82
|
const str_ = i18n.i18n.registerUIStrings('panels/application/CookieItemsView.ts', UIStrings);
|
|
83
83
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
84
84
|
const {Size} = Geometry;
|
|
85
|
+
const {widget} = UI.Widget;
|
|
85
86
|
|
|
86
87
|
interface CookiePreviewWidgetInput {
|
|
87
88
|
cookie: SDK.Cookie.Cookie|null;
|
|
@@ -184,10 +185,8 @@ type View = (input: CookieItemsViewInput, output: CookieItemsViewOutput, target:
|
|
|
184
185
|
export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
185
186
|
// clang-format off
|
|
186
187
|
render(html`<style>${cookieItemsViewStyles}</style>
|
|
187
|
-
<devtools-widget class="storage-view"
|
|
188
|
-
|
|
189
|
-
<devtools-widget
|
|
190
|
-
.widgetConfig=${UI.Widget.widgetConfig(StorageItemsToolbar, {
|
|
188
|
+
<devtools-widget class="storage-view" ${widget(UI.Widget.VBox, {minimumSize: new Size(0, 50)})}>
|
|
189
|
+
<devtools-widget ${widget(StorageItemsToolbar, {
|
|
191
190
|
onDeleteSelectedCallback: input.onDeleteSelectedItems,
|
|
192
191
|
onDeleteAllCallback: input.onDeleteAllItems,
|
|
193
192
|
onRefreshCallback: input.onRefreshItems,
|
|
@@ -196,10 +195,8 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
196
195
|
${UI.Widget.widgetRef(StorageItemsToolbar, toolbar => { output.toolbar = toolbar; })}
|
|
197
196
|
></devtools-widget>
|
|
198
197
|
<devtools-split-view sidebar-position="second" name="cookie-items-split-view-state">
|
|
199
|
-
<devtools-widget
|
|
200
|
-
|
|
201
|
-
.widgetConfig=${UI.Widget.widgetConfig(UI.Widget.VBox, {minimumSize: new Size(0, 50)})}>
|
|
202
|
-
<devtools-widget slot="main" .widgetConfig=${UI.Widget.widgetConfig(CookieTable.CookiesTable.CookiesTable, {
|
|
198
|
+
<devtools-widget slot="main" ${widget(UI.Widget.VBox, {minimumSize: new Size(0, 50)})}>
|
|
199
|
+
<devtools-widget slot="main" ${widget(CookieTable.CookiesTable.CookiesTable, {
|
|
203
200
|
cookieDomain: input.cookieDomain,
|
|
204
201
|
cookiesData: input.cookiesData,
|
|
205
202
|
saveCallback: input.onSaveCookie,
|
|
@@ -210,15 +207,12 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
210
207
|
})}
|
|
211
208
|
></devtools-widget>
|
|
212
209
|
</devtools-widget>
|
|
213
|
-
<devtools-widget
|
|
214
|
-
slot="sidebar"
|
|
215
|
-
.widgetConfig=${UI.Widget.widgetConfig(UI.Widget.VBox, {minimumSize: new Size(0, 50)})}
|
|
210
|
+
<devtools-widget slot="sidebar" ${widget(UI.Widget.VBox, {minimumSize: new Size(0, 50)})}
|
|
216
211
|
jslog=${VisualLogging.pane('preview').track({resize: true})}>
|
|
217
212
|
${input.selectedCookie ?
|
|
218
|
-
html`<devtools-widget
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
html`<devtools-widget .widgetConfig=${UI.Widget.widgetConfig(UI.EmptyWidget.EmptyWidget, {
|
|
213
|
+
html`<devtools-widget ${widget(CookiePreviewWidget, {cookie: input.selectedCookie})}>
|
|
214
|
+
</devtools-widget>` :
|
|
215
|
+
html`<devtools-widget ${widget(UI.EmptyWidget.EmptyWidget, {
|
|
222
216
|
header: i18nString(UIStrings.noCookieSelected),
|
|
223
217
|
text: i18nString(UIStrings.selectACookieToPreviewItsValue)
|
|
224
218
|
})}></devtools-widget>`}
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
type SessionAndEvents
|
|
20
20
|
} from './DeviceBoundSessionsModel.js';
|
|
21
21
|
import deviceBoundSessionsViewStyles from './deviceBoundSessionsView.css.js';
|
|
22
|
-
const {widget
|
|
22
|
+
const {widget} = UI.Widget;
|
|
23
23
|
|
|
24
24
|
const UIStrings = {
|
|
25
25
|
/**
|
|
@@ -583,10 +583,8 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTML
|
|
|
583
583
|
<style>${UI.inspectorCommonStyles}</style>
|
|
584
584
|
<style>${deviceBoundSessionsViewStyles}</style>
|
|
585
585
|
${toolbarHtml}
|
|
586
|
-
<devtools-widget
|
|
587
|
-
|
|
588
|
-
text: defaultDescription
|
|
589
|
-
})} jslog=${VisualLogging.pane('device-bound-sessions-empty')}></devtools-widget>
|
|
586
|
+
<devtools-widget ${widget(UI.EmptyWidget.EmptyWidget, {header: defaultTitle, text: defaultDescription})} jslog=${
|
|
587
|
+
VisualLogging.pane('device-bound-sessions-empty')}></devtools-widget>
|
|
590
588
|
`,
|
|
591
589
|
target);
|
|
592
590
|
return;
|
|
@@ -30,7 +30,7 @@ import * as ApplicationComponents from './components/components.js';
|
|
|
30
30
|
import frameDetailsReportViewStyles from './frameDetailsReportView.css.js';
|
|
31
31
|
import {OriginTrialTreeView} from './OriginTrialTreeView.js';
|
|
32
32
|
|
|
33
|
-
const {widget
|
|
33
|
+
const {widget} = UI.Widget;
|
|
34
34
|
|
|
35
35
|
const UIStrings = {
|
|
36
36
|
/**
|
|
@@ -327,7 +327,7 @@ function renderOriginTrial(trials: Protocol.Page.OriginTrial[]|null): LitTemplat
|
|
|
327
327
|
</devtools-link>
|
|
328
328
|
</span>
|
|
329
329
|
</devtools-report-section>
|
|
330
|
-
<devtools-widget class="span-cols"
|
|
330
|
+
<devtools-widget class="span-cols" ${widget(OriginTrialTreeView, {data})}>
|
|
331
331
|
</devtools-widget>
|
|
332
332
|
<devtools-report-divider></devtools-report-divider>`;
|
|
333
333
|
// clang-format on
|
|
@@ -13,7 +13,7 @@ import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
|
|
|
13
13
|
|
|
14
14
|
import * as ApplicationComponents from './components/components.js';
|
|
15
15
|
|
|
16
|
-
const {widget
|
|
16
|
+
const {widget} = UI.Widget;
|
|
17
17
|
|
|
18
18
|
const UIStrings = {
|
|
19
19
|
/**
|
|
@@ -97,7 +97,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: undefined, target: HTMLEl
|
|
|
97
97
|
} else {
|
|
98
98
|
// clang-format off
|
|
99
99
|
render(html`
|
|
100
|
-
<devtools-widget
|
|
100
|
+
<devtools-widget ${widget(UI.EmptyWidget.EmptyWidget, {
|
|
101
101
|
header: i18nString(UIStrings.noReportOrEndpoint),
|
|
102
102
|
text: i18nString(UIStrings.reportingApiDescription),
|
|
103
103
|
link: REPORTING_API_EXPLANATION_URL,
|