Skip to content

Commit fcab2ab

Browse files
committed
aggregated and format
Change-Id: I479ca2b692498b16a0f64f2f28a7ee710ce3e317
1 parent 187041c commit fcab2ab

File tree

3 files changed

+221
-63
lines changed

3 files changed

+221
-63
lines changed

src/tools/performance.ts

Lines changed: 73 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ import {logger} from '../logger.js';
88
import {zod} from '../third_party/index.js';
99
import type {Page} from '../third_party/index.js';
1010
import type {InsightName} from '../trace-processing/parse.js';
11-
import {getInsightOutput, getTraceSummary, parseRawTraceBuffer, traceResultIsSuccess} from '../trace-processing/parse.js';
11+
import {
12+
getInsightOutput,
13+
getTraceSummary,
14+
parseRawTraceBuffer,
15+
traceResultIsSuccess,
16+
} from '../trace-processing/parse.js';
1217

1318
import {ToolCategory} from './categories.js';
1419
import type {Context, Response} from './ToolDefinition.js';
@@ -23,13 +28,21 @@ export const startTrace = defineTool({
2328
readOnlyHint: true,
2429
},
2530
schema: {
26-
reload: zod.boolean().describe('Determines if, once tracing has started, the page should be automatically reloaded.'),
27-
autoStop: zod.boolean().describe('Determines if the trace recording should be automatically stopped.'),
31+
reload: zod
32+
.boolean()
33+
.describe(
34+
'Determines if, once tracing has started, the page should be automatically reloaded.',
35+
),
36+
autoStop: zod
37+
.boolean()
38+
.describe(
39+
'Determines if the trace recording should be automatically stopped.',
40+
),
2841
},
2942
handler: async (request, response, context) => {
3043
if (context.isRunningPerformanceTrace()) {
3144
response.appendResponseLine(
32-
'Error: a performance trace is already running. Use performance_stop_trace to stop it. Only one trace can be running at any given time.'
45+
'Error: a performance trace is already running. Use performance_stop_trace to stop it. Only one trace can be running at any given time.',
3346
);
3447
return;
3548
}
@@ -80,14 +93,17 @@ export const startTrace = defineTool({
8093
await new Promise(resolve => setTimeout(resolve, 5_000));
8194
await stopTracingAndAppendOutput(page, response, context);
8295
} else {
83-
response.appendResponseLine(`The performance trace is being recorded. Use performance_stop_trace to stop it.`);
96+
response.appendResponseLine(
97+
`The performance trace is being recorded. Use performance_stop_trace to stop it.`,
98+
);
8499
}
85100
},
86101
});
87102

