chrome-devtools-frontend 1.0.1646286 → 1.0.1649421

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.
Files changed (57) hide show
  1. package/SECURITY.md +1 -1
  2. package/extension-api/ExtensionAPI.d.ts +26 -0
  3. package/front_end/core/common/Debouncer.ts +9 -1
  4. package/front_end/core/sdk/CSSMatchedStyles.ts +3 -1
  5. package/front_end/core/sdk/CSSMetadata.ts +1 -0
  6. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +65 -0
  7. package/front_end/generated/InspectorBackendCommands.ts +2 -1
  8. package/front_end/generated/SupportedCSSProperties.js +739 -21
  9. package/front_end/generated/protocol.ts +26 -0
  10. package/front_end/models/ai_assistance/AiAgent2.ts +14 -9
  11. package/front_end/models/ai_assistance/agents/AiAgent.ts +10 -3
  12. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +7 -0
  13. package/front_end/models/ai_assistance/agents/StorageAgent.ts +45 -0
  14. package/front_end/models/ai_assistance/ai_assistance.ts +4 -0
  15. package/front_end/models/ai_assistance/skills/Skill.ts +1 -1
  16. package/front_end/models/ai_assistance/skills/SkillRegistry.ts +2 -0
  17. package/front_end/models/ai_assistance/skills/network.md +16 -0
  18. package/front_end/models/ai_assistance/skills/styling.md +1 -1
  19. package/front_end/models/ai_assistance/tools/GetNetworkRequestDetails.ts +118 -0
  20. package/front_end/models/ai_assistance/tools/ListNetworkRequests.ts +124 -0
  21. package/front_end/models/ai_assistance/tools/Tool.ts +2 -0
  22. package/front_end/models/ai_assistance/tools/ToolRegistry.ts +4 -0
  23. package/front_end/models/emulation/EmulatedDevices.ts +430 -12
  24. package/front_end/models/extensions/ExtensionAPI.ts +47 -21
  25. package/front_end/models/javascript_metadata/NativeFunctions.js +5 -1
  26. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +40 -1
  27. package/front_end/panels/ai_assistance/ai_assistance.ts +1 -0
  28. package/front_end/panels/ai_assistance/components/AIv2MarkdownRenderer.ts +228 -0
  29. package/front_end/panels/ai_assistance/components/ChatMessage.ts +39 -2
  30. package/front_end/panels/application/ApplicationPanelSidebar.ts +4 -0
  31. package/front_end/panels/application/CookieItemsView.ts +55 -6
  32. package/front_end/panels/application/DOMStorageItemsView.ts +43 -8
  33. package/front_end/panels/application/KeyValueStorageItemsView.ts +17 -9
  34. package/front_end/panels/application/WebMCPTreeElement.ts +8 -0
  35. package/front_end/panels/elements/StylePropertyTreeElement.ts +73 -16
  36. package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +9 -1
  37. package/front_end/panels/elements/StylesSidebarPane.ts +22 -8
  38. package/front_end/panels/layer_viewer/PaintProfilerView.ts +309 -182
  39. package/front_end/panels/layer_viewer/paintProfiler.css +27 -23
  40. package/front_end/panels/layers/LayerPaintProfilerView.ts +86 -29
  41. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +210 -356
  42. package/front_end/panels/sources/watchExpressionsSidebarPane.css +7 -0
  43. package/front_end/panels/timeline/TimelinePaintProfilerView.ts +5 -5
  44. package/front_end/panels/timeline/components/NetworkTrackWidget.ts +122 -0
  45. package/front_end/panels/timeline/components/components.ts +2 -0
  46. package/front_end/panels/timeline/components/networkTrackWidget.css +31 -0
  47. package/front_end/panels/timeline/timeline.ts +2 -0
  48. package/front_end/third_party/chromium/README.chromium +1 -1
  49. package/front_end/ui/components/buttons/FloatingButton.ts +17 -2
  50. package/front_end/ui/components/buttons/floatingButton.css +2 -2
  51. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +1 -1
  52. package/front_end/ui/legacy/TextPrompt.ts +24 -18
  53. package/front_end/ui/legacy/Treeoutline.ts +31 -4
  54. package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +50 -24
  55. package/front_end/ui/legacy/components/utils/Linkifier.ts +10 -0
  56. package/front_end/ui/visual_logging/KnownContextValues.ts +13 -0
  57. package/package.json +1 -1
