chrome-devtools-frontend 1.0.1643099 → 1.0.1645245
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/eslint.config.mjs +3 -1
- package/extension-api/ExtensionAPI.d.ts +83 -12
- package/front_end/core/host/UserMetrics.ts +3 -3
- package/front_end/core/root/ExperimentNames.ts +0 -1
- package/front_end/core/sdk/CSSPropertyParserMatchers.ts +2 -3
- package/front_end/core/sdk/ConsoleModel.ts +4 -0
- package/front_end/core/sdk/NetworkRequest.ts +12 -1
- package/front_end/core/sdk/SourceMap.ts +15 -18
- package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +0 -2
- package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +0 -2
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +37 -0
- package/front_end/entrypoints/main/MainImpl.ts +0 -6
- package/front_end/generated/SupportedCSSProperties.js +4 -2
- package/front_end/models/ai_assistance/AiAgent2.ts +23 -12
- package/front_end/models/ai_assistance/README.md +5 -4
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +22 -16
- package/front_end/models/ai_assistance/agents/AiAgent.ts +19 -6
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +5 -5
- package/front_end/models/ai_assistance/agents/ExecuteJavascript.ts +1 -94
- package/front_end/models/ai_assistance/agents/NetworkAgent.ts +25 -0
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +37 -0
- package/front_end/models/ai_assistance/agents/README.md +57 -0
- package/front_end/models/ai_assistance/agents/StorageAgent.ts +54 -1
- package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +1 -2
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +31 -3
- package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +12 -21
- 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 +78 -9
- package/front_end/models/ai_assistance/tools/ToolRegistry.ts +21 -5
- package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +6 -9
- package/front_end/models/bindings/DefaultScriptMapping.ts +2 -1
- package/front_end/models/bindings/SymbolizedError.ts +45 -35
- package/front_end/models/extensions/ExtensionAPI.ts +138 -47
- package/front_end/models/har/Importer.ts +1 -0
- package/front_end/models/heap_snapshot/HeapSnapshotModel.ts +18 -2
- package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +4 -0
- package/front_end/models/source_map_scopes/FunctionCodeResolver.ts +12 -2
- package/front_end/models/stack_trace/DetailedErrorStackParser.ts +58 -52
- package/front_end/models/stack_trace/StackTrace.ts +7 -0
- package/front_end/models/stack_trace/StackTraceImpl.ts +13 -4
- package/front_end/models/stack_trace/StackTraceModel.ts +43 -9
- package/front_end/models/trace/Styles.ts +29 -7
- 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/panels/accessibility/AccessibilitySidebarView.ts +2 -1
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +9 -2
- package/front_end/panels/ai_assistance/ai_assistance-meta.ts +16 -0
- package/front_end/panels/application/ApplicationPanelSidebar.ts +83 -0
- package/front_end/panels/application/ApplicationPanelTreeElement.ts +39 -0
- package/front_end/panels/application/CookieItemsView.ts +2 -2
- package/front_end/panels/application/ServiceWorkersView.ts +2 -2
- package/front_end/panels/application/WebMCPView.ts +0 -1
- package/front_end/panels/application/components/BackForwardCacheView.ts +1 -2
- package/front_end/panels/application/resourcesSidebar.css +11 -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 +14 -8
- 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/settings/components/SyncSection.ts +1 -1
- package/front_end/panels/settings/emulation/DevicesSettingsTab.ts +1 -0
- package/front_end/panels/sources/SourcesPanel.ts +2 -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/StackedPane.ts +229 -0
- package/front_end/ui/legacy/ViewManager.ts +59 -169
- 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/legacy/legacy.ts +3 -1
- package/front_end/ui/visual_logging/KnownContextValues.ts +5 -0
- package/package.json +1 -1
|
@@ -509,8 +509,8 @@ export abstract class AiAgent<T> {
|
|
|
509
509
|
this.#allowedOrigin = opts.allowedOrigin;
|
|
510
510
|
}
|
|
511
511
|
|
|
512
|
-
async enhanceQuery(query: string, selected: ConversationContext<T>|null,
|
|
513
|
-
|
|
512
|
+
async enhanceQuery(query: string, selected: ConversationContext<T>|null,
|
|
513
|
+
multimodalInputType?: MultimodalInputType): Promise<string>;
|
|
514
514
|
async enhanceQuery(query: string): Promise<string> {
|
|
515
515
|
return query;
|
|
516
516
|
}
|
|
@@ -557,9 +557,21 @@ export abstract class AiAgent<T> {
|
|
|
557
557
|
return undefined;
|
|
558
558
|
}
|
|
559
559
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
560
|
+
/**
|
|
561
|
+
* Preamble features appended to the `client_version` in metadata.
|
|
562
|
+
* This is required ONLY for the Styling Agent for legacy reasons to serve
|
|
563
|
+
* different server-side preambles based on the Chrome version.
|
|
564
|
+
* Other agents should NOT set or override this.
|
|
565
|
+
* If you are curious about this, look for `do_conversation_handler.cc` in
|
|
566
|
+
* Google3 or chat to @jacktfranklin.
|
|
567
|
+
*/
|
|
568
|
+
preambleFeatures(): string[] {
|
|
569
|
+
return [];
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
buildRequest(part: Host.AidaClient.Part|Host.AidaClient.Part[],
|
|
573
|
+
role: Host.AidaClient.Role.USER|
|
|
574
|
+
Host.AidaClient.Role.ROLE_UNSPECIFIED): Host.AidaClient.DoConversationRequest {
|
|
563
575
|
const parts = Array.isArray(part) ? part : [part];
|
|
564
576
|
const currentMessage: Host.AidaClient.Content = {
|
|
565
577
|
parts,
|
|
@@ -600,7 +612,8 @@ export abstract class AiAgent<T> {
|
|
|
600
612
|
disable_user_content_logging: !(this.#serverSideLoggingEnabled ?? false),
|
|
601
613
|
string_session_id: this.#sessionId,
|
|
602
614
|
user_tier: userTier,
|
|
603
|
-
client_version:
|
|
615
|
+
client_version:
|
|
616
|
+
Root.Runtime.getChromeVersion() + this.preambleFeatures().map(feature => `+${feature}`).join(''),
|
|
604
617
|
},
|
|
605
618
|
|
|
606
619
|
functionality_type: enableAidaFunctionCalling ? Host.AidaClient.FunctionalityType.AGENTIC_CHAT :
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
type RequestOptions,
|
|
28
28
|
} from './AiAgent.js';
|
|
29
29
|
import {FileContext} from './FileAgent.js';
|
|
30
|
-
import {RequestContext} from './NetworkAgent.js';
|
|
30
|
+
import {getRequestContextOrigin, RequestContext} from './NetworkAgent.js';
|
|
31
31
|
import {PerformanceTraceContext} from './PerformanceAgent.js';
|
|
32
32
|
import {StorageContext} from './StorageAgent.js';
|
|
33
33
|
|
|
@@ -146,7 +146,7 @@ export class ContextSelectionAgent extends AiAgent<never> {
|
|
|
146
146
|
let hasCrossOriginRequest = false;
|
|
147
147
|
const requestsToShow: NetworkRequest[] = [];
|
|
148
148
|
for (const request of Logs.NetworkLog.NetworkLog.instance().requests()) {
|
|
149
|
-
const
|
|
149
|
+
const requestOrigin = getRequestContextOrigin(request);
|
|
150
150
|
/**
|
|
151
151
|
* NOTE: this origin check does not ensure that all the requests are
|
|
152
152
|
* from the same origin as the target page. Instead, it ensures that
|
|
@@ -155,7 +155,7 @@ export class ContextSelectionAgent extends AiAgent<never> {
|
|
|
155
155
|
* during the loading of the target page, and do not leak URLs from
|
|
156
156
|
* other pages.
|
|
157
157
|
*/
|
|
158
|
-
if (origin &&
|
|
158
|
+
if (origin && requestOrigin !== origin) {
|
|
159
159
|
hasCrossOriginRequest = true;
|
|
160
160
|
continue;
|
|
161
161
|
}
|
|
@@ -230,8 +230,8 @@ export class ContextSelectionAgent extends AiAgent<never> {
|
|
|
230
230
|
return false;
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
-
const
|
|
234
|
-
return !origin ||
|
|
233
|
+
const requestOrigin = getRequestContextOrigin(req);
|
|
234
|
+
return !origin || requestOrigin === origin;
|
|
235
235
|
});
|
|
236
236
|
|
|
237
237
|
if (request) {
|
|
@@ -12,9 +12,7 @@ import {debugLog} from '../debug.js';
|
|
|
12
12
|
import {EvaluateAction, formatError, SideEffectError} from '../EvaluateAction.js';
|
|
13
13
|
import {FREESTYLER_WORLD_NAME} from '../injected.js';
|
|
14
14
|
|
|
15
|
-
import type {
|
|
16
|
-
AgentOptions as BaseAgentOptions, FunctionCallHandlerResult, FunctionDeclaration, FunctionHandlerOptions,} from
|
|
17
|
-
'./AiAgent.js';
|
|
15
|
+
import type {AgentOptions as BaseAgentOptions, FunctionCallHandlerResult, FunctionHandlerOptions,} from './AiAgent.js';
|
|
18
16
|
|
|
19
17
|
const lockedString = i18n.i18n.lockedString;
|
|
20
18
|
|
|
@@ -28,97 +26,6 @@ export interface ExecuteJsAgentOptions extends BaseAgentOptions {
|
|
|
28
26
|
execJs?: typeof executeJsCode;
|
|
29
27
|
}
|
|
30
28
|
|
|
31
|
-
// TODO(crbug.com/510206549): De-duplicate this function by migrating AccessibilityAgent to use
|
|
32
|
-
// the registry-based ExecuteJavaScriptTool in tools/ExecuteJavaScript.ts.
|
|
33
|
-
export function executeJavaScriptFunction(executor: JavascriptExecutor): FunctionDeclaration<
|
|
34
|
-
{
|
|
35
|
-
title: string,
|
|
36
|
-
explanation: string,
|
|
37
|
-
code: string,
|
|
38
|
-
},
|
|
39
|
-
unknown> {
|
|
40
|
-
return {
|
|
41
|
-
description:
|
|
42
|
-
'This function allows you to run JavaScript code on the inspected page to access the element styles and page content.\nCall this function to gather additional information or modify the page state. Call this function enough times to investigate the user request.',
|
|
43
|
-
parameters: {
|
|
44
|
-
type: Host.AidaClient.ParametersTypes.OBJECT,
|
|
45
|
-
description: '',
|
|
46
|
-
nullable: false,
|
|
47
|
-
properties: {
|
|
48
|
-
code: {
|
|
49
|
-
type: Host.AidaClient.ParametersTypes.STRING,
|
|
50
|
-
description:
|
|
51
|
-
`JavaScript code snippet to run on the inspected page. Make sure the code is formatted for readability.
|
|
52
|
-
|
|
53
|
-
# Instructions
|
|
54
|
-
|
|
55
|
-
* To return data, define a top-level \`data\` variable and populate it with data you want to get. Only JSON-serializable objects can be assigned to \`data\`.
|
|
56
|
-
* If you modify styles on an element, ALWAYS call the pre-defined global \`async setElementStyles(el: Element, styles: object)\` function. This function is an internal mechanism for you and should never be presented as a command/advice to the user.
|
|
57
|
-
* **CRITICAL** Only get styles that might be relevant to the user request.
|
|
58
|
-
* **CRITICAL** Never assume a selector for the elements unless you verified your knowledge.
|
|
59
|
-
* **CRITICAL** Consider that \`data\` variable from the previous function calls are not available in a new function call.
|
|
60
|
-
|
|
61
|
-
For example, the code to change element styles:
|
|
62
|
-
|
|
63
|
-
\`\`\`
|
|
64
|
-
await setElementStyles($0, {
|
|
65
|
-
color: 'blue',
|
|
66
|
-
});
|
|
67
|
-
\`\`\`
|
|
68
|
-
|
|
69
|
-
For example, the code to get overlapping elements:
|
|
70
|
-
|
|
71
|
-
\`\`\`
|
|
72
|
-
const data = {
|
|
73
|
-
overlappingElements: Array.from(document.querySelectorAll('*'))
|
|
74
|
-
.filter(el => {
|
|
75
|
-
const rect = el.getBoundingClientRect();
|
|
76
|
-
const popupRect = $0.getBoundingClientRect();
|
|
77
|
-
return (
|
|
78
|
-
el !== $0 &&
|
|
79
|
-
rect.left < popupRect.right &&
|
|
80
|
-
rect.right > popupRect.left &&
|
|
81
|
-
rect.top < popupRect.bottom &&
|
|
82
|
-
rect.bottom > popupRect.top
|
|
83
|
-
);
|
|
84
|
-
})
|
|
85
|
-
.map(el => ({
|
|
86
|
-
tagName: el.tagName,
|
|
87
|
-
id: el.id,
|
|
88
|
-
className: el.className,
|
|
89
|
-
zIndex: window.getComputedStyle(el)['z-index']
|
|
90
|
-
}))
|
|
91
|
-
};
|
|
92
|
-
\`\`\`
|
|
93
|
-
`,
|
|
94
|
-
},
|
|
95
|
-
explanation: {
|
|
96
|
-
type: Host.AidaClient.ParametersTypes.STRING,
|
|
97
|
-
description: 'Explain why you want to run this code',
|
|
98
|
-
},
|
|
99
|
-
title: {
|
|
100
|
-
type: Host.AidaClient.ParametersTypes.STRING,
|
|
101
|
-
description: 'Provide a summary of what the code does. For example, "Checking related element styles".',
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
required: ['code', 'explanation', 'title']
|
|
105
|
-
},
|
|
106
|
-
displayInfoFromArgs: params => {
|
|
107
|
-
return {
|
|
108
|
-
title: params.title,
|
|
109
|
-
thought: params.explanation,
|
|
110
|
-
action: params.code,
|
|
111
|
-
};
|
|
112
|
-
},
|
|
113
|
-
handler: async (
|
|
114
|
-
params,
|
|
115
|
-
options,
|
|
116
|
-
) => {
|
|
117
|
-
return await executor.executeAction(params.code, options);
|
|
118
|
-
},
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
|
|
122
29
|
export async function executeJsCode(
|
|
123
30
|
functionDeclaration: string,
|
|
124
31
|
{throwOnSideEffect, contextNode}: {throwOnSideEffect: boolean, contextNode: SDK.DOMModel.DOMNode|null}):
|
|
@@ -2,11 +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';
|
|
5
6
|
import * as Host from '../../../core/host/host.js';
|
|
6
7
|
import * as i18n from '../../../core/i18n/i18n.js';
|
|
8
|
+
import type * as Platform from '../../../core/platform/platform.js';
|
|
7
9
|
import * as Root from '../../../core/root/root.js';
|
|
8
10
|
import type * as SDK from '../../../core/sdk/sdk.js';
|
|
9
11
|
import type * as NetworkTimeCalculator from '../../network_time_calculator/network_time_calculator.js';
|
|
12
|
+
import {extractContextOrigin} from '../AiOrigins.js';
|
|
10
13
|
import {NetworkRequestFormatter} from '../data_formatters/NetworkRequestFormatter.js';
|
|
11
14
|
|
|
12
15
|
import {
|
|
@@ -98,6 +101,24 @@ const UIStringsNotTranslate = {
|
|
|
98
101
|
|
|
99
102
|
const lockedString = i18n.i18n.lockedString;
|
|
100
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
|
+
|
|
101
122
|
export class RequestContext extends ConversationContext<SDK.NetworkRequest.NetworkRequest> {
|
|
102
123
|
#request: SDK.NetworkRequest.NetworkRequest;
|
|
103
124
|
#calculator: NetworkTimeCalculator.NetworkTransferTimeCalculator;
|
|
@@ -119,6 +140,10 @@ export class RequestContext extends ConversationContext<SDK.NetworkRequest.Netwo
|
|
|
119
140
|
return this.#request.documentURL;
|
|
120
141
|
}
|
|
121
142
|
|
|
143
|
+
override getOrigin(): string {
|
|
144
|
+
return getRequestContextOrigin(this.#request);
|
|
145
|
+
}
|
|
146
|
+
|
|
122
147
|
override getItem(): SDK.NetworkRequest.NetworkRequest {
|
|
123
148
|
return this.#request;
|
|
124
149
|
}
|
|
@@ -15,6 +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
19
|
import {sanitizeHeaders} from '../data_formatters/NetworkRequestFormatter.js';
|
|
19
20
|
import {
|
|
20
21
|
PerformanceInsightFormatter,
|
|
@@ -256,6 +257,27 @@ export class PerformanceTraceContext extends ConversationContext<AgentFocus> {
|
|
|
256
257
|
}
|
|
257
258
|
}
|
|
258
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Returns the origin for a performance trace in the AI context.
|
|
262
|
+
*
|
|
263
|
+
* To prevent cross-origin prompt injection attacks, imported traces
|
|
264
|
+
* are isolated from live pages. We assign them a virtual origin
|
|
265
|
+
* (`imported-trace://${domain}`) so they do not share the origin of live pages
|
|
266
|
+
* (e.g., `https://${domain}`). This forces a conversation reset when transitioning
|
|
267
|
+
* between imported trace data and live pages.
|
|
268
|
+
*/
|
|
269
|
+
override getOrigin(): string {
|
|
270
|
+
const parsedTrace = this.#focus.parsedTrace;
|
|
271
|
+
const url = this.getURL();
|
|
272
|
+
const origin = extractContextOrigin(url);
|
|
273
|
+
const isFresh = Tracing.FreshRecording.Tracker.instance().recordingIsFresh(parsedTrace);
|
|
274
|
+
if (!isFresh) {
|
|
275
|
+
const parsed = Common.ParsedURL.ParsedURL.fromString(origin as Platform.DevToolsPath.UrlString);
|
|
276
|
+
return `imported-trace://${parsed ? parsed.domain() : origin}`;
|
|
277
|
+
}
|
|
278
|
+
return origin;
|
|
279
|
+
}
|
|
280
|
+
|
|
259
281
|
override getItem(): AgentFocus {
|
|
260
282
|
return this.#focus;
|
|
261
283
|
}
|
|
@@ -729,11 +751,26 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
729
751
|
yield* super.run(initialQuery, options);
|
|
730
752
|
}
|
|
731
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
|
+
*/
|
|
732
760
|
override clearCache(): void {
|
|
761
|
+
super.clearCache();
|
|
733
762
|
// Clear the function call cache to prevent stashed tool execution results
|
|
734
763
|
// (which might contain cross-origin resource content fetched before navigation
|
|
735
764
|
// was detected) from being replayed as facts in subsequent runs.
|
|
736
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();
|
|
737
774
|
}
|
|
738
775
|
|
|
739
776
|
#createFactForTraceSummary(): void {
|
|
@@ -2,6 +2,35 @@
|
|
|
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
|
+
|
|
5
34
|
## Performance Agent
|
|
6
35
|
|
|
7
36
|
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 +99,31 @@ The agent can request additional data by calling functions. Here is the data the
|
|
|
70
99
|
#### `selectEventByKey`
|
|
71
100
|
- **Arguments**: `eventKey` (string)
|
|
72
101
|
- **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).
|
|
102
|
+
|
|
103
|
+
## Styling Agent
|
|
104
|
+
|
|
105
|
+
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.
|
|
106
|
+
|
|
107
|
+
### Initial Data Provided to the Agent
|
|
108
|
+
|
|
109
|
+
The agent is initialized with the selected DOM node context.
|
|
110
|
+
|
|
111
|
+
### Data Retrieval & Action Functions (Tools)
|
|
112
|
+
|
|
113
|
+
The agent can call the following functions to retrieve more details or perform actions:
|
|
114
|
+
|
|
115
|
+
#### `getStyles`
|
|
116
|
+
- **Arguments**: None (it uses the currently selected DOM node).
|
|
117
|
+
- **Data Returned to Agent**: Computed styles and authored styles (matching rules, active stylesheets, etc.) for the selected node.
|
|
118
|
+
|
|
119
|
+
#### `executeJavaScript`
|
|
120
|
+
- **Arguments**: `query` (string)
|
|
121
|
+
- **Data Returned to Agent**: The result of executing the JavaScript query in the context of the page.
|
|
122
|
+
|
|
123
|
+
#### `addElementAnnotation`
|
|
124
|
+
- **Arguments**: `elementId` (string), `annotationMessage` (string)
|
|
125
|
+
- **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).
|
|
126
|
+
|
|
127
|
+
#### `activateDeviceEmulation`
|
|
128
|
+
- **Arguments**: `deviceName` (string), `visionDeficiency` (string, optional)
|
|
129
|
+
- **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).
|
|
@@ -23,7 +23,7 @@ const lockedString = i18n.i18n.lockedString;
|
|
|
23
23
|
const preamble =
|
|
24
24
|
`You are a Senior Software Engineer specializing in state audit and storage analysis within Chrome DevTools. Your mission is to help developers debug storage-related issues faster by analyzing the evidence in LocalStorage, SessionStorage, and Cookies.
|
|
25
25
|
|
|
26
|
-
You have access to the site's storage using tools like \`listPageOrigins\`, \`listStorageKeys\`, \`getStorageValues\`, \`listCookies\`, and \`getCookieValues\`.
|
|
26
|
+
You have access to the site's storage using tools like \`getStorageBreakdown\`, \`listPageOrigins\`, \`listStorageKeys\`, \`getStorageValues\`, \`listCookies\`, and \`getCookieValues\`.
|
|
27
27
|
|
|
28
28
|
# Goals
|
|
29
29
|
|
|
@@ -34,6 +34,7 @@ const preamble =
|
|
|
34
34
|
# Tools & Workflow
|
|
35
35
|
|
|
36
36
|
- **Prioritize Top-Level Context**: Always initiate your investigation from the top-level page's storage. Explicitly state if you are analyzing storage from a different context (e.g., an iframe).
|
|
37
|
+
- **Storage Breakdown**: Calling \`getStorageBreakdown\` gives you the total usage and quota per storage for the top-level page.
|
|
37
38
|
- **Address Specific Selections**: The user can select individual storage items in the DevTools UI (provided in the '# Active Context' section of the prompt). If the query is about a selected item (e.g., "Why is this cookie set?"), focus your response on that specific item.
|
|
38
39
|
- **Expand Scope When Necessary**: For general questions or those implying a wider scope (e.g., "Check all storages," "Are there related cookies on subdomains?"), proactively use your tools to explore other relevant storage contexts, including iframes and different origins.
|
|
39
40
|
- **Discovery**: Start by calling \`listPageOrigins\` to discover all active, non-empty frame origins loaded by the page.
|
|
@@ -479,6 +480,58 @@ export class StorageAgent extends AiAgent<StorageItem> {
|
|
|
479
480
|
return {result: {cookies: cookieData}};
|
|
480
481
|
},
|
|
481
482
|
});
|
|
483
|
+
|
|
484
|
+
this.declareFunction<Record<string, never>, {
|
|
485
|
+
totalUsage: string,
|
|
486
|
+
totalQuota: string,
|
|
487
|
+
usageBreakdown: Array<{
|
|
488
|
+
storageType: string,
|
|
489
|
+
usage: string,
|
|
490
|
+
}>,
|
|
491
|
+
}>('getStorageBreakdown', {
|
|
492
|
+
description:
|
|
493
|
+
'Retrieves the total storage usage, total storage quota, and a breakdown of active storage usage per storage type for the top-level page.',
|
|
494
|
+
parameters: {
|
|
495
|
+
type: Host.AidaClient.ParametersTypes.OBJECT,
|
|
496
|
+
description: '',
|
|
497
|
+
nullable: false,
|
|
498
|
+
properties: {},
|
|
499
|
+
required: [],
|
|
500
|
+
},
|
|
501
|
+
displayInfoFromArgs: () => {
|
|
502
|
+
return {
|
|
503
|
+
title: lockedString('Retrieving storage breakdown'),
|
|
504
|
+
action: 'getStorageBreakdown()',
|
|
505
|
+
};
|
|
506
|
+
},
|
|
507
|
+
handler: async () => {
|
|
508
|
+
const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
|
|
509
|
+
if (!target || !this.context || !isSamePageOrigin(target, this.context)) {
|
|
510
|
+
return {error: 'No origin available or not allowed.'};
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const origin = this.context.getOrigin();
|
|
514
|
+
const response = await target.storageAgent().invoke_getUsageAndQuota({origin});
|
|
515
|
+
if (response.getError()) {
|
|
516
|
+
return {error: response.getError() || 'Unknown CDP error'};
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const usageBreakdown = response.usageBreakdown.filter(entry => entry.usage > 0)
|
|
520
|
+
.sort((a, b) => b.usage - a.usage)
|
|
521
|
+
.map(entry => ({
|
|
522
|
+
storageType: entry.storageType as string,
|
|
523
|
+
usage: i18n.ByteUtilities.bytesToString(entry.usage),
|
|
524
|
+
}));
|
|
525
|
+
|
|
526
|
+
return {
|
|
527
|
+
result: {
|
|
528
|
+
totalUsage: i18n.ByteUtilities.bytesToString(response.usage),
|
|
529
|
+
totalQuota: i18n.ByteUtilities.bytesToString(response.quota),
|
|
530
|
+
usageBreakdown,
|
|
531
|
+
},
|
|
532
|
+
};
|
|
533
|
+
},
|
|
534
|
+
});
|
|
482
535
|
}
|
|
483
536
|
|
|
484
537
|
static #formatContext(item: StorageItem): string {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
Title: StylingAgent buildRequest structure matches the snapshot
|
|
3
2
|
Content:
|
|
4
3
|
{
|
|
@@ -129,7 +128,7 @@ Content:
|
|
|
129
128
|
"disable_user_content_logging": false,
|
|
130
129
|
"string_session_id": "sessionId",
|
|
131
130
|
"user_tier": 3,
|
|
132
|
-
"client_version": "unit_test"
|
|
131
|
+
"client_version": "unit_test+function_calling"
|
|
133
132
|
},
|
|
134
133
|
"functionality_type": 5,
|
|
135
134
|
"client_feature": 2
|
|
@@ -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);
|
|
@@ -211,6 +220,7 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
|
|
|
211
220
|
changeManager: this.#changes,
|
|
212
221
|
createExtensionScope: this.#createExtensionScope.bind(this),
|
|
213
222
|
execJs: this.#execJs,
|
|
223
|
+
getExecutionContextNode: () => this.context?.getItem() ?? null,
|
|
214
224
|
},
|
|
215
225
|
options,
|
|
216
226
|
),
|
|
@@ -280,6 +290,24 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
|
|
|
280
290
|
});
|
|
281
291
|
}
|
|
282
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
|
+
|
|
307
|
+
override preambleFeatures(): string[] {
|
|
308
|
+
return ['function_calling'];
|
|
309
|
+
}
|
|
310
|
+
|
|
283
311
|
#getSelectedNode(): SDK.DOMModel.DOMNode|null {
|
|
284
312
|
return this.context?.getItem() ?? null;
|
|
285
313
|
}
|
|
@@ -6,12 +6,13 @@ import * as Host from '../../../core/host/host.js';
|
|
|
6
6
|
import * as Root from '../../../core/root/root.js';
|
|
7
7
|
import type {FunctionCallHandlerResult, FunctionHandlerOptions,} from '../agents/AiAgent.js';
|
|
8
8
|
import {JavascriptExecutor} from '../agents/ExecuteJavascript.js';
|
|
9
|
-
import {DOMNodeContext} from '../contexts/DOMNodeContext.js';
|
|
10
9
|
|
|
11
10
|
import {
|
|
11
|
+
type BaseToolCapability,
|
|
12
|
+
type PageExecutionCapability,
|
|
13
|
+
type StyleMutationCapability,
|
|
12
14
|
type Tool,
|
|
13
15
|
type ToolArgs,
|
|
14
|
-
type ToolContext,
|
|
15
16
|
ToolName,
|
|
16
17
|
} from './Tool.js';
|
|
17
18
|
|
|
@@ -21,7 +22,8 @@ export interface ExecuteJavaScriptArgs extends ToolArgs {
|
|
|
21
22
|
title: string;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
export class ExecuteJavaScriptTool implements
|
|
25
|
+
export class ExecuteJavaScriptTool implements
|
|
26
|
+
Tool<ExecuteJavaScriptArgs, unknown, BaseToolCapability&PageExecutionCapability&StyleMutationCapability> {
|
|
25
27
|
readonly name = ToolName.EXECUTE_JAVASCRIPT;
|
|
26
28
|
|
|
27
29
|
readonly description =
|
|
@@ -105,33 +107,22 @@ const data = {
|
|
|
105
107
|
|
|
106
108
|
async handler(
|
|
107
109
|
params: ExecuteJavaScriptArgs,
|
|
108
|
-
context:
|
|
110
|
+
context: BaseToolCapability&PageExecutionCapability&StyleMutationCapability,
|
|
109
111
|
options?: FunctionHandlerOptions,
|
|
110
112
|
): Promise<FunctionCallHandlerResult<unknown>> {
|
|
111
|
-
const
|
|
112
|
-
if (!
|
|
113
|
-
return {error: 'Error: Could not find the
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const selectedNode = activeContext.getItem();
|
|
117
|
-
if (!selectedNode) {
|
|
118
|
-
return {error: 'Error: Could not find the currently selected element.'};
|
|
113
|
+
const executionNode = context.getExecutionContextNode();
|
|
114
|
+
if (!executionNode) {
|
|
115
|
+
return {error: 'Error: Could not find the context node for execution.'};
|
|
119
116
|
}
|
|
120
117
|
|
|
121
118
|
const executionMode = Root.Runtime.hostConfig.devToolsFreestyler?.executionMode ??
|
|
122
119
|
Root.Runtime.HostConfigFreestylerExecutionMode.ALL_SCRIPTS;
|
|
123
120
|
|
|
124
|
-
const changes = context.changeManager;
|
|
125
|
-
const createExtensionScope = context.createExtensionScope;
|
|
126
|
-
if (!changes || !createExtensionScope) {
|
|
127
|
-
return {error: 'Internal Error: Required change manager or extension scope creator is missing.'};
|
|
128
|
-
}
|
|
129
|
-
|
|
130
121
|
const executor = new JavascriptExecutor({
|
|
131
122
|
executionMode,
|
|
132
|
-
getContextNode: () =>
|
|
133
|
-
createExtensionScope,
|
|
134
|
-
changes,
|
|
123
|
+
getContextNode: () => executionNode,
|
|
124
|
+
createExtensionScope: context.createExtensionScope,
|
|
125
|
+
changes: context.changeManager,
|
|
135
126
|
},
|
|
136
127
|
context.execJs);
|
|
137
128
|
|
|
@@ -9,7 +9,14 @@ import type {ComputedStyleAiWidget, FunctionCallHandlerResult, FunctionHandlerOp
|
|
|
9
9
|
import {DOMNodeContext} from '../contexts/DOMNodeContext.js';
|
|
10
10
|
import {debugLog} from '../debug.js';
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
type BaseToolCapability,
|
|
14
|
+
type OriginLockCapability,
|
|
15
|
+
type TargetCapability,
|
|
16
|
+
type Tool,
|
|
17
|
+
type ToolArgs,
|
|
18
|
+
ToolName,
|
|
19
|
+
} from './Tool.js';
|
|
13
20
|
|
|
14
21
|
export interface GetStylesArgs extends ToolArgs {
|
|
15
22
|
elements: number[];
|
|
@@ -17,7 +24,8 @@ export interface GetStylesArgs extends ToolArgs {
|
|
|
17
24
|
explanation: string;
|
|
18
25
|
}
|
|
19
26
|
|
|
20
|
-
export class GetStylesTool implements
|
|
27
|
+
export class GetStylesTool implements
|
|
28
|
+
Tool<GetStylesArgs, unknown, BaseToolCapability&TargetCapability&OriginLockCapability> {
|
|
21
29
|
readonly name = ToolName.GET_STYLES;
|
|
22
30
|
readonly description =
|
|
23
31
|
`Get computed and source styles for one or multiple elements on the inspected page for multiple elements at once by uid.
|
|
@@ -71,34 +79,33 @@ export class GetStylesTool implements Tool<GetStylesArgs, unknown> {
|
|
|
71
79
|
|
|
72
80
|
async handler(
|
|
73
81
|
params: GetStylesArgs,
|
|
74
|
-
context:
|
|
82
|
+
context: BaseToolCapability&TargetCapability&OriginLockCapability,
|
|
75
83
|
_options?: FunctionHandlerOptions,
|
|
76
84
|
): Promise<FunctionCallHandlerResult<unknown>> {
|
|
77
85
|
const widgets: ComputedStyleAiWidget[] = [];
|
|
78
86
|
const result:
|
|
79
87
|
Record<string, {computed: Record<string, string|undefined>, authored: Record<string, string|undefined>}> = {};
|
|
80
88
|
|
|
81
|
-
const
|
|
82
|
-
if (!
|
|
83
|
-
return {error: 'Error: Could not find the
|
|
89
|
+
const target = context.getTarget();
|
|
90
|
+
if (!target) {
|
|
91
|
+
return {error: 'Error: Could not find the inspected page.'};
|
|
84
92
|
}
|
|
85
93
|
|
|
86
|
-
const
|
|
87
|
-
if (!
|
|
88
|
-
return {error: 'Error:
|
|
94
|
+
const establishedOrigin = context.getEstablishedOrigin();
|
|
95
|
+
if (!establishedOrigin) {
|
|
96
|
+
return {error: 'Error: Origin lock is not established.'};
|
|
89
97
|
}
|
|
90
98
|
|
|
91
99
|
for (const uid of params.elements) {
|
|
92
100
|
result[uid] = {computed: {}, authored: {}};
|
|
93
101
|
debugLog(`Action to execute: uid=${uid}`);
|
|
94
|
-
const node =
|
|
95
|
-
new SDK.DOMModel.DeferredDOMNode(selectedNode.domModel().target(), uid as Protocol.DOM.BackendNodeId);
|
|
102
|
+
const node = new SDK.DOMModel.DeferredDOMNode(target, uid as Protocol.DOM.BackendNodeId);
|
|
96
103
|
const resolved = await node.resolvePromise();
|
|
97
104
|
if (!resolved) {
|
|
98
105
|
return {error: 'Error: Could not find the element with uid=' + uid};
|
|
99
106
|
}
|
|
100
107
|
const newContext = new DOMNodeContext(resolved);
|
|
101
|
-
if (
|
|
108
|
+
if (establishedOrigin !== newContext.getOrigin()) {
|
|
102
109
|
return {error: 'Error: Node does not belong to the current origin.'};
|
|
103
110
|
}
|
|
104
111
|
const styles = await resolved.domModel().cssModel().getComputedStyle(resolved.id);
|