chrome-devtools-frontend 1.0.1518653 → 1.0.1520139
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 +1 -2
- package/config/typescript/tsconfig.eslint.json +12 -1
- package/docs/ui_engineering.md +1011 -0
- package/eslint.config.mjs +1 -0
- package/front_end/core/host/GdpClient.ts +12 -3
- package/front_end/core/sdk/EnhancedTracesParser.ts +5 -5
- package/front_end/core/sdk/NetworkManager.ts +1 -0
- package/front_end/core/sdk/NetworkRequest.ts +10 -0
- package/front_end/core/sdk/RehydratingConnection.snapshot.txt +211 -0
- package/front_end/core/sdk/TargetManager.ts +4 -0
- package/front_end/entrypoints/main/MainImpl.ts +6 -1
- package/front_end/entrypoints/main/main-meta.ts +3 -3
- 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 +64 -87
- package/front_end/models/ai_assistance/agents/PerformanceAnnotationsAgent.ts +4 -4
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +0 -31
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +127 -29
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +106 -55
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +317 -640
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +23 -19
- package/front_end/models/ai_assistance/performance/AICallTree.snapshot.txt +75 -0
- package/front_end/models/ai_assistance/performance/AICallTree.ts +14 -6
- package/front_end/models/ai_assistance/performance/AIContext.ts +63 -8
- 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 +8 -1
- 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 +6 -0
- package/front_end/models/badges/badges.ts +1 -0
- package/front_end/models/javascript_metadata/NativeFunctions.js +4 -0
- 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 +18 -8
- package/front_end/panels/ai_assistance/PatchWidget.ts +17 -55
- package/front_end/panels/ai_assistance/components/ChatView.ts +44 -68
- package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +63 -15
- package/front_end/panels/ai_assistance/components/chatView.css +12 -0
- package/front_end/panels/animation/AnimationTimeline.ts +1 -1
- package/front_end/panels/animation/animationTimeline.css +4 -0
- package/front_end/panels/application/components/BounceTrackingMitigationsView.ts +2 -2
- package/front_end/panels/application/preloading/components/PreloadingString.ts +2 -5
- package/front_end/panels/common/AiCodeCompletionTeaser.ts +5 -0
- package/front_end/panels/common/BadgeNotification.ts +3 -3
- package/front_end/panels/common/GdpSignUpDialog.ts +3 -4
- package/front_end/panels/common/aiCodeCompletionTeaser.css +6 -1
- package/front_end/panels/console/ConsolePrompt.ts +6 -0
- package/front_end/panels/console/ConsoleView.ts +4 -2
- package/front_end/panels/coverage/CoverageListView.ts +133 -158
- package/front_end/panels/coverage/CoverageView.ts +39 -16
- package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +5 -5
- package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +2 -0
- package/front_end/panels/network/NetworkDataGridNode.ts +22 -0
- package/front_end/panels/network/NetworkLogViewColumns.ts +9 -0
- package/front_end/panels/recorder/components/CreateRecordingView.ts +2 -0
- package/front_end/panels/recorder/components/RecordingView.ts +2 -2
- package/front_end/panels/search/SearchResultsPane.ts +186 -134
- package/front_end/panels/search/SearchView.ts +42 -36
- package/front_end/panels/search/searchResultsPane.css +9 -0
- package/front_end/panels/search/searchView.css +0 -2
- 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 +26 -12
- package/front_end/panels/settings/emulation/components/UserAgentClientHintsForm.ts +1 -1
- package/front_end/panels/sources/AiCodeCompletionPlugin.ts +4 -4
- package/front_end/panels/sources/DebuggerPlugin.ts +4 -0
- package/front_end/panels/sources/SourcesPanel.ts +1 -1
- package/front_end/panels/sources/sourcesView.css +6 -1
- package/front_end/panels/timeline/ThirdPartyTreeView.ts +1 -1
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +0 -8
- package/front_end/panels/timeline/TimelineFlameChartView.ts +5 -5
- package/front_end/panels/timeline/TimelinePanel.ts +2 -0
- package/front_end/panels/timeline/TimelineTreeView.ts +1 -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/BrowserLauncher.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.js.map +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/node/PipeTransport.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/PipeTransport.js +15 -16
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/PipeTransport.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/BrowserLauncher.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.js.map +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/node/PipeTransport.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/PipeTransport.js +15 -16
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/PipeTransport.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 +12 -4
- 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/BrowserLauncher.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/node/ChromeLauncher.ts +1 -0
- package/front_end/third_party/puppeteer/package/src/node/PipeTransport.ts +15 -17
- 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/tsconfig.json +12 -1
- 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/InspectorView.ts +86 -13
- package/front_end/ui/legacy/TabbedPane.ts +2 -1
- 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 +15 -5
- package/front_end/ui/visual_logging/LoggingEvents.ts +1 -1
- package/package.json +1 -1
@@ -9,7 +9,7 @@ import type {AgentFocus} from '../performance/AIContext.js';
|
|
9
9
|
import {AIQueries} from '../performance/AIQueries.js';
|
10
10
|
|
11
11
|
import {NetworkRequestFormatter} from './NetworkRequestFormatter.js';
|
12
|
-
import {PerformanceInsightFormatter} from './PerformanceInsightFormatter.js';
|
12
|
+
import type {PerformanceInsightFormatter} from './PerformanceInsightFormatter.js';
|
13
13
|
import {bytes, micros, millis} from './UnitFormatters.js';
|
14
14
|
|
15
15
|
export interface NetworkRequestFormatOptions {
|
@@ -17,17 +17,27 @@ export interface NetworkRequestFormatOptions {
|
|
17
17
|
customTitle?: string;
|
18
18
|
}
|
19
19
|
|
20
|
+
type GetInsightFormatter = (focus: AgentFocus, model: Trace.Insights.Types.InsightModel) => PerformanceInsightFormatter;
|
21
|
+
|
20
22
|
export class PerformanceTraceFormatter {
|
21
23
|
#focus: AgentFocus;
|
22
24
|
#parsedTrace: Trace.TraceModel.ParsedTrace;
|
23
25
|
#insightSet: Trace.Insights.Types.InsightSet|null;
|
26
|
+
#getInsightFormatter: GetInsightFormatter|null = null;
|
24
27
|
protected eventsSerializer: Trace.EventsSerializer.EventsSerializer;
|
25
28
|
|
26
|
-
|
29
|
+
/**
|
30
|
+
* We inject the insight formatter because otherwise we get a circular
|
31
|
+
* dependency between PerformanceInsightFormatter and
|
32
|
+
* PerformanceTraceFormatter. This is OK in the browser build, but breaks when
|
33
|
+
* we reuse this code in NodeJS for DevTools MCP.
|
34
|
+
*/
|
35
|
+
constructor(focus: AgentFocus, getInsightFormatter: GetInsightFormatter|null) {
|
27
36
|
this.#focus = focus;
|
28
|
-
this.#parsedTrace = focus.
|
29
|
-
this.#insightSet = focus.
|
37
|
+
this.#parsedTrace = focus.parsedTrace;
|
38
|
+
this.#insightSet = focus.insightSet;
|
30
39
|
this.eventsSerializer = focus.eventsSerializer;
|
40
|
+
this.#getInsightFormatter = getInsightFormatter;
|
31
41
|
}
|
32
42
|
|
33
43
|
serializeEvent(event: Trace.Types.Events.Event): string {
|
@@ -133,7 +143,10 @@ export class PerformanceTraceFormatter {
|
|
133
143
|
if (lcp || cls || inp) {
|
134
144
|
parts.push('Metrics (lab / observed):');
|
135
145
|
if (lcp) {
|
136
|
-
|
146
|
+
const nodeId = insightSet?.model.LCPBreakdown.lcpEvent?.args.data?.nodeId;
|
147
|
+
const nodeIdText = nodeId !== undefined ? `, nodeId: ${nodeId}` : '';
|
148
|
+
parts.push(
|
149
|
+
` - LCP: ${Math.round(lcp.value / 1000)} ms, event: ${this.serializeEvent(lcp.event)}${nodeIdText}`);
|
137
150
|
const subparts = insightSet?.model.LCPBreakdown.subparts;
|
138
151
|
if (subparts) {
|
139
152
|
const serializeSubpart = (subpart: Trace.Insights.Models.LCPBreakdown.Subpart): string => {
|
@@ -175,7 +188,10 @@ export class PerformanceTraceFormatter {
|
|
175
188
|
continue;
|
176
189
|
}
|
177
190
|
|
178
|
-
const formatter =
|
191
|
+
const formatter = this.#getInsightFormatter?.(this.#focus, model);
|
192
|
+
if (!formatter) {
|
193
|
+
continue;
|
194
|
+
}
|
179
195
|
if (!formatter.insightIsSupported()) {
|
180
196
|
continue;
|
181
197
|
}
|
@@ -442,19 +458,7 @@ export class PerformanceTraceFormatter {
|
|
442
458
|
}
|
443
459
|
|
444
460
|
formatCallTree(tree: AICallTree, headerLevel = 1): string {
|
445
|
-
|
446
|
-
|
447
|
-
// TODO(b/425270067): add eventKey to tree.serialize, but need to wait for other
|
448
|
-
// performance agent to be consolidated.
|
449
|
-
results.push('#'.repeat(headerLevel) + ' Node id to eventKey\n');
|
450
|
-
results.push('These node ids correspond to the call tree nodes listed in the above section.\n');
|
451
|
-
tree.breadthFirstWalk(tree.rootNode.children().values(), (node, nodeId) => {
|
452
|
-
results.push(`${nodeId}: ${this.eventsSerializer.keyForEvent(node.event)}`);
|
453
|
-
});
|
454
|
-
|
455
|
-
results.push('\nIMPORTANT: Never show eventKey to the user.');
|
456
|
-
|
457
|
-
return results.join('\n');
|
461
|
+
return `${tree.serialize(headerLevel)}\n\nIMPORTANT: Never show eventKey to the user.`;
|
458
462
|
}
|
459
463
|
|
460
464
|
formatNetworkRequests(
|
@@ -0,0 +1,75 @@
|
|
1
|
+
Title: AICallTree supports NodeJS traces that do not have a "main thread"
|
2
|
+
Content:
|
3
|
+
# All URLs:
|
4
|
+
|
5
|
+
* 0: node:internal/main/run_main_module
|
6
|
+
* 1: node:internal/modules/run_main
|
7
|
+
* 2: node:internal/modules/cjs/loader
|
8
|
+
* 3: file:///Users/andoli/Desktop/mocks/fixnodeinspector/app.js
|
9
|
+
|
10
|
+
# Call tree:
|
11
|
+
|
12
|
+
1;p-1-1-0-2;(anonymous);2370;;0;2
|
13
|
+
2;p-1-1-0-3;executeUserEntryPoint;2370;;1;3
|
14
|
+
3;p-1-1-0-4;Module._load;2370;;2;4
|
15
|
+
4;p-1-1-0-5;Module.load;2370;;2;5
|
16
|
+
5;p-1-1-0-6;Module._extensions..js;2370;;2;6
|
17
|
+
6;p-1-1-0-7;Module._compile;2370;;2;7
|
18
|
+
7;p-1-1-0-8;callAndPauseOnStart;2370;;;8;S
|
19
|
+
8;p-1-1-0-9;(anonymous);2370;2370;3;
|
20
|
+
=== end content
|
21
|
+
|
22
|
+
Title: AICallTree serializes a simple tree
|
23
|
+
Content:
|
24
|
+
# All URLs:
|
25
|
+
|
26
|
+
* 0: https://www.gstatic.com/devrel-devsite/prod/vafe2e13ca17bb026e70df42a2ead1c8192750e86a12923a88eda839025dabf95/js/devsite_app_module.js
|
27
|
+
|
28
|
+
# Call tree:
|
29
|
+
|
30
|
+
1;r-36071;Task;0.2;;;2
|
31
|
+
2;r-36072;Timer fired;0.2;;;3
|
32
|
+
3;r-36076;Function call;0.2;;0;4
|
33
|
+
4;p-74406-259-16342-528;_ds.q.ns;0.2;;0;5;S
|
34
|
+
5;p-74406-259-16342-529;clearTimeout;0.2;0;;6
|
35
|
+
6;r-36082;Recalculate style;0.2;0.2;;
|
36
|
+
=== end content
|
37
|
+
|
38
|
+
Title: AICallTree serializes a simple tree in a concise format
|
39
|
+
Content:
|
40
|
+
# All URLs:
|
41
|
+
|
42
|
+
* 0: https://www.gstatic.com/devrel-devsite/prod/vafe2e13ca17bb026e70df42a2ead1c8192750e86a12923a88eda839025dabf95/js/devsite_app_module.js
|
43
|
+
|
44
|
+
# Call tree:
|
45
|
+
|
46
|
+
1;r-36071;Task;0.2;;;2
|
47
|
+
2;r-36072;Timer fired;0.2;;;3
|
48
|
+
3;r-36076;Function call;0.2;;0;4
|
49
|
+
4;p-74406-259-16342-528;_ds.q.ns;0.2;;0;5;S
|
50
|
+
5;p-74406-259-16342-529;clearTimeout;0.2;0;;6
|
51
|
+
6;r-36082;Recalculate style;0.2;0.2;;
|
52
|
+
=== end content
|
53
|
+
|
54
|
+
Title: AICallTree serializes a tree in a concise format
|
55
|
+
Content:
|
56
|
+
# All URLs:
|
57
|
+
|
58
|
+
* 0: https://www.gstatic.com/firebasejs/6.6.1/firebase-performance.js
|
59
|
+
|
60
|
+
# Call tree:
|
61
|
+
|
62
|
+
1;r-5764;Task;0.9;0;;2;S
|
63
|
+
2;r-5765;Timer fired;0.9;0;;3
|
64
|
+
3;r-5766;Function call;0.9;0.1;0;4
|
65
|
+
4;p-73704-775-2873-705;(anonymous);0.8;;0;5
|
66
|
+
5;p-73704-775-2873-706;(anonymous);0.8;;0;6-8
|
67
|
+
6;p-73704-775-2873-707;Ot.getEntriesByType;0.1;;0;8
|
68
|
+
7;p-73704-775-2874-709;le.createOobTrace;0.6;0.2;0;9-11
|
69
|
+
8;p-73704-775-2873-708;getEntriesByType;0.1;0.1;;
|
70
|
+
9;p-73704-775-2875-710;le;0.1;0.1;0;
|
71
|
+
10;p-73704-775-2877-711;ie;0.2;;0;11-13
|
72
|
+
11;p-73704-775-2877-712;Ot.requiredApisAvailable;0.2;0.2;0;
|
73
|
+
12;p-73704-775-2879-713;oe;0;;0;13
|
74
|
+
13;p-73704-775-2879-714;setTimeout;0;0;;
|
75
|
+
=== end content
|
@@ -24,6 +24,10 @@ export interface FromTimeOnThreadOptions {
|
|
24
24
|
}
|
25
25
|
|
26
26
|
export class AICallTree {
|
27
|
+
// Note: ideally this is passed in (or lived on ParsedTrace), but this class is
|
28
|
+
// stateless (mostly, there's a cache for some stuff) so it doesn't match much.
|
29
|
+
#eventsSerializer = new Trace.EventsSerializer.EventsSerializer();
|
30
|
+
|
27
31
|
constructor(
|
28
32
|
public selectedNode: Trace.Extras.TraceTree.Node|null,
|
29
33
|
public rootNode: Trace.Extras.TraceTree.TopDownRootNode,
|
@@ -307,7 +311,10 @@ export class AICallTree {
|
|
307
311
|
// 1. ID
|
308
312
|
const idStr = String(nodeId);
|
309
313
|
|
310
|
-
// 2.
|
314
|
+
// 2. eventKey
|
315
|
+
const eventKey = this.#eventsSerializer.keyForEvent(node.event);
|
316
|
+
|
317
|
+
// 3. Name
|
311
318
|
const name = Trace.Name.forEntry(event, parsedTrace);
|
312
319
|
|
313
320
|
// Round milliseconds to one decimal place, return empty string if zero/undefined
|
@@ -318,13 +325,13 @@ export class AICallTree {
|
|
318
325
|
return String(Math.round(num * 10) / 10);
|
319
326
|
};
|
320
327
|
|
321
|
-
//
|
328
|
+
// 4. Duration
|
322
329
|
const durationStr = roundToTenths(node.totalTime);
|
323
330
|
|
324
|
-
//
|
331
|
+
// 5. Self Time
|
325
332
|
const selfTimeStr = roundToTenths(node.selfTime);
|
326
333
|
|
327
|
-
//
|
334
|
+
// 6. URL Index
|
328
335
|
const url = SourceMapsResolver.SourceMapsResolver.resolvedURLForEntry(parsedTrace, event);
|
329
336
|
let urlIndexStr = '';
|
330
337
|
if (url) {
|
@@ -336,7 +343,7 @@ export class AICallTree {
|
|
336
343
|
}
|
337
344
|
}
|
338
345
|
|
339
|
-
//
|
346
|
+
// 7. Child Range
|
340
347
|
const children = Array.from(node.children().values());
|
341
348
|
let childRangeStr = '';
|
342
349
|
if (childStartingNodeIndex) {
|
@@ -344,11 +351,12 @@ export class AICallTree {
|
|
344
351
|
`${childStartingNodeIndex}-${childStartingNodeIndex + children.length}`;
|
345
352
|
}
|
346
353
|
|
347
|
-
//
|
354
|
+
// 8. Selected Marker
|
348
355
|
const selectedMarker = selectedNode?.event === node.event ? 'S' : '';
|
349
356
|
|
350
357
|
// Combine fields
|
351
358
|
let line = idStr;
|
359
|
+
line += ';' + eventKey;
|
352
360
|
line += ';' + name;
|
353
361
|
line += ';' + durationStr;
|
354
362
|
line += ';' + selfTimeStr;
|
@@ -4,11 +4,14 @@
|
|
4
4
|
|
5
5
|
import * as Trace from '../../../models/trace/trace.js';
|
6
6
|
|
7
|
-
import
|
7
|
+
import {AICallTree} from './AICallTree.js';
|
8
8
|
|
9
|
-
|
9
|
+
interface AgentFocusData {
|
10
10
|
parsedTrace: Trace.TraceModel.ParsedTrace;
|
11
11
|
insightSet: Trace.Insights.Types.InsightSet|null;
|
12
|
+
/** Note: at most one of event or callTree is non-null. */
|
13
|
+
event: Trace.Types.Events.Event|null;
|
14
|
+
/** Note: at most one of event or callTree is non-null. */
|
12
15
|
callTree: AICallTree|null;
|
13
16
|
insight: Trace.Insights.Types.InsightModel|null;
|
14
17
|
}
|
@@ -30,6 +33,7 @@ export class AgentFocus {
|
|
30
33
|
return new AgentFocus({
|
31
34
|
parsedTrace,
|
32
35
|
insightSet,
|
36
|
+
event: null,
|
33
37
|
callTree: null,
|
34
38
|
insight: null,
|
35
39
|
});
|
@@ -45,11 +49,22 @@ export class AgentFocus {
|
|
45
49
|
return new AgentFocus({
|
46
50
|
parsedTrace,
|
47
51
|
insightSet,
|
52
|
+
event: null,
|
48
53
|
callTree: null,
|
49
54
|
insight,
|
50
55
|
});
|
51
56
|
}
|
52
57
|
|
58
|
+
static fromEvent(parsedTrace: Trace.TraceModel.ParsedTrace, event: Trace.Types.Events.Event): AgentFocus {
|
59
|
+
if (!parsedTrace.insights) {
|
60
|
+
throw new Error('missing insights');
|
61
|
+
}
|
62
|
+
|
63
|
+
const insightSet = getFirstInsightSet(parsedTrace.insights);
|
64
|
+
const result = AgentFocus.#getCallTreeOrEvent(parsedTrace, event);
|
65
|
+
return new AgentFocus({parsedTrace, insightSet, event: result.event, callTree: result.callTree, insight: null});
|
66
|
+
}
|
67
|
+
|
53
68
|
static fromCallTree(callTree: AICallTree): AgentFocus {
|
54
69
|
const insights = callTree.parsedTrace.insights;
|
55
70
|
|
@@ -65,7 +80,7 @@ export class AgentFocus {
|
|
65
80
|
getFirstInsightSet(insights);
|
66
81
|
}
|
67
82
|
|
68
|
-
return new AgentFocus({parsedTrace: callTree.parsedTrace, insightSet, callTree, insight: null});
|
83
|
+
return new AgentFocus({parsedTrace: callTree.parsedTrace, insightSet, event: null, callTree, insight: null});
|
69
84
|
}
|
70
85
|
|
71
86
|
#data: AgentFocusData;
|
@@ -75,8 +90,26 @@ export class AgentFocus {
|
|
75
90
|
this.#data = data;
|
76
91
|
}
|
77
92
|
|
78
|
-
get
|
79
|
-
return this.#data;
|
93
|
+
get parsedTrace(): Trace.TraceModel.ParsedTrace {
|
94
|
+
return this.#data.parsedTrace;
|
95
|
+
}
|
96
|
+
|
97
|
+
get insightSet(): Trace.Insights.Types.InsightSet|null {
|
98
|
+
return this.#data.insightSet;
|
99
|
+
}
|
100
|
+
|
101
|
+
/** Note: at most one of event or callTree is non-null. */
|
102
|
+
get event(): Trace.Types.Events.Event|null {
|
103
|
+
return this.#data.event;
|
104
|
+
}
|
105
|
+
|
106
|
+
/** Note: at most one of event or callTree is non-null. */
|
107
|
+
get callTree(): AICallTree|null {
|
108
|
+
return this.#data.callTree;
|
109
|
+
}
|
110
|
+
|
111
|
+
get insight(): Trace.Insights.Types.InsightModel|null {
|
112
|
+
return this.#data.insight;
|
80
113
|
}
|
81
114
|
|
82
115
|
withInsight(insight: Trace.Insights.Types.InsightModel|null): AgentFocus {
|
@@ -85,9 +118,11 @@ export class AgentFocus {
|
|
85
118
|
return focus;
|
86
119
|
}
|
87
120
|
|
88
|
-
|
121
|
+
withEvent(event: Trace.Types.Events.Event|null): AgentFocus {
|
89
122
|
const focus = new AgentFocus(this.#data);
|
90
|
-
|
123
|
+
const result = AgentFocus.#getCallTreeOrEvent(this.#data.parsedTrace, event);
|
124
|
+
focus.#data.callTree = result.callTree;
|
125
|
+
focus.#data.event = result.event;
|
91
126
|
return focus;
|
92
127
|
}
|
93
128
|
|
@@ -95,13 +130,33 @@ export class AgentFocus {
|
|
95
130
|
try {
|
96
131
|
return this.eventsSerializer.eventForKey(key, this.#data.parsedTrace);
|
97
132
|
} catch (err) {
|
98
|
-
if (err.toString().includes('Unknown trace event')) {
|
133
|
+
if (err.toString().includes('Unknown trace event') || err.toString().includes('Unknown profile call')) {
|
99
134
|
return null;
|
100
135
|
}
|
101
136
|
|
102
137
|
throw err;
|
103
138
|
}
|
104
139
|
}
|
140
|
+
|
141
|
+
/**
|
142
|
+
* If an event is a call tree, this returns that call tree and a null event.
|
143
|
+
* If not a call tree, this only returns a non-null event if the event is a network
|
144
|
+
* request.
|
145
|
+
* This is an arbitrary limitation – it should be removed, but first we need to
|
146
|
+
* improve the agent's knowledge of events that are not main-thread or network
|
147
|
+
* events.
|
148
|
+
*/
|
149
|
+
static #getCallTreeOrEvent(parsedTrace: Trace.TraceModel.ParsedTrace, event: Trace.Types.Events.Event|null):
|
150
|
+
{callTree: AICallTree|null, event: Trace.Types.Events.Event|null} {
|
151
|
+
const callTree = event && AICallTree.fromEvent(event, parsedTrace);
|
152
|
+
if (callTree) {
|
153
|
+
return {callTree, event: null};
|
154
|
+
}
|
155
|
+
if (event && Trace.Types.Events.isSyntheticNetworkRequest(event)) {
|
156
|
+
return {callTree: null, event};
|
157
|
+
}
|
158
|
+
return {callTree: null, event: null};
|
159
|
+
}
|
105
160
|
}
|
106
161
|
|
107
162
|
export function getPerformanceAgentFocusFromModel(model: Trace.TraceModel.Model): AgentFocus|null {
|
@@ -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
|
|
@@ -456,6 +457,10 @@ export class AiCodeCompletion extends Common.ObjectWrapper.ObjectWrapper<EventTy
|
|
456
457
|
Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiCodeCompletionSuggestionAccepted);
|
457
458
|
}
|
458
459
|
|
460
|
+
clearCachedRequest(): void {
|
461
|
+
this.#aidaRequestCache = undefined;
|
462
|
+
}
|
463
|
+
|
459
464
|
onTextChanged(
|
460
465
|
prefix: string, suffix: string, cursorPositionAtRequest: number,
|
461
466
|
inferenceLanguage?: Host.AidaClient.AidaInferenceLanguage): void {
|
@@ -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,9 +10,15 @@ 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
|
-
DEBUGGER_PAUSED = 'debugger-paused'
|
16
|
+
DEBUGGER_PAUSED = 'debugger-paused',
|
17
|
+
BREAKPOINT_ADDED = 'breakpoint-added',
|
18
|
+
CONSOLE_PROMPT_EXECUTED = 'console-prompt-executed',
|
19
|
+
PERFORMANCE_RECORDING_STARTED = 'performance-recording-started',
|
20
|
+
NETWORK_SPEED_THROTTLED = 'network-speed-throttled',
|
21
|
+
RECORDER_RECORDING_STARTED = 'recorder-recording-started',
|
16
22
|
}
|
17
23
|
|
18
24
|
export type BadgeActionEvents = Record<BadgeAction, void>;
|
@@ -36,6 +42,7 @@ export abstract class Badge {
|
|
36
42
|
abstract readonly title: string;
|
37
43
|
abstract readonly imageUri: string;
|
38
44
|
abstract readonly interestedActions: readonly BadgeAction[];
|
45
|
+
abstract readonly jslogContext: string;
|
39
46
|
readonly isStarterBadge: boolean = false;
|
40
47
|
|
41
48
|
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;
|
@@ -10,6 +10,7 @@ export class StarterBadge extends Badge {
|
|
10
10
|
override readonly name =
|
11
11
|
'profiles/me/awards/developers.google.com%2Fprofile%2Fbadges%2Factivity%2Fchrome-devtools%2Fchrome-devtools-user';
|
12
12
|
override readonly title = 'Chrome DevTools User';
|
13
|
+
override readonly jslogContext = 'chrome-devtools-user';
|
13
14
|
override readonly imageUri = STARTER_BADGE_IMAGE_URI;
|
14
15
|
|
15
16
|
// TODO(ergunsh): Add remaining non-trivial event definitions
|
@@ -18,6 +19,11 @@ export class StarterBadge extends Badge {
|
|
18
19
|
BadgeAction.RECEIVE_BADGES_SETTING_ENABLED,
|
19
20
|
BadgeAction.CSS_RULE_MODIFIED,
|
20
21
|
BadgeAction.DOM_ELEMENT_OR_ATTRIBUTE_EDITED,
|
22
|
+
BadgeAction.BREAKPOINT_ADDED,
|
23
|
+
BadgeAction.CONSOLE_PROMPT_EXECUTED,
|
24
|
+
BadgeAction.PERFORMANCE_RECORDING_STARTED,
|
25
|
+
BadgeAction.NETWORK_SPEED_THROTTLED,
|
26
|
+
BadgeAction.RECORDER_RECORDING_STARTED,
|
21
27
|
] as const;
|
22
28
|
|
23
29
|
handleAction(action: BadgeAction): void {
|
@@ -7277,6 +7277,10 @@ export const NativeFunctions = [
|
|
7277
7277
|
name: "unregisterTool",
|
7278
7278
|
signatures: [["tool_name"]]
|
7279
7279
|
},
|
7280
|
+
{
|
7281
|
+
name: "provideContext",
|
7282
|
+
signatures: [["params"]]
|
7283
|
+
},
|
7280
7284
|
{
|
7281
7285
|
name: "SnapEvent",
|
7282
7286
|
signatures: [["type","?eventInitDict"]]
|
@@ -39,7 +39,7 @@ export class EventsSerializer {
|
|
39
39
|
if (EventsSerializer.isLegacyTimelineFrameKey(eventValues)) {
|
40
40
|
const event = parsedTrace.data.Frames.frames.at(eventValues.rawIndex);
|
41
41
|
if (!event) {
|
42
|
-
throw new Error(`Could not find frame with index ${eventValues.rawIndex}`);
|
42
|
+
throw new Error(`Unknown trace event. Could not find frame with index ${eventValues.rawIndex}`);
|
43
43
|
}
|
44
44
|
return event;
|
45
45
|
}
|
@@ -48,7 +48,8 @@ export class EventsSerializer {
|
|
48
48
|
const syntheticEvents = Helpers.SyntheticEvents.SyntheticEventsManager.getActiveManager().getSyntheticTraces();
|
49
49
|
const syntheticEvent = syntheticEvents.at(eventValues.rawIndex);
|
50
50
|
if (!syntheticEvent) {
|
51
|
-
throw new Error(`Attempted to get a synthetic event from an unknown raw event index: ${
|
51
|
+
throw new Error(`Unknown trace event. Attempted to get a synthetic event from an unknown raw event index: ${
|
52
|
+
eventValues.rawIndex}`);
|
52
53
|
}
|
53
54
|
return syntheticEvent;
|
54
55
|
}
|
@@ -57,7 +58,7 @@ export class EventsSerializer {
|
|
57
58
|
const rawEvents = Helpers.SyntheticEvents.SyntheticEventsManager.getActiveManager().getRawTraceEvents();
|
58
59
|
return rawEvents[eventValues.rawIndex];
|
59
60
|
}
|
60
|
-
throw new Error(`Unknown trace event
|
61
|
+
throw new Error(`Unknown trace event. Serializable key values: ${(eventValues as unknown[]).join('-')}`);
|
61
62
|
}
|
62
63
|
|
63
64
|
static isProfileCallKey(key: Types.File.SerializableKeyValues): key is Types.File.ProfileCallKeyValues {
|