88103
export const stopTrace = defineTool({
89104
name: 'performance_stop_trace',
90-
description: 'Stops the active performance trace recording on the selected page.',
105+
description:
106+
'Stops the active performance trace recording on the selected page.',
91107
annotations: {
92108
category: ToolCategory.PERFORMANCE,
93109
readOnlyHint: true,
@@ -104,22 +120,32 @@ export const stopTrace = defineTool({
104120

105121
export const analyzeInsight = defineTool({
106122
name: 'performance_analyze_insight',
107-
description: 'Provides more detailed information on a specific Performance Insight that was highlighted in the results of a trace recording.',
123+
description:
124+
'Provides more detailed information on a specific Performance Insight that was highlighted in the results of a trace recording.',
108125
annotations: {
109126
category: ToolCategory.PERFORMANCE,
110127
readOnlyHint: true,
111128
},
112129
schema: {
113-
insightName: zod.string().describe('The name of the Insight you want more information on. For example: "DocumentLatency" or "LCPBreakdown"'),
130+
insightName: zod
131+
.string()
132+
.describe(
133+
'The name of the Insight you want more information on. For example: "DocumentLatency" or "LCPBreakdown"',
134+
),
114135
},
115136
handler: async (request, response, context) => {
116137
const lastRecording = context.recordedTraces().at(-1);
117138
if (!lastRecording) {
118-
response.appendResponseLine('No recorded traces found. Record a performance trace so you have Insights to analyze.');
139+
response.appendResponseLine(
140+
'No recorded traces found. Record a performance trace so you have Insights to analyze.',
141+
);
119142
return;
120143
}
121144

122-
const insightOutput = getInsightOutput(lastRecording, request.params.insightName as InsightName);
145+
const insightOutput = getInsightOutput(
146+
lastRecording,
147+
request.params.insightName as InsightName,
148+
);
123149
if ('error' in insightOutput) {
124150
response.appendResponseLine(insightOutput.error);
125151
return;
@@ -129,7 +155,11 @@ export const analyzeInsight = defineTool({
129155
},
130156
});
131157

132-
async function stopTracingAndAppendOutput(page: Page, response: Response, context: Context): Promise<void> {
158+
async function stopTracingAndAppendOutput(
159+
page: Page,
160+
response: Response,
161+
context: Context,
162+
): Promise<void> {
133163
try {
134164
const traceEventsBuffer = await page.tracing.stop();
135165
const result = await parseRawTraceBuffer(traceEventsBuffer);
@@ -139,13 +169,17 @@ async function stopTracingAndAppendOutput(page: Page, response: Response, contex
139169
const traceSummaryText = getTraceSummary(result);
140170
response.appendResponseLine(traceSummaryText);
141171
} else {
142-
response.appendResponseLine('There was an unexpected error parsing the trace:');
172+
response.appendResponseLine(
173+
'There was an unexpected error parsing the trace:',
174+
);
143175
response.appendResponseLine(result.error);
144176
}
145177
} catch (e) {
146178
const errorText = e instanceof Error ? e.message : JSON.stringify(e);
147179
logger(`Error stopping performance trace: ${errorText}`);
148-
response.appendResponseLine('An error occurred generating the response for this trace:');
180+
response.appendResponseLine(
181+
'An error occurred generating the response for this trace:',
182+
);
149183
response.appendResponseLine(errorText);
150184
} finally {
151185
context.setIsRunningPerformanceTrace(false);
@@ -159,41 +193,60 @@ const CRUX_ENDPOINT = `https://chromeuxreport.googleapis.com/v1/records:queryRec
159193
export const queryChromeUXReport = defineTool({
160194
name: 'performance_query_chrome_ux_report',
161195
description:
162-
'Queries the Chrome UX Report (CrUX) API to get real-user experience metrics (like Core Web Vitals) for a given URL or origin. You must provide EITHER "origin" OR "url", but not both. You can optionally filter by "formFactor".',
196+
'Queries the Chrome UX Report (aka CrUX) to get aggregated real-user experience metrics (like Core Web Vitals) for a given URL or origin. You must provide EITHER "origin" OR "url", but not both. You can optionally filter by "formFactor".',
163197
annotations: {
164198
category: ToolCategory.PERFORMANCE,
165199
readOnlyHint: true,
166200
},
167201
schema: {
168-
origin: zod.string().describe('The origin to query, e.g., "https://www.google.com". Do not provide this if "url" is specified.').optional(),
202+
origin: zod
203+
.string()
204+
.describe(
205+
'The origin to query, e.g., "https://www.google.com". Do not provide this if "url" is specified.',
206+
)
207+
.optional(),
169208
url: zod
170209
.string()
171-
.describe('The specific page URL to query, e.g., "https://www.google.com/search?q=puppies". Do not provide this if "origin" is specified.')
210+
.describe(
211+
'The specific page URL to query, e.g., "https://www.google.com/search?q=puppies". Do not provide this if "origin" is specified.',
212+
)
172213
.optional(),
173214
formFactor: zod
174215
.enum(['DESKTOP', 'PHONE', 'TABLET'])
175-
.describe('The form factor to filter by. If omitted, data for all form factors is aggregated.')
216+
.describe(
217+
'The form factor to filter by. If omitted, data for all form factors is aggregated.',
218+
)
176219
.optional(),
177220
},
178221
handler: async (request, response) => {
179222
const {origin, url, formFactor} = request.params;
180223

181224
if ((!origin && !url) || (origin && url)) {
182-
response.appendResponseLine('Error: you must provide either "origin" or "url", but not both.');
225+
response.appendResponseLine(
226+
'Error: you must provide either "origin" or "url", but not both.',
227+
);
183228
return;
184229
}
185230

186231
const body = JSON.stringify({
187232
origin,
188233
url,
189234
formFactor,
190-
metrics: ['first_contentful_paint', 'largest_contentful_paint', 'cumulative_layout_shift', 'interaction_to_next_paint'],
235+
metrics: [
236+
'first_contentful_paint',
237+
'largest_contentful_paint',
238+
'cumulative_layout_shift',
239+
'interaction_to_next_paint',
240+
],
191241
});
192242

193243
try {
194244
const cruxResponse = await fetch(CRUX_ENDPOINT, {
195245
method: 'POST',
196-
headers: {'Content-Type': 'application/json', referer: 'devtools://mcp'},
246+
headers: {
247+
'Content-Type': 'application/json',
248+
referer: 'devtools://mcp',
249+
},
197250
body,
198251
});
199252

0 commit comments

Comments
 (0)