@@ -2918,6 +2918,28 @@ export namespace CSS {
2918
2918
  specificity?: Specificity;
2919
2919
  }
2920
2920
 
2921
+ /**
2922
+ * Contribution of an individual simple selector to specificity.
2923
+ */
2924
+ export interface SpecificityComponent {
2925
+ /**
2926
+ * The simple selector text that contributes to specificity.
2927
+ */
2928
+ text: string;
2929
+ /**
2930
+ * The a component contribution.
2931
+ */
2932
+ a: integer;
2933
+ /**
2934
+ * The b component contribution.
2935
+ */
2936
+ b: integer;
2937
+ /**
2938
+ * The c component contribution.
2939
+ */
2940
+ c: integer;
2941
+ }
2942
+
2921
2943
  /**
2922
2944
  * Specificity:
2923
2945
  * https://drafts.csswg.org/selectors/#specificity-rules
@@ -2936,6 +2958,10 @@ export namespace CSS {
2936
2958
  * The c component, which represents the number of type selectors and pseudo-elements.
2937
2959
  */
2938
2960
  c: integer;
2961
+ /**
2962
+ * Per-simple-selector contributions used to explain this specificity.
2963
+ */
2964
+ components?: SpecificityComponent[];
2939
2965
  }
2940
2966
 
