chrome-devtools-frontend 1.0.1645245 → 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/.agents/skills/devtools-source-maps/SKILL.md +124 -0
- package/SECURITY.md +1 -1
- package/docs/README.md +1 -0
- package/docs/using_source_maps.md +159 -0
- package/front_end/core/host/AidaClientTypes.ts +2 -0
- package/front_end/core/host/UserMetrics.ts +2 -1
- package/front_end/core/root/Runtime.ts +10 -0
- package/front_end/core/sdk/DebuggerModel.ts +7 -9
- package/front_end/core/sdk/NetworkRequest.ts +0 -24
- package/front_end/generated/InspectorBackendCommands.ts +1 -1
- package/front_end/generated/SupportedCSSProperties.js +279 -0
- package/front_end/generated/protocol.ts +0 -1
- package/front_end/models/ai_assistance/AiAgent2.ts +43 -11
- package/front_end/models/ai_assistance/AiConversation.ts +4 -2
- package/front_end/models/ai_assistance/AiOrigins.ts +63 -2
- package/front_end/models/ai_assistance/README.md +15 -4
- package/front_end/models/ai_assistance/agents/AiAgent.ts +2 -2
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +2 -2
- package/front_end/models/ai_assistance/agents/FileAgent.ts +9 -42
- package/front_end/models/ai_assistance/agents/NetworkAgent.snapshot.txt +2 -2
- package/front_end/models/ai_assistance/agents/NetworkAgent.ts +9 -133
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +10 -2
- package/front_end/models/ai_assistance/agents/README.md +7 -0
- package/front_end/models/ai_assistance/agents/StorageAgent.ts +45 -0
- package/front_end/models/ai_assistance/ai_assistance.ts +8 -0
- package/front_end/models/ai_assistance/contexts/FileContext.ts +45 -0
- package/front_end/models/ai_assistance/contexts/RequestContext.snapshot.txt +48 -0
- package/front_end/models/ai_assistance/contexts/RequestContext.ts +116 -0
- package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +2 -1
- package/front_end/models/ai_assistance/skills/Skill.ts +1 -1
- package/front_end/models/ai_assistance/skills/SkillRegistry.ts +2 -0
- package/front_end/models/ai_assistance/skills/network.md +16 -0
- package/front_end/models/ai_assistance/skills/styling.md +1 -1
- package/front_end/models/ai_assistance/tools/GetNetworkRequestDetails.ts +118 -0
- package/front_end/models/ai_assistance/tools/ListNetworkRequests.ts +124 -0
- package/front_end/models/ai_assistance/tools/README.md +1 -1
- package/front_end/models/ai_assistance/tools/Tool.ts +2 -0
- package/front_end/models/ai_assistance/tools/ToolRegistry.ts +4 -0
- package/front_end/models/emulation/EmulatedDevices.ts +430 -12
- package/front_end/models/trace/handlers/NetworkRequestsHandler.ts +15 -11
- package/front_end/models/web_mcp/WebMCPModel.ts +8 -48
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +14 -13
- package/front_end/panels/ai_assistance/components/ChatInput.ts +4 -4
- package/front_end/panels/application/ApplicationPanelSidebar.ts +25 -0
- package/front_end/panels/application/WebMCPTreeElement.ts +8 -0
- package/front_end/panels/application/WebMCPView.ts +40 -70
- package/front_end/panels/application/components/AdsView.ts +31 -28
- package/front_end/panels/application/components/adsView.css +6 -0
- package/front_end/panels/common/ExtensionServer.ts +5 -0
- package/front_end/panels/profiler/IsolateSelector.ts +4 -2
- package/front_end/panels/profiler/ProfileLauncherView.ts +194 -126
- package/front_end/panels/profiler/ProfilesPanel.ts +1 -3
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/legacy/components/utils/Linkifier.ts +10 -0
- package/front_end/ui/visual_logging/KnownContextValues.ts +9 -0
- package/package.json +1 -1
|
@@ -23,6 +23,8 @@ import * as AiUtils from './AiUtils.js';
|
|
|
23
23
|
import * as BuiltInAi from './BuiltInAi.js';
|
|
24
24
|
import * as ChangeManager from './ChangeManager.js';
|
|
25
25
|
import * as DOMNodeContext from './contexts/DOMNodeContext.js';
|
|
26
|
+
import * as FileContext from './contexts/FileContext.js';
|
|
27
|
+
import * as RequestContext from './contexts/RequestContext.js';
|
|
26
28
|
import * as ConversationSummary from './ConversationSummary.js';
|
|
27
29
|
import * as FileFormatter from './data_formatters/FileFormatter.js';
|
|
28
30
|
import * as LighthouseFormatter from './data_formatters/LighthouseFormatter.js';
|
|
@@ -40,7 +42,9 @@ import * as AIQueries from './performance/AIQueries.js';
|
|
|
40
42
|
import * as PerformanceAnnotations from './PerformanceAnnotations.js';
|
|
41
43
|
import * as StorageItem from './StorageItem.js';
|
|
42
44
|
import * as ExecuteJavaScript from './tools/ExecuteJavaScript.js';
|
|
45
|
+
import * as GetNetworkRequestDetails from './tools/GetNetworkRequestDetails.js';
|
|
43
46
|
import * as GetStyles from './tools/GetStyles.js';
|
|
47
|
+
import * as ListNetworkRequests from './tools/ListNetworkRequests.js';
|
|
44
48
|
import * as Tool from './tools/Tool.js';
|
|
45
49
|
import * as ToolRegistry from './tools/ToolRegistry.js';
|
|
46
50
|
|
|
@@ -66,13 +70,16 @@ export {
|
|
|
66
70
|
ExecuteJavaScript,
|
|
67
71
|
ExtensionScope,
|
|
68
72
|
FileAgent,
|
|
73
|
+
FileContext,
|
|
69
74
|
FileFormatter,
|
|
75
|
+
GetNetworkRequestDetails,
|
|
70
76
|
GetStyles,
|
|
71
77
|
GreenDevAgent,
|
|
72
78
|
GreenDevAgentAntigravityCliSocketClient,
|
|
73
79
|
GreenDevAgentGeminiCliSocketClient,
|
|
74
80
|
Injected,
|
|
75
81
|
LighthouseFormatter,
|
|
82
|
+
ListNetworkRequests,
|
|
76
83
|
NetworkAgent,
|
|
77
84
|
NetworkRequestFormatter,
|
|
78
85
|
PatchAgent,
|
|
@@ -80,6 +87,7 @@ export {
|
|
|
80
87
|
PerformanceAnnotations,
|
|
81
88
|
PerformanceInsightFormatter,
|
|
82
89
|
PerformanceTraceFormatter,
|
|
90
|
+
RequestContext,
|
|
83
91
|
StorageAgent,
|
|
84
92
|
StorageItem,
|
|
85
93
|
StylingAgent,
|
|
@@ -0,0 +1,45 @@
|
|
|
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 type * as Workspace from '../../workspace/workspace.js';
|
|
6
|
+
import {type ContextDetail, ConversationContext} from '../agents/AiAgent.js';
|
|
7
|
+
import {FileFormatter} from '../data_formatters/FileFormatter.js';
|
|
8
|
+
|
|
9
|
+
export class FileContext extends ConversationContext<Workspace.UISourceCode.UISourceCode> {
|
|
10
|
+
#file: Workspace.UISourceCode.UISourceCode;
|
|
11
|
+
|
|
12
|
+
constructor(file: Workspace.UISourceCode.UISourceCode) {
|
|
13
|
+
super();
|
|
14
|
+
this.#file = file;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
override getURL(): string {
|
|
18
|
+
return this.#file.url();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
override getItem(): Workspace.UISourceCode.UISourceCode {
|
|
22
|
+
return this.#file;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
override getTitle(): string {
|
|
26
|
+
return this.#file.displayName();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
override async getPromptDetails(): Promise<string|null> {
|
|
30
|
+
return `# Selected file\n${new FileFormatter(this.#file).formatFile()}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
override async getUserFacingDetails(): Promise<[ContextDetail, ...ContextDetail[]]|null> {
|
|
34
|
+
return [
|
|
35
|
+
{
|
|
36
|
+
title: 'Selected file',
|
|
37
|
+
text: new FileFormatter(this.#file).formatFile(),
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
override async refresh(): Promise<void> {
|
|
43
|
+
await this.#file.requestContentData();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
Title: RequestContext getPromptDetails describes the network request correctly
|
|
2
|
+
Content:
|
|
3
|
+
# Selected network request
|
|
4
|
+
Request: https://www.example.com/api/users
|
|
5
|
+
|
|
6
|
+
Request headers:
|
|
7
|
+
Accept: application/json
|
|
8
|
+
|
|
9
|
+
Response headers:
|
|
10
|
+
Content-Type: application/json
|
|
11
|
+
|
|
12
|
+
Response body:
|
|
13
|
+
{}
|
|
14
|
+
|
|
15
|
+
Response status: 200
|
|
16
|
+
Network request status: pending
|
|
17
|
+
|
|
18
|
+
Request timing:
|
|
19
|
+
Queued at (timestamp): 0 s
|
|
20
|
+
Started at (timestamp): 0 s
|
|
21
|
+
Connection start (stalled) (duration): -
|
|
22
|
+
Duration (duration): -
|
|
23
|
+
|
|
24
|
+
Request initiator chain:
|
|
25
|
+
- URL: https://www.example.com/api/users
|
|
26
|
+
=== end content
|
|
27
|
+
|
|
28
|
+
Title: RequestContext getUserFacingDetails returns details correctly
|
|
29
|
+
Content:
|
|
30
|
+
[
|
|
31
|
+
{
|
|
32
|
+
"title": "Request",
|
|
33
|
+
"text": "Request URL: https://www.example.com/api/users\n\nRequest headers:\nAccept: application/json"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"title": "Response",
|
|
37
|
+
"text": "Response headers:\nContent-Type: application/json\n\nResponse body:\n{}\n\nResponse status: 200\nNetwork request status: pending\n"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"title": "Timing",
|
|
41
|
+
"text": "Queued at (timestamp): 0 s\nStarted at (timestamp): 0 s\nConnection start (stalled) (duration): -\nDuration (duration): -"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"title": "Request initiator chain",
|
|
45
|
+
"text": "- URL: https://www.example.com/api/users"
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
=== end content
|
|
@@ -0,0 +1,116 @@
|
|
|
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 Common from '../../../core/common/common.js';
|
|
6
|
+
import * as i18n from '../../../core/i18n/i18n.js';
|
|
7
|
+
import type * as Platform from '../../../core/platform/platform.js';
|
|
8
|
+
import type * as SDK from '../../../core/sdk/sdk.js';
|
|
9
|
+
import type * as NetworkTimeCalculator from '../../network_time_calculator/network_time_calculator.js';
|
|
10
|
+
import {
|
|
11
|
+
type ContextDetail,
|
|
12
|
+
ConversationContext,
|
|
13
|
+
} from '../agents/AiAgent.js';
|
|
14
|
+
import {extractContextOrigin} from '../AiOrigins.js';
|
|
15
|
+
import {NetworkRequestFormatter} from '../data_formatters/NetworkRequestFormatter.js';
|
|
16
|
+
|
|
17
|
+
const UIStringsNotTranslate = {
|
|
18
|
+
request: 'Request',
|
|
19
|
+
response: 'Response',
|
|
20
|
+
requestUrl: 'Request URL',
|
|
21
|
+
timing: 'Timing',
|
|
22
|
+
requestInitiatorChain: 'Request initiator chain',
|
|
23
|
+
} as const;
|
|
24
|
+
|
|
25
|
+
const lockedString = i18n.i18n.lockedString;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Returns the origin for a network request in the AI context.
|
|
29
|
+
*
|
|
30
|
+
* To prevent cross-origin prompt injection attacks, HAR-imported requests
|
|
31
|
+
* are isolated from live pages. We assign them a virtual origin
|
|
32
|
+
* (`imported-har://${domain}`) so they do not share the origin of live pages
|
|
33
|
+
* (e.g., `https://${domain}`). This forces a conversation reset when transitioning
|
|
34
|
+
* between imported HAR data and live pages.
|
|
35
|
+
*/
|
|
36
|
+
export function getRequestContextOrigin(request: SDK.NetworkRequest.NetworkRequest): string {
|
|
37
|
+
const origin = extractContextOrigin(request.documentURL);
|
|
38
|
+
if (request.isImportedHar()) {
|
|
39
|
+
const parsed = Common.ParsedURL.ParsedURL.fromString(origin as Platform.DevToolsPath.UrlString);
|
|
40
|
+
return `imported-har://${parsed ? parsed.domain() : origin}`;
|
|
41
|
+
}
|
|
42
|
+
return origin;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class RequestContext extends ConversationContext<SDK.NetworkRequest.NetworkRequest> {
|
|
46
|
+
#request: SDK.NetworkRequest.NetworkRequest;
|
|
47
|
+
#calculator: NetworkTimeCalculator.NetworkTransferTimeCalculator;
|
|
48
|
+
|
|
49
|
+
constructor(
|
|
50
|
+
request: SDK.NetworkRequest.NetworkRequest,
|
|
51
|
+
calculator: NetworkTimeCalculator.NetworkTransferTimeCalculator,
|
|
52
|
+
) {
|
|
53
|
+
super();
|
|
54
|
+
this.#request = request;
|
|
55
|
+
this.#calculator = calculator;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Note: this is not the literal origin of the network request. This URL
|
|
60
|
+
* is used to determine when we should force the user to start a new AI
|
|
61
|
+
* conversation when the context changes. We allow a single AI conversation to
|
|
62
|
+
* inspect all network requests that were made for that given target URL.
|
|
63
|
+
*/
|
|
64
|
+
override getURL(): string {
|
|
65
|
+
return this.#request.documentURL;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
override getOrigin(): string {
|
|
69
|
+
return getRequestContextOrigin(this.#request);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
override getItem(): SDK.NetworkRequest.NetworkRequest {
|
|
73
|
+
return this.#request;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
override getTitle(): string {
|
|
77
|
+
return this.#request.name();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
override async getPromptDetails(): Promise<string|null> {
|
|
81
|
+
const formatter = new NetworkRequestFormatter(this.#request, this.#calculator);
|
|
82
|
+
return `# Selected network request\n${await formatter.formatNetworkRequest()}`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
override async getUserFacingDetails(): Promise<[ContextDetail, ...ContextDetail[]]|null> {
|
|
86
|
+
const formatter = new NetworkRequestFormatter(this.#request, this.#calculator);
|
|
87
|
+
const requestContextDetail: ContextDetail = {
|
|
88
|
+
title: lockedString(UIStringsNotTranslate.request),
|
|
89
|
+
text: lockedString(UIStringsNotTranslate.requestUrl) + ': ' + this.#request.url() + '\n\n' +
|
|
90
|
+
formatter.formatRequestHeaders(),
|
|
91
|
+
};
|
|
92
|
+
const responseBody = await formatter.formatResponseBody();
|
|
93
|
+
const responseBodyString = responseBody ? `\n\n${responseBody}` : '';
|
|
94
|
+
|
|
95
|
+
const responseContextDetail: ContextDetail = {
|
|
96
|
+
title: lockedString(UIStringsNotTranslate.response),
|
|
97
|
+
text: formatter.formatResponseHeaders() + responseBodyString +
|
|
98
|
+
`\n\n${formatter.formatStatus()}${formatter.formatFailureReasons()}`,
|
|
99
|
+
};
|
|
100
|
+
const timingContextDetail: ContextDetail = {
|
|
101
|
+
title: lockedString(UIStringsNotTranslate.timing),
|
|
102
|
+
text: formatter.formatNetworkRequestTiming(),
|
|
103
|
+
};
|
|
104
|
+
const initiatorChainContextDetail: ContextDetail = {
|
|
105
|
+
title: lockedString(UIStringsNotTranslate.requestInitiatorChain),
|
|
106
|
+
text: formatter.formatRequestInitiatorChain(),
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
return [
|
|
110
|
+
requestContextDetail,
|
|
111
|
+
responseContextDetail,
|
|
112
|
+
timingContextDetail,
|
|
113
|
+
initiatorChainContextDetail,
|
|
114
|
+
];
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -92,7 +92,8 @@ export class NetworkRequestFormatter {
|
|
|
92
92
|
}): string {
|
|
93
93
|
let responseStatus = '';
|
|
94
94
|
if (status.statusCode) {
|
|
95
|
-
|
|
95
|
+
const statusText = status.statusText ? ` ${status.statusText}` : '';
|
|
96
|
+
responseStatus = `Response status: ${status.statusCode}${statusText}\n`;
|
|
96
97
|
}
|
|
97
98
|
const flags = [];
|
|
98
99
|
flags.push(status.finished ? 'finished' : 'pending');
|
|
@@ -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).
|
|
@@ -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
|
+
}
|
|
@@ -17,7 +17,7 @@ Instead of passing a monolithic "grab-bag" context object to all tool handlers,
|
|
|
17
17
|
- `PageExecutionCapability`: For tools executing JavaScript code on the inspected page.
|
|
18
18
|
- `StyleMutationCapability`: For tools managing and applying style mutations via a `ChangeManager`.
|
|
19
19
|
- `TargetCapability`: For tools requiring access to the page's current SDK `Target`.
|
|
20
|
-
- `OriginLockCapability`: For tools enforcing cross-origin security via origin locks.
|
|
20
|
+
- `OriginLockCapability`: For tools enforcing cross-origin security via origin locks. Tools that fetch resources or state from the inspected page (such as styling or source code) must use this capability to verify that the target resource matches the conversation's established origin. This prevents the LLM from executing tools against out-of-origin elements or documents.
|
|
21
21
|
|
|
22
22
|
### Unified Context
|
|
23
23
|
|
|
@@ -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
|
/**
|