chrome-devtools-frontend 1.0.1518653 → 1.0.1519267
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/owner/COMMON_OWNERS +2 -2
- package/eslint.config.mjs +1 -0
- package/front_end/core/sdk/EnhancedTracesParser.ts +5 -5
- package/front_end/core/sdk/RehydratingConnection.snapshot.txt +211 -0
- package/front_end/core/sdk/TargetManager.ts +4 -0
- package/front_end/generated/SupportedCSSProperties.js +19 -4
- package/front_end/models/ai_assistance/agents/AiAgent.ts +57 -10
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +4 -53
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +0 -31
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +6 -0
- package/front_end/models/ai_assistance/performance/AIContext.ts +1 -1
- package/front_end/models/ai_code_completion/AiCodeCompletion.ts +5 -0
- package/front_end/models/badges/AiExplorerBadge.ts +19 -3
- package/front_end/models/badges/Badge.ts +2 -0
- package/front_end/models/badges/CodeWhispererBadge.ts +1 -0
- package/front_end/models/badges/DOMDetectiveBadge.ts +1 -0
- package/front_end/models/badges/SpeedsterBadge.ts +1 -0
- package/front_end/models/badges/StarterBadge.ts +1 -0
- package/front_end/models/badges/badges.ts +1 -0
- package/front_end/models/javascript_metadata/NativeFunctions.js +1 -1
- package/front_end/models/trace/EventsSerializer.ts +4 -3
- package/front_end/models/trace/handlers/UserInteractionsHandler.ts +101 -73
- package/front_end/models/trace/helpers/Timing.ts +1 -1
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +4 -1
- package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +16 -14
- package/front_end/panels/application/components/BounceTrackingMitigationsView.ts +2 -2
- package/front_end/panels/common/BadgeNotification.ts +3 -3
- package/front_end/panels/common/GdpSignUpDialog.ts +3 -4
- package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +5 -5
- package/front_end/panels/recorder/components/RecordingView.ts +2 -2
- package/front_end/panels/search/SearchResultsPane.ts +157 -138
- package/front_end/panels/search/SearchView.ts +12 -9
- package/front_end/panels/search/searchResultsPane.css +9 -0
- package/front_end/panels/security/CookieControlsView.ts +2 -1
- package/front_end/panels/settings/AISettingsTab.ts +6 -3
- package/front_end/panels/settings/components/SyncSection.ts +23 -9
- package/front_end/panels/settings/emulation/components/UserAgentClientHintsForm.ts +1 -1
- package/front_end/panels/sources/AiCodeCompletionPlugin.ts +3 -0
- package/front_end/panels/sources/SourcesPanel.ts +1 -1
- package/front_end/panels/sources/sourcesView.css +6 -1
- package/front_end/panels/timeline/components/LayoutShiftDetails.ts +1 -1
- package/front_end/panels/timeline/components/NetworkRequestDetails.ts +1 -1
- package/front_end/panels/timeline/components/RelatedInsightChips.ts +1 -1
- package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +1 -1
- 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/core/Realm.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.js +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/node/ChromeLauncher.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.js +1 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.js.map +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/Function.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Function.js +16 -25
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Function.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/es5-iife/puppeteer-core-browser.js +19 -28
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.js +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.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/Function.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/Function.js +16 -25
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/Function.js.map +1 -1
- package/front_end/third_party/puppeteer/package/package.json +10 -3
- package/front_end/third_party/puppeteer/package/src/generated/injected.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/generated/version.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/node/ChromeLauncher.ts +1 -0
- package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
- package/front_end/third_party/puppeteer/package/src/util/Function.ts +22 -30
- package/front_end/ui/components/dialogs/Dialog.ts +1 -1
- package/front_end/ui/components/markdown_view/MarkdownImage.ts +4 -5
- package/front_end/ui/components/switch/SwitchImpl.ts +12 -1
- package/front_end/ui/components/text_editor/config.ts +16 -2
- package/front_end/ui/legacy/Treeoutline.ts +3 -1
- package/front_end/ui/legacy/components/source_frame/XMLView.ts +12 -11
- package/front_end/ui/lit/i18n-template.ts +5 -2
- package/front_end/ui/visual_logging/KnownContextValues.ts +9 -5
- package/package.json +1 -1
@@ -16,15 +16,15 @@ kprokopenko@chromium.org
|
|
16
16
|
leese@chromium.org
|
17
17
|
mathias@chromium.org
|
18
18
|
nancyly@chromium.org
|
19
|
-
nechaev@chromium.org
|
20
19
|
nharshunova@chromium.org
|
20
|
+
nroscino@chromium.org
|
21
21
|
nvitkov@chromium.org
|
22
22
|
paulirish@chromium.org
|
23
23
|
petermueller@chromium.org
|
24
24
|
pfaffe@chromium.org
|
25
25
|
piotrpaulski@chromium.org
|
26
26
|
sadym@chromium.org
|
27
|
-
samiyac@
|
27
|
+
samiyac@google.com
|
28
28
|
szuend@chromium.org
|
29
29
|
victorporof@chromium.org
|
30
30
|
wolfi@chromium.org
|
package/eslint.config.mjs
CHANGED
@@ -720,6 +720,7 @@ export default defineConfig([
|
|
720
720
|
'rulesdir/no-assert-deep-strict-equal': 'error',
|
721
721
|
'rulesdir/no-assert-equal': 'error',
|
722
722
|
'rulesdir/no-assert-equal-boolean-null-undefined': 'error',
|
723
|
+
'rulesdir/no-capture-screenshot': 'error',
|
723
724
|
'rulesdir/no-imperative-dom-api': 'off',
|
724
725
|
'rulesdir/no-lit-render-outside-of-view': 'off',
|
725
726
|
'rulesdir/prefer-assert-instance-of': 'error',
|
@@ -459,11 +459,11 @@ export class EnhancedTracesParser {
|
|
459
459
|
for (const orphanScript of orphanScripts) {
|
460
460
|
const orphanScriptExecutionContextIsolateId =
|
461
461
|
this.getExecutionContextIsolateId(orphanScript.isolate, orphanScript.executionContextId);
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
462
|
+
const frameId = executionContextIsolateToTarget.get(orphanScriptExecutionContextIsolateId);
|
463
|
+
|
464
|
+
if (frameId) {
|
465
|
+
// Found a link via execution context, use it.
|
466
|
+
targetToScripts.get(frameId)?.push(orphanScript);
|
467
467
|
} else if (orphanScript.pid) {
|
468
468
|
const target = targets.find(target => target.pid === orphanScript.pid);
|
469
469
|
if (target) {
|
@@ -992,6 +992,217 @@ Content:
|
|
992
992
|
"sessionId": 1
|
993
993
|
}
|
994
994
|
|
995
|
+
/* RehydratingConnection says: */
|
996
|
+
{
|
997
|
+
"method": "Debugger.scriptParsed",
|
998
|
+
"params": {
|
999
|
+
"scriptId": "6",
|
1000
|
+
"isolate": "7348673817420155000",
|
1001
|
+
"buildId": "",
|
1002
|
+
"executionContextId": 1,
|
1003
|
+
"startLine": 0,
|
1004
|
+
"startColumn": 0,
|
1005
|
+
"endLine": 0,
|
1006
|
+
"endColumn": 0,
|
1007
|
+
"hash": "",
|
1008
|
+
"isModule": false,
|
1009
|
+
"url": "",
|
1010
|
+
"hasSourceURL": false,
|
1011
|
+
"sourceURL": "",
|
1012
|
+
"pid": 97964,
|
1013
|
+
"sourceText": "(async function(){ a…",
|
1014
|
+
"length": 32
|
1015
|
+
},
|
1016
|
+
"sessionId": 1
|
1017
|
+
}
|
1018
|
+
|
1019
|
+
/* fakeDevToolsFrontend says: */
|
1020
|
+
{
|
1021
|
+
"id": 21,
|
1022
|
+
"sessionId": 1,
|
1023
|
+
"method": "Debugger.getScriptSource",
|
1024
|
+
"params": {
|
1025
|
+
"scriptId": "6"
|
1026
|
+
}
|
1027
|
+
}
|
1028
|
+
|
1029
|
+
/* RehydratingConnection says: */
|
1030
|
+
{
|
1031
|
+
"id": 21,
|
1032
|
+
"result": {
|
1033
|
+
"scriptSource": "(async function(){ a…"
|
1034
|
+
},
|
1035
|
+
"sessionId": 1
|
1036
|
+
}
|
1037
|
+
|
1038
|
+
/* RehydratingConnection says: */
|
1039
|
+
{
|
1040
|
+
"method": "Debugger.scriptParsed",
|
1041
|
+
"params": {
|
1042
|
+
"scriptId": "1",
|
1043
|
+
"isolate": "7348673817420155000",
|
1044
|
+
"buildId": "",
|
1045
|
+
"executionContextId": 1,
|
1046
|
+
"startLine": 0,
|
1047
|
+
"startColumn": 0,
|
1048
|
+
"endLine": 0,
|
1049
|
+
"endColumn": 0,
|
1050
|
+
"hash": "",
|
1051
|
+
"isModule": false,
|
1052
|
+
"url": "",
|
1053
|
+
"hasSourceURL": false,
|
1054
|
+
"sourceURL": "",
|
1055
|
+
"pid": 97964
|
1056
|
+
},
|
1057
|
+
"sessionId": 1
|
1058
|
+
}
|
1059
|
+
|
1060
|
+
/* fakeDevToolsFrontend says: */
|
1061
|
+
{
|
1062
|
+
"id": 22,
|
1063
|
+
"sessionId": 1,
|
1064
|
+
"method": "Debugger.getScriptSource",
|
1065
|
+
"params": {
|
1066
|
+
"scriptId": "1"
|
1067
|
+
}
|
1068
|
+
}
|
1069
|
+
|
1070
|
+
/* RehydratingConnection says: */
|
1071
|
+
{
|
1072
|
+
"id": 22,
|
1073
|
+
"result": {
|
1074
|
+
"scriptSource": "No source text avail…"
|
1075
|
+
},
|
1076
|
+
"sessionId": 1
|
1077
|
+
}
|
1078
|
+
|
1079
|
+
/* RehydratingConnection says: */
|
1080
|
+
{
|
1081
|
+
"method": "Debugger.scriptParsed",
|
1082
|
+
"params": {
|
1083
|
+
"scriptId": "2",
|
1084
|
+
"isolate": "7348673817420155000",
|
1085
|
+
"buildId": "",
|
1086
|
+
"executionContextId": 1,
|
1087
|
+
"startLine": 0,
|
1088
|
+
"startColumn": 0,
|
1089
|
+
"endLine": 0,
|
1090
|
+
"endColumn": 0,
|
1091
|
+
"hash": "",
|
1092
|
+
"isModule": false,
|
1093
|
+
"url": "",
|
1094
|
+
"hasSourceURL": false,
|
1095
|
+
"sourceURL": "",
|
1096
|
+
"pid": 97964,
|
1097
|
+
"sourceText": "() {}…",
|
1098
|
+
"length": 5
|
1099
|
+
},
|
1100
|
+
"sessionId": 1
|
1101
|
+
}
|
1102
|
+
|
1103
|
+
/* fakeDevToolsFrontend says: */
|
1104
|
+
{
|
1105
|
+
"id": 23,
|
1106
|
+
"sessionId": 1,
|
1107
|
+
"method": "Debugger.getScriptSource",
|
1108
|
+
"params": {
|
1109
|
+
"scriptId": "2"
|
1110
|
+
}
|
1111
|
+
}
|
1112
|
+
|
1113
|
+
/* RehydratingConnection says: */
|
1114
|
+
{
|
1115
|
+
"id": 23,
|
1116
|
+
"result": {
|
1117
|
+
"scriptSource": "() {}…"
|
1118
|
+
},
|
1119
|
+
"sessionId": 1
|
1120
|
+
}
|
1121
|
+
|
1122
|
+
/* RehydratingConnection says: */
|
1123
|
+
{
|
1124
|
+
"method": "Debugger.scriptParsed",
|
1125
|
+
"params": {
|
1126
|
+
"scriptId": "3",
|
1127
|
+
"isolate": "7348673817420155000",
|
1128
|
+
"buildId": "",
|
1129
|
+
"executionContextId": 1,
|
1130
|
+
"startLine": 0,
|
1131
|
+
"startColumn": 0,
|
1132
|
+
"endLine": 0,
|
1133
|
+
"endColumn": 0,
|
1134
|
+
"hash": "",
|
1135
|
+
"isModule": false,
|
1136
|
+
"url": "extensions::SafeBuiltins",
|
1137
|
+
"hasSourceURL": false,
|
1138
|
+
"sourceURL": "",
|
1139
|
+
"pid": 97964
|
1140
|
+
},
|
1141
|
+
"sessionId": 1
|
1142
|
+
}
|
1143
|
+
|
1144
|
+
/* fakeDevToolsFrontend says: */
|
1145
|
+
{
|
1146
|
+
"id": 24,
|
1147
|
+
"sessionId": 1,
|
1148
|
+
"method": "Debugger.getScriptSource",
|
1149
|
+
"params": {
|
1150
|
+
"scriptId": "3"
|
1151
|
+
}
|
1152
|
+
}
|
1153
|
+
|
1154
|
+
/* RehydratingConnection says: */
|
1155
|
+
{
|
1156
|
+
"id": 24,
|
1157
|
+
"result": {
|
1158
|
+
"scriptSource": "No source text avail…"
|
1159
|
+
},
|
1160
|
+
"sessionId": 1
|
1161
|
+
}
|
1162
|
+
|
1163
|
+
/* RehydratingConnection says: */
|
1164
|
+
{
|
1165
|
+
"method": "Debugger.scriptParsed",
|
1166
|
+
"params": {
|
1167
|
+
"scriptId": "4",
|
1168
|
+
"isolate": "7348673817420155000",
|
1169
|
+
"buildId": "",
|
1170
|
+
"executionContextId": 1,
|
1171
|
+
"startLine": 0,
|
1172
|
+
"startColumn": 0,
|
1173
|
+
"endLine": 0,
|
1174
|
+
"endColumn": 0,
|
1175
|
+
"hash": "",
|
1176
|
+
"isModule": false,
|
1177
|
+
"url": "v8/LoadTimes",
|
1178
|
+
"hasSourceURL": false,
|
1179
|
+
"sourceURL": "",
|
1180
|
+
"pid": 97964,
|
1181
|
+
"sourceText": "var chrome;if (!chro…",
|
1182
|
+
"length": 198
|
1183
|
+
},
|
1184
|
+
"sessionId": 1
|
1185
|
+
}
|
1186
|
+
|
1187
|
+
/* fakeDevToolsFrontend says: */
|
1188
|
+
{
|
1189
|
+
"id": 25,
|
1190
|
+
"sessionId": 1,
|
1191
|
+
"method": "Debugger.getScriptSource",
|
1192
|
+
"params": {
|
1193
|
+
"scriptId": "4"
|
1194
|
+
}
|
1195
|
+
}
|
1196
|
+
|
1197
|
+
/* RehydratingConnection says: */
|
1198
|
+
{
|
1199
|
+
"id": 25,
|
1200
|
+
"result": {
|
1201
|
+
"scriptSource": "var chrome;if (!chro…"
|
1202
|
+
},
|
1203
|
+
"sessionId": 1
|
1204
|
+
}
|
1205
|
+
|
995
1206
|
/* RehydratingConnection says: */
|
996
1207
|
{
|
997
1208
|
"id": 2,
|
@@ -318,6 +318,10 @@ export class TargetManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes
|
|
318
318
|
* (eg., tab URL of `devtools://devtools/bundled/devtools_app.html` uses a MainConnection but has no CDP server behind it).
|
319
319
|
*/
|
320
320
|
hasFakeConnection(): boolean {
|
321
|
+
// Rehydrated DevTools always has a fake connection, so we shortcut and avoid the race.
|
322
|
+
if (Root.Runtime.getPathName().includes('rehydrated_devtools_app')) {
|
323
|
+
return true;
|
324
|
+
}
|
321
325
|
// There _may_ be a race condition hiding here on the router/connection creation.
|
322
326
|
// So we play it safe and consider "no connection yet" as "not fake".
|
323
327
|
const connection = this.primaryPageTarget()?.router()?.connection();
|
@@ -641,6 +641,7 @@ export const generatedProperties = [
|
|
641
641
|
"row-rule-style",
|
642
642
|
"row-rule-width",
|
643
643
|
"ruby-align",
|
644
|
+
"ruby-overhang",
|
644
645
|
"ruby-position",
|
645
646
|
"rx",
|
646
647
|
"ry",
|
@@ -738,7 +739,7 @@ export const generatedProperties = [
|
|
738
739
|
"timeline-trigger-name",
|
739
740
|
"timeline-trigger-range-end",
|
740
741
|
"timeline-trigger-range-start",
|
741
|
-
"timeline-trigger-
|
742
|
+
"timeline-trigger-source",
|
742
743
|
"top",
|
743
744
|
"touch-action",
|
744
745
|
"transform",
|
@@ -3732,6 +3733,14 @@ export const generatedProperties = [
|
|
3732
3733
|
],
|
3733
3734
|
"name": "ruby-align"
|
3734
3735
|
},
|
3736
|
+
{
|
3737
|
+
"inherited": true,
|
3738
|
+
"keywords": [
|
3739
|
+
"auto",
|
3740
|
+
"none"
|
3741
|
+
],
|
3742
|
+
"name": "ruby-overhang"
|
3743
|
+
},
|
3735
3744
|
{
|
3736
3745
|
"inherited": true,
|
3737
3746
|
"keywords": [
|
@@ -4422,7 +4431,7 @@ export const generatedProperties = [
|
|
4422
4431
|
{
|
4423
4432
|
"longhands": [
|
4424
4433
|
"timeline-trigger-name",
|
4425
|
-
"timeline-trigger-
|
4434
|
+
"timeline-trigger-source",
|
4426
4435
|
"timeline-trigger-behavior",
|
4427
4436
|
"timeline-trigger-range-start",
|
4428
4437
|
"timeline-trigger-range-end",
|
@@ -4460,7 +4469,7 @@ export const generatedProperties = [
|
|
4460
4469
|
"none",
|
4461
4470
|
"auto"
|
4462
4471
|
],
|
4463
|
-
"name": "timeline-trigger-
|
4472
|
+
"name": "timeline-trigger-source"
|
4464
4473
|
},
|
4465
4474
|
{
|
4466
4475
|
"keywords": [
|
@@ -6482,6 +6491,12 @@ export const generatedPropertyValues = {
|
|
6482
6491
|
"space-between"
|
6483
6492
|
]
|
6484
6493
|
},
|
6494
|
+
"ruby-overhang": {
|
6495
|
+
"values": [
|
6496
|
+
"auto",
|
6497
|
+
"none"
|
6498
|
+
]
|
6499
|
+
},
|
6485
6500
|
"ruby-position": {
|
6486
6501
|
"values": [
|
6487
6502
|
"over",
|
@@ -6839,7 +6854,7 @@ export const generatedPropertyValues = {
|
|
6839
6854
|
"state"
|
6840
6855
|
]
|
6841
6856
|
},
|
6842
|
-
"timeline-trigger-
|
6857
|
+
"timeline-trigger-source": {
|
6843
6858
|
"values": [
|
6844
6859
|
"none",
|
6845
6860
|
"auto"
|
@@ -133,13 +133,7 @@ export interface ParsedAnswer {
|
|
133
133
|
suggestions?: [string, ...string[]];
|
134
134
|
}
|
135
135
|
|
136
|
-
export
|
137
|
-
thought?: string;
|
138
|
-
title?: string;
|
139
|
-
action?: string;
|
140
|
-
}
|
141
|
-
|
142
|
-
export type ParsedResponse = ParsedAnswer|ParsedStep;
|
136
|
+
export type ParsedResponse = ParsedAnswer;
|
143
137
|
|
144
138
|
export const MAX_STEPS = 10;
|
145
139
|
|
@@ -404,13 +398,66 @@ export abstract class AiAgent<T> {
|
|
404
398
|
return this.#origin;
|
405
399
|
}
|
406
400
|
|
401
|
+
/**
|
402
|
+
* The AI has instructions to emit structured suggestions in their response. This
|
403
|
+
* function parses for that.
|
404
|
+
*
|
405
|
+
* Note: currently only StylingAgent and PerformanceAgent utilize this, but
|
406
|
+
* eventually all agents should support this.
|
407
|
+
*/
|
408
|
+
parseTextResponseForSuggestions(text: string): ParsedResponse {
|
409
|
+
if (!text) {
|
410
|
+
return {answer: ''};
|
411
|
+
}
|
412
|
+
|
413
|
+
const lines = text.split('\n');
|
414
|
+
const answerLines: string[] = [];
|
415
|
+
let suggestions: [string, ...string[]]|undefined;
|
416
|
+
|
417
|
+
for (const line of lines) {
|
418
|
+
const trimmed = line.trim();
|
419
|
+
if (trimmed.startsWith('SUGGESTIONS:')) {
|
420
|
+
try {
|
421
|
+
// TODO: Do basic validation this is an array with strings
|
422
|
+
suggestions = JSON.parse(trimmed.substring('SUGGESTIONS:'.length).trim());
|
423
|
+
} catch {
|
424
|
+
}
|
425
|
+
} else {
|
426
|
+
answerLines.push(line);
|
427
|
+
}
|
428
|
+
}
|
429
|
+
|
430
|
+
// Sometimes the model fails to put the SUGGESTIONS text on its own line. Handle
|
431
|
+
// the case where the suggestions are part of the last line of the answer.
|
432
|
+
if (!suggestions && answerLines.at(-1)?.includes('SUGGESTIONS:')) {
|
433
|
+
const [answer, suggestionsText] = answerLines[answerLines.length - 1].split('SUGGESTIONS:', 2);
|
434
|
+
try {
|
435
|
+
// TODO: Do basic validation this is an array with strings
|
436
|
+
suggestions = JSON.parse(suggestionsText.trim().substring('SUGGESTIONS:'.length).trim());
|
437
|
+
} catch {
|
438
|
+
}
|
439
|
+
answerLines[answerLines.length - 1] = answer;
|
440
|
+
}
|
441
|
+
|
442
|
+
const response: ParsedResponse = {
|
443
|
+
// If we could not parse the parts, consider the response to be an
|
444
|
+
// answer.
|
445
|
+
answer: answerLines.join('\n'),
|
446
|
+
};
|
447
|
+
|
448
|
+
if (suggestions) {
|
449
|
+
response.suggestions = suggestions;
|
450
|
+
}
|
451
|
+
|
452
|
+
return response;
|
453
|
+
}
|
454
|
+
|
407
455
|
/**
|
408
456
|
* Parses a streaming text response into a
|
409
|
-
* though/action/title/answer/suggestions component.
|
410
|
-
* by StylingAgent.
|
457
|
+
* though/action/title/answer/suggestions component.
|
411
458
|
*/
|
412
459
|
parseTextResponse(response: string): ParsedResponse {
|
413
|
-
return
|
460
|
+
return this.parseTextResponseForSuggestions(response.trim());
|
414
461
|
}
|
415
462
|
|
416
463
|
/**
|
@@ -2,8 +2,6 @@
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
3
3
|
// found in the LICENSE file.
|
4
4
|
|
5
|
-
import '../../../ui/components/icon_button/icon_button.js';
|
6
|
-
|
7
5
|
import * as Common from '../../../core/common/common.js';
|
8
6
|
import * as Host from '../../../core/host/host.js';
|
9
7
|
import * as i18n from '../../../core/i18n/i18n.js';
|
@@ -420,53 +418,6 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
420
418
|
});
|
421
419
|
}
|
422
420
|
|
423
|
-
#parseSuggestions(text: string): ParsedResponse {
|
424
|
-
if (!text) {
|
425
|
-
return {answer: ''};
|
426
|
-
}
|
427
|
-
|
428
|
-
const lines = text.split('\n');
|
429
|
-
const answerLines: string[] = [];
|
430
|
-
let suggestions: [string, ...string[]]|undefined;
|
431
|
-
|
432
|
-
for (const line of lines) {
|
433
|
-
const trimmed = line.trim();
|
434
|
-
if (trimmed.startsWith('SUGGESTIONS:')) {
|
435
|
-
try {
|
436
|
-
// TODO: Do basic validation this is an array with strings
|
437
|
-
suggestions = JSON.parse(trimmed.substring('SUGGESTIONS:'.length).trim());
|
438
|
-
} catch {
|
439
|
-
}
|
440
|
-
} else {
|
441
|
-
answerLines.push(line);
|
442
|
-
}
|
443
|
-
}
|
444
|
-
|
445
|
-
// Sometimes the model fails to put the SUGGESTIONS text on its own line. Handle
|
446
|
-
// the case where the suggestions are part of the last line of the answer.
|
447
|
-
if (!suggestions && answerLines.at(-1)?.includes('SUGGESTIONS:')) {
|
448
|
-
const [answer, suggestionsText] = answerLines[answerLines.length - 1].split('SUGGESTIONS:', 2);
|
449
|
-
try {
|
450
|
-
// TODO: Do basic validation this is an array with strings
|
451
|
-
suggestions = JSON.parse(suggestionsText.trim().substring('SUGGESTIONS:'.length).trim());
|
452
|
-
} catch {
|
453
|
-
}
|
454
|
-
answerLines[answerLines.length - 1] = answer;
|
455
|
-
}
|
456
|
-
|
457
|
-
const response: ParsedResponse = {
|
458
|
-
// If we could not parse the parts, consider the response to be an
|
459
|
-
// answer.
|
460
|
-
answer: answerLines.join('\n'),
|
461
|
-
};
|
462
|
-
|
463
|
-
if (suggestions) {
|
464
|
-
response.suggestions = suggestions;
|
465
|
-
}
|
466
|
-
|
467
|
-
return response;
|
468
|
-
}
|
469
|
-
|
470
421
|
#parseMarkdown(response: string): string {
|
471
422
|
/**
|
472
423
|
* Sometimes the LLM responds with code chunks that wrap a text based markdown response.
|
@@ -482,10 +433,10 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
482
433
|
}
|
483
434
|
|
484
435
|
override parseTextResponse(response: string): ParsedResponse {
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
return
|
436
|
+
const parsedResponse = super.parseTextResponse(response);
|
437
|
+
parsedResponse.answer = this.#parseForKnownUrls(parsedResponse.answer);
|
438
|
+
parsedResponse.answer = this.#parseMarkdown(parsedResponse.answer);
|
439
|
+
return parsedResponse;
|
489
440
|
}
|
490
441
|
|
491
442
|
override async enhanceQuery(query: string, context: PerformanceTraceContext|null): Promise<string> {
|
@@ -21,7 +21,6 @@ import {
|
|
21
21
|
type ConversationSuggestions,
|
22
22
|
type FunctionCallHandlerResult,
|
23
23
|
MultimodalInputType,
|
24
|
-
type ParsedResponse,
|
25
24
|
type RequestOptions,
|
26
25
|
ResponseType,
|
27
26
|
} from './AiAgent.js';
|
@@ -265,36 +264,6 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
|
|
265
264
|
override preambleFeatures(): string[] {
|
266
265
|
return ['function_calling'];
|
267
266
|
}
|
268
|
-
override parseTextResponse(text: string): ParsedResponse {
|
269
|
-
// We're returning an empty answer to denote the erroneous case.
|
270
|
-
if (!text.trim()) {
|
271
|
-
return {answer: ''};
|
272
|
-
}
|
273
|
-
|
274
|
-
const lines = text.split('\n');
|
275
|
-
const answerLines: string[] = [];
|
276
|
-
let suggestions: [string, ...string[]]|undefined;
|
277
|
-
|
278
|
-
for (const line of lines) {
|
279
|
-
const trimmed = line.trim();
|
280
|
-
if (trimmed.startsWith('SUGGESTIONS:')) {
|
281
|
-
try {
|
282
|
-
// TODO: Do basic validation this is an array with strings
|
283
|
-
suggestions = JSON.parse(trimmed.substring('SUGGESTIONS:'.length).trim());
|
284
|
-
} catch {
|
285
|
-
}
|
286
|
-
} else {
|
287
|
-
answerLines.push(line);
|
288
|
-
}
|
289
|
-
}
|
290
|
-
|
291
|
-
return {
|
292
|
-
// If we could not parse the parts, consider the response to be an
|
293
|
-
// answer.
|
294
|
-
answer: answerLines.join('\n'),
|
295
|
-
suggestions,
|
296
|
-
};
|
297
|
-
}
|
298
267
|
|
299
268
|
#execJs: typeof executeJsCode;
|
300
269
|
|
@@ -100,6 +100,12 @@ export class PerformanceInsightFormatter extends PerformanceTraceFormatter {
|
|
100
100
|
}
|
101
101
|
|
102
102
|
insightIsSupported(): boolean {
|
103
|
+
// Although our types don't show it, Insights can end up as Errors if there
|
104
|
+
// is an issue in the processing stage. In this case we should gracefully
|
105
|
+
// ignore this error.
|
106
|
+
if (this.#insight instanceof Error) {
|
107
|
+
return false;
|
108
|
+
}
|
103
109
|
return this.#description().length > 0;
|
104
110
|
}
|
105
111
|
|
@@ -95,7 +95,7 @@ export class AgentFocus {
|
|
95
95
|
try {
|
96
96
|
return this.eventsSerializer.eventForKey(key, this.#data.parsedTrace);
|
97
97
|
} catch (err) {
|
98
|
-
if (err.toString().includes('Unknown trace event')) {
|
98
|
+
if (err.toString().includes('Unknown trace event') || err.toString().includes('Unknown profile call')) {
|
99
99
|
return null;
|
100
100
|
}
|
101
101
|
|
@@ -332,6 +332,7 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
|
|
332
332
|
sampleId,
|
333
333
|
startTime,
|
334
334
|
onImpression: this.#registerUserImpression.bind(this),
|
335
|
+
clearCachedRequest: this.#clearCachedRequest.bind(this),
|
335
336
|
})
|
336
337
|
});
|
337
338
|
|
@@ -414,6 +415,10 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
|
|
414
415
|
this.#aidaRequestCache = {request, response};
|
415
416
|
}
|
416
417
|
|
418
|
+
#clearCachedRequest(): void {
|
419
|
+
this.#aidaRequestCache = undefined;
|
420
|
+
}
|
421
|
+
|
417
422
|
#registerUserImpression(rpcGlobalId: Host.AidaClient.RpcGlobalId, sampleId: number, latency: number): void {
|
418
423
|
const seconds = Math.floor(latency / 1_000);
|
419
424
|
const remainingMs = latency % 1_000;
|
@@ -2,20 +2,36 @@
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
3
3
|
// found in the LICENSE file.
|
4
4
|
|
5
|
-
import
|
5
|
+
import * as Common from '../../core/common/common.js';
|
6
|
+
|
7
|
+
import {Badge, BadgeAction} from './Badge.js';
|
6
8
|
|
7
9
|
const AI_EXPLORER_BADGE_URI = new URL('../../Images/ai-explorer-badge.svg', import.meta.url).toString();
|
10
|
+
const AI_CONVERSATION_COUNT_SETTING_NAME = 'gdp.ai-conversation-count';
|
11
|
+
const AI_CONVERSATION_COUNT_LIMIT = 5;
|
12
|
+
|
8
13
|
export class AiExplorerBadge extends Badge {
|
9
14
|
override readonly name =
|
10
15
|
'profiles/me/awards/developers.google.com%2Fprofile%2Fbadges%2Factivity%2Fchrome-devtools%2Fai-explorer';
|
11
16
|
override readonly title = 'AI Explorer';
|
17
|
+
override readonly jslogContext = 'ai-explorer';
|
12
18
|
override readonly imageUri = AI_EXPLORER_BADGE_URI;
|
19
|
+
#aiConversationCountSetting: Common.Settings.Setting<number> = Common.Settings.Settings.instance().createSetting(
|
20
|
+
AI_CONVERSATION_COUNT_SETTING_NAME, 0, Common.Settings.SettingStorageType.SYNCED);
|
13
21
|
|
14
22
|
override readonly interestedActions = [
|
15
|
-
|
23
|
+
BadgeAction.STARTED_AI_CONVERSATION,
|
16
24
|
] as const;
|
17
25
|
|
18
26
|
handleAction(_action: BadgeAction): void {
|
19
|
-
this.
|
27
|
+
const currentCount = this.#aiConversationCountSetting.get();
|
28
|
+
if (currentCount >= AI_CONVERSATION_COUNT_LIMIT) {
|
29
|
+
return;
|
30
|
+
}
|
31
|
+
|
32
|
+
this.#aiConversationCountSetting.set(currentCount + 1);
|
33
|
+
if (this.#aiConversationCountSetting.get() === AI_CONVERSATION_COUNT_LIMIT) {
|
34
|
+
this.trigger();
|
35
|
+
}
|
20
36
|
}
|
21
37
|
}
|
@@ -10,6 +10,7 @@ export enum BadgeAction {
|
|
10
10
|
CSS_RULE_MODIFIED = 'css-rule-modified',
|
11
11
|
DOM_ELEMENT_OR_ATTRIBUTE_EDITED = 'dom-element-or-attribute-edited',
|
12
12
|
MODERN_DOM_BADGE_CLICKED = 'modern-dom-badge-clicked',
|
13
|
+
STARTED_AI_CONVERSATION = 'started-ai-conversation',
|
13
14
|
// TODO(ergunsh): Instrument performance insight clicks.
|
14
15
|
PERFORMANCE_INSIGHT_CLICKED = 'performance-insight-clicked',
|
15
16
|
DEBUGGER_PAUSED = 'debugger-paused'
|
@@ -36,6 +37,7 @@ export abstract class Badge {
|
|
36
37
|
abstract readonly title: string;
|
37
38
|
abstract readonly imageUri: string;
|
38
39
|
abstract readonly interestedActions: readonly BadgeAction[];
|
40
|
+
abstract readonly jslogContext: string;
|
39
41
|
readonly isStarterBadge: boolean = false;
|
40
42
|
|
41
43
|
constructor(context: BadgeContext) {
|
@@ -9,6 +9,7 @@ export class CodeWhispererBadge extends Badge {
|
|
9
9
|
override readonly name =
|
10
10
|
'profiles/me/awards/developers.google.com%2Fprofile%2Fbadges%2Factivity%2Fchrome-devtools%2Fcode-whisperer';
|
11
11
|
override readonly title = 'Code Whisperer';
|
12
|
+
override readonly jslogContext = 'code-whisperer';
|
12
13
|
override readonly imageUri = CODE_WHISPERER_BADGE_IMAGE_URI;
|
13
14
|
|
14
15
|
override readonly interestedActions = [BadgeAction.DEBUGGER_PAUSED] as const;
|
@@ -9,6 +9,7 @@ export class DOMDetectiveBadge extends Badge {
|
|
9
9
|
override readonly name =
|
10
10
|
'profiles/me/awards/developers.google.com%2Fprofile%2Fbadges%2Factivity%2Fchrome-devtools%2Fdom-detective';
|
11
11
|
override readonly title = 'DOM Detective';
|
12
|
+
override readonly jslogContext = 'dom-detective';
|
12
13
|
override readonly imageUri = DOM_DETECTIVE_BADGE_IMAGE_URI;
|
13
14
|
|
14
15
|
override readonly interestedActions = [
|
@@ -9,6 +9,7 @@ export class SpeedsterBadge extends Badge {
|
|
9
9
|
override readonly name =
|
10
10
|
'profiles/me/awards/developers.google.com%2Fprofile%2Fbadges%2Factivity%2Fchrome-devtools%2Fspeedster';
|
11
11
|
override readonly title = 'Speedster';
|
12
|
+
override readonly jslogContext = 'speedster';
|
12
13
|
override readonly interestedActions = [
|
13
14
|
BadgeAction.PERFORMANCE_INSIGHT_CLICKED,
|
14
15
|
] as const;
|