2941
2967
  /**
@@ -26,6 +26,7 @@ import {ToolRegistry} from './tools/ToolRegistry.js';
26
26
 
27
27
  const SKILL_DISPLAY_NAMES: Record<SkillName, string> = {
28
28
  styling: 'CSS and styling',
29
+ network: 'Network requests',
29
30
  };
30
31
 
31
32
  const preamble = `You are the most advanced unified AI assistant integrated into Chrome DevTools.
@@ -61,7 +62,6 @@ export class AiAgent2 extends AiAgent<unknown> {
61
62
  readonly clientFeature = Host.AidaClient.ClientFeature.CHROME_DEVTOOLS_V2_AGENT;
62
63
  readonly userTier = 'TESTERS';
63
64
 
64
- #skillsInjected = false;
65
65
  #changes = new ChangeManager();
66
66
  #execJs: typeof executeJsCode;
67
67
  readonly #allowedOrigin?: () => AllowedOriginResult;
@@ -78,9 +78,12 @@ export class AiAgent2 extends AiAgent<unknown> {
78
78
  this.#execJs = opts.execJs ?? executeJsCode;
79
79
  this.#allowedOrigin = opts.allowedOrigin;
80
80
  this.#declaredTools.add('learnSkills');
81
- const skillsList = Object.keys(SKILLS).join(', ');
82
81
  this.declareFunction<{skills: SkillName[]}>('learnSkills', {
83
- description: `Load skills to help with the task. Available skills: ${skillsList}.`,
82
+ description: () => {
83
+ const unloadedSkills = Object.keys(SKILLS).filter(name => !this.#activeSkills.has(name as SkillName));
84
+ return `Loads the specified skills to gain access to their specialized tools. Call this if the user's query relates to an available skill that is not yet loaded. Available skills: ${
85
+ unloadedSkills.join(', ')}.`;
86
+ },
84
87
  parameters: {
85
88
  type: Host.AidaClient.ParametersTypes.OBJECT,
86
89
  description: 'Parameters for learning skills',
@@ -130,16 +133,18 @@ QUERY: ${query}`;
130
133
  }
131
134
  }
132
135
 
133
- if (this.#skillsInjected) {
136
+ const unloadedSkills =
137
+ Object.entries(this.getSkills()).filter(([name]) => !this.#activeSkills.has(name as SkillName));
138
+ if (unloadedSkills.length === 0) {
134
139
  return enhancedQuery;
135
140
  }
136
- this.#skillsInjected = true;
137
- const skillsManifest =
138
- Object.entries(this.getSkills()).map(([name, skill]) => `- ${name}: ${skill.description}`).join('\n');
139
- return `Available skills:
141
+
142
+ const skillsManifest = unloadedSkills.map(([name, skill]) => `- ${name}: ${skill.description}`).join('\n');
143
+ return `Available skills that are not yet loaded:
140
144
  ${skillsManifest}
141
145
 
142
- You must call \`learnSkills\` to load a skill before you can use it.
146
+ You must call \`learnSkills\` to load a skill before you can use its tools.
147
+ If the user's request requires a skill that is not currently loaded, you MUST call \`learnSkills\` to load that skill first, instead of attempting to solve the query using tools from other skills.
143
148
 
144
149
  User query: ${enhancedQuery}`;
145
150
  }
@@ -338,6 +338,13 @@ export interface NetworkRequestsListAiWidget {
338
338
  requests: SDK.NetworkRequest.NetworkRequest[],
339
339
  };
340
340
  }
341
+ export interface NetworkTrackAiWidget {
342
+ name: 'NETWORK_TRACK';
343
+ data: {
344
+ parsedTrace: Trace.TraceModel.ParsedTrace,
345
+ bounds: Trace.Types.Timing.TraceWindowMicro,
346
+ };
347
+ }
341
348
 
342
349
  export interface LighthouseReportAiWidget {
343
350
  name: 'LIGHTHOUSE_REPORT';
@@ -376,7 +383,7 @@ export interface SourceCodeAiWidget {
376
383
  export type AiWidget = ComputedStyleAiWidget|CoreVitalsAiWidget|StylePropertiesAiWidget|DomTreeAiWidget|
377
384
  PerformanceTraceAiWidget|PerfInsightAiWidget|TimelineRangeSummaryAiWidget|BottomUpTreeAiWidget|SourceFileAiWidget|
378
385
  LighthouseReportAiWidget|TimelineEventSummaryAiWidget|NetworkRequestGeneralHeadersAiWidget|SourceCodeAiWidget|
379
- SourceFilesListAiWidget|NetworkRequestsListAiWidget;
386
+ SourceFilesListAiWidget|NetworkRequestsListAiWidget|NetworkTrackAiWidget;
380
387
 
381
388
  export type FunctionCallHandlerResult<Result> = {
382
389
  requiresApproval: true,
@@ -410,7 +417,7 @@ export interface FunctionDeclaration<Args extends Record<string, unknown>, Retur
410
417
  * Description of function, this is send to the LLM
411
418
  * to explain what will the function do.
412
419
  */
