Skip to content

Commit a12b79f

Browse files
Connor ClarkDevtools-frontend LUCI CQ
authored andcommitted
[AI] For performance conversations, provide suggestions based on metrics
Also move the call tree suggestions into PerformanceTraceContext. Bug: 442392194 Change-Id: Ib88981d308e699b06adf8070d4cd30d0b210173b Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6955434 Reviewed-by: Paul Irish <[email protected]> Auto-Submit: Connor Clark <[email protected]> Commit-Queue: Connor Clark <[email protected]>
1 parent ff48a11 commit a12b79f

File tree

5 files changed

+44
-20
lines changed

5 files changed

+44
-20
lines changed

front_end/models/ai_assistance/agents/AiAgent.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@ export interface ConversationSuggestion {
148148
jslogContext?: string;
149149
}
150150

151+
/** At least one. */
152+
export type ConversationSuggestions = [ConversationSuggestion, ...ConversationSuggestion[]];
153+
151154
export const enum ExternalRequestResponseType {
152155
ANSWER = 'answer',
153156
NOTIFICATION = 'notification',
@@ -196,7 +199,7 @@ export abstract class ConversationContext<T> {
196199
return;
197200
}
198201

199-
async getSuggestions(): Promise<[ConversationSuggestion, ...ConversationSuggestion[]]|undefined> {
202+
async getSuggestions(): Promise<ConversationSuggestions|undefined> {
200203
return;
201204
}
202205
}

front_end/models/ai_assistance/agents/PerformanceAgent.ts

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
AiAgent,
2626
type ContextResponse,
2727
ConversationContext,
28-
type ConversationSuggestion,
28+
type ConversationSuggestions,
2929
type ParsedResponse,
3030
type RequestOptions,
3131
type ResponseData,
@@ -209,14 +209,44 @@ export class PerformanceTraceContext extends ConversationContext<AgentFocus> {
209209
* Presents the default suggestions that are shown when the user first clicks
210210
* "Ask AI".
211211
*/
212-
override async getSuggestions(): Promise<[ConversationSuggestion, ...ConversationSuggestion[]]|undefined> {
213-
const focus = this.#focus.data;
212+
override async getSuggestions(): Promise<ConversationSuggestions|undefined> {
213+
const data = this.#focus.data;
214+
215+
if (data.callTree) {
216+
return [
217+
{title: 'What\'s the purpose of this work?', jslogContext: 'performance-default'},
218+
{title: 'Where is time being spent?', jslogContext: 'performance-default'},
219+
{title: 'How can I optimize this?', jslogContext: 'performance-default'},
220+
];
221+
}
214222

215-
if (!focus.insight) {
216-
return;
223+
if (data.insight) {
224+
return new PerformanceInsightFormatter(data.parsedTrace, data.insight).getSuggestions();
225+
}
226+
227+
const suggestions: ConversationSuggestions =
228+
[{title: 'What performance issues exist with my page?', jslogContext: 'performance-default'}];
229+
230+
if (data.insightSet) {
231+
const lcp = data.insightSet ? Trace.Insights.Common.getLCP(data.insightSet) : null;
232+
const cls = data.insightSet ? Trace.Insights.Common.getCLS(data.insightSet) : null;
233+
const inp = data.insightSet ? Trace.Insights.Common.getINP(data.insightSet) : null;
234+
235+
const ModelHandlers = Trace.Handlers.ModelHandlers;
236+
const GOOD = Trace.Handlers.ModelHandlers.PageLoadMetrics.ScoreClassification.GOOD;
237+
238+
if (lcp && ModelHandlers.PageLoadMetrics.scoreClassificationForLargestContentfulPaint(lcp.value) !== GOOD) {
239+
suggestions.push({title: 'How can I improve LCP?', jslogContext: 'performance-default'});
240+
}
241+
if (inp && ModelHandlers.UserInteractions.scoreClassificationForInteractionToNextPaint(inp.value) !== GOOD) {
242+
suggestions.push({title: 'How can I improve INP?', jslogContext: 'performance-default'});
243+
}
244+
if (cls && ModelHandlers.LayoutShifts.scoreClassificationForLayoutShift(cls.value) !== GOOD) {
245+
suggestions.push({title: 'How can I improve CLS?', jslogContext: 'performance-default'});
246+
}
217247
}
218248

219-
return new PerformanceInsightFormatter(focus.parsedTrace, focus.insight).getSuggestions();
249+
return suggestions;
220250
}
221251
}
222252

front_end/models/ai_assistance/agents/StylingAgent.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
AiAgent,
1919
type ContextResponse,
2020
ConversationContext,
21-
type ConversationSuggestion,
21+
type ConversationSuggestions,
2222
type FunctionCallHandlerResult,
2323
MultimodalInputType,
2424
type ParsedResponse,
@@ -182,7 +182,7 @@ export class NodeContext extends ConversationContext<SDK.DOMModel.DOMNode> {
182182
throw new Error('Not implemented');
183183
}
184184

185-
override async getSuggestions(): Promise<[ConversationSuggestion, ...ConversationSuggestion[]]|undefined> {
185+
override async getSuggestions(): Promise<ConversationSuggestions|undefined> {
186186
const layoutProps = await this.#node.domModel().cssModel().getLayoutPropertiesFromComputedStyle(this.#node.id);
187187

188188
if (!layoutProps) {

front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import * as Common from '../../../core/common/common.js';
66
import * as Trace from '../../trace/trace.js';
7-
import type {ConversationSuggestion} from '../agents/AiAgent.js';
7+
import type {ConversationSuggestions} from '../agents/AiAgent.js';
88

99
import {
1010
NetworkRequestFormatter,
@@ -103,7 +103,7 @@ export class PerformanceInsightFormatter {
103103
return this.#description().length > 0;
104104
}
105105

106-
getSuggestions(): [ConversationSuggestion, ...ConversationSuggestion[]] {
106+
getSuggestions(): ConversationSuggestions {
107107
switch (this.#insight.insightKey) {
108108
case 'CLSCulprits':
109109
return [

front_end/panels/ai_assistance/AiAssistancePanel.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -253,15 +253,6 @@ async function getEmptyStateSuggestions(
253253
{title: 'Why is the request failing?', jslogContext: 'network-default'},
254254
];
255255
case AiAssistanceModel.ConversationType.PERFORMANCE: {
256-
const focus = context?.getItem() as AiAssistanceModel.AgentFocus | null;
257-
if (focus?.data.callTree) {
258-
return [
259-
{title: 'What\'s the purpose of this work?', jslogContext: 'performance-default'},
260-
{title: 'Where is time being spent?', jslogContext: 'performance-default'},
261-
{title: 'How can I optimize this?', jslogContext: 'performance-default'},
262-
];
263-
}
264-
265256
return [
266257
{title: 'What performance issues exist with my page?', jslogContext: 'performance-default'},
267258
];

0 commit comments

Comments
 (0)