chrome-devtools-frontend 1.0.1643855 → 1.0.1646286
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/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 +5 -3
- package/front_end/core/root/Runtime.ts +10 -0
- package/front_end/core/sdk/CSSPropertyParserMatchers.ts +2 -3
- package/front_end/core/sdk/DebuggerModel.ts +7 -9
- package/front_end/core/sdk/NetworkRequest.ts +0 -25
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +37 -0
- package/front_end/generated/InspectorBackendCommands.ts +2 -2
- package/front_end/generated/SupportedCSSProperties.js +79 -2
- package/front_end/generated/protocol.ts +0 -5
- package/front_end/models/ai_assistance/AiAgent2.ts +52 -15
- 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 +20 -8
- 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 +25 -2
- package/front_end/models/ai_assistance/agents/README.md +64 -0
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +26 -3
- package/front_end/models/ai_assistance/ai_assistance.ts +4 -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/tools/ExecuteJavaScript.ts +9 -12
- package/front_end/models/ai_assistance/tools/GetStyles.ts +19 -12
- package/front_end/models/ai_assistance/tools/README.md +45 -0
- package/front_end/models/ai_assistance/tools/Tool.ts +74 -11
- package/front_end/models/ai_assistance/tools/ToolRegistry.ts +21 -5
- package/front_end/models/heap_snapshot/HeapSnapshotModel.ts +18 -2
- package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +4 -0
- package/front_end/models/stack_trace/DetailedErrorStackParser.ts +17 -4
- package/front_end/models/stack_trace/StackTraceModel.ts +34 -1
- package/front_end/models/trace/Styles.ts +29 -7
- package/front_end/models/trace/handlers/NetworkRequestsHandler.ts +15 -11
- package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +33 -4
- package/front_end/models/trace/helpers/Timing.ts +10 -0
- package/front_end/models/trace/types/TraceEvents.ts +22 -2
- package/front_end/models/web_mcp/WebMCPModel.ts +8 -48
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +21 -15
- package/front_end/panels/ai_assistance/ai_assistance-meta.ts +16 -0
- package/front_end/panels/ai_assistance/components/ChatInput.ts +4 -4
- package/front_end/panels/application/ApplicationPanelSidebar.ts +69 -0
- package/front_end/panels/application/ServiceWorkersView.ts +2 -2
- package/front_end/panels/application/WebMCPView.ts +40 -71
- package/front_end/panels/application/components/AdsView.ts +31 -28
- package/front_end/panels/application/components/BackForwardCacheView.ts +1 -2
- package/front_end/panels/application/components/adsView.css +6 -0
- package/front_end/panels/common/ExtensionServer.ts +5 -0
- package/front_end/panels/console/ConsoleView.ts +6 -1
- package/front_end/panels/console/ConsoleViewMessage.ts +46 -213
- package/front_end/panels/console/SymbolizedErrorWidget.ts +4 -1
- package/front_end/panels/elements/AdoptedStyleSheetTreeElement.ts +0 -1
- package/front_end/panels/elements/ElementsTreeElement.ts +0 -2
- package/front_end/panels/elements/PropertyRenderer.ts +0 -1
- package/front_end/panels/elements/StylesSidebarPane.ts +9 -2
- package/front_end/panels/issues/AffectedResourcesView.ts +1 -1
- package/front_end/panels/issues/AffectedSourcesView.ts +1 -1
- package/front_end/panels/lighthouse/LighthouseReportRenderer.ts +0 -1
- package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +10 -0
- package/front_end/panels/network/NetworkDataGridNode.ts +1 -2
- package/front_end/panels/network/NetworkLogView.ts +34 -7
- package/front_end/panels/profiler/HeapProfileView.ts +0 -1
- package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +0 -1
- package/front_end/panels/profiler/HeapSnapshotView.ts +1 -1
- 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/panels/settings/components/SyncSection.ts +1 -1
- package/front_end/panels/timeline/TimelineFlameChartView.ts +5 -4
- package/front_end/panels/timeline/TimelinePanel.ts +7 -0
- package/front_end/panels/timeline/TimelineUIUtils.ts +13 -14
- package/front_end/panels/timeline/TimingsTrackAppender.ts +7 -5
- package/front_end/panels/timeline/components/LayoutShiftDetails.ts +0 -1
- package/front_end/panels/timeline/components/NetworkRequestDetails.ts +0 -2
- package/front_end/panels/timeline/components/insights/ForcedReflow.ts +0 -1
- package/front_end/panels/timeline/components/insights/NodeLink.ts +0 -1
- package/front_end/panels/timeline/overlays/OverlaysImpl.ts +2 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/helpers/OpenInNewTab.ts +3 -3
- package/front_end/ui/kit/link/Link.ts +16 -2
- package/front_end/ui/legacy/InspectorDrawerView.ts +14 -5
- package/front_end/ui/legacy/InspectorView.ts +4 -1
- package/front_end/ui/legacy/PlusButton.ts +6 -1
- package/front_end/ui/legacy/Widget.ts +19 -1
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +95 -31
- package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +0 -1
- package/front_end/ui/legacy/components/utils/Linkifier.ts +2 -16
- package/front_end/ui/visual_logging/KnownContextValues.ts +6 -0
- package/package.json +1 -1
|
@@ -15,6 +15,8 @@ import type * as Trace from '../../trace/trace.js';
|
|
|
15
15
|
import * as Workspace from '../../workspace/workspace.js';
|
|
16
16
|
import {isOpaqueOrigin} from '../AiOrigins.js';
|
|
17
17
|
import {DOMNodeContext} from '../contexts/DOMNodeContext.js';
|
|
18
|
+
import {FileContext} from '../contexts/FileContext.js';
|
|
19
|
+
import {getRequestContextOrigin, RequestContext} from '../contexts/RequestContext.js';
|
|
18
20
|
import {debugLog} from '../debug.js';
|
|
19
21
|
import {StorageItem} from '../StorageItem.js';
|
|
20
22
|
|
|
@@ -26,8 +28,6 @@ import {
|
|
|
26
28
|
type ContextResponse,
|
|
27
29
|
type RequestOptions,
|
|
28
30
|
} from './AiAgent.js';
|
|
29
|
-
import {FileContext} from './FileAgent.js';
|
|
30
|
-
import {getRequestContextOrigin, RequestContext} from './NetworkAgent.js';
|
|
31
31
|
import {PerformanceTraceContext} from './PerformanceAgent.js';
|
|
32
32
|
import {StorageContext} from './StorageAgent.js';
|
|
33
33
|
|
|
@@ -5,13 +5,11 @@
|
|
|
5
5
|
import * as Host from '../../../core/host/host.js';
|
|
6
6
|
import * as Root from '../../../core/root/root.js';
|
|
7
7
|
import type * as Workspace from '../../workspace/workspace.js';
|
|
8
|
-
import {FileFormatter} from '../data_formatters/FileFormatter.js';
|
|
9
8
|
|
|
10
9
|
import {
|
|
11
10
|
AiAgent,
|
|
12
|
-
type ContextDetail,
|
|
13
11
|
type ContextResponse,
|
|
14
|
-
ConversationContext,
|
|
12
|
+
type ConversationContext,
|
|
15
13
|
type RequestOptions,
|
|
16
14
|
ResponseType,
|
|
17
15
|
} from './AiAgent.js';
|
|
@@ -75,31 +73,6 @@ External Resources:
|
|
|
75
73
|
MDN Web Docs: JavaScript Functions: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions
|
|
76
74
|
`;
|
|
77
75
|
|
|
78
|
-
export class FileContext extends ConversationContext<Workspace.UISourceCode.UISourceCode> {
|
|
79
|
-
#file: Workspace.UISourceCode.UISourceCode;
|
|
80
|
-
|
|
81
|
-
constructor(file: Workspace.UISourceCode.UISourceCode) {
|
|
82
|
-
super();
|
|
83
|
-
this.#file = file;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
override getURL(): string {
|
|
87
|
-
return this.#file.url();
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
override getItem(): Workspace.UISourceCode.UISourceCode {
|
|
91
|
-
return this.#file;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
override getTitle(): string {
|
|
95
|
-
return this.#file.displayName();
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
override async refresh(): Promise<void> {
|
|
99
|
-
await this.#file.requestContentData();
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
76
|
/**
|
|
104
77
|
* One agent instance handles one conversation. Create a new agent
|
|
105
78
|
* instance for a new conversation.
|
|
@@ -126,27 +99,21 @@ export class FileAgent extends AiAgent<Workspace.UISourceCode.UISourceCode> {
|
|
|
126
99
|
return;
|
|
127
100
|
}
|
|
128
101
|
|
|
102
|
+
const details = await selectedFile.getUserFacingDetails();
|
|
103
|
+
if (!details) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
129
107
|
yield {
|
|
130
108
|
type: ResponseType.CONTEXT,
|
|
131
|
-
details
|
|
109
|
+
details,
|
|
132
110
|
};
|
|
133
111
|
}
|
|
134
112
|
|
|
135
113
|
override async enhanceQuery(
|
|
136
114
|
query: string, selectedFile: ConversationContext<Workspace.UISourceCode.UISourceCode>|null): Promise<string> {
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
'';
|
|
115
|
+
const promptDetails = selectedFile ? await selectedFile.getPromptDetails() : null;
|
|
116
|
+
const fileEnchantmentQuery = promptDetails ? `${promptDetails}\n\n# User request\n\n` : '';
|
|
140
117
|
return `${fileEnchantmentQuery}${query}`;
|
|
141
118
|
}
|
|
142
119
|
}
|
|
143
|
-
|
|
144
|
-
function createContextDetailsForFileAgent(selectedFile: ConversationContext<Workspace.UISourceCode.UISourceCode>):
|
|
145
|
-
[ContextDetail, ...ContextDetail[]] {
|
|
146
|
-
return [
|
|
147
|
-
{
|
|
148
|
-
title: 'Selected file',
|
|
149
|
-
text: new FileFormatter(selectedFile.getItem()).formatFile(),
|
|
150
|
-
},
|
|
151
|
-
];
|
|
152
|
-
}
|
|
@@ -10,7 +10,7 @@ Content:
|
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
12
|
"title": "Response",
|
|
13
|
-
"text": "Response headers:\ncontent-type: bar2\nx-forwarded-for: bar3\n\nResponse body:\n{\"request\":\"body\"}\n\nResponse status: 200
|
|
13
|
+
"text": "Response headers:\ncontent-type: bar2\nx-forwarded-for: bar3\n\nResponse body:\n{\"request\":\"body\"}\n\nResponse status: 200\nNetwork request status: pending\n"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"title": "Timing",
|
|
@@ -59,7 +59,7 @@ Content:
|
|
|
59
59
|
{
|
|
60
60
|
"parts": [
|
|
61
61
|
{
|
|
62
|
-
"text": "# Selected network request
|
|
62
|
+
"text": "# Selected network request\nRequest: https://www.example.com\n\nRequest headers:\ncontent-type: bar1\n\nResponse headers:\ncontent-type: bar2\nx-forwarded-for: bar3\n\nResponse body:\n{\"request\":\"body\"}\n\nResponse status: 200\nNetwork request status: pending\n\nRequest timing:\nQueued at (timestamp): 0 s\nStarted at (timestamp): 501 s\nQueueing (duration): 501 s\nConnection start (stalled) (duration): 800 ms\nRequest sent (duration): 100 ms\nDuration (duration): 501 s\n\nRequest initiator chain:\n- URL: <redacted cross-origin initiator URL>\n\t- URL: https://www.example.com\n\t\t- URL: https://www.example.com/1\n\t\t- URL: https://www.example.com/2\n\n# User request\n\ntest"
|
|
63
63
|
}
|
|
64
64
|
],
|
|
65
65
|
"role": 1
|
|
@@ -2,21 +2,14 @@
|
|
|
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 * as Common from '../../../core/common/common.js';
|
|
6
5
|
import * as Host from '../../../core/host/host.js';
|
|
7
|
-
import * as i18n from '../../../core/i18n/i18n.js';
|
|
8
|
-
import type * as Platform from '../../../core/platform/platform.js';
|
|
9
6
|
import * as Root from '../../../core/root/root.js';
|
|
10
7
|
import type * as SDK from '../../../core/sdk/sdk.js';
|
|
11
|
-
import type
|
|
12
|
-
import {extractContextOrigin} from '../AiOrigins.js';
|
|
13
|
-
import {NetworkRequestFormatter} from '../data_formatters/NetworkRequestFormatter.js';
|
|
8
|
+
import type {RequestContext} from '../contexts/RequestContext.js';
|
|
14
9
|
|
|
15
10
|
import {
|
|
16
11
|
AiAgent,
|
|
17
|
-
type ContextDetail,
|
|
18
12
|
type ContextResponse,
|
|
19
|
-
ConversationContext,
|
|
20
13
|
type RequestOptions,
|
|
21
14
|
ResponseType,
|
|
22
15
|
} from './AiAgent.js';
|
|
@@ -73,90 +66,6 @@ This request aims to retrieve a list of products matching the search query "lapt
|
|
|
73
66
|
`;
|
|
74
67
|
/* clang-format on */
|
|
75
68
|
|
|
76
|
-
/*
|
|
77
|
-
* Strings that don't need to be translated at this time.
|
|
78
|
-
*/
|
|
79
|
-
const UIStringsNotTranslate = {
|
|
80
|
-
/**
|
|
81
|
-
* @description Heading text for the block that shows the network request details.
|
|
82
|
-
*/
|
|
83
|
-
request: 'Request',
|
|
84
|
-
/**
|
|
85
|
-
* @description Heading text for the block that shows the network response details.
|
|
86
|
-
*/
|
|
87
|
-
response: 'Response',
|
|
88
|
-
/**
|
|
89
|
-
* @description Prefix text for request URL.
|
|
90
|
-
*/
|
|
91
|
-
requestUrl: 'Request URL',
|
|
92
|
-
/**
|
|
93
|
-
* @description Title text for request timing details.
|
|
94
|
-
*/
|
|
95
|
-
timing: 'Timing',
|
|
96
|
-
/**
|
|
97
|
-
* @description Title text for request initiator chain.
|
|
98
|
-
*/
|
|
99
|
-
requestInitiatorChain: 'Request initiator chain',
|
|
100
|
-
} as const;
|
|
101
|
-
|
|
102
|
-
const lockedString = i18n.i18n.lockedString;
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Returns the origin for a network request in the AI context.
|
|
106
|
-
*
|
|
107
|
-
* To prevent cross-origin prompt injection attacks, HAR-imported requests
|
|
108
|
-
* are isolated from live pages. We assign them a virtual origin
|
|
109
|
-
* (`imported-har://${domain}`) so they do not share the origin of live pages
|
|
110
|
-
* (e.g., `https://${domain}`). This forces a conversation reset when transitioning
|
|
111
|
-
* between imported HAR data and live pages.
|
|
112
|
-
*/
|
|
113
|
-
export function getRequestContextOrigin(request: SDK.NetworkRequest.NetworkRequest): string {
|
|
114
|
-
const origin = extractContextOrigin(request.documentURL);
|
|
115
|
-
if (request.isImportedHar()) {
|
|
116
|
-
const parsed = Common.ParsedURL.ParsedURL.fromString(origin as Platform.DevToolsPath.UrlString);
|
|
117
|
-
return `imported-har://${parsed ? parsed.domain() : origin}`;
|
|
118
|
-
}
|
|
119
|
-
return origin;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export class RequestContext extends ConversationContext<SDK.NetworkRequest.NetworkRequest> {
|
|
123
|
-
#request: SDK.NetworkRequest.NetworkRequest;
|
|
124
|
-
#calculator: NetworkTimeCalculator.NetworkTransferTimeCalculator;
|
|
125
|
-
|
|
126
|
-
constructor(
|
|
127
|
-
request: SDK.NetworkRequest.NetworkRequest, calculator: NetworkTimeCalculator.NetworkTransferTimeCalculator) {
|
|
128
|
-
super();
|
|
129
|
-
this.#request = request;
|
|
130
|
-
this.#calculator = calculator;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Note: this is not the literal origin of the network request. This URL
|
|
135
|
-
* is used to determine when we should force the user to start a new AI
|
|
136
|
-
* conversation when the context changes. We allow a single AI conversation to
|
|
137
|
-
* inspect all network requests that were made for that given target URL.
|
|
138
|
-
*/
|
|
139
|
-
override getURL(): string {
|
|
140
|
-
return this.#request.documentURL;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
override getOrigin(): string {
|
|
144
|
-
return getRequestContextOrigin(this.#request);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
override getItem(): SDK.NetworkRequest.NetworkRequest {
|
|
148
|
-
return this.#request;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
get calculator(): NetworkTimeCalculator.NetworkTimeCalculator {
|
|
152
|
-
return this.#calculator;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
override getTitle(): string {
|
|
156
|
-
return this.#request.name();
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
69
|
/**
|
|
161
70
|
* One agent instance handles one conversation. Create a new agent
|
|
162
71
|
* instance for a new conversation.
|
|
@@ -183,9 +92,14 @@ export class NetworkAgent extends AiAgent<SDK.NetworkRequest.NetworkRequest> {
|
|
|
183
92
|
return;
|
|
184
93
|
}
|
|
185
94
|
|
|
95
|
+
const details = await selectedNetworkRequest.getUserFacingDetails();
|
|
96
|
+
if (!details) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
186
100
|
yield {
|
|
187
101
|
type: ResponseType.CONTEXT,
|
|
188
|
-
details
|
|
102
|
+
details,
|
|
189
103
|
widgets: [{
|
|
190
104
|
name: 'NETWORK_REQUEST_GENERAL_HEADERS',
|
|
191
105
|
data: {
|
|
@@ -196,46 +110,8 @@ export class NetworkAgent extends AiAgent<SDK.NetworkRequest.NetworkRequest> {
|
|
|
196
110
|
}
|
|
197
111
|
|
|
198
112
|
override async enhanceQuery(query: string, selectedNetworkRequest: RequestContext|null): Promise<string> {
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
await (new NetworkRequestFormatter(selectedNetworkRequest.getItem(), selectedNetworkRequest.calculator)
|
|
202
|
-
.formatNetworkRequest())}\n\n# User request\n\n` :
|
|
203
|
-
'';
|
|
113
|
+
const promptDetails = selectedNetworkRequest ? await selectedNetworkRequest.getPromptDetails() : null;
|
|
114
|
+
const networkEnchantmentQuery = promptDetails ? `${promptDetails}\n\n# User request\n\n` : '';
|
|
204
115
|
return `${networkEnchantmentQuery}${query}`;
|
|
205
116
|
}
|
|
206
117
|
}
|
|
207
|
-
|
|
208
|
-
async function createContextDetailsForNetworkAgent(
|
|
209
|
-
selectedNetworkRequest: RequestContext,
|
|
210
|
-
): Promise<[ContextDetail, ...ContextDetail[]]> {
|
|
211
|
-
const request = selectedNetworkRequest.getItem();
|
|
212
|
-
const formatter = new NetworkRequestFormatter(request, selectedNetworkRequest.calculator);
|
|
213
|
-
const requestContextDetail: ContextDetail = {
|
|
214
|
-
title: lockedString(UIStringsNotTranslate.request),
|
|
215
|
-
text: lockedString(UIStringsNotTranslate.requestUrl) + ': ' + request.url() + '\n\n' +
|
|
216
|
-
formatter.formatRequestHeaders(),
|
|
217
|
-
};
|
|
218
|
-
const responseBody = await formatter.formatResponseBody();
|
|
219
|
-
const responseBodyString = responseBody ? `\n\n${responseBody}` : '';
|
|
220
|
-
|
|
221
|
-
const responseContextDetail: ContextDetail = {
|
|
222
|
-
title: lockedString(UIStringsNotTranslate.response),
|
|
223
|
-
text: formatter.formatResponseHeaders() + responseBodyString +
|
|
224
|
-
`\n\n${formatter.formatStatus()}${formatter.formatFailureReasons()}`,
|
|
225
|
-
};
|
|
226
|
-
const timingContextDetail: ContextDetail = {
|
|
227
|
-
title: lockedString(UIStringsNotTranslate.timing),
|
|
228
|
-
text: formatter.formatNetworkRequestTiming(),
|
|
229
|
-
};
|
|
230
|
-
const initiatorChainContextDetail: ContextDetail = {
|
|
231
|
-
title: lockedString(UIStringsNotTranslate.requestInitiatorChain),
|
|
232
|
-
text: formatter.formatRequestInitiatorChain(),
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
return [
|
|
236
|
-
requestContextDetail,
|
|
237
|
-
responseContextDetail,
|
|
238
|
-
timingContextDetail,
|
|
239
|
-
initiatorChainContextDetail,
|
|
240
|
-
];
|
|
241
|
-
}
|
|
@@ -15,7 +15,7 @@ import * as Logs from '../../logs/logs.js';
|
|
|
15
15
|
import * as SourceMapScopes from '../../source_map_scopes/source_map_scopes.js';
|
|
16
16
|
import * as TextUtils from '../../text_utils/text_utils.js';
|
|
17
17
|
import * as Trace from '../../trace/trace.js';
|
|
18
|
-
import {extractContextOrigin} from '../AiOrigins.js';
|
|
18
|
+
import {canResourceContentsBeReadForTrace, extractContextOrigin} from '../AiOrigins.js';
|
|
19
19
|
import {sanitizeHeaders} from '../data_formatters/NetworkRequestFormatter.js';
|
|
20
20
|
import {
|
|
21
21
|
PerformanceInsightFormatter,
|
|
@@ -751,11 +751,26 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
751
751
|
yield* super.run(initialQuery, options);
|
|
752
752
|
}
|
|
753
753
|
|
|
754
|
+
/**
|
|
755
|
+
* Clears performance-agent-specific caches and state.
|
|
756
|
+
* This is called when the conversation needs to be reset (e.g. on navigation)
|
|
757
|
+
* to prevent stale formatters, trace facts, or selection contexts from leaking
|
|
758
|
+
* into subsequent runs.
|
|
759
|
+
*/
|
|
754
760
|
override clearCache(): void {
|
|
761
|
+
super.clearCache();
|
|
755
762
|
// Clear the function call cache to prevent stashed tool execution results
|
|
756
763
|
// (which might contain cross-origin resource content fetched before navigation
|
|
757
764
|
// was detected) from being replayed as facts in subsequent runs.
|
|
758
765
|
this.#functionCallCacheForFocus.clear();
|
|
766
|
+
// Reset the formatter and trace facts so they are recreated with the
|
|
767
|
+
// correct target and origin on the next execution.
|
|
768
|
+
this.#formatter = null;
|
|
769
|
+
this.#traceFacts = [];
|
|
770
|
+
this.#lastEventForEnhancedQuery = undefined;
|
|
771
|
+
this.#lastInsightForEnhancedQuery = undefined;
|
|
772
|
+
this.#additionalSelectionsForDisclosure = [];
|
|
773
|
+
this.#callTreeContextSet = new WeakSet();
|
|
759
774
|
}
|
|
760
775
|
|
|
761
776
|
#createFactForTraceSummary(): void {
|
|
@@ -1457,8 +1472,16 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
1457
1472
|
},
|
|
1458
1473
|
handler: async args => {
|
|
1459
1474
|
debugLog('Function call: getResourceContent');
|
|
1475
|
+
if (!isFresh) {
|
|
1476
|
+
return {error: 'Cannot use this tool on an imported file.'};
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
const url = args.url;
|
|
1480
|
+
const allowedOrigin = context.getOrigin();
|
|
1481
|
+
if (!canResourceContentsBeReadForTrace(url, allowedOrigin)) {
|
|
1482
|
+
return {error: 'Resource not found'};
|
|
1483
|
+
}
|
|
1460
1484
|
|
|
1461
|
-
const url = args.url as Platform.DevToolsPath.UrlString;
|
|
1462
1485
|
let content: string|undefined;
|
|
1463
1486
|
|
|
1464
1487
|
// First check parsedTrace.data.Scripts.
|
|
@@ -2,6 +2,42 @@
|
|
|
2
2
|
|
|
3
3
|
This directory contains the implementations of various AI agents used in the AI Assistance panel in Chrome DevTools.
|
|
4
4
|
|
|
5
|
+
## Agent Lifecycle & State Management
|
|
6
|
+
|
|
7
|
+
AI Agents can maintain internal stateful variables to optimize performance or store context (e.g., stashed tool results, formatters, or instruction flags). However, this state must be carefully managed to prevent security leaks (such as cross-origin data leaks after page navigation) or stale results.
|
|
8
|
+
|
|
9
|
+
### Cache Clearing (`clearCache()`)
|
|
10
|
+
|
|
11
|
+
The `AiAgent` base class defines a `clearCache()` method. This method is automatically invoked by the system when:
|
|
12
|
+
- An execution error occurs.
|
|
13
|
+
- The user aborts the execution.
|
|
14
|
+
- A cross-origin navigation is detected (via the top-level origin blocking mechanism).
|
|
15
|
+
|
|
16
|
+
#### Overriding `clearCache()` in Subclasses
|
|
17
|
+
|
|
18
|
+
If you introduce new stateful member variables in an `AiAgent` subclass, you **must** override `clearCache()` to reset them:
|
|
19
|
+
|
|
20
|
+
1. Always call `super.clearCache()` to ensure base class cleanup is executed.
|
|
21
|
+
2. Reset any subclass-specific state (e.g., setting formatters to `null`, clearing lists, resetting boolean flags).
|
|
22
|
+
|
|
23
|
+
Example from `PerformanceAgent`:
|
|
24
|
+
```typescript
|
|
25
|
+
override clearCache(): void {
|
|
26
|
+
super.clearCache();
|
|
27
|
+
this.#functionCallCacheForFocus.clear();
|
|
28
|
+
this.#formatter = null;
|
|
29
|
+
this.#traceFacts = [];
|
|
30
|
+
// ... reset other stateful fields
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Origin Validation (`isOriginAllowed`)
|
|
35
|
+
|
|
36
|
+
Before running an execution loop, the system validates the context's origin:
|
|
37
|
+
* **Opaque Origin Rejection**: Opaque origins are rejected immediately, blocking conversations on untrusted/opaque contexts (like `about:blank`, `data:` URLs, or opaque blob URLs).
|
|
38
|
+
* **Origin Lock Integrity**: If the conversation is already locked to an origin, the new context's origin must be equivalent (as defined by `areOriginsEquivalent()`) to the locked origin.
|
|
39
|
+
* **Safety Termination**: If validation fails, a cross-origin error is yielded and execution stops.
|
|
40
|
+
|
|
5
41
|
## Performance Agent
|
|
6
42
|
|
|
7
43
|
The `PerformanceAgent` analyzes performance traces. This documentation details the specific data provided to the agent and the data it can retrieve via functions.
|
|
@@ -70,3 +106,31 @@ The agent can request additional data by calling functions. Here is the data the
|
|
|
70
106
|
#### `selectEventByKey`
|
|
71
107
|
- **Arguments**: `eventKey` (string)
|
|
72
108
|
- **Data Returned to Agent**: Confirmation of success or an error message. (Note: This function also modifies the DevTools UI by selecting the event in the flamechart).
|
|
109
|
+
|
|
110
|
+
## Styling Agent
|
|
111
|
+
|
|
112
|
+
The `StylingAgent` assists with CSS styling and layout questions. It can interact with the page to inspect styles, execute Javascript, and optionally emulate devices or vision deficiencies.
|
|
113
|
+
|
|
114
|
+
### Initial Data Provided to the Agent
|
|
115
|
+
|
|
116
|
+
The agent is initialized with the selected DOM node context.
|
|
117
|
+
|
|
118
|
+
### Data Retrieval & Action Functions (Tools)
|
|
119
|
+
|
|
120
|
+
The agent can call the following functions to retrieve more details or perform actions:
|
|
121
|
+
|
|
122
|
+
#### `getStyles`
|
|
123
|
+
- **Arguments**: None (it uses the currently selected DOM node).
|
|
124
|
+
- **Data Returned to Agent**: Computed styles and authored styles (matching rules, active stylesheets, etc.) for the selected node.
|
|
125
|
+
|
|
126
|
+
#### `executeJavaScript`
|
|
127
|
+
- **Arguments**: `query` (string)
|
|
128
|
+
- **Data Returned to Agent**: The result of executing the JavaScript query in the context of the page.
|
|
129
|
+
|
|
130
|
+
#### `addElementAnnotation`
|
|
131
|
+
- **Arguments**: `elementId` (string), `annotationMessage` (string)
|
|
132
|
+
- **Data Returned to Agent**: Confirmation of success or an error message. (Note: This function also modifies the DevTools UI by adding a visual annotation to the node).
|
|
133
|
+
|
|
134
|
+
#### `activateDeviceEmulation`
|
|
135
|
+
- **Arguments**: `deviceName` (string), `visionDeficiency` (string, optional)
|
|
136
|
+
- **Data Returned to Agent**: Confirmation of success or an error message. (Note: This function modifies the DevTools UI by enabling device and/or vision deficiency emulation).
|
|
@@ -191,9 +191,18 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
|
|
|
191
191
|
description: getStylesTool.description,
|
|
192
192
|
parameters: getStylesTool.parameters,
|
|
193
193
|
displayInfoFromArgs: getStylesTool.displayInfoFromArgs,
|
|
194
|
-
handler: args =>
|
|
195
|
-
|
|
196
|
-
|
|
194
|
+
handler: async args => {
|
|
195
|
+
const context = this.context;
|
|
196
|
+
if (!context) {
|
|
197
|
+
return {error: 'Error: Could not find the currently selected element.'};
|
|
198
|
+
}
|
|
199
|
+
return await getStylesTool.handler(args, {
|
|
200
|
+
conversationContext: context,
|
|
201
|
+
getTarget: () =>
|
|
202
|
+
SDK.TargetManager.TargetManager.instance().primaryPageTarget() ?? context.getItem().domModel().target(),
|
|
203
|
+
getEstablishedOrigin: () => context.getOrigin(),
|
|
204
|
+
});
|
|
205
|
+
},
|
|
197
206
|
});
|
|
198
207
|
|
|
199
208
|
const executeJsTool = ToolRegistry.get(ToolName.EXECUTE_JAVASCRIPT);
|
|
@@ -281,6 +290,20 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
|
|
|
281
290
|
});
|
|
282
291
|
}
|
|
283
292
|
|
|
293
|
+
/**
|
|
294
|
+
* Clears styling-agent-specific caches and state.
|
|
295
|
+
* Resets cached emulation data (screenshots, accessibility tree) and the
|
|
296
|
+
* instructions flag to ensure they are re-evaluated in subsequent queries.
|
|
297
|
+
*/
|
|
298
|
+
override clearCache(): void {
|
|
299
|
+
super.clearCache();
|
|
300
|
+
// Reset emulation state so that subsequent queries will re-initialize
|
|
301
|
+
// emulation details and fetch fresh data.
|
|
302
|
+
this.#greenDevEmulationScreenshot = null;
|
|
303
|
+
this.#greenDevEmulationAxTree = null;
|
|
304
|
+
this.#hasAddedEmulationInstructions = false;
|
|
305
|
+
}
|
|
306
|
+
|
|
284
307
|
override preambleFeatures(): string[] {
|
|
285
308
|
return ['function_calling'];
|
|
286
309
|
}
|
|
@@ -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';
|
|
@@ -66,6 +68,7 @@ export {
|
|
|
66
68
|
ExecuteJavaScript,
|
|
67
69
|
ExtensionScope,
|
|
68
70
|
FileAgent,
|
|
71
|
+
FileContext,
|
|
69
72
|
FileFormatter,
|
|
70
73
|
GetStyles,
|
|
71
74
|
GreenDevAgent,
|
|
@@ -80,6 +83,7 @@ export {
|
|
|
80
83
|
PerformanceAnnotations,
|
|
81
84
|
PerformanceInsightFormatter,
|
|
82
85
|
PerformanceTraceFormatter,
|
|
86
|
+
RequestContext,
|
|
83
87
|
StorageAgent,
|
|
84
88
|
StorageItem,
|
|
85
89
|
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
|