chrome-devtools-frontend 1.0.1544076 → 1.0.1547147
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/config/typescript/tsconfig.eslint.json +1 -0
- package/docs/styleguide/ux/styles.md +1 -1
- package/eslint.config.mjs +1 -1
- package/front_end/Images/src/arrow-down.svg +8 -1
- package/front_end/Images/src/arrow-up.svg +8 -1
- package/front_end/core/common/ParsedURL.ts +1 -1
- package/front_end/core/common/common.ts +0 -2
- package/front_end/core/host/AidaClient.ts +1 -1
- package/front_end/core/host/InspectorFrontendHostAPI.ts +0 -1
- package/front_end/core/host/UserMetrics.ts +0 -5
- package/front_end/core/platform/HostRuntime.ts +18 -0
- package/front_end/core/platform/KeyboardUtilities.ts +2 -2
- package/front_end/core/platform/StringUtilities.ts +1 -1
- package/front_end/core/platform/api/HostRuntime.ts +20 -0
- package/front_end/core/platform/api/api.ts +7 -0
- package/front_end/core/platform/browser/HostRuntime.ts +14 -0
- package/front_end/core/platform/browser/browser.ts +7 -0
- package/front_end/core/platform/node/HostRuntime.ts +13 -0
- package/front_end/core/platform/node/node.ts +7 -0
- package/front_end/core/platform/platform.ts +2 -2
- package/front_end/core/protocol_client/CDPConnection.ts +3 -3
- package/front_end/core/protocol_client/DevToolsCDPConnection.ts +2 -1
- package/front_end/core/sdk/CSSMetadata.ts +17 -5
- package/front_end/core/sdk/NetworkManager.ts +6 -8
- package/front_end/core/sdk/NetworkRequest.ts +4 -0
- package/front_end/core/sdk/SDKModel.ts +4 -2
- package/front_end/core/sdk/SourceMapScopesInfo.ts +141 -23
- package/front_end/core/sdk/Target.ts +5 -14
- package/front_end/core/sdk/TargetManager.ts +39 -18
- package/front_end/core/sdk/sdk-meta.ts +62 -0
- package/front_end/devtools_compatibility.js +0 -1
- package/front_end/entrypoints/main/MainImpl.ts +2 -2
- package/front_end/foundation/Universe.ts +2 -2
- package/front_end/generated/Deprecation.ts +11 -0
- package/front_end/generated/InspectorBackendCommands.ts +3 -6
- package/front_end/generated/SupportedCSSProperties.js +4 -25
- package/front_end/generated/protocol-mapping.d.ts +0 -15
- package/front_end/generated/protocol-proxy-api.d.ts +0 -11
- package/front_end/generated/protocol.ts +5 -36
- package/front_end/models/ai_assistance/AiConversation.ts +188 -0
- package/front_end/models/ai_assistance/AiHistoryStorage.ts +1 -172
- package/front_end/models/ai_assistance/ConversationHandler.ts +5 -5
- package/front_end/models/ai_assistance/agents/AiAgent.ts +1 -3
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +6 -2
- package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +1 -1
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +3 -9
- package/front_end/models/ai_assistance/ai_assistance.ts +2 -0
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +313 -313
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +8 -6
- package/front_end/models/ai_assistance/performance/AICallTree.snapshot.txt +33 -33
- package/front_end/models/ai_assistance/performance/AICallTree.ts +9 -3
- package/front_end/models/bindings/CSSWorkspaceBinding.ts +5 -3
- package/front_end/models/bindings/SASSSourceMapping.ts +6 -4
- package/front_end/models/cpu_profile/CPUProfileDataModel.ts +10 -7
- package/front_end/models/crux-manager/CrUXManager.ts +7 -4
- package/front_end/models/issues_manager/GenericIssue.ts +12 -9
- package/front_end/models/javascript_metadata/NativeFunctions.js +4 -0
- package/front_end/models/trace/handlers/SamplesHandler.ts +3 -0
- package/front_end/models/trace/helpers/Trace.ts +13 -0
- package/front_end/models/trace/types/TraceEvents.ts +2 -1
- package/front_end/models/trace_source_maps_resolver/SourceMapsResolver.ts +29 -0
- package/front_end/models/workspace/IgnoreListManager.ts +1 -2
- package/front_end/models/workspace/UISourceCode.ts +50 -0
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +11 -10
- package/front_end/panels/ai_assistance/ai_assistance-meta.ts +8 -0
- package/front_end/panels/ai_assistance/components/ChatView.ts +2 -2
- package/front_end/panels/ai_assistance/components/UserActionRow.ts +2 -1
- package/front_end/panels/animation/AnimationTimeline.ts +0 -8
- package/front_end/panels/application/ApplicationPanelSidebar.ts +6 -7
- package/front_end/panels/application/{components/FrameDetailsView.ts → FrameDetailsView.ts} +140 -171
- package/front_end/panels/application/{components/OriginTrialTreeView.ts → OriginTrialTreeView.ts} +9 -9
- package/front_end/panels/application/application.ts +4 -0
- package/front_end/panels/application/components/StackTrace.ts +89 -88
- package/front_end/panels/application/components/components.ts +2 -4
- package/front_end/panels/application/{components/frameDetailsReportView.css → frameDetailsReportView.css} +5 -1
- package/front_end/panels/common/AiCodeGenerationTeaser.ts +80 -0
- package/front_end/panels/common/BadgeNotification.ts +2 -1
- package/front_end/panels/common/DOMLinkifier.ts +7 -2
- package/front_end/panels/common/GdpSignUpDialog.ts +2 -1
- package/front_end/panels/common/common.ts +2 -1
- package/front_end/panels/console/ConsolePrompt.ts +3 -1
- package/front_end/panels/console/ConsoleViewport.ts +1 -2
- package/front_end/panels/elements/ElementIssueUtils.ts +2 -2
- package/front_end/panels/elements/ElementStatePaneWidget.ts +2 -1
- package/front_end/panels/elements/StylePropertiesSection.ts +1 -1
- package/front_end/panels/elements/StylePropertyTreeElement.ts +23 -19
- package/front_end/panels/elements/StylesSidebarPane.ts +1 -1
- package/front_end/panels/elements/cssValueTraceView.css +1 -1
- package/front_end/panels/elements/elements-meta.ts +1 -22
- package/front_end/panels/explain/components/ConsoleInsight.ts +44 -57
- package/front_end/panels/explain/components/consoleInsight.css +46 -1
- package/front_end/panels/layer_viewer/LayerTreeOutline.ts +1 -2
- package/front_end/panels/lighthouse/LighthouseProtocolService.ts +3 -6
- package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +19 -0
- package/front_end/panels/network/RequestConditionsDrawer.ts +54 -24
- package/front_end/panels/network/networkLogView.css +11 -0
- package/front_end/panels/network/networkTimingTable.css +8 -6
- package/front_end/panels/network/requestConditionsDrawer.css +10 -1
- package/front_end/panels/profiler/ProfilesPanel.ts +1 -2
- package/front_end/panels/settings/FrameworkIgnoreListSettingsTab.ts +2 -1
- package/front_end/panels/settings/KeybindsSettingsTab.ts +20 -21
- package/front_end/panels/settings/SettingsScreen.ts +3 -2
- package/front_end/panels/sources/CoveragePlugin.ts +5 -5
- package/front_end/panels/sources/Plugin.ts +1 -1
- package/front_end/panels/sources/ProfilePlugin.ts +22 -14
- package/front_end/panels/sources/UISourceCodeFrame.ts +2 -1
- package/front_end/panels/sources/sources-meta.ts +0 -62
- package/front_end/panels/timeline/README.md +1 -9
- package/front_end/panels/timeline/ThreadAppender.ts +0 -7
- package/front_end/panels/timeline/TimelinePanel.ts +1 -1
- package/front_end/panels/timeline/TimelineUIUtils.ts +2 -0
- package/front_end/panels/timeline/components/ExportTraceOptions.ts +15 -1
- package/front_end/panels/timeline/components/LiveMetricsView.ts +51 -6
- package/front_end/panels/timeline/components/MetricCard.ts +2 -2
- package/front_end/panels/timeline/components/exportTraceOptions.css +11 -2
- package/front_end/panels/timeline/components/insights/NodeLink.ts +2 -3
- package/front_end/panels/timeline/overlays/components/EntryLabelOverlay.ts +2 -1
- package/front_end/panels/timeline/timeline-meta.ts +0 -10
- package/front_end/panels/timeline/timeline.ts +0 -2
- package/front_end/panels/whats_new/ReleaseNoteView.ts +2 -1
- package/front_end/panels/whats_new/WhatsNewImpl.ts +3 -2
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/tsconfig.json +1 -0
- package/front_end/ui/components/buttons/Button.docs.ts +6 -5
- package/front_end/ui/components/markdown_view/MarkdownLinksMap.ts +1 -0
- package/front_end/ui/components/snackbars/Snackbars.docs.ts +1 -1
- package/front_end/ui/components/spinners/Spinners.docs.ts +1 -1
- package/front_end/ui/components/survey_link/SurveyLink.docs.ts +2 -1
- package/front_end/ui/components/switch/Switch.docs.ts +1 -1
- package/front_end/ui/components/tooltips/Tooltip.docs.ts +3 -3
- package/front_end/ui/helpers/OpenInNewTab.ts +87 -0
- package/front_end/ui/helpers/helpers.ts +5 -0
- package/front_end/ui/legacy/ARIAUtils.ts +2 -2
- package/front_end/ui/legacy/ActionRegistration.ts +11 -0
- package/front_end/ui/legacy/ContextMenu.docs.ts +12 -11
- package/front_end/ui/legacy/RadioButton.docs.ts +1 -1
- package/front_end/ui/legacy/SelectMenu.docs.ts +1 -1
- package/front_end/ui/legacy/Slider.docs.ts +1 -1
- package/front_end/ui/legacy/SoftDropDown.ts +2 -2
- package/front_end/ui/legacy/TextPrompt.ts +3 -2
- package/front_end/ui/legacy/Treeoutline.ts +2 -1
- package/front_end/ui/legacy/UIUtils.ts +11 -43
- package/front_end/ui/legacy/Widget.ts +3 -2
- package/front_end/ui/legacy/XLink.ts +4 -4
- package/front_end/ui/legacy/components/color_picker/ContrastDetails.ts +2 -1
- package/front_end/ui/legacy/components/data_grid/DataGrid.ts +2 -2
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +144 -143
- package/front_end/ui/legacy/components/perf_ui/LineLevelProfile.ts +62 -39
- package/front_end/ui/legacy/components/perf_ui/OverviewGrid.ts +1 -1
- package/front_end/ui/legacy/components/perf_ui/TimelineGrid.ts +2 -2
- package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +2 -7
- package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +1 -2
- package/front_end/ui/legacy/components/utils/Linkifier.ts +2 -1
- package/front_end/ui/legacy/inspectorCommon.css +2 -2
- package/front_end/ui/legacy/legacy.ts +2 -0
- package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
- package/mcp/tsconfig.json +16 -0
- package/package.json +2 -2
- package/front_end/core/common/Linkifier.ts +0 -55
- package/front_end/panels/explain/components/consoleInsightSourcesList.css +0 -51
- package/front_end/panels/timeline/CLSLinkifier.ts +0 -58
- package/front_end/ui/components/docs/README.md +0 -6
- package/front_end/ui/components/docs/building-ui-documentation/ComponentEvents.md +0 -54
- package/front_end/ui/components/docs/building-ui-documentation/ComponentPerformance.md +0 -136
- package/front_end/ui/components/docs/building-ui-documentation/CreatingComponents.md +0 -242
- package/front_end/ui/components/docs/building-ui-documentation/README.md +0 -23
- package/front_end/ui/components/docs/building-ui-documentation/StylingComponents.md +0 -66
- package/front_end/ui/components/docs/building-ui-documentation/TestingComponents.md +0 -111
- package/front_end/ui/components/docs/component_docs.ts +0 -24
- package/front_end/ui/components/docs/component_docs_styles.css +0 -53
- package/front_end/ui/components/docs/create_breadcrumbs.ts +0 -44
- package/front_end/ui/components/docs/slider/basic.html +0 -20
- package/front_end/ui/components/docs/switch/basic.html +0 -20
- /package/front_end/models/issues_manager/descriptions/{genericFormAriaLabelledByToNonExistingId.md → genericFormAriaLabelledByToNonExistingIdError.md} +0 -0
- /package/front_end/models/issues_manager/descriptions/{genericFormLabelHasNeitherForNorNestedInput.md → genericFormLabelHasNeitherForNorNestedInputError.md} +0 -0
- /package/front_end/panels/application/{components/originTrialTokenRows.css → originTrialTokenRows.css} +0 -0
- /package/front_end/panels/application/{components/originTrialTreeView.css → originTrialTreeView.css} +0 -0
- /package/front_end/{core/platform → ui/legacy}/DOMUtilities.ts +0 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// Copyright 2024 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 {type ContextDetail, type ResponseData, ResponseType} from './agents/AiAgent.js';
|
|
6
|
+
import {AiHistoryStorage, type ConversationType, type SerializedConversation} from './AiHistoryStorage.js';
|
|
7
|
+
|
|
8
|
+
export const NOT_FOUND_IMAGE_DATA = '';
|
|
9
|
+
const MAX_TITLE_LENGTH = 80;
|
|
10
|
+
|
|
11
|
+
export class AiConversation {
|
|
12
|
+
readonly id: string;
|
|
13
|
+
type: ConversationType;
|
|
14
|
+
#isReadOnly: boolean;
|
|
15
|
+
readonly history: ResponseData[];
|
|
16
|
+
#isExternal: boolean;
|
|
17
|
+
|
|
18
|
+
static generateContextDetailsMarkdown(details: ContextDetail[]): string {
|
|
19
|
+
const detailsMarkdown: string[] = [];
|
|
20
|
+
for (const detail of details) {
|
|
21
|
+
const text = `\`\`\`\`${detail.codeLang || ''}\n${detail.text.trim()}\n\`\`\`\``;
|
|
22
|
+
detailsMarkdown.push(`**${detail.title}:**\n${text}`);
|
|
23
|
+
}
|
|
24
|
+
return detailsMarkdown.join('\n\n');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
constructor(
|
|
28
|
+
type: ConversationType,
|
|
29
|
+
data: ResponseData[] = [],
|
|
30
|
+
id: string = crypto.randomUUID(),
|
|
31
|
+
isReadOnly = true,
|
|
32
|
+
isExternal = false,
|
|
33
|
+
) {
|
|
34
|
+
this.type = type;
|
|
35
|
+
this.id = id;
|
|
36
|
+
this.#isReadOnly = isReadOnly;
|
|
37
|
+
this.#isExternal = isExternal;
|
|
38
|
+
this.history = this.#reconstructHistory(data);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get isReadOnly(): boolean {
|
|
42
|
+
return this.#isReadOnly;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get title(): string|undefined {
|
|
46
|
+
const query = this.history.find(response => response.type === ResponseType.USER_QUERY)?.query;
|
|
47
|
+
|
|
48
|
+
if (!query) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (this.#isExternal) {
|
|
53
|
+
return `[External] ${query.substring(0, MAX_TITLE_LENGTH - 11)}${
|
|
54
|
+
query.length > MAX_TITLE_LENGTH - 11 ? '…' : ''}`;
|
|
55
|
+
}
|
|
56
|
+
return `${query.substring(0, MAX_TITLE_LENGTH)}${query.length > MAX_TITLE_LENGTH ? '…' : ''}`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get isEmpty(): boolean {
|
|
60
|
+
return this.history.length === 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
#reconstructHistory(historyWithoutImages: ResponseData[]): ResponseData[] {
|
|
64
|
+
const imageHistory = AiHistoryStorage.instance().getImageHistory();
|
|
65
|
+
if (imageHistory && imageHistory.length > 0) {
|
|
66
|
+
const history: ResponseData[] = [];
|
|
67
|
+
for (const data of historyWithoutImages) {
|
|
68
|
+
if (data.type === ResponseType.USER_QUERY && data.imageId) {
|
|
69
|
+
const image = imageHistory.find(item => item.id === data.imageId);
|
|
70
|
+
const inlineData = image ? {data: image.data, mimeType: image.mimeType} :
|
|
71
|
+
{data: NOT_FOUND_IMAGE_DATA, mimeType: 'image/jpeg'};
|
|
72
|
+
history.push({...data, imageInput: {inlineData}});
|
|
73
|
+
} else {
|
|
74
|
+
history.push(data);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return history;
|
|
78
|
+
}
|
|
79
|
+
return historyWithoutImages;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
getConversationMarkdown(): string {
|
|
83
|
+
const contentParts: string[] = [];
|
|
84
|
+
contentParts.push(
|
|
85
|
+
'# Exported Chat from Chrome DevTools AI Assistance\n\n' +
|
|
86
|
+
`**Export Timestamp (UTC):** ${new Date().toISOString()}\n\n` +
|
|
87
|
+
'---',
|
|
88
|
+
);
|
|
89
|
+
for (const item of this.history) {
|
|
90
|
+
switch (item.type) {
|
|
91
|
+
case ResponseType.USER_QUERY: {
|
|
92
|
+
contentParts.push(`## User\n\n${item.query}`);
|
|
93
|
+
if (item.imageInput) {
|
|
94
|
+
contentParts.push('User attached an image');
|
|
95
|
+
}
|
|
96
|
+
contentParts.push('## AI');
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
case ResponseType.CONTEXT: {
|
|
100
|
+
contentParts.push(`### ${item.title}`);
|
|
101
|
+
if (item.details && item.details.length > 0) {
|
|
102
|
+
contentParts.push(AiConversation.generateContextDetailsMarkdown(item.details));
|
|
103
|
+
}
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
case ResponseType.TITLE: {
|
|
107
|
+
contentParts.push(`### ${item.title}`);
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
case ResponseType.THOUGHT: {
|
|
111
|
+
contentParts.push(`${item.thought}`);
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
case ResponseType.ACTION: {
|
|
115
|
+
// We want to export only actions with output field
|
|
116
|
+
if (!item.output) {
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
if (item.code) {
|
|
120
|
+
contentParts.push(`**Code executed:**\n\`\`\`\n${item.code.trim()}\n\`\`\``);
|
|
121
|
+
}
|
|
122
|
+
contentParts.push(`**Data returned:**\n\`\`\`\n${item.output}\n\`\`\``);
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
case ResponseType.ANSWER: {
|
|
126
|
+
if (item.complete) {
|
|
127
|
+
contentParts.push(`### Answer\n\n${item.text.trim()}`);
|
|
128
|
+
}
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return contentParts.join('\n\n');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
archiveConversation(): void {
|
|
137
|
+
this.#isReadOnly = true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async addHistoryItem(item: ResponseData): Promise<void> {
|
|
141
|
+
this.history.push(item);
|
|
142
|
+
await AiHistoryStorage.instance().upsertHistoryEntry(this.serialize());
|
|
143
|
+
if (item.type === ResponseType.USER_QUERY) {
|
|
144
|
+
if (item.imageId && item.imageInput && 'inlineData' in item.imageInput) {
|
|
145
|
+
const inlineData = item.imageInput.inlineData;
|
|
146
|
+
await AiHistoryStorage.instance().upsertImage({
|
|
147
|
+
id: item.imageId,
|
|
148
|
+
data: inlineData.data,
|
|
149
|
+
mimeType: inlineData.mimeType,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
serialize(): SerializedConversation {
|
|
156
|
+
return {
|
|
157
|
+
id: this.id,
|
|
158
|
+
history: this.history.map(item => {
|
|
159
|
+
if (item.type === ResponseType.USER_QUERY) {
|
|
160
|
+
return {...item, imageInput: undefined};
|
|
161
|
+
}
|
|
162
|
+
// Remove the `confirm()`-function because `structuredClone()` throws on functions
|
|
163
|
+
if (item.type === ResponseType.SIDE_EFFECT) {
|
|
164
|
+
return {...item, confirm: undefined};
|
|
165
|
+
}
|
|
166
|
+
return item;
|
|
167
|
+
}),
|
|
168
|
+
type: this.type,
|
|
169
|
+
isExternal: this.#isExternal,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
static fromSerializedConversation(serializedConversation: SerializedConversation): AiConversation {
|
|
174
|
+
const history = serializedConversation.history.map(entry => {
|
|
175
|
+
if (entry.type === ResponseType.SIDE_EFFECT) {
|
|
176
|
+
return {...entry, confirm: () => {}};
|
|
177
|
+
}
|
|
178
|
+
return entry;
|
|
179
|
+
});
|
|
180
|
+
return new AiConversation(
|
|
181
|
+
serializedConversation.type,
|
|
182
|
+
history,
|
|
183
|
+
serializedConversation.id,
|
|
184
|
+
true,
|
|
185
|
+
serializedConversation.isExternal,
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
@@ -5,9 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import * as Common from '../../core/common/common.js';
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
const MAX_TITLE_LENGTH = 80;
|
|
8
|
+
import {ResponseType, type SerializedResponseData} from './agents/AiAgent.js';
|
|
11
9
|
|
|
12
10
|
export const enum ConversationType {
|
|
13
11
|
STYLING = 'freestyler',
|
|
@@ -16,8 +14,6 @@ export const enum ConversationType {
|
|
|
16
14
|
PERFORMANCE = 'drjones-performance-full',
|
|
17
15
|
}
|
|
18
16
|
|
|
19
|
-
export const NOT_FOUND_IMAGE_DATA = '';
|
|
20
|
-
|
|
21
17
|
export interface SerializedConversation {
|
|
22
18
|
id: string;
|
|
23
19
|
type: ConversationType;
|
|
@@ -35,173 +31,6 @@ export interface SerializedImage {
|
|
|
35
31
|
data: string;
|
|
36
32
|
}
|
|
37
33
|
|
|
38
|
-
export class Conversation {
|
|
39
|
-
readonly id: string;
|
|
40
|
-
readonly type: ConversationType;
|
|
41
|
-
#isReadOnly: boolean;
|
|
42
|
-
readonly history: ResponseData[];
|
|
43
|
-
#isExternal: boolean;
|
|
44
|
-
|
|
45
|
-
static generateContextDetailsMarkdown(details: ContextDetail[]): string {
|
|
46
|
-
const detailsMarkdown: string[] = [];
|
|
47
|
-
for (const detail of details) {
|
|
48
|
-
const text = `\`\`\`\`${detail.codeLang || ''}\n${detail.text.trim()}\n\`\`\`\``;
|
|
49
|
-
detailsMarkdown.push(`**${detail.title}:**\n${text}`);
|
|
50
|
-
}
|
|
51
|
-
return detailsMarkdown.join('\n\n');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
constructor(
|
|
55
|
-
type: ConversationType, data: ResponseData[] = [], id: string = crypto.randomUUID(), isReadOnly = true,
|
|
56
|
-
isExternal = false) {
|
|
57
|
-
this.type = type;
|
|
58
|
-
this.id = id;
|
|
59
|
-
this.#isReadOnly = isReadOnly;
|
|
60
|
-
this.#isExternal = isExternal;
|
|
61
|
-
this.history = this.#reconstructHistory(data);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
get isReadOnly(): boolean {
|
|
65
|
-
return this.#isReadOnly;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
get title(): string|undefined {
|
|
69
|
-
const query = this.history.find(response => response.type === ResponseType.USER_QUERY)?.query;
|
|
70
|
-
|
|
71
|
-
if (!query) {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (this.#isExternal) {
|
|
76
|
-
return `[External] ${query.substring(0, MAX_TITLE_LENGTH - 11)}${
|
|
77
|
-
query.length > MAX_TITLE_LENGTH - 11 ? '…' : ''}`;
|
|
78
|
-
}
|
|
79
|
-
return `${query.substring(0, MAX_TITLE_LENGTH)}${query.length > MAX_TITLE_LENGTH ? '…' : ''}`;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
get isEmpty(): boolean {
|
|
83
|
-
return this.history.length === 0;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
#reconstructHistory(historyWithoutImages: ResponseData[]): ResponseData[] {
|
|
87
|
-
const imageHistory = AiHistoryStorage.instance().getImageHistory();
|
|
88
|
-
if (imageHistory && imageHistory.length > 0) {
|
|
89
|
-
const history: ResponseData[] = [];
|
|
90
|
-
for (const data of historyWithoutImages) {
|
|
91
|
-
if (data.type === ResponseType.USER_QUERY && data.imageId) {
|
|
92
|
-
const image = imageHistory.find(item => item.id === data.imageId);
|
|
93
|
-
const inlineData = image ? {data: image.data, mimeType: image.mimeType} :
|
|
94
|
-
{data: NOT_FOUND_IMAGE_DATA, mimeType: 'image/jpeg'};
|
|
95
|
-
history.push({...data, imageInput: {inlineData}});
|
|
96
|
-
} else {
|
|
97
|
-
history.push(data);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return history;
|
|
101
|
-
}
|
|
102
|
-
return historyWithoutImages;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
getConversationMarkdown(): string {
|
|
106
|
-
const contentParts: string[] = [];
|
|
107
|
-
contentParts.push(
|
|
108
|
-
'# Exported Chat from Chrome DevTools AI Assistance\n\n' +
|
|
109
|
-
`**Export Timestamp (UTC):** ${new Date().toISOString()}\n\n` +
|
|
110
|
-
'---',
|
|
111
|
-
);
|
|
112
|
-
for (const item of this.history) {
|
|
113
|
-
switch (item.type) {
|
|
114
|
-
case ResponseType.USER_QUERY: {
|
|
115
|
-
contentParts.push(`## User\n\n${item.query}`);
|
|
116
|
-
if (item.imageInput) {
|
|
117
|
-
contentParts.push('User attached an image');
|
|
118
|
-
}
|
|
119
|
-
contentParts.push('## AI');
|
|
120
|
-
break;
|
|
121
|
-
}
|
|
122
|
-
case ResponseType.CONTEXT: {
|
|
123
|
-
contentParts.push(`### ${item.title}`);
|
|
124
|
-
if (item.details && item.details.length > 0) {
|
|
125
|
-
contentParts.push(Conversation.generateContextDetailsMarkdown(item.details));
|
|
126
|
-
}
|
|
127
|
-
break;
|
|
128
|
-
}
|
|
129
|
-
case ResponseType.TITLE: {
|
|
130
|
-
contentParts.push(`### ${item.title}`);
|
|
131
|
-
break;
|
|
132
|
-
}
|
|
133
|
-
case ResponseType.THOUGHT: {
|
|
134
|
-
contentParts.push(`${item.thought}`);
|
|
135
|
-
break;
|
|
136
|
-
}
|
|
137
|
-
case ResponseType.ACTION: {
|
|
138
|
-
// We want to export only actions with output field
|
|
139
|
-
if (!item.output) {
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
142
|
-
if (item.code) {
|
|
143
|
-
contentParts.push(`**Code executed:**\n\`\`\`\n${item.code.trim()}\n\`\`\``);
|
|
144
|
-
}
|
|
145
|
-
contentParts.push(`**Data returned:**\n\`\`\`\n${item.output}\n\`\`\``);
|
|
146
|
-
break;
|
|
147
|
-
}
|
|
148
|
-
case ResponseType.ANSWER: {
|
|
149
|
-
if (item.complete) {
|
|
150
|
-
contentParts.push(`### Answer\n\n${item.text.trim()}`);
|
|
151
|
-
}
|
|
152
|
-
break;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
return contentParts.join('\n\n');
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
archiveConversation(): void {
|
|
160
|
-
this.#isReadOnly = true;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
async addHistoryItem(item: ResponseData): Promise<void> {
|
|
164
|
-
this.history.push(item);
|
|
165
|
-
await AiHistoryStorage.instance().upsertHistoryEntry(this.serialize());
|
|
166
|
-
if (item.type === ResponseType.USER_QUERY) {
|
|
167
|
-
if (item.imageId && item.imageInput && 'inlineData' in item.imageInput) {
|
|
168
|
-
const inlineData = item.imageInput.inlineData;
|
|
169
|
-
await AiHistoryStorage.instance().upsertImage(
|
|
170
|
-
{id: item.imageId, data: inlineData.data, mimeType: inlineData.mimeType});
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
serialize(): SerializedConversation {
|
|
176
|
-
return {
|
|
177
|
-
id: this.id,
|
|
178
|
-
history: this.history.map(item => {
|
|
179
|
-
if (item.type === ResponseType.USER_QUERY) {
|
|
180
|
-
return {...item, imageInput: undefined};
|
|
181
|
-
}
|
|
182
|
-
// Remove the `confirm()`-function because `structuredClone()` throws on functions
|
|
183
|
-
if (item.type === ResponseType.SIDE_EFFECT) {
|
|
184
|
-
return {...item, confirm: undefined};
|
|
185
|
-
}
|
|
186
|
-
return item;
|
|
187
|
-
}),
|
|
188
|
-
type: this.type,
|
|
189
|
-
isExternal: this.#isExternal,
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
static fromSerializedConversation(serializedConversation: SerializedConversation): Conversation {
|
|
194
|
-
const history = serializedConversation.history.map(entry => {
|
|
195
|
-
if (entry.type === ResponseType.SIDE_EFFECT) {
|
|
196
|
-
return {...entry, confirm: () => {}};
|
|
197
|
-
}
|
|
198
|
-
return entry;
|
|
199
|
-
});
|
|
200
|
-
return new Conversation(
|
|
201
|
-
serializedConversation.type, history, serializedConversation.id, true, serializedConversation.isExternal);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
34
|
let instance: AiHistoryStorage|null = null;
|
|
206
35
|
|
|
207
36
|
const DEFAULT_MAX_STORAGE_SIZE = 50 * 1024 * 1024;
|
|
@@ -21,8 +21,8 @@ import {FileAgent} from './agents/FileAgent.js';
|
|
|
21
21
|
import {NetworkAgent, RequestContext} from './agents/NetworkAgent.js';
|
|
22
22
|
import {PerformanceAgent, type PerformanceTraceContext} from './agents/PerformanceAgent.js';
|
|
23
23
|
import {NodeContext, StylingAgent} from './agents/StylingAgent.js';
|
|
24
|
+
import {AiConversation} from './AiConversation.js';
|
|
24
25
|
import {
|
|
25
|
-
Conversation,
|
|
26
26
|
ConversationType,
|
|
27
27
|
} from './AiHistoryStorage.js';
|
|
28
28
|
import {getDisabledReasons} from './AiUtils.js';
|
|
@@ -42,7 +42,7 @@ interface ExternalNetworkRequestParameters {
|
|
|
42
42
|
|
|
43
43
|
export interface ExternalPerformanceAIConversationData {
|
|
44
44
|
conversationHandler: ConversationHandler;
|
|
45
|
-
conversation:
|
|
45
|
+
conversation: AiConversation;
|
|
46
46
|
agent: AiAgent<unknown>;
|
|
47
47
|
selected: PerformanceTraceContext;
|
|
48
48
|
}
|
|
@@ -207,7 +207,7 @@ export class ConversationHandler extends Common.ObjectWrapper.ObjectWrapper<Even
|
|
|
207
207
|
|
|
208
208
|
async *
|
|
209
209
|
handleConversationWithHistory(
|
|
210
|
-
items: AsyncIterable<ResponseData, void, void>, conversation:
|
|
210
|
+
items: AsyncIterable<ResponseData, void, void>, conversation: AiConversation|undefined):
|
|
211
211
|
AsyncGenerator<ResponseData, void, void> {
|
|
212
212
|
for await (const data of items) {
|
|
213
213
|
// We don't want to save partial responses to the conversation history.
|
|
@@ -225,7 +225,7 @@ export class ConversationHandler extends Common.ObjectWrapper.ObjectWrapper<Even
|
|
|
225
225
|
selected: NodeContext|PerformanceTraceContext|RequestContext|null,
|
|
226
226
|
}): AsyncGenerator<ExternalRequestResponse, ExternalRequestResponse> {
|
|
227
227
|
const {conversationType, aiAgent, prompt, selected} = opts;
|
|
228
|
-
const conversation = new
|
|
228
|
+
const conversation = new AiConversation(
|
|
229
229
|
conversationType,
|
|
230
230
|
[],
|
|
231
231
|
aiAgent.id,
|
|
@@ -236,7 +236,7 @@ export class ConversationHandler extends Common.ObjectWrapper.ObjectWrapper<Even
|
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
async * #doExternalConversation(opts: {
|
|
239
|
-
conversation:
|
|
239
|
+
conversation: AiConversation,
|
|
240
240
|
aiAgent: AiAgent<unknown>,
|
|
241
241
|
prompt: string,
|
|
242
242
|
selected: NodeContext|PerformanceTraceContext|RequestContext|null,
|
|
@@ -682,9 +682,7 @@ export abstract class AiAgent<T> {
|
|
|
682
682
|
|
|
683
683
|
yield {
|
|
684
684
|
type: ResponseType.SIDE_EFFECT,
|
|
685
|
-
confirm:
|
|
686
|
-
sideEffectConfirmationPromiseWithResolvers.resolve(result);
|
|
687
|
-
},
|
|
685
|
+
confirm: sideEffectConfirmationPromiseWithResolvers.resolve,
|
|
688
686
|
};
|
|
689
687
|
|
|
690
688
|
const approvedRun = await sideEffectConfirmationPromiseWithResolvers.promise;
|
|
@@ -492,7 +492,7 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
492
492
|
this.#addFacts(options.selected);
|
|
493
493
|
}
|
|
494
494
|
|
|
495
|
-
|
|
495
|
+
yield* super.run(initialQuery, options);
|
|
496
496
|
}
|
|
497
497
|
|
|
498
498
|
#createFactForTraceSummary(): void {
|
|
@@ -870,7 +870,11 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
870
870
|
}
|
|
871
871
|
|
|
872
872
|
const tree = AICallTree.fromEvent(event, parsedTrace);
|
|
873
|
-
|
|
873
|
+
if (!tree) {
|
|
874
|
+
return {error: 'No call tree found'};
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
const callTree = this.#formatter.formatCallTree(tree);
|
|
874
878
|
|
|
875
879
|
const key = `getDetailedCallTree(${args.eventKey})`;
|
|
876
880
|
this.#cacheFunctionResult(focus, key, callTree);
|
|
@@ -327,11 +327,8 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
|
|
|
327
327
|
action: `getStyles(${JSON.stringify(params.elements)}, ${JSON.stringify(params.styleProperties)})`,
|
|
328
328
|
};
|
|
329
329
|
},
|
|
330
|
-
handler: async
|
|
331
|
-
|
|
332
|
-
options,
|
|
333
|
-
) => {
|
|
334
|
-
return await this.getStyles(params.elements, params.styleProperties, options);
|
|
330
|
+
handler: async params => {
|
|
331
|
+
return await this.getStyles(params.elements, params.styleProperties);
|
|
335
332
|
},
|
|
336
333
|
});
|
|
337
334
|
|
|
@@ -583,10 +580,7 @@ const data = {
|
|
|
583
580
|
return this.context?.getItem() ?? null;
|
|
584
581
|
}
|
|
585
582
|
|
|
586
|
-
async getStyles(elements: string[], properties: string[]
|
|
587
|
-
signal?: AbortSignal,
|
|
588
|
-
approved?: boolean,
|
|
589
|
-
}): Promise<FunctionCallHandlerResult<unknown>> {
|
|
583
|
+
async getStyles(elements: string[], properties: string[]): Promise<FunctionCallHandlerResult<unknown>> {
|
|
590
584
|
const result:
|
|
591
585
|
Record<string, {computed: Record<string, string|undefined>, authored: Record<string, string|undefined>}> = {};
|
|
592
586
|
for (const uid of elements) {
|
|
@@ -10,6 +10,7 @@ import * as PatchAgent from './agents/PatchAgent.js';
|
|
|
10
10
|
import * as PerformanceAgent from './agents/PerformanceAgent.js';
|
|
11
11
|
import * as PerformanceAnnotationsAgent from './agents/PerformanceAnnotationsAgent.js';
|
|
12
12
|
import * as StylingAgent from './agents/StylingAgent.js';
|
|
13
|
+
import * as AiConversation from './AiConversation.js';
|
|
13
14
|
import * as AiHistoryStorage from './AiHistoryStorage.js';
|
|
14
15
|
import * as AiUtils from './AiUtils.js';
|
|
15
16
|
import * as BuiltInAi from './BuiltInAi.js';
|
|
@@ -33,6 +34,7 @@ export {
|
|
|
33
34
|
AiAgent,
|
|
34
35
|
AICallTree,
|
|
35
36
|
AIContext,
|
|
37
|
+
AiConversation,
|
|
36
38
|
AiHistoryStorage,
|
|
37
39
|
AIQueries,
|
|
38
40
|
AiUtils,
|