chrome-devtools-frontend 1.0.1646286 → 1.0.1646714

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/SECURITY.md CHANGED
@@ -18,7 +18,7 @@ Chrome DevTools is a privileged web app running in a sandboxed renderer process,
18
18
  * Triggering Chrome memory corruption exploits.
19
19
 
20
20
  ### Outside Threat Model
21
- * **Social Engineering:** Convincing developers to paste payloads into the Console or connect to malicious remote debugging ports.
21
+ * **Social Engineering:** Convincing developers to paste payloads into the Console, download and open a compromised file, or connect to malicious remote debugging ports, etc.
22
22
  * **Legitimate Data Exposure:** Displaying local user data, cookies, tokens, or auth headers within UI panels.
23
23
  * **Local Data Persistence:** Saving user-initiated traces, heaps, profiles, or logs to disk.
24
24
  * **Correctness & Availability:** Stale, misleading, or missing UI information (classified as functional bugs).
@@ -798,7 +798,7 @@ inspectorBackend.registerEnum("Network.ServiceWorkerRouterSource", {Network: "ne
798
798
  inspectorBackend.registerEnum("Network.InitiatorType", {Parser: "parser", Script: "script", Preload: "preload", SignedExchange: "SignedExchange", Preflight: "preflight", FedCM: "FedCM", Other: "other"});
799
799
  inspectorBackend.registerEnum("Network.SetCookieBlockedReason", {SecureOnly: "SecureOnly", SameSiteStrict: "SameSiteStrict", SameSiteLax: "SameSiteLax", SameSiteUnspecifiedTreatedAsLax: "SameSiteUnspecifiedTreatedAsLax", SameSiteNoneInsecure: "SameSiteNoneInsecure", UserPreferences: "UserPreferences", ThirdPartyPhaseout: "ThirdPartyPhaseout", ThirdPartyBlockedInFirstPartySet: "ThirdPartyBlockedInFirstPartySet", SyntaxError: "SyntaxError", SchemeNotSupported: "SchemeNotSupported", OverwriteSecure: "OverwriteSecure", InvalidDomain: "InvalidDomain", InvalidPrefix: "InvalidPrefix", UnknownError: "UnknownError", SchemefulSameSiteStrict: "SchemefulSameSiteStrict", SchemefulSameSiteLax: "SchemefulSameSiteLax", SchemefulSameSiteUnspecifiedTreatedAsLax: "SchemefulSameSiteUnspecifiedTreatedAsLax", NameValuePairExceedsMaxSize: "NameValuePairExceedsMaxSize", DisallowedCharacter: "DisallowedCharacter", NoCookieContent: "NoCookieContent"});
800
800
  inspectorBackend.registerEnum("Network.CookieBlockedReason", {SecureOnly: "SecureOnly", NotOnPath: "NotOnPath", DomainMismatch: "DomainMismatch", SameSiteStrict: "SameSiteStrict", SameSiteLax: "SameSiteLax", SameSiteUnspecifiedTreatedAsLax: "SameSiteUnspecifiedTreatedAsLax", SameSiteNoneInsecure: "SameSiteNoneInsecure", UserPreferences: "UserPreferences", ThirdPartyPhaseout: "ThirdPartyPhaseout", ThirdPartyBlockedInFirstPartySet: "ThirdPartyBlockedInFirstPartySet", UnknownError: "UnknownError", SchemefulSameSiteStrict: "SchemefulSameSiteStrict", SchemefulSameSiteLax: "SchemefulSameSiteLax", SchemefulSameSiteUnspecifiedTreatedAsLax: "SchemefulSameSiteUnspecifiedTreatedAsLax", NameValuePairExceedsMaxSize: "NameValuePairExceedsMaxSize", PortMismatch: "PortMismatch", SchemeMismatch: "SchemeMismatch", AnonymousContext: "AnonymousContext"});
801
- inspectorBackend.registerEnum("Network.CookieExemptionReason", {None: "None", UserSetting: "UserSetting", EnterprisePolicy: "EnterprisePolicy", StorageAccess: "StorageAccess", TopLevelStorageAccess: "TopLevelStorageAccess", Scheme: "Scheme", SameSiteNoneCookiesInSandbox: "SameSiteNoneCookiesInSandbox"});
801
+ inspectorBackend.registerEnum("Network.CookieExemptionReason", {None: "None", UserSetting: "UserSetting", TPCDMetadata: "TPCDMetadata", TPCDDeprecationTrial: "TPCDDeprecationTrial", TopLevelTPCDDeprecationTrial: "TopLevelTPCDDeprecationTrial", TPCDHeuristics: "TPCDHeuristics", EnterprisePolicy: "EnterprisePolicy", StorageAccess: "StorageAccess", TopLevelStorageAccess: "TopLevelStorageAccess", Scheme: "Scheme", SameSiteNoneCookiesInSandbox: "SameSiteNoneCookiesInSandbox"});
802
802
  inspectorBackend.registerEnum("Network.AuthChallengeSource", {Server: "Server", Proxy: "Proxy"});
803
803
  inspectorBackend.registerEnum("Network.AuthChallengeResponseResponse", {Default: "Default", CancelAuth: "CancelAuth", ProvideCredentials: "ProvideCredentials"});
804
804
  inspectorBackend.registerEnum("Network.InterceptionStage", {Request: "Request", HeadersReceived: "HeadersReceived"});
@@ -259,6 +259,20 @@ export const generatedProperties = [
259
259
  "name": "align-items"
260
260
  },
261
261
  {
262
+ "keywords": [
263
+ "auto",
264
+ "normal",
265
+ "stretch",
266
+ "baseline",
267
+ "center",
268
+ "start",
269
+ "end",
270
+ "self-start",
271
+ "self-end",
272
+ "flex-start",
273
+ "flex-end",
274
+ "anchor-center"
275
+ ],
262
276
  "name": "align-self"
263
277
  },
264
278
  {
@@ -1251,6 +1265,13 @@ export const generatedProperties = [
1251
1265
  "name": "border-end-start-radius"
1252
1266
  },
1253
1267
  {
1268
+ "keywords": [
1269
+ "none",
1270
+ "repeat",
1271
+ "stretch",
1272
+ "space",
1273
+ "round"
1274
+ ],
1254
1275
  "longhands": [
1255
1276
  "border-image-source",
1256
1277
  "border-image-slice",
@@ -1894,6 +1915,9 @@ export const generatedProperties = [
1894
1915
  "name": "contain"
1895
1916
  },
1896
1917
  {
1918
+ "keywords": [
1919
+ "none"
1920
+ ],
1897
1921
  "name": "contain-intrinsic-block-size"
1898
1922
  },
1899
1923
  {
@@ -1903,6 +1927,9 @@ export const generatedProperties = [
1903
1927
  "name": "contain-intrinsic-height"
1904
1928
  },
1905
1929
  {
1930
+ "keywords": [
1931
+ "none"
1932
+ ],
1906
1933
  "name": "contain-intrinsic-inline-size"
1907
1934
  },
1908
1935
  {
@@ -3160,6 +3187,22 @@ export const generatedProperties = [
3160
3187
  "name": "justify-items"
3161
3188
  },
3162
3189
  {
3190
+ "keywords": [
3191
+ "auto",
3192
+ "normal",
3193
+ "stretch",
3194
+ "baseline",
3195
+ "center",
3196
+ "start",
3197
+ "end",
3198
+ "self-start",
3199
+ "self-end",
3200
+ "flex-start",
3201
+ "flex-end",
3202
+ "left",
3203
+ "right",
3204
+ "anchor-center"
3205
+ ],
3163
3206
  "name": "justify-self"
3164
3207
  },
3165
3208
  {
@@ -3468,12 +3511,33 @@ export const generatedProperties = [
3468
3511
  "name": "min-block-size"
3469
3512
  },
3470
3513
  {
3514
+ "keywords": [
3515
+ "auto",
3516
+ "min-content",
3517
+ "max-content",
3518
+ "fit-content",
3519
+ "stretch"
3520
+ ],
3471
3521
  "name": "min-height"
3472
3522
  },
3473
3523
  {
3524
+ "keywords": [
3525
+ "auto",
3526
+ "min-content",
3527
+ "max-content",
3528
+ "fit-content",
3529
+ "stretch"
3530
+ ],
3474
3531
  "name": "min-inline-size"
3475
3532
  },
3476
3533
  {
3534
+ "keywords": [
3535
+ "auto",
3536
+ "min-content",
3537
+ "max-content",
3538
+ "fit-content",
3539
+ "stretch"
3540
+ ],
3477
3541
  "name": "min-width"
3478
3542
  },
3479
3543
  {
@@ -3584,6 +3648,21 @@ export const generatedProperties = [
3584
3648
  "name": "orphans"
3585
3649
  },
3586
3650
  {
3651
+ "keywords": [
3652
+ "auto",
3653
+ "none",
3654
+ "inset",
3655
+ "groove",
3656
+ "ridge",
3657
+ "outset",
3658
+ "dotted",
3659
+ "dashed",
3660
+ "solid",
3661
+ "double",
3662
+ "medium",
3663
+ "thick",
3664
+ "thin"
3665
+ ],
3587
3666
  "longhands": [
3588
3667
  "outline-color",
3589
3668
  "outline-style",
@@ -3697,6 +3776,11 @@ export const generatedProperties = [
3697
3776
  "name": "override-colors"
3698
3777
  },
3699
3778
  {
3779
+ "keywords": [
3780
+ "auto",
3781
+ "none",
3782
+ "contain"
3783
+ ],
3700
3784
  "longhands": [
3701
3785
  "overscroll-behavior-x",
3702
3786
  "overscroll-behavior-y"
@@ -3792,6 +3876,13 @@ export const generatedProperties = [
3792
3876
  "name": "page-break-after"
3793
3877
  },
3794
3878
  {
3879
+ "keywords": [
3880
+ "auto",
3881
+ "left",
3882
+ "right",
3883
+ "always",
3884
+ "avoid"
3885
+ ],
3795
3886
  "longhands": [
3796
3887
  "break-before"
3797
3888
  ],
@@ -5393,6 +5484,22 @@ export const generatedPropertyValues = {
5393
5484
  "currentcolor"
5394
5485
  ]
5395
5486
  },
5487
+ "align-self": {
5488
+ "values": [
5489
+ "auto",
5490
+ "normal",
5491
+ "stretch",
5492
+ "baseline",
5493
+ "center",
5494
+ "start",
5495
+ "end",
5496
+ "self-start",
5497
+ "self-end",
5498
+ "flex-start",
5499
+ "flex-end",
5500
+ "anchor-center"
5501
+ ]
5502
+ },
5396
5503
  "alignment-baseline": {
5397
5504
  "values": [
5398
5505
  "auto",
@@ -5626,6 +5733,15 @@ export const generatedPropertyValues = {
5626
5733
  "collapse"
5627
5734
  ]
5628
5735
  },
5736
+ "border-image": {
5737
+ "values": [
5738
+ "none",
5739
+ "repeat",
5740
+ "stretch",
5741
+ "space",
5742
+ "round"
5743
+ ]
5744
+ },
5629
5745
  "border-image-repeat": {
5630
5746
  "values": [
5631
5747
  "stretch",
@@ -5995,11 +6111,21 @@ export const generatedPropertyValues = {
5995
6111
  "block-size"
5996
6112
  ]
5997
6113
  },
6114
+ "contain-intrinsic-block-size": {
6115
+ "values": [
6116
+ "none"
6117
+ ]
6118
+ },
5998
6119
  "contain-intrinsic-height": {
5999
6120
  "values": [
6000
6121
  "none"
6001
6122
  ]
6002
6123
  },
6124
+ "contain-intrinsic-inline-size": {
6125
+ "values": [
6126
+ "none"
6127
+ ]
6128
+ },
6003
6129
  "contain-intrinsic-width": {
6004
6130
  "values": [
6005
6131
  "none"
@@ -6689,6 +6815,24 @@ export const generatedPropertyValues = {
6689
6815
  "isolate"
6690
6816
  ]
6691
6817
  },
6818
+ "justify-self": {
6819
+ "values": [
6820
+ "auto",
6821
+ "normal",
6822
+ "stretch",
6823
+ "baseline",
6824
+ "center",
6825
+ "start",
6826
+ "end",
6827
+ "self-start",
6828
+ "self-end",
6829
+ "flex-start",
6830
+ "flex-end",
6831
+ "left",
6832
+ "right",
6833
+ "anchor-center"
6834
+ ]
6835
+ },
6692
6836
  "left": {
6693
6837
  "values": [
6694
6838
  "auto"
@@ -6854,6 +6998,33 @@ export const generatedPropertyValues = {
6854
6998
  "none"
6855
6999
  ]
6856
7000
  },
7001
+ "min-height": {
7002
+ "values": [
7003
+ "auto",
7004
+ "min-content",
7005
+ "max-content",
7006
+ "fit-content",
7007
+ "stretch"
7008
+ ]
7009
+ },
7010
+ "min-inline-size": {
7011
+ "values": [
7012
+ "auto",
7013
+ "min-content",
7014
+ "max-content",
7015
+ "fit-content",
7016
+ "stretch"
7017
+ ]
7018
+ },
7019
+ "min-width": {
7020
+ "values": [
7021
+ "auto",
7022
+ "min-content",
7023
+ "max-content",
7024
+ "fit-content",
7025
+ "stretch"
7026
+ ]
7027
+ },
6857
7028
  "mix-blend-mode": {
6858
7029
  "values": [
6859
7030
  "normal",
@@ -6917,6 +7088,23 @@ export const generatedPropertyValues = {
6917
7088
  "none"
6918
7089
  ]
6919
7090
  },
7091
+ "outline": {
7092
+ "values": [
7093
+ "auto",
7094
+ "none",
7095
+ "inset",
7096
+ "groove",
7097
+ "ridge",
7098
+ "outset",
7099
+ "dotted",
7100
+ "dashed",
7101
+ "solid",
7102
+ "double",
7103
+ "medium",
7104
+ "thick",
7105
+ "thin"
7106
+ ]
7107
+ },
6920
7108
  "outline-color": {
6921
7109
  "values": [
6922
7110
  "currentcolor"
@@ -6990,6 +7178,13 @@ export const generatedPropertyValues = {
6990
7178
  "auto"
6991
7179
  ]
6992
7180
  },
7181
+ "overscroll-behavior": {
7182
+ "values": [
7183
+ "auto",
7184
+ "none",
7185
+ "contain"
7186
+ ]
7187
+ },
6993
7188
  "overscroll-behavior-x": {
6994
7189
  "values": [
6995
7190
  "auto",
@@ -7011,6 +7206,15 @@ export const generatedPropertyValues = {
7011
7206
  "auto"
7012
7207
  ]
7013
7208
  },
7209
+ "page-break-before": {
7210
+ "values": [
7211
+ "auto",
7212
+ "left",
7213
+ "right",
7214
+ "always",
7215
+ "avoid"
7216
+ ]
7217
+ },
7014
7218
  "page-margin-safety": {
7015
7219
  "values": [
7016
7220
  "none",
@@ -11136,6 +11136,10 @@ export namespace Network {
11136
11136
  export const enum CookieExemptionReason {
11137
11137
  None = 'None',
11138
11138
  UserSetting = 'UserSetting',
11139
+ TPCDMetadata = 'TPCDMetadata',
11140
+ TPCDDeprecationTrial = 'TPCDDeprecationTrial',
11141
+ TopLevelTPCDDeprecationTrial = 'TopLevelTPCDDeprecationTrial',
11142
+ TPCDHeuristics = 'TPCDHeuristics',
11139
11143
  EnterprisePolicy = 'EnterprisePolicy',
11140
11144
  StorageAccess = 'StorageAccess',
11141
11145
  TopLevelStorageAccess = 'TopLevelStorageAccess',
@@ -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
  }
@@ -410,7 +410,7 @@ export interface FunctionDeclaration<Args extends Record<string, unknown>, Retur
410
410
  * Description of function, this is send to the LLM
411
411
  * to explain what will the function do.
412
412
  */
413
- description: string;
413
+ description: string|(() => string);
414
414
  /**
415
415
  * JSON schema like representation of the parameters
416
416
  * the function needs to be called with.
@@ -582,7 +582,7 @@ export abstract class AiAgent<T> {
582
582
  for (const [name, definition] of this.#functionDeclarations.entries()) {
583
583
  declarations.push({
584
584
  name,
585
- description: definition.description,
585
+ description: typeof definition.description === 'function' ? definition.description() : definition.description,
586
586
  parameters: definition.parameters,
587
587
  });
588
588
  }
@@ -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
+ }