chrome-devtools-frontend 1.0.1596535 → 1.0.1597624
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/agents/prompts/ui-widgets.md +7 -8
- package/docs/ui_engineering.md +10 -11
- package/front_end/core/host/AidaClient.ts +4 -0
- package/front_end/core/host/InspectorFrontendHostAPI.ts +1 -0
- package/front_end/core/host/UserMetrics.ts +12 -0
- package/front_end/core/root/Runtime.ts +5 -0
- package/front_end/core/sdk/CPUThrottlingManager.ts +14 -13
- package/front_end/core/sdk/CSSMatchedStyles.ts +2 -0
- package/front_end/core/sdk/CSSPropertyParserMatchers.ts +28 -0
- package/front_end/core/sdk/PageResourceLoader.ts +22 -1
- package/front_end/devtools_compatibility.js +2 -1
- package/front_end/models/ai_assistance/AiConversation.ts +29 -8
- package/front_end/models/ai_assistance/ChangeManager.ts +16 -0
- package/front_end/models/ai_assistance/ExtensionScope.ts +11 -3
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +127 -0
- package/front_end/models/ai_assistance/agents/AiAgent.ts +26 -3
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +1 -1
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +11 -8
- package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +24 -0
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +323 -16
- package/front_end/models/ai_assistance/ai_assistance.ts +2 -0
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +27 -0
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +21 -0
- package/front_end/models/greendev/Prototypes.ts +7 -1
- package/front_end/models/trace/Processor.ts +1 -0
- package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +33 -0
- package/front_end/models/trace/insights/CharacterSet.ts +172 -0
- package/front_end/models/trace/insights/Models.ts +1 -0
- package/front_end/models/trace/insights/types.ts +1 -0
- package/front_end/models/trace/types/TraceEvents.ts +17 -0
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +51 -36
- package/front_end/panels/ai_assistance/PatchWidget.ts +6 -6
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +93 -74
- package/front_end/panels/ai_assistance/components/ChatView.ts +6 -11
- package/front_end/panels/ai_assistance/components/MarkdownRendererWithCodeBlock.ts +18 -9
- package/front_end/panels/ai_assistance/components/StylingAgentMarkdownRenderer.ts +200 -0
- package/front_end/panels/ai_assistance/components/chatMessage.css +11 -8
- package/front_end/panels/application/AppManifestView.ts +3 -4
- package/front_end/panels/application/DeviceBoundSessionsView.ts +18 -22
- package/front_end/panels/application/FrameDetailsView.ts +9 -15
- package/front_end/panels/application/OriginTrialTreeView.ts +2 -3
- package/front_end/panels/application/ReportingApiView.ts +13 -17
- package/front_end/panels/application/ServiceWorkerCacheViews.ts +1 -1
- package/front_end/panels/application/components/BackForwardCacheView.ts +3 -3
- package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +2 -3
- package/front_end/panels/browser_debugger/DOMBreakpointsSidebarPane.ts +3 -2
- package/front_end/panels/changes/ChangesView.ts +6 -4
- package/front_end/panels/common/ExtensionServer.ts +15 -0
- package/front_end/panels/console/ConsolePinPane.ts +3 -3
- package/front_end/panels/coverage/CoverageListView.ts +1 -1
- package/front_end/panels/css_overview/CSSOverviewPanel.ts +11 -15
- package/front_end/panels/developer_resources/DeveloperResourcesView.ts +3 -5
- package/front_end/panels/elements/ElementsTreeElement.ts +55 -47
- package/front_end/panels/elements/ElementsTreeOutline.ts +149 -28
- package/front_end/panels/elements/EventListenersWidget.ts +3 -2
- package/front_end/panels/elements/StandaloneStylesContainer.ts +21 -6
- package/front_end/panels/elements/StylePropertyTreeElement.ts +49 -4
- package/front_end/panels/layer_viewer/Layers3DView.ts +5 -4
- package/front_end/panels/lighthouse/LighthousePanel.ts +8 -0
- package/front_end/panels/linear_memory_inspector/components/LinearMemoryInspector.ts +5 -6
- package/front_end/panels/linear_memory_inspector/components/LinearMemoryValueInterpreter.ts +6 -11
- package/front_end/panels/network/RequestCookiesView.ts +3 -4
- package/front_end/panels/network/RequestInitiatorView.ts +7 -5
- package/front_end/panels/network/RequestResponseView.ts +10 -15
- package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +3 -4
- package/front_end/panels/recorder/components/RecordingView.ts +31 -36
- package/front_end/panels/recorder/components/StepEditor.ts +6 -7
- package/front_end/panels/search/SearchView.ts +2 -3
- package/front_end/panels/settings/SettingsScreen.ts +3 -2
- package/front_end/panels/settings/WorkspaceSettingsTab.ts +2 -5
- package/front_end/panels/timeline/components/LiveMetricsView.ts +5 -8
- package/front_end/panels/timeline/components/insights/Cache.ts +8 -10
- package/front_end/panels/timeline/components/insights/CharacterSet.ts +38 -0
- package/front_end/panels/timeline/components/insights/DOMSize.ts +16 -20
- package/front_end/panels/timeline/components/insights/DocumentLatency.ts +2 -6
- package/front_end/panels/timeline/components/insights/DuplicatedJavaScript.ts +3 -4
- package/front_end/panels/timeline/components/insights/FontDisplay.ts +3 -4
- package/front_end/panels/timeline/components/insights/ForcedReflow.ts +5 -7
- package/front_end/panels/timeline/components/insights/INPBreakdown.ts +3 -4
- package/front_end/panels/timeline/components/insights/ImageDelivery.ts +3 -4
- package/front_end/panels/timeline/components/insights/ImageRef.ts +2 -4
- package/front_end/panels/timeline/components/insights/InsightRenderer.ts +2 -0
- package/front_end/panels/timeline/components/insights/LCPBreakdown.ts +5 -7
- package/front_end/panels/timeline/components/insights/LCPDiscovery.ts +2 -4
- package/front_end/panels/timeline/components/insights/LegacyJavaScript.ts +3 -4
- package/front_end/panels/timeline/components/insights/ModernHTTP.ts +3 -4
- package/front_end/panels/timeline/components/insights/NetworkDependencyTree.ts +7 -11
- package/front_end/panels/timeline/components/insights/NodeLink.ts +2 -4
- package/front_end/panels/timeline/components/insights/RenderBlocking.ts +3 -4
- package/front_end/panels/timeline/components/insights/SlowCSSSelector.ts +7 -10
- package/front_end/panels/timeline/components/insights/ThirdParties.ts +5 -7
- package/front_end/panels/timeline/components/insights/insights.ts +2 -0
- package/front_end/panels/web_audio/WebAudioView.ts +3 -4
- package/front_end/ui/components/settings/SettingCheckbox.ts +2 -0
- package/front_end/ui/legacy/UIUtils.ts +5 -5
- package/front_end/ui/legacy/Widget.ts +33 -2
- package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +3 -3
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +8 -8
- package/front_end/ui/visual_logging/Debugging.ts +0 -32
- package/front_end/ui/visual_logging/KnownContextValues.ts +3 -0
- package/package.json +1 -1
|
@@ -0,0 +1,172 @@
|
|
|
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 i18n from '../../../core/i18n/i18n.js';
|
|
6
|
+
import type * as Handlers from '../handlers/handlers.js';
|
|
7
|
+
import type * as Types from '../types/types.js';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
type Checklist,
|
|
11
|
+
InsightCategory,
|
|
12
|
+
InsightKeys,
|
|
13
|
+
type InsightModel,
|
|
14
|
+
type InsightSetContext,
|
|
15
|
+
InsightWarning,
|
|
16
|
+
type PartialInsightModel,
|
|
17
|
+
} from './types.js';
|
|
18
|
+
|
|
19
|
+
export const UIStrings = {
|
|
20
|
+
/**
|
|
21
|
+
* @description Title of an insight that checks whether the page declares a character encoding early enough.
|
|
22
|
+
*/
|
|
23
|
+
title: 'Declare a character encoding',
|
|
24
|
+
/**
|
|
25
|
+
* @description Description of an insight that checks whether the page has a proper character encoding declaration via HTTP header or early meta tag.
|
|
26
|
+
*/
|
|
27
|
+
description:
|
|
28
|
+
'A character encoding declaration is required. It can be done with a meta charset tag in the first 1024 bytes of the HTML or in the Content-Type HTTP response header. [Learn more about declaring the character encoding](https://developer.chrome.com/docs/insights/charset/).',
|
|
29
|
+
/**
|
|
30
|
+
* @description Text to tell the user that the charset is declared in the Content-Type HTTP response header.
|
|
31
|
+
*/
|
|
32
|
+
passingHttpHeader: 'Declares charset in HTTP header',
|
|
33
|
+
/**
|
|
34
|
+
* @description Text to tell the user that the charset is NOT declared in the Content-Type HTTP response header.
|
|
35
|
+
*/
|
|
36
|
+
failedHttpHeader: 'Does not declare charset in HTTP header',
|
|
37
|
+
/**
|
|
38
|
+
* @description Text to tell the user that a meta charset tag was found in the first 1024 bytes of the HTML.
|
|
39
|
+
*/
|
|
40
|
+
passingMetaCharsetEarly: 'Declares charset using a meta tag in the first 1024 bytes',
|
|
41
|
+
/**
|
|
42
|
+
* @description Text to tell the user that a meta charset tag was found, but too late in the HTML.
|
|
43
|
+
*/
|
|
44
|
+
failedMetaCharsetLate: 'Declares charset using a meta tag after the first 1024 bytes',
|
|
45
|
+
/**
|
|
46
|
+
* @description Text to tell the user that no meta charset tag was found in the HTML.
|
|
47
|
+
*/
|
|
48
|
+
failedMetaCharsetMissing: 'Does not declare charset using a meta tag',
|
|
49
|
+
/**
|
|
50
|
+
* @description Text to tell the user that trace data did not include the Blink signal for meta charset.
|
|
51
|
+
*/
|
|
52
|
+
failedMetaCharsetUnknown: 'Could not determine meta charset declaration from trace',
|
|
53
|
+
} as const;
|
|
54
|
+
|
|
55
|
+
const str_ = i18n.i18n.registerUIStrings('models/trace/insights/CharacterSet.ts', UIStrings);
|
|
56
|
+
export const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
57
|
+
|
|
58
|
+
const CHARSET_HTTP_REGEX = /charset\s*=\s*[a-zA-Z0-9\-_:.()]{2,}/i;
|
|
59
|
+
|
|
60
|
+
export type CharacterSetInsightModel = InsightModel<typeof UIStrings, {
|
|
61
|
+
data?: {
|
|
62
|
+
hasHttpCharset: boolean,
|
|
63
|
+
checklist: Checklist<'httpCharset'|'metaCharset'>,
|
|
64
|
+
metaCharsetDisposition?: Types.Events.MetaCharsetDisposition,
|
|
65
|
+
documentRequest?: Types.Events.SyntheticNetworkRequest,
|
|
66
|
+
},
|
|
67
|
+
}>;
|
|
68
|
+
|
|
69
|
+
export function isCharacterSetInsight(model: InsightModel): model is CharacterSetInsightModel {
|
|
70
|
+
return model.insightKey === InsightKeys.CHARACTER_SET;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function finalize(partialModel: PartialInsightModel<CharacterSetInsightModel>): CharacterSetInsightModel {
|
|
74
|
+
let hasFailure = false;
|
|
75
|
+
if (partialModel.data) {
|
|
76
|
+
hasFailure = !partialModel.data.checklist.httpCharset.value && !partialModel.data.checklist.metaCharset.value;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
insightKey: InsightKeys.CHARACTER_SET,
|
|
81
|
+
strings: UIStrings,
|
|
82
|
+
title: i18nString(UIStrings.title),
|
|
83
|
+
description: i18nString(UIStrings.description),
|
|
84
|
+
docs: 'https://developer.chrome.com/docs/insights/charset/',
|
|
85
|
+
category: InsightCategory.ALL,
|
|
86
|
+
state: hasFailure ? 'fail' : 'pass',
|
|
87
|
+
...partialModel,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function hasCharsetInContentType(request: Types.Events.SyntheticNetworkRequest): boolean {
|
|
92
|
+
if (!request.args.data.responseHeaders) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
for (const header of request.args.data.responseHeaders) {
|
|
96
|
+
if (header.name.toLowerCase() === 'content-type') {
|
|
97
|
+
return CHARSET_HTTP_REGEX.test(header.value);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function findMetaCharsetDisposition(
|
|
104
|
+
data: Handlers.Types.HandlerData,
|
|
105
|
+
context: InsightSetContext,
|
|
106
|
+
): Types.Events.MetaCharsetDisposition|undefined {
|
|
107
|
+
if (!context.navigation) {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
return data.PageLoadMetrics.metaCharsetCheckEventsByNavigation.get(context.navigation)
|
|
111
|
+
?.at(-1)
|
|
112
|
+
?.args.data?.disposition;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function metaCharsetLabel(disposition: Types.Events.MetaCharsetDisposition|undefined): ReturnType<typeof i18nString> {
|
|
116
|
+
switch (disposition) {
|
|
117
|
+
case 'found-in-first-1024-bytes':
|
|
118
|
+
return i18nString(UIStrings.passingMetaCharsetEarly);
|
|
119
|
+
case 'found-after-first-1024-bytes':
|
|
120
|
+
return i18nString(UIStrings.failedMetaCharsetLate);
|
|
121
|
+
case 'not-found':
|
|
122
|
+
return i18nString(UIStrings.failedMetaCharsetMissing);
|
|
123
|
+
default:
|
|
124
|
+
return i18nString(UIStrings.failedMetaCharsetUnknown);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function generateInsight(
|
|
129
|
+
data: Handlers.Types.HandlerData, context: InsightSetContext): CharacterSetInsightModel {
|
|
130
|
+
if (!context.navigation) {
|
|
131
|
+
return finalize({});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const documentRequest = data.NetworkRequests.byId.get(context.navigationId);
|
|
135
|
+
if (!documentRequest) {
|
|
136
|
+
return finalize({warnings: [InsightWarning.NO_DOCUMENT_REQUEST]});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const hasHttpCharset = hasCharsetInContentType(documentRequest);
|
|
140
|
+
const metaCharsetDisposition = findMetaCharsetDisposition(data, context);
|
|
141
|
+
const hasMetaCharsetInFirst1024Bytes = metaCharsetDisposition === 'found-in-first-1024-bytes';
|
|
142
|
+
|
|
143
|
+
return finalize({
|
|
144
|
+
relatedEvents: [documentRequest],
|
|
145
|
+
data: {
|
|
146
|
+
hasHttpCharset,
|
|
147
|
+
metaCharsetDisposition,
|
|
148
|
+
documentRequest,
|
|
149
|
+
checklist: {
|
|
150
|
+
httpCharset: {
|
|
151
|
+
label: hasHttpCharset ? i18nString(UIStrings.passingHttpHeader) : i18nString(UIStrings.failedHttpHeader),
|
|
152
|
+
value: hasHttpCharset,
|
|
153
|
+
},
|
|
154
|
+
metaCharset: {
|
|
155
|
+
label: metaCharsetLabel(metaCharsetDisposition),
|
|
156
|
+
value: hasMetaCharsetInFirst1024Bytes,
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function createOverlays(model: CharacterSetInsightModel): Types.Overlays.Overlay[] {
|
|
164
|
+
if (!model.data?.documentRequest) {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return [{
|
|
169
|
+
type: 'ENTRY_SELECTED',
|
|
170
|
+
entry: model.data.documentRequest,
|
|
171
|
+
}];
|
|
172
|
+
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
5
|
export * as Cache from './Cache.js';
|
|
6
|
+
export * as CharacterSet from './CharacterSet.js';
|
|
6
7
|
export * as CLSCulprits from './CLSCulprits.js';
|
|
7
8
|
export * as DocumentLatency from './DocumentLatency.js';
|
|
8
9
|
export * as DOMSize from './DOMSize.js';
|
|
@@ -1360,6 +1360,22 @@ export function isParseMetaViewport(event: Event): event is ParseMetaViewport {
|
|
|
1360
1360
|
return event.name === Name.PARSE_META_VIEWPORT;
|
|
1361
1361
|
}
|
|
1362
1362
|
|
|
1363
|
+
export type MetaCharsetDisposition = 'found-in-first-1024-bytes'|'found-after-first-1024-bytes'|'not-found';
|
|
1364
|
+
|
|
1365
|
+
export interface MetaCharsetCheck extends Instant {
|
|
1366
|
+
name: Name.META_CHARSET_CHECK;
|
|
1367
|
+
args: Args&{
|
|
1368
|
+
data: {
|
|
1369
|
+
frame: string,
|
|
1370
|
+
disposition: MetaCharsetDisposition,
|
|
1371
|
+
},
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
export function isMetaCharsetCheck(event: Event): event is MetaCharsetCheck {
|
|
1376
|
+
return event.name === Name.META_CHARSET_CHECK;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1363
1379
|
export interface LinkPreconnect extends Instant {
|
|
1364
1380
|
name: Name.LINK_PRECONNECT;
|
|
1365
1381
|
args: Args&{
|
|
@@ -3110,6 +3126,7 @@ export const enum Name {
|
|
|
3110
3126
|
SELECTOR_STATS = 'SelectorStats',
|
|
3111
3127
|
BEGIN_COMMIT_COMPOSITOR_FRAME = 'BeginCommitCompositorFrame',
|
|
3112
3128
|
PARSE_META_VIEWPORT = 'ParseMetaViewport',
|
|
3129
|
+
META_CHARSET_CHECK = 'MetaCharsetCheck',
|
|
3113
3130
|
|
|
3114
3131
|
/* Paint */
|
|
3115
3132
|
SCROLL_LAYER = 'ScrollLayer',
|
|
@@ -43,6 +43,7 @@ import {DisabledWidget} from './components/DisabledWidget.js';
|
|
|
43
43
|
import {ExploreWidget} from './components/ExploreWidget.js';
|
|
44
44
|
import {MarkdownRendererWithCodeBlock} from './components/MarkdownRendererWithCodeBlock.js';
|
|
45
45
|
import {PerformanceAgentMarkdownRenderer} from './components/PerformanceAgentMarkdownRenderer.js';
|
|
46
|
+
import {StylingAgentMarkdownRenderer} from './components/StylingAgentMarkdownRenderer.js';
|
|
46
47
|
import {
|
|
47
48
|
WalkthroughView,
|
|
48
49
|
} from './components/WalkthroughView.js';
|
|
@@ -233,6 +234,10 @@ const lockedString = i18n.i18n.lockedString;
|
|
|
233
234
|
|
|
234
235
|
function selectedElementFilter(maybeNode: SDK.DOMModel.DOMNode|null): SDK.DOMModel.DOMNode|null {
|
|
235
236
|
if (maybeNode) {
|
|
237
|
+
if (Greendev.Prototypes.instance().isEnabled('emulationCapabilities')) {
|
|
238
|
+
return maybeNode;
|
|
239
|
+
}
|
|
240
|
+
|
|
236
241
|
return maybeNode.nodeType() === Node.ELEMENT_NODE ? maybeNode : null;
|
|
237
242
|
}
|
|
238
243
|
|
|
@@ -260,7 +265,12 @@ async function getEmptyStateSuggestions(conversation?: AiAssistanceModel.AiConve
|
|
|
260
265
|
return [
|
|
261
266
|
{title: 'What can you help me with?', jslogContext: 'styling-default'},
|
|
262
267
|
{title: 'Why isn’t this element visible?', jslogContext: 'styling-default'},
|
|
263
|
-
{
|
|
268
|
+
{
|
|
269
|
+
title: Greendev.Prototypes.instance().isEnabled('emulationCapabilities') ?
|
|
270
|
+
'Are there display issues on this page for people using an Android phone?' :
|
|
271
|
+
'How do I center this element?',
|
|
272
|
+
jslogContext: 'styling-default'
|
|
273
|
+
},
|
|
264
274
|
];
|
|
265
275
|
case AiAssistanceModel.AiHistoryStorage.ConversationType.FILE:
|
|
266
276
|
return [
|
|
@@ -313,6 +323,14 @@ function getMarkdownRenderer(conversation?: AiAssistanceModel.AiConversation.AiC
|
|
|
313
323
|
} else if (conversation?.type === AiAssistanceModel.AiHistoryStorage.ConversationType.PERFORMANCE) {
|
|
314
324
|
// Handle historical conversations (can't linkify anything).
|
|
315
325
|
return new PerformanceAgentMarkdownRenderer();
|
|
326
|
+
} else if (
|
|
327
|
+
Greendev.Prototypes.instance().isEnabled('emulationCapabilities') &&
|
|
328
|
+
conversation?.type === AiAssistanceModel.AiHistoryStorage.ConversationType.STYLING &&
|
|
329
|
+
SDK.TargetManager.TargetManager.instance().primaryPageTarget()?.model(SDK.DOMModel.DOMModel)) {
|
|
330
|
+
const domModel = SDK.TargetManager.TargetManager.instance().primaryPageTarget()?.model(SDK.DOMModel.DOMModel);
|
|
331
|
+
const resourceTreeModel = domModel?.target().model(SDK.ResourceTreeModel.ResourceTreeModel);
|
|
332
|
+
const mainFrameId = resourceTreeModel?.mainFrame?.id;
|
|
333
|
+
return new StylingAgentMarkdownRenderer(mainFrameId);
|
|
316
334
|
}
|
|
317
335
|
|
|
318
336
|
return new MarkdownRendererWithCodeBlock();
|
|
@@ -602,12 +620,6 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
602
620
|
#isLoading = false;
|
|
603
621
|
// Stores the availability status of the `AidaClient` and the reason for unavailability, if any.
|
|
604
622
|
#aidaAvailability: Host.AidaClient.AidaAccessPreconditions;
|
|
605
|
-
// Info of the currently logged in user.
|
|
606
|
-
#userInfo: {
|
|
607
|
-
accountImage?: string,
|
|
608
|
-
accountFullName?: string,
|
|
609
|
-
accountGivenName?: string,
|
|
610
|
-
};
|
|
611
623
|
#timelinePanelInstance: TimelinePanel.TimelinePanel.TimelinePanel|null = null;
|
|
612
624
|
#runAbortController = new AbortController();
|
|
613
625
|
#walkthrough: WalkthroughState = {
|
|
@@ -616,10 +628,9 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
616
628
|
activeMessage: null,
|
|
617
629
|
};
|
|
618
630
|
|
|
619
|
-
constructor(private view: View = defaultView, {aidaClient, aidaAvailability
|
|
631
|
+
constructor(private view: View = defaultView, {aidaClient, aidaAvailability}: {
|
|
620
632
|
aidaClient: Host.AidaClient.AidaClient,
|
|
621
633
|
aidaAvailability: Host.AidaClient.AidaAccessPreconditions,
|
|
622
|
-
syncInfo: Host.InspectorFrontendHostAPI.SyncInformation,
|
|
623
634
|
}) {
|
|
624
635
|
super(AiAssistancePanel.panelName);
|
|
625
636
|
this.registerRequiredCSS(aiAssistancePanelStyles);
|
|
@@ -627,11 +638,6 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
627
638
|
|
|
628
639
|
this.#aidaClient = aidaClient;
|
|
629
640
|
this.#aidaAvailability = aidaAvailability;
|
|
630
|
-
this.#userInfo = {
|
|
631
|
-
accountImage: syncInfo.accountImage,
|
|
632
|
-
accountFullName: syncInfo.accountFullName,
|
|
633
|
-
accountGivenName: syncInfo.accountGivenName,
|
|
634
|
-
};
|
|
635
641
|
|
|
636
642
|
if (UI.ActionRegistry.ActionRegistry.instance().hasAction('elements.toggle-element-search')) {
|
|
637
643
|
this.#toggleSearchElementAction =
|
|
@@ -706,7 +712,6 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
706
712
|
isReadOnly: this.#conversation.isReadOnly ?? false,
|
|
707
713
|
changeSummary: this.#getChangeSummary(),
|
|
708
714
|
inspectElementToggled: this.#toggleSearchElementAction?.toggled() ?? false,
|
|
709
|
-
userInfo: this.#userInfo,
|
|
710
715
|
canShowFeedbackForm: this.#serverSideLoggingEnabled,
|
|
711
716
|
multimodalInputEnabled: isAiAssistanceMultimodalInputEnabled() &&
|
|
712
717
|
this.#conversation.type === AiAssistanceModel.AiHistoryStorage.ConversationType.STYLING,
|
|
@@ -792,11 +797,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
792
797
|
const {forceNew} = opts;
|
|
793
798
|
if (!panelInstance || forceNew) {
|
|
794
799
|
const aidaClient = new Host.AidaClient.AidaClient();
|
|
795
|
-
const
|
|
796
|
-
|
|
797
|
-
const [aidaAvailability, syncInfo] =
|
|
798
|
-
await Promise.all([Host.AidaClient.AidaClient.checkAccessPreconditions(), syncInfoPromise]);
|
|
799
|
-
panelInstance = new AiAssistancePanel(defaultView, {aidaClient, aidaAvailability, syncInfo});
|
|
800
|
+
const aidaAvailability = await Host.AidaClient.AidaClient.checkAccessPreconditions();
|
|
801
|
+
panelInstance = new AiAssistancePanel(defaultView, {aidaClient, aidaAvailability});
|
|
800
802
|
}
|
|
801
803
|
|
|
802
804
|
return panelInstance;
|
|
@@ -1059,13 +1061,6 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1059
1061
|
const currentAidaAvailability = await Host.AidaClient.AidaClient.checkAccessPreconditions();
|
|
1060
1062
|
if (currentAidaAvailability !== this.#aidaAvailability) {
|
|
1061
1063
|
this.#aidaAvailability = currentAidaAvailability;
|
|
1062
|
-
const syncInfo = await new Promise<Host.InspectorFrontendHostAPI.SyncInformation>(
|
|
1063
|
-
resolve => Host.InspectorFrontendHost.InspectorFrontendHostInstance.getSyncInformation(resolve));
|
|
1064
|
-
this.#userInfo = {
|
|
1065
|
-
accountImage: syncInfo.accountImage,
|
|
1066
|
-
accountFullName: syncInfo.accountFullName,
|
|
1067
|
-
accountGivenName: syncInfo.accountGivenName,
|
|
1068
|
-
};
|
|
1069
1064
|
this.requestUpdate();
|
|
1070
1065
|
}
|
|
1071
1066
|
};
|
|
@@ -1635,12 +1630,19 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1635
1630
|
if (this.#conversation.isEmpty) {
|
|
1636
1631
|
Badges.UserBadges.instance().recordAction(Badges.BadgeAction.STARTED_AI_CONVERSATION);
|
|
1637
1632
|
}
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1633
|
+
|
|
1634
|
+
const greenDevEmulationEnabled = Greendev.Prototypes.instance().isEnabled('emulationCapabilities');
|
|
1635
|
+
let multimodalInput: AiAssistanceModel.AiAgent.MultimodalInput|undefined;
|
|
1636
|
+
const pendingInput = this.#conversation.getPendingMultimodalInput();
|
|
1637
|
+
if (greenDevEmulationEnabled && pendingInput) {
|
|
1638
|
+
multimodalInput = pendingInput;
|
|
1639
|
+
} else if (isAiAssistanceMultimodalInputEnabled() && imageInput && multimodalInputType) {
|
|
1640
|
+
multimodalInput = {
|
|
1641
|
+
input: imageInput,
|
|
1642
|
+
id: crypto.randomUUID(),
|
|
1643
|
+
type: multimodalInputType,
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1644
1646
|
|
|
1645
1647
|
void VisualLogging.logFunctionCall(`start-conversation-${this.#conversation.type}`, 'ui');
|
|
1646
1648
|
|
|
@@ -1697,8 +1699,14 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1697
1699
|
parts: [],
|
|
1698
1700
|
};
|
|
1699
1701
|
this.#messages.push(systemMessage);
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
+
// If the walkthrough is currently expanded in the sidebar, we want to
|
|
1703
|
+
// automatically swap it to the newly created message's walkthrough.
|
|
1704
|
+
// This ensures that when a user asks a new question, the sidebar updates
|
|
1705
|
+
// immediately to show the "loading" state of the new walkthrough.
|
|
1706
|
+
const isSidebarWalkthroughOpen = this.#walkthrough.isExpanded && !this.#walkthrough.isInlined;
|
|
1707
|
+
if (isSidebarWalkthroughOpen ||
|
|
1708
|
+
(Greendev.Prototypes.instance().isEnabled('breakpointDebuggerAgent') &&
|
|
1709
|
+
this.#conversation?.type === AiAssistanceModel.AiHistoryStorage.ConversationType.BREAKPOINT)) {
|
|
1702
1710
|
this.#openWalkthrough(systemMessage);
|
|
1703
1711
|
}
|
|
1704
1712
|
break;
|
|
@@ -1786,6 +1794,13 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1786
1794
|
systemMessage.parts.push(newPart);
|
|
1787
1795
|
}
|
|
1788
1796
|
|
|
1797
|
+
if (data.widgets && Root.Runtime.hostConfig.devToolsAiAssistanceV2?.enabled) {
|
|
1798
|
+
systemMessage.parts.push({
|
|
1799
|
+
type: 'widget',
|
|
1800
|
+
widgets: data.widgets,
|
|
1801
|
+
});
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1789
1804
|
// When there is an answer without any thinking steps, we don't want to show the thinking step.
|
|
1790
1805
|
// TODO(crbug.com/463323934): Remove specially handling this case.
|
|
1791
1806
|
if (systemMessage.parts.length > 1) {
|
|
@@ -1879,7 +1894,7 @@ export function getResponseMarkdown(message: ModelChatMessage): string {
|
|
|
1879
1894
|
for (const part of message.parts) {
|
|
1880
1895
|
if (part.type === 'answer') {
|
|
1881
1896
|
contentParts.push(`### Answer\n\n${part.text}`);
|
|
1882
|
-
} else {
|
|
1897
|
+
} else if (part.type === 'step') {
|
|
1883
1898
|
const step = part.step;
|
|
1884
1899
|
if (step.title) {
|
|
1885
1900
|
contentParts.push(`### ${step.title}`);
|
|
@@ -125,6 +125,7 @@ const UIStringsNotTranslate = {
|
|
|
125
125
|
const lockedString = i18n.i18n.lockedString;
|
|
126
126
|
|
|
127
127
|
const CODE_SNIPPET_WARNING_URL = 'https://support.google.com/legal/answer/13505487';
|
|
128
|
+
const {widget} = UI.Widget;
|
|
128
129
|
|
|
129
130
|
export enum PatchSuggestionState {
|
|
130
131
|
/**
|
|
@@ -251,12 +252,11 @@ const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
251
252
|
}
|
|
252
253
|
|
|
253
254
|
if (input.patchSuggestionState === PatchSuggestionState.SUCCESS) {
|
|
254
|
-
return html
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
})}></devtools-widget>`;
|
|
255
|
+
return html`${widget(ChangesPanel.CombinedDiffView.CombinedDiffView, {
|
|
256
|
+
workspaceDiff: input.workspaceDiff,
|
|
257
|
+
// Ignore user creates inspector-stylesheets
|
|
258
|
+
ignoredUrls: ['inspector://']
|
|
259
|
+
})}`;
|
|
260
260
|
}
|
|
261
261
|
|
|
262
262
|
return html`<devtools-code-block
|