413
- description: string;
420
+ description: string|(() => string);
414
421
  /**
415
422
  * JSON schema like representation of the parameters
416
423
  * the function needs to be called with.
@@ -582,7 +589,7 @@ export abstract class AiAgent<T> {
582
589
  for (const [name, definition] of this.#functionDeclarations.entries()) {
583
590
  declarations.push({
584
591
  name,
585
- description: definition.description,
592
+ description: typeof definition.description === 'function' ? definition.description() : definition.description,
586
593
  parameters: definition.parameters,
587
594
  });
588
595
  }
@@ -1232,6 +1232,13 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
1232
1232
  this.#cacheFunctionResult(focus, key, summary);
1233
1233
  return {
1234
1234
  result: {summary},
1235
+ widgets: [{
1236
+ name: 'NETWORK_TRACK',
1237
+ data: {
1238
+ parsedTrace,
1239
+ bounds,
1240
+ },
1241
+ }],
1235
1242
  };
1236
1243
  },
1237
1244
 
@@ -14,6 +14,7 @@ import {
14
14
  AiAgent,
15
15
  type ContextResponse,
16
16
  ConversationContext,
17
+ type ConversationSuggestions,
17
18
  type RequestOptions,
18
19
  ResponseType,
19
20
  } from './AiAgent.js';
@@ -97,6 +98,50 @@ export class StorageContext extends ConversationContext<StorageItem> {
97
98
  }
98
99
  return `Storage: ${this.getOrigin()}`;
99
100
  }
101
+
102
+ override async getSuggestions(): Promise<ConversationSuggestions|undefined> {
103
+ if (this.#item instanceof CookieItem) {
104
+ if (this.#item.name) {
105
+ return [
106
+ {
107
+ title: 'Why is this cookie set?',
108
+ jslogContext: 'storage-cookie',
109
+ },
110
+ {
111
+ title: 'Explain the value of this cookie',
112
+ jslogContext: 'storage-cookie',
113
+ },
114
+ ];
115
+ }
116
+ return [
117
+ {
118
+ title: 'Explain the cookies set by this page',
119
+ jslogContext: 'storage-cookie',
120
+ },
121
+ ];
122
+ }
123
+ if (this.#item instanceof DOMStorageItem) {
124
+ if (this.#item.key) {
125
+ return [
126
+ {
127
+ title: 'What is the purpose of this storage entry?',
128
+ jslogContext: 'storage-domstorage',
129
+ },
130
+ {
131
+ title: 'Explain the value of this storage entry',
132
+ jslogContext: 'storage-domstorage',
133
+ },
134
+ ];
135
+ }
136
+ return [
137
+ {
138
+ title: 'Explain these storage items',
139
+ jslogContext: 'storage-domstorage',
140
+ },
141
+ ];
142
+ }
143
+ return undefined;
144
+ }
100
145
  }
101
146
 
102
147
  // Maximum character length of values allowed.
@@ -42,7 +42,9 @@ import * as AIQueries from './performance/AIQueries.js';
42
42
  import * as PerformanceAnnotations from './PerformanceAnnotations.js';
43
43
  import * as StorageItem from './StorageItem.js';
44
44
  import * as ExecuteJavaScript from './tools/ExecuteJavaScript.js';
45
+ import * as GetNetworkRequestDetails from './tools/GetNetworkRequestDetails.js';
45
46
  import * as GetStyles from './tools/GetStyles.js';
47
+ import * as ListNetworkRequests from './tools/ListNetworkRequests.js';
46
48
  import * as Tool from './tools/Tool.js';
47
49
  import * as ToolRegistry from './tools/ToolRegistry.js';
48
50
 
@@ -70,12 +72,14 @@ export {
70
72
  FileAgent,
71
73
  FileContext,
72
74
  FileFormatter,
75
+ GetNetworkRequestDetails,
73
76
  GetStyles,
74
77
  GreenDevAgent,
75
78
  GreenDevAgentAntigravityCliSocketClient,
76
79
  GreenDevAgentGeminiCliSocketClient,
77
80
  Injected,
78
81
  LighthouseFormatter,
82
+ ListNetworkRequests,
79
83
  NetworkAgent,
80
84
  NetworkRequestFormatter,
81
85
  PatchAgent,
@@ -3,7 +3,7 @@
3
3
  // found in the LICENSE file.
4
4
 
5
5
  // This will become a union type as we add more skills (e.g. 'styling' | 'network').
6
- export type SkillName = 'styling';
6
+ export type SkillName = 'styling'|'network';
7
7
 
8
8
  export interface Skill {
9
9
  name: SkillName;
@@ -2,9 +2,11 @@
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 {skill as networkSkill} from './network.skill.js';
5
6
  import type {Skill, SkillName} from './Skill.js';
6
7
  import {skill as stylingSkill} from './styling.skill.js';
7
8
 
8
9
  export const SKILLS: Record<SkillName, Skill> = {
9
10
  styling: stylingSkill,
11
+ network: networkSkill,
10
12
  };
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: network
3
+ description: Analyzing network traffic, network requests, HTTP/HTTPS headers, status codes, payload details, timing/performance, and request sizes.
4
+ allowed-tools:
5
+ - listNetworkRequests
6
+ - getNetworkRequestDetails
7
+ ---
8
+ You are the most advanced network request debugging assistant integrated into Chrome DevTools.
9
+ Provide a comprehensive analysis of network requests, focusing on areas crucial for a software engineer. Your analysis should include:
10
+ * Briefly explain the purpose of the request based on the URL, method, and any relevant headers or payload.
11
+ * Analyze timing information to identify potential bottlenecks or areas for optimization.
12
+ * Highlight potential issues indicated by the status code.
13
+
14
+ # Considerations
15
+ * If the response payload or request payload contains sensitive data, redact or generalize it in your analysis to ensure privacy.
16
+ * Tailor your explanations and suggestions to the specific context of the request and the technologies involved (if discernible from the provided details).
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: styling
3
- description: Helping with CSS and styling
3
+ description: CSS, styling, layouts, positioning, computed styles, DOM tree structure, and page styles.
4
4
  allowed-tools:
5
5
  - executeJavaScript
6
6
  - getStyles
@@ -0,0 +1,118 @@
1
+ // Copyright 2026 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 * as Host from '../../../core/host/host.js';
6
+ import * as i18n from '../../../core/i18n/i18n.js';
7
+ import * as Logs from '../../logs/logs.js';
8
+ import * as NetworkTimeCalculator from '../../network_time_calculator/network_time_calculator.js';
9
+ import type {FunctionCallHandlerResult} from '../agents/AiAgent.js';
10
+ import {isOpaqueOrigin} from '../AiOrigins.js';
11
+ import {getRequestContextOrigin} from '../contexts/RequestContext.js';
12
+ import {NetworkRequestFormatter} from '../data_formatters/NetworkRequestFormatter.js';
13
+
14
+ import {
15
+ type BaseToolCapability,
16
+ type OriginLockCapability,
17
+ type Tool,
18
+ type ToolArgs,
19
+ ToolName,
20
+ } from './Tool.js';
21
+ const UIStringsNotTranslate = {
22
+ gettingNetworkRequestDetails: 'Getting network request details',
23
+ } as const;
24
+
25
+ const lockedString = i18n.i18n.lockedString;
26
+
27
+ export interface GetNetworkRequestDetailsArgs extends ToolArgs {
28
+ id: string;
29
+ }
30
+
31
+ /**
32
+ * A tool that retrieves detailed information about a specific network request.
33
+ * The details include request/response headers, status code, timings, and the response body.
34
+ */
35
+ export class GetNetworkRequestDetailsTool implements
36
+ Tool<GetNetworkRequestDetailsArgs, unknown, BaseToolCapability&OriginLockCapability> {
37
+ readonly name = ToolName.GET_NETWORK_REQUEST_DETAILS;
38
+ readonly description =
39
+ 'Retrieves the full headers, timing, status, and body details of a specific network request by ID.';
40
+
41
+ readonly parameters: Host.AidaClient.FunctionObjectParam<keyof GetNetworkRequestDetailsArgs> = {
42
+ type: Host.AidaClient.ParametersTypes.OBJECT,
43
+ description: 'Arguments for retrieving detailed information about a specific network request.',
44
+ nullable: false,
45
+ properties: {
46
+ id: {
47
+ type: Host.AidaClient.ParametersTypes.STRING,
48
+ description: 'The id of the network request to inspect.',
49
+ nullable: false,
50
+ },
51
+ },
52
+ required: ['id'],
53
+ };
54
+
55
+ displayInfoFromArgs(args: GetNetworkRequestDetailsArgs): {
56
+ title: string,
57
+ action: string,
58
+ } {
59
+ return {
60
+ title: lockedString(UIStringsNotTranslate.gettingNetworkRequestDetails),
61
+ action: `getNetworkRequestDetails(${args.id})`,
62
+ };
63
+ }
64
+
65
+ /**
66
+ * Handles the request to retrieve details for a network request by its ID.
67
+ * Filters by the conversation's established origin to prevent cross-origin data exposure.
68
+ */
69
+ async handler(
70
+ args: GetNetworkRequestDetailsArgs,
71
+ context: BaseToolCapability&OriginLockCapability,
72
+ ): Promise<FunctionCallHandlerResult<unknown>> {
73
+ // A conversation is locked to an origin once the first query is made.
74
+ // We only allow inspecting requests matching the conversation's established origin.
75
+ const origin = context.getEstablishedOrigin();
76
+
77
+ // Opaque origins are never allowed to be used as context.
78
+ if (origin && isOpaqueOrigin(origin)) {
79
+ return {
80
+ error: 'Opaque origin not allowed',
81
+ };
82
+ }
83
+
84
+ const request = Logs.NetworkLog.NetworkLog.instance().requests().find(req => {
85
+ if (req.requestId() !== args.id) {
86
+ return false;
87
+ }
88
+
89
+ // To prevent cross-origin prompt injection attacks, HAR-imported requests
90
+ // are assigned a virtual origin (e.g., `imported-har://${domain}`) rather than
91
+ // sharing the origin of live pages.
92
+ const requestOrigin = getRequestContextOrigin(req);
93
+
94
+ // If the conversation is locked to an origin, only allow accessing requests from that origin.
95
+ return !origin || requestOrigin === origin;
96
+ });
97
+
98
+ if (!request) {
99
+ return {
100
+ error: 'No request found',
101
+ };
102
+ }
103
+
104
+ const calculator = new NetworkTimeCalculator.NetworkTransferTimeCalculator();
105
+ const formatter = new NetworkRequestFormatter(request, calculator);
106
+ const formattedDetails = await formatter.formatNetworkRequest();
107
+
108
+ return {
109
+ result: formattedDetails,
110
+ widgets: [{
111
+ name: 'NETWORK_REQUEST_GENERAL_HEADERS',
112
+ data: {
113
+ request,
114
+ },
115
+ }],
116
+ };
117
+ }
118
+ }
@@ -0,0 +1,124 @@
1
+ // Copyright 2026 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 * as Host from '../../../core/host/host.js';
6
+ import * as i18n from '../../../core/i18n/i18n.js';
7
+ import type * as SDK from '../../../core/sdk/sdk.js';
8
+ import * as Logs from '../../logs/logs.js';
9
+ import type {FunctionCallHandlerResult} from '../agents/AiAgent.js';
10
+ import {isOpaqueOrigin} from '../AiOrigins.js';
11
+ import {getRequestContextOrigin} from '../contexts/RequestContext.js';
12
+
13
+ import {
14
+ type BaseToolCapability,
15
+ type OriginLockCapability,
16
+ type Tool,
17
+ ToolName,
18
+ } from './Tool.js';
19
+
20
+ const UIStringsNotTranslate = {
21
+ listingNetworkRequests: 'Listing network requests',
22
+ } as const;
23
+
24
+ const lockedString = i18n.i18n.lockedString;
25
+
26
+ interface NetworkRequestSummary {
27
+ id: string;
28
+ url: string;
29
+ statusCode: number;
30
+ duration: string;
31
+ transferSize: string;
32
+ }
33
+
34
+ /**
35
+ * A tool that lists all network requests recorded by DevTools.
36
+ * Filters the list by the conversation's established origin to prevent cross-origin data exposure.
37
+ */
38
+ export class ListNetworkRequestsTool implements
39
+ Tool<Record<string, never>, unknown, BaseToolCapability&OriginLockCapability> {
40
+ readonly name = ToolName.LIST_NETWORK_REQUESTS;
41
+ readonly description = 'Gives a list of network requests including URL, status code, and duration.';
42
+
43
+ readonly parameters: Host.AidaClient.FunctionObjectParam<never> = {
44
+ type: Host.AidaClient.ParametersTypes.OBJECT,
45
+ description: '',
46
+ nullable: true,
47
+ required: [],
48
+ properties: {},
49
+ };
50
+
51
+ displayInfoFromArgs(): {
52
+ title: string,
53
+ action: string,
54
+ } {
55
+ return {
56
+ title: lockedString(UIStringsNotTranslate.listingNetworkRequests),
57
+ action: 'listNetworkRequests()',
58
+ };
59
+ }
60
+
61
+ /**
62
+ * Handles the request to list network requests.
63
+ * Returns requests matching the conversation's established origin, if set.
64
+ */
65
+ async handler(
66
+ _params: Record<string, never>,
67
+ context: BaseToolCapability&OriginLockCapability,
68
+ ): Promise<FunctionCallHandlerResult<unknown>> {
69
+ const requests: NetworkRequestSummary[] = [];
70
+ // A conversation is locked to an origin once the first query is made.
71
+ // We only allow inspecting requests matching the conversation's established origin.
72
+ const origin = context.getEstablishedOrigin();
73
+
74
+ // Opaque origins are never allowed to be used as context.
75
+ if (origin && isOpaqueOrigin(origin)) {
76
+ return {
77
+ error: 'Opaque origin not allowed',
78
+ };
79
+ }
80
+
81
+ let hasCrossOriginRequest = false;
82
+ const requestsToShow: SDK.NetworkRequest.NetworkRequest[] = [];
83
+ for (const request of Logs.NetworkLog.NetworkLog.instance().requests()) {
84
+ // To prevent cross-origin prompt injection attacks, HAR-imported requests
85
+ // are assigned a virtual origin (e.g., `imported-har://${domain}`) rather than
86
+ // sharing the origin of live pages.
87
+ const requestOrigin = getRequestContextOrigin(request);
88
+
89
+ // If the conversation is locked to an origin, skip requests from other origins.
90
+ if (origin && requestOrigin !== origin) {
91
+ hasCrossOriginRequest = true;
92
+ continue;
93
+ }
94
+
95
+ requests.push({
96
+ id: request.requestId(),
97
+ url: request.url(),
98
+ statusCode: request.statusCode,
99
+ duration: i18n.TimeUtilities.secondsToString(request.duration),
100
+ transferSize: i18n.ByteUtilities.formatBytesToKb(request.transferSize),
101
+ });
102
+ requestsToShow.push(request);
103
+ }
104
+
105
+ if (requests.length === 0) {
106
+ return {
107
+ // If there were requests but they were filtered out due to the origin lock,
108
+ // we ask the user to start a new chat so they can select a request from the other origin.
109
+ error: hasCrossOriginRequest ? `No requests showing with origin ${origin}. Tell the user to start a new chat` :
110
+ 'No requests recorded by DevTools',
111
+ };
112
+ }
113
+
114
+ return {
115
+ result: JSON.stringify(requests),
116
+ widgets: [{
117
+ name: 'NETWORK_REQUESTS_LIST',
118
+ data: {
119
+ requests: requestsToShow,
120
+ },
121
+ }],
122
+ };
123
+ }
124
+ }
@@ -87,6 +87,8 @@ export type ToolArgs = Record<string, unknown>;
87
87
  export const enum ToolName {
88
88
  EXECUTE_JAVASCRIPT = 'executeJavaScript',
89
89
  GET_STYLES = 'getStyles',
90
+ LIST_NETWORK_REQUESTS = 'listNetworkRequests',
91
+ GET_NETWORK_REQUEST_DETAILS = 'getNetworkRequestDetails',
90
92
  }
91
93
 
92
94
  /**
@@ -3,7 +3,9 @@
3
3
  // found in the LICENSE file.
4
4
 
5
5
  import {ExecuteJavaScriptTool} from './ExecuteJavaScript.js';
6
+ import {GetNetworkRequestDetailsTool} from './GetNetworkRequestDetails.js';
6
7
  import {GetStylesTool} from './GetStyles.js';
8
+ import {ListNetworkRequestsTool} from './ListNetworkRequests.js';
7
9
  import {type AllToolsContext, type Tool, type ToolArgs, ToolName} from './Tool.js';
8
10
 
9
11
  /**
@@ -17,6 +19,8 @@ import {type AllToolsContext, type Tool, type ToolArgs, ToolName} from './Tool.j
17
19
  export const TOOLS = {
18
20
  [ToolName.EXECUTE_JAVASCRIPT]: new ExecuteJavaScriptTool(),
19
21
  [ToolName.GET_STYLES]: new GetStylesTool(),
22
+ [ToolName.LIST_NETWORK_REQUESTS]: new ListNetworkRequestsTool(),
23
+ [ToolName.GET_NETWORK_REQUEST_DETAILS]: new GetNetworkRequestDetailsTool(),
20
24
  };
21
25
 
22
26
  /**