chrome-devtools-frontend 1.0.1642899 → 1.0.1643099
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/front_end/core/protocol_client/InspectorBackend.ts +4 -0
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +4 -5
- package/front_end/generated/InspectorBackendCommands.ts +1 -1
- package/front_end/generated/protocol.ts +7 -0
- package/front_end/models/ai_assistance/AiAgent2.ts +23 -5
- package/front_end/models/ai_assistance/AiConversation.ts +15 -12
- package/front_end/models/ai_assistance/AiUtils.ts +71 -0
- package/front_end/models/ai_assistance/ChangeManager.ts +2 -5
- package/front_end/models/ai_assistance/{agents/ConversationSummaryAgent.ts → ConversationSummary.ts} +29 -66
- package/front_end/models/ai_assistance/ExtensionScope.ts +1 -4
- package/front_end/models/ai_assistance/{agents/PerformanceAnnotationsAgent.ts → PerformanceAnnotations.ts} +47 -89
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +31 -21
- package/front_end/models/ai_assistance/agents/AiAgent.ts +21 -6
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +11 -0
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +53 -3
- package/front_end/models/ai_assistance/agents/ExecuteJavascript.ts +2 -0
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +72 -79
- package/front_end/models/ai_assistance/agents/StorageAgent.ts +47 -38
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +22 -21
- package/front_end/models/ai_assistance/ai_assistance.ts +6 -4
- package/front_end/models/ai_assistance/skills/styling.md +12 -4
- package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +140 -0
- package/front_end/models/ai_assistance/tools/GetStyles.ts +6 -2
- package/front_end/models/ai_assistance/tools/Tool.ts +10 -1
- package/front_end/models/ai_assistance/tools/ToolRegistry.ts +2 -0
- package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +5 -7
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +6 -7
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +96 -4
- package/front_end/panels/ai_assistance/components/chatMessage.css +6 -0
- package/front_end/panels/application/components/AdsView.ts +219 -0
- package/front_end/panels/application/components/adsView.css +54 -0
- package/front_end/panels/application/components/components.ts +2 -0
- package/front_end/panels/console/SymbolizedErrorWidget.ts +73 -22
- package/front_end/panels/network/NetworkLogView.ts +5 -1
- package/front_end/panels/timeline/overlays/components/EntryLabelOverlay.ts +5 -4
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/lighthouse/README.chromium +2 -2
- package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +1607 -5733
- package/front_end/third_party/lighthouse/locales/ar-XB.json +290 -65
- package/front_end/third_party/lighthouse/locales/ar.json +290 -65
- package/front_end/third_party/lighthouse/locales/bg.json +290 -65
- package/front_end/third_party/lighthouse/locales/ca.json +295 -70
- package/front_end/third_party/lighthouse/locales/cs.json +290 -65
- package/front_end/third_party/lighthouse/locales/da.json +294 -69
- package/front_end/third_party/lighthouse/locales/de.json +295 -70
- package/front_end/third_party/lighthouse/locales/el.json +290 -65
- package/front_end/third_party/lighthouse/locales/en-GB.json +290 -65
- package/front_end/third_party/lighthouse/locales/en-US.json +79 -67
- package/front_end/third_party/lighthouse/locales/en-XA.json +253 -64
- package/front_end/third_party/lighthouse/locales/en-XL.json +79 -67
- package/front_end/third_party/lighthouse/locales/es-419.json +290 -65
- package/front_end/third_party/lighthouse/locales/es.json +298 -73
- package/front_end/third_party/lighthouse/locales/fi.json +290 -65
- package/front_end/third_party/lighthouse/locales/fil.json +290 -65
- package/front_end/third_party/lighthouse/locales/fr.json +294 -69
- package/front_end/third_party/lighthouse/locales/he.json +293 -68
- package/front_end/third_party/lighthouse/locales/hi.json +291 -66
- package/front_end/third_party/lighthouse/locales/hr.json +290 -65
- package/front_end/third_party/lighthouse/locales/hu.json +290 -65
- package/front_end/third_party/lighthouse/locales/id.json +290 -65
- package/front_end/third_party/lighthouse/locales/it.json +294 -69
- package/front_end/third_party/lighthouse/locales/ja.json +290 -65
- package/front_end/third_party/lighthouse/locales/ko.json +290 -65
- package/front_end/third_party/lighthouse/locales/lt.json +290 -65
- package/front_end/third_party/lighthouse/locales/lv.json +290 -65
- package/front_end/third_party/lighthouse/locales/nl.json +290 -65
- package/front_end/third_party/lighthouse/locales/no.json +290 -65
- package/front_end/third_party/lighthouse/locales/pl.json +290 -65
- package/front_end/third_party/lighthouse/locales/pt-PT.json +291 -66
- package/front_end/third_party/lighthouse/locales/pt.json +290 -65
- package/front_end/third_party/lighthouse/locales/ro.json +290 -65
- package/front_end/third_party/lighthouse/locales/ru.json +301 -76
- package/front_end/third_party/lighthouse/locales/sk.json +291 -66
- package/front_end/third_party/lighthouse/locales/sl.json +290 -65
- package/front_end/third_party/lighthouse/locales/sr-Latn.json +290 -65
- package/front_end/third_party/lighthouse/locales/sr.json +290 -65
- package/front_end/third_party/lighthouse/locales/sv.json +297 -72
- package/front_end/third_party/lighthouse/locales/ta.json +291 -66
- package/front_end/third_party/lighthouse/locales/te.json +293 -68
- package/front_end/third_party/lighthouse/locales/th.json +291 -66
- package/front_end/third_party/lighthouse/locales/tr.json +290 -65
- package/front_end/third_party/lighthouse/locales/uk.json +290 -65
- package/front_end/third_party/lighthouse/locales/vi.json +291 -66
- package/front_end/third_party/lighthouse/locales/zh-HK.json +292 -67
- package/front_end/third_party/lighthouse/locales/zh-TW.json +291 -66
- package/front_end/third_party/lighthouse/locales/zh.json +291 -66
- package/front_end/third_party/lighthouse/report/bundle.d.ts +6 -6
- package/front_end/third_party/lighthouse/report/bundle.js +4 -7
- package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +2 -2
- package/front_end/ui/legacy/Widget.ts +32 -8
- package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
- package/mcp/mcp.ts +1 -0
- package/package.json +1 -1
|
@@ -27,10 +27,8 @@ import {
|
|
|
27
27
|
} from './AiAgent.js';
|
|
28
28
|
import {
|
|
29
29
|
type CreateExtensionScopeFunction,
|
|
30
|
-
executeJavaScriptFunction,
|
|
31
30
|
type ExecuteJsAgentOptions,
|
|
32
31
|
executeJsCode,
|
|
33
|
-
JavascriptExecutor
|
|
34
32
|
} from './ExecuteJavascript.js';
|
|
35
33
|
|
|
36
34
|
const preamble = `You are the most advanced CSS/DOM/HTML debugging assistant integrated into Chrome DevTools.
|
|
@@ -169,32 +167,21 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
|
|
|
169
167
|
}
|
|
170
168
|
|
|
171
169
|
#execJs: typeof executeJsCode;
|
|
172
|
-
#javascriptExecutor: JavascriptExecutor;
|
|
173
170
|
|
|
174
171
|
#changes: ChangeManager;
|
|
175
172
|
#createExtensionScope: CreateExtensionScopeFunction;
|
|
176
173
|
#greenDevEmulationScreenshot: string|null = null;
|
|
177
174
|
#greenDevEmulationAxTree: string|null = null;
|
|
178
175
|
#hasAddedEmulationInstructions = false;
|
|
179
|
-
#currentTurnId = 0;
|
|
180
176
|
|
|
181
177
|
constructor(opts: ExecuteJsAgentOptions) {
|
|
182
178
|
super(opts);
|
|
183
179
|
|
|
184
180
|
this.#changes = opts.changeManager || new ChangeManager();
|
|
185
181
|
this.#execJs = opts.execJs ?? executeJsCode;
|
|
186
|
-
this.#createExtensionScope =
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
});
|
|
190
|
-
this.#javascriptExecutor = new JavascriptExecutor(
|
|
191
|
-
{
|
|
192
|
-
executionMode: this.executionMode,
|
|
193
|
-
getContextNode: () => this.#getSelectedNode(),
|
|
194
|
-
createExtensionScope: this.#createExtensionScope.bind(this),
|
|
195
|
-
changes: this.#changes,
|
|
196
|
-
},
|
|
197
|
-
this.#execJs);
|
|
182
|
+
this.#createExtensionScope = opts.createExtensionScope ?? ((changes: ChangeManager) => {
|
|
183
|
+
return new ExtensionScope(changes, this.sessionId, this.context?.getItem() ?? null);
|
|
184
|
+
});
|
|
198
185
|
|
|
199
186
|
const getStylesTool = ToolRegistry.get(ToolName.GET_STYLES);
|
|
200
187
|
if (!getStylesTool) {
|
|
@@ -209,7 +196,25 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
|
|
|
209
196
|
}),
|
|
210
197
|
});
|
|
211
198
|
|
|
212
|
-
|
|
199
|
+
const executeJsTool = ToolRegistry.get(ToolName.EXECUTE_JAVASCRIPT);
|
|
200
|
+
if (!executeJsTool) {
|
|
201
|
+
throw new Error('Required tool "executeJavaScript" not found');
|
|
202
|
+
}
|
|
203
|
+
this.declareFunction(ToolName.EXECUTE_JAVASCRIPT, {
|
|
204
|
+
description: executeJsTool.description,
|
|
205
|
+
parameters: executeJsTool.parameters,
|
|
206
|
+
displayInfoFromArgs: executeJsTool.displayInfoFromArgs,
|
|
207
|
+
handler: (args, options) => executeJsTool.handler(
|
|
208
|
+
args,
|
|
209
|
+
{
|
|
210
|
+
conversationContext: this.context ?? null,
|
|
211
|
+
changeManager: this.#changes,
|
|
212
|
+
createExtensionScope: this.#createExtensionScope.bind(this),
|
|
213
|
+
execJs: this.#execJs,
|
|
214
|
+
},
|
|
215
|
+
options,
|
|
216
|
+
),
|
|
217
|
+
});
|
|
213
218
|
|
|
214
219
|
if (Annotations.AnnotationRepository.annotationsEnabled()) {
|
|
215
220
|
this.declareFunction<{
|
|
@@ -515,10 +520,6 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
|
|
|
515
520
|
}
|
|
516
521
|
}
|
|
517
522
|
|
|
518
|
-
protected override async preRun(): Promise<void> {
|
|
519
|
-
this.#currentTurnId++;
|
|
520
|
-
}
|
|
521
|
-
|
|
522
523
|
override async enhanceQuery(
|
|
523
524
|
query: string, selectedElement: ConversationContext<SDK.DOMModel.DOMNode>|null,
|
|
524
525
|
multimodalInputType?: MultimodalInputType): Promise<string> {
|
|
@@ -6,7 +6,6 @@ import * as AgentProject from './AgentProject.js';
|
|
|
6
6
|
import * as AccessibilityAgent from './agents/AccessibilityAgent.js';
|
|
7
7
|
import * as AiAgent from './agents/AiAgent.js';
|
|
8
8
|
import * as ContextSelectionAgent from './agents/ContextSelectionAgent.js';
|
|
9
|
-
import * as ConversationSummaryAgent from './agents/ConversationSummaryAgent.js';
|
|
10
9
|
import * as FileAgent from './agents/FileAgent.js';
|
|
11
10
|
import * as GreenDevAgent from './agents/GreenDevAgent.js';
|
|
12
11
|
import * as GreenDevAgentAntigravityCliSocketClient from './agents/GreenDevAgentAntigravityCliSocketClient.js';
|
|
@@ -14,7 +13,6 @@ import * as GreenDevAgentGeminiCliSocketClient from './agents/GreenDevAgentGemin
|
|
|
14
13
|
import * as NetworkAgent from './agents/NetworkAgent.js';
|
|
15
14
|
import * as PatchAgent from './agents/PatchAgent.js';
|
|
16
15
|
import * as PerformanceAgent from './agents/PerformanceAgent.js';
|
|
17
|
-
import * as PerformanceAnnotationsAgent from './agents/PerformanceAnnotationsAgent.js';
|
|
18
16
|
import * as StorageAgent from './agents/StorageAgent.js';
|
|
19
17
|
import * as StylingAgent from './agents/StylingAgent.js';
|
|
20
18
|
import * as AiAgent2 from './AiAgent2.js';
|
|
@@ -25,6 +23,7 @@ import * as AiUtils from './AiUtils.js';
|
|
|
25
23
|
import * as BuiltInAi from './BuiltInAi.js';
|
|
26
24
|
import * as ChangeManager from './ChangeManager.js';
|
|
27
25
|
import * as DOMNodeContext from './contexts/DOMNodeContext.js';
|
|
26
|
+
import * as ConversationSummary from './ConversationSummary.js';
|
|
28
27
|
import * as FileFormatter from './data_formatters/FileFormatter.js';
|
|
29
28
|
import * as LighthouseFormatter from './data_formatters/LighthouseFormatter.js';
|
|
30
29
|
import * as NetworkRequestFormatter from './data_formatters/NetworkRequestFormatter.js';
|
|
@@ -38,7 +37,9 @@ import * as Injected from './injected.js';
|
|
|
38
37
|
import * as AICallTree from './performance/AICallTree.js';
|
|
39
38
|
import * as AIContext from './performance/AIContext.js';
|
|
40
39
|
import * as AIQueries from './performance/AIQueries.js';
|
|
40
|
+
import * as PerformanceAnnotations from './PerformanceAnnotations.js';
|
|
41
41
|
import * as StorageItem from './StorageItem.js';
|
|
42
|
+
import * as ExecuteJavaScript from './tools/ExecuteJavaScript.js';
|
|
42
43
|
import * as GetStyles from './tools/GetStyles.js';
|
|
43
44
|
import * as Tool from './tools/Tool.js';
|
|
44
45
|
import * as ToolRegistry from './tools/ToolRegistry.js';
|
|
@@ -58,10 +59,11 @@ export {
|
|
|
58
59
|
BuiltInAi,
|
|
59
60
|
ChangeManager,
|
|
60
61
|
ContextSelectionAgent,
|
|
61
|
-
|
|
62
|
+
ConversationSummary,
|
|
62
63
|
Debug,
|
|
63
64
|
DOMNodeContext,
|
|
64
65
|
EvaluateAction,
|
|
66
|
+
ExecuteJavaScript,
|
|
65
67
|
ExtensionScope,
|
|
66
68
|
FileAgent,
|
|
67
69
|
FileFormatter,
|
|
@@ -75,7 +77,7 @@ export {
|
|
|
75
77
|
NetworkRequestFormatter,
|
|
76
78
|
PatchAgent,
|
|
77
79
|
PerformanceAgent,
|
|
78
|
-
|
|
80
|
+
PerformanceAnnotations,
|
|
79
81
|
PerformanceInsightFormatter,
|
|
80
82
|
PerformanceTraceFormatter,
|
|
81
83
|
StorageAgent,
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
name: styling
|
|
3
3
|
description: Helping with CSS and styling
|
|
4
4
|
allowed-tools:
|
|
5
|
+
- executeJavaScript
|
|
5
6
|
- getStyles
|
|
6
7
|
---
|
|
7
|
-
You are
|
|
8
|
+
You are the most advanced CSS/DOM/HTML debugging assistant integrated into Chrome DevTools.
|
|
8
9
|
You always suggest considering the best web development practices and the newest platform features such as view transitions.
|
|
9
10
|
The user selected a DOM element in the browser's DevTools and sends a query about the page or the selected DOM element.
|
|
10
|
-
First, examine the provided context, then use the getStyles
|
|
11
|
+
First, examine the provided context, then use the getStyles and executeJavaScript functions to gather additional context and resolve the user request.
|
|
11
12
|
|
|
12
13
|
# Considerations
|
|
13
14
|
|
|
@@ -19,10 +20,17 @@ First, examine the provided context, then use the getStyles function to gather a
|
|
|
19
20
|
* Please answer only if you are sure about the answer. Otherwise, explain why you're not able to answer.
|
|
20
21
|
* When answering, always consider MULTIPLE possible solutions.
|
|
21
22
|
* When answering, remember to consider CSS concepts such as the CSS cascade, explicit and implicit stacking contexts and various CSS layout types.
|
|
22
|
-
* Use the
|
|
23
|
-
*
|
|
23
|
+
* Use the functions available to you to investigate and fulfill the user request.
|
|
24
|
+
* After applying a fix, please ask the user to confirm if the fix worked or not.
|
|
25
|
+
* ALWAYS OUTPUT a list of follow-up queries at the end of your text response. The format is SUGGESTIONS: ["suggestion1", "suggestion2", "suggestion3"]. Make sure that the array and the `SUGGESTIONS: ` text is in the same line. You're also capable of executing the fix for the issue user mentioned. Reflect this in your suggestions.
|
|
24
26
|
* Use the precision of Strunk & White, the brevity of Hemingway, and the simple clarity of Vonnegut. Don't add repeated information, and keep the whole answer short.
|
|
27
|
+
* **CRITICAL** NEVER output text before a function call. Always do a function call first.
|
|
25
28
|
* **CRITICAL** When answering questions about positioning or layout, ALWAYS inspect `position`, `display` and all other related properties. You MUST provide a specific list of CSS property names when calling getStyles. Do not use generic values like "all" or "*".
|
|
29
|
+
* **CRITICAL** When writing JavaScript via the `executeJavaScript` tool:
|
|
30
|
+
- To return data, define a top-level `data` variable and populate it with a JSON-serializable object.
|
|
31
|
+
- 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 and should never be presented to the user.
|
|
32
|
+
- Never assume a selector for the elements unless you verified your knowledge.
|
|
33
|
+
- Consider that `data` variables from previous function calls are not available in a new function call.
|
|
26
34
|
* **CRITICAL** You are a CSS/DOM/HTML debugging assistant. NEVER provide answers to questions of unrelated topics such as legal advice, financial advice, personal opinions, medical advice, religion, race, politics, sexuality, gender, or any other non web-development topics. Answer "Sorry, I can't answer that. I'm best at questions about debugging web pages." to such questions.
|
|
27
35
|
|
|
28
36
|
## Response Structure
|
|
@@ -0,0 +1,140 @@
|
|
|
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 Root from '../../../core/root/root.js';
|
|
7
|
+
import type {FunctionCallHandlerResult, FunctionHandlerOptions,} from '../agents/AiAgent.js';
|
|
8
|
+
import {JavascriptExecutor} from '../agents/ExecuteJavascript.js';
|
|
9
|
+
import {DOMNodeContext} from '../contexts/DOMNodeContext.js';
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
type Tool,
|
|
13
|
+
type ToolArgs,
|
|
14
|
+
type ToolContext,
|
|
15
|
+
ToolName,
|
|
16
|
+
} from './Tool.js';
|
|
17
|
+
|
|
18
|
+
export interface ExecuteJavaScriptArgs extends ToolArgs {
|
|
19
|
+
code: string;
|
|
20
|
+
explanation: string;
|
|
21
|
+
title: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class ExecuteJavaScriptTool implements Tool<ExecuteJavaScriptArgs, unknown> {
|
|
25
|
+
readonly name = ToolName.EXECUTE_JAVASCRIPT;
|
|
26
|
+
|
|
27
|
+
readonly description =
|
|
28
|
+
'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.';
|
|
29
|
+
|
|
30
|
+
readonly parameters: Host.AidaClient.FunctionObjectParam<keyof ExecuteJavaScriptArgs> = {
|
|
31
|
+
type: Host.AidaClient.ParametersTypes.OBJECT,
|
|
32
|
+
description: '',
|
|
33
|
+
nullable: false,
|
|
34
|
+
properties: {
|
|
35
|
+
code: {
|
|
36
|
+
type: Host.AidaClient.ParametersTypes.STRING,
|
|
37
|
+
description:
|
|
38
|
+
`JavaScript code snippet to run on the inspected page. Make sure the code is formatted for readability.
|
|
39
|
+
|
|
40
|
+
# Instructions
|
|
41
|
+
|
|
42
|
+
* 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\`.
|
|
43
|
+
* 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.
|
|
44
|
+
* **CRITICAL** Only get styles that might be relevant to the user request.
|
|
45
|
+
* **CRITICAL** Never assume a selector for the elements unless you verified your knowledge.
|
|
46
|
+
* **CRITICAL** Consider that \`data\` variable from the previous function calls are not available in a new function call.
|
|
47
|
+
|
|
48
|
+
For example, the code to change element styles:
|
|
49
|
+
|
|
50
|
+
\`\`\`
|
|
51
|
+
await setElementStyles($0, {
|
|
52
|
+
color: 'blue',
|
|
53
|
+
});
|
|
54
|
+
\`\`\`
|
|
55
|
+
|
|
56
|
+
For example, the code to get overlapping elements:
|
|
57
|
+
|
|
58
|
+
\`\`\`
|
|
59
|
+
const data = {
|
|
60
|
+
overlappingElements: Array.from(document.querySelectorAll('*'))
|
|
61
|
+
.filter(el => {
|
|
62
|
+
const rect = el.getBoundingClientRect();
|
|
63
|
+
const popupRect = $0.getBoundingClientRect();
|
|
64
|
+
return (
|
|
65
|
+
el !== $0 &&
|
|
66
|
+
rect.left < popupRect.right &&
|
|
67
|
+
rect.right > popupRect.left &&
|
|
68
|
+
rect.top < popupRect.bottom &&
|
|
69
|
+
rect.bottom > popupRect.top
|
|
70
|
+
);
|
|
71
|
+
})
|
|
72
|
+
.map(el => ({
|
|
73
|
+
tagName: el.tagName,
|
|
74
|
+
id: el.id,
|
|
75
|
+
className: el.className,
|
|
76
|
+
zIndex: window.getComputedStyle(el)['z-index']
|
|
77
|
+
}))
|
|
78
|
+
};
|
|
79
|
+
\`\`\`
|
|
80
|
+
`,
|
|
81
|
+
},
|
|
82
|
+
explanation: {
|
|
83
|
+
type: Host.AidaClient.ParametersTypes.STRING,
|
|
84
|
+
description: 'Explain why you want to run this code',
|
|
85
|
+
},
|
|
86
|
+
title: {
|
|
87
|
+
type: Host.AidaClient.ParametersTypes.STRING,
|
|
88
|
+
description: 'Provide a summary of what the code does. For example, "Checking related element styles".',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
required: ['code', 'explanation', 'title'],
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
displayInfoFromArgs(params: ExecuteJavaScriptArgs): {
|
|
95
|
+
title: string,
|
|
96
|
+
thought: string,
|
|
97
|
+
action: string,
|
|
98
|
+
} {
|
|
99
|
+
return {
|
|
100
|
+
title: params.title,
|
|
101
|
+
thought: params.explanation,
|
|
102
|
+
action: params.code,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async handler(
|
|
107
|
+
params: ExecuteJavaScriptArgs,
|
|
108
|
+
context: ToolContext,
|
|
109
|
+
options?: FunctionHandlerOptions,
|
|
110
|
+
): Promise<FunctionCallHandlerResult<unknown>> {
|
|
111
|
+
const activeContext = context.conversationContext;
|
|
112
|
+
if (!activeContext || !(activeContext instanceof DOMNodeContext)) {
|
|
113
|
+
return {error: 'Error: Could not find the currently selected element.'};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const selectedNode = activeContext.getItem();
|
|
117
|
+
if (!selectedNode) {
|
|
118
|
+
return {error: 'Error: Could not find the currently selected element.'};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const executionMode = Root.Runtime.hostConfig.devToolsFreestyler?.executionMode ??
|
|
122
|
+
Root.Runtime.HostConfigFreestylerExecutionMode.ALL_SCRIPTS;
|
|
123
|
+
|
|
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
|
+
const executor = new JavascriptExecutor({
|
|
131
|
+
executionMode,
|
|
132
|
+
getContextNode: () => selectedNode,
|
|
133
|
+
createExtensionScope,
|
|
134
|
+
changes,
|
|
135
|
+
},
|
|
136
|
+
context.execJs);
|
|
137
|
+
|
|
138
|
+
return await executor.executeAction(params.code, options);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as Host from '../../../core/host/host.js';
|
|
6
6
|
import * as SDK from '../../../core/sdk/sdk.js';
|
|
7
7
|
import type * as Protocol from '../../../generated/protocol.js';
|
|
8
|
-
import type {ComputedStyleAiWidget, FunctionCallHandlerResult} from '../agents/AiAgent.js';
|
|
8
|
+
import type {ComputedStyleAiWidget, FunctionCallHandlerResult, FunctionHandlerOptions} from '../agents/AiAgent.js';
|
|
9
9
|
import {DOMNodeContext} from '../contexts/DOMNodeContext.js';
|
|
10
10
|
import {debugLog} from '../debug.js';
|
|
11
11
|
|
|
@@ -69,7 +69,11 @@ export class GetStylesTool implements Tool<GetStylesArgs, unknown> {
|
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
async handler(
|
|
72
|
+
async handler(
|
|
73
|
+
params: GetStylesArgs,
|
|
74
|
+
context: ToolContext,
|
|
75
|
+
_options?: FunctionHandlerOptions,
|
|
76
|
+
): Promise<FunctionCallHandlerResult<unknown>> {
|
|
73
77
|
const widgets: ComputedStyleAiWidget[] = [];
|
|
74
78
|
const result:
|
|
75
79
|
Record<string, {computed: Record<string, string|undefined>, authored: Record<string, string|undefined>}> = {};
|
|
@@ -3,13 +3,20 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
5
|
import type * as Host from '../../../core/host/host.js';
|
|
6
|
-
import type {ConversationContext, FunctionCallHandlerResult,} from '../agents/AiAgent.js';
|
|
6
|
+
import type {ConversationContext, FunctionCallHandlerResult, FunctionHandlerOptions} from '../agents/AiAgent.js';
|
|
7
|
+
import type {executeJsCode} from '../agents/ExecuteJavascript.js';
|
|
8
|
+
import type {ChangeManager} from '../ChangeManager.js';
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Context provided to the tool's handler execution.
|
|
10
12
|
*/
|
|
11
13
|
export interface ToolContext {
|
|
12
14
|
conversationContext: ConversationContext<unknown>|null;
|
|
15
|
+
changeManager?: ChangeManager;
|
|
16
|
+
createExtensionScope?: (changes: ChangeManager) => {
|
|
17
|
+
install(): Promise<void>, uninstall(): Promise<void>,
|
|
18
|
+
};
|
|
19
|
+
execJs?: typeof executeJsCode;
|
|
13
20
|
}
|
|
14
21
|
|
|
15
22
|
/**
|
|
@@ -18,6 +25,7 @@ export interface ToolContext {
|
|
|
18
25
|
export type ToolArgs = Record<string, unknown>;
|
|
19
26
|
|
|
20
27
|
export const enum ToolName {
|
|
28
|
+
EXECUTE_JAVASCRIPT = 'executeJavaScript',
|
|
21
29
|
GET_STYLES = 'getStyles',
|
|
22
30
|
}
|
|
23
31
|
|
|
@@ -51,5 +59,6 @@ export interface Tool<Args extends ToolArgs = ToolArgs, ReturnType = unknown, >
|
|
|
51
59
|
handler(
|
|
52
60
|
args: Args,
|
|
53
61
|
context: ToolContext,
|
|
62
|
+
options?: FunctionHandlerOptions,
|
|
54
63
|
): Promise<FunctionCallHandlerResult<ReturnType>>;
|
|
55
64
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
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 {ExecuteJavaScriptTool} from './ExecuteJavaScript.js';
|
|
5
6
|
import {GetStylesTool} from './GetStyles.js';
|
|
6
7
|
import {type Tool, ToolName} from './Tool.js';
|
|
7
8
|
|
|
@@ -10,6 +11,7 @@ import {type Tool, ToolName} from './Tool.js';
|
|
|
10
11
|
* Keep this type concrete (no type-erasure) to preserve exact tool types.
|
|
11
12
|
*/
|
|
12
13
|
export const TOOLS = {
|
|
14
|
+
[ToolName.EXECUTE_JAVASCRIPT]: new ExecuteJavaScriptTool(),
|
|
13
15
|
[ToolName.GET_STYLES]: new GetStylesTool(),
|
|
14
16
|
};
|
|
15
17
|
|
|
@@ -244,8 +244,6 @@ export class HeapSnapshotLoaderProxy extends HeapSnapshotProxyObject implements
|
|
|
244
244
|
const snapshotProxy = await this.callFactoryMethodPromise('buildSnapshot', HeapSnapshotProxy, [channel.port1]);
|
|
245
245
|
secondWorker.dispose();
|
|
246
246
|
this.dispose();
|
|
247
|
-
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
|
|
248
|
-
// @ts-expect-error
|
|
249
247
|
snapshotProxy.setProfileUid(this.profileUid);
|
|
250
248
|
await snapshotProxy.updateStaticData();
|
|
251
249
|
this.snapshotReceivedCallback(snapshotProxy);
|
|
@@ -254,7 +252,7 @@ export class HeapSnapshotLoaderProxy extends HeapSnapshotProxyObject implements
|
|
|
254
252
|
|
|
255
253
|
export class HeapSnapshotProxy extends HeapSnapshotProxyObject {
|
|
256
254
|
staticData: HeapSnapshotModel.StaticData|null;
|
|
257
|
-
profileUid?:
|
|
255
|
+
profileUid?: number;
|
|
258
256
|
|
|
259
257
|
constructor(worker: HeapSnapshotWorkerProxy, objectId: number) {
|
|
260
258
|
super(worker, objectId);
|
|
@@ -279,7 +277,7 @@ export class HeapSnapshotProxy extends HeapSnapshotProxyObject {
|
|
|
279
277
|
}
|
|
280
278
|
|
|
281
279
|
calculateSnapshotDiff(
|
|
282
|
-
baseSnapshotId:
|
|
280
|
+
baseSnapshotId: number,
|
|
283
281
|
baseSnapshotAggregates: Record<string, HeapSnapshotModel.AggregateForDiff>,
|
|
284
282
|
): Promise<Record<string, HeapSnapshotModel.Diff>> {
|
|
285
283
|
return this.callMethodPromise('calculateSnapshotDiff', baseSnapshotId, baseSnapshotAggregates);
|
|
@@ -301,7 +299,7 @@ export class HeapSnapshotProxy extends HeapSnapshotProxyObject {
|
|
|
301
299
|
return this.callFactoryMethod('createRetainingEdgesProvider', HeapSnapshotProviderProxy, nodeIndex);
|
|
302
300
|
}
|
|
303
301
|
|
|
304
|
-
createAddedNodesProvider(baseSnapshotId:
|
|
302
|
+
createAddedNodesProvider(baseSnapshotId: number, classKey: string): HeapSnapshotProviderProxy {
|
|
305
303
|
return this.callFactoryMethod('createAddedNodesProvider', HeapSnapshotProviderProxy, baseSnapshotId, classKey);
|
|
306
304
|
}
|
|
307
305
|
|
|
@@ -391,11 +389,11 @@ export class HeapSnapshotProxy extends HeapSnapshotProxyObject {
|
|
|
391
389
|
return this.staticData.totalSize;
|
|
392
390
|
}
|
|
393
391
|
|
|
394
|
-
get uid():
|
|
392
|
+
get uid(): number|undefined {
|
|
395
393
|
return this.profileUid;
|
|
396
394
|
}
|
|
397
395
|
|
|
398
|
-
setProfileUid(profileUid:
|
|
396
|
+
setProfileUid(profileUid: number): void {
|
|
399
397
|
this.profileUid = profileUid;
|
|
400
398
|
}
|
|
401
399
|
|
|
@@ -657,7 +657,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
657
657
|
// NodeJS debugging does not have Elements panel, thus this action might not exist.
|
|
658
658
|
#toggleSearchElementAction?: UI.ActionRegistration.Action;
|
|
659
659
|
#aidaClient: Host.AidaClient.AidaClient;
|
|
660
|
-
#
|
|
660
|
+
#conversationSummary?: AiAssistanceModel.ConversationSummary.ConversationSummary;
|
|
661
661
|
#viewOutput: PanelViewOutput = {};
|
|
662
662
|
#serverSideLoggingEnabled = isAiAssistanceServerSideLoggingEnabled();
|
|
663
663
|
#aiAssistanceEnabledSetting: Common.Settings.Setting<boolean>|undefined;
|
|
@@ -784,17 +784,16 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
784
784
|
markdownRenderer,
|
|
785
785
|
conversationMarkdown: this.#conversation.getConversationMarkdown(),
|
|
786
786
|
generateConversationSummary: async (markdown: string) => {
|
|
787
|
-
if (!this.#
|
|
788
|
-
this.#
|
|
787
|
+
if (!this.#conversationSummary) {
|
|
788
|
+
this.#conversationSummary = new AiAssistanceModel.ConversationSummary.ConversationSummary({
|
|
789
789
|
aidaClient: this.#aidaClient,
|
|
790
790
|
serverSideLoggingEnabled: this.#serverSideLoggingEnabled,
|
|
791
791
|
});
|
|
792
792
|
}
|
|
793
|
-
return await this.#
|
|
793
|
+
return await this.#conversationSummary.summarizeConversation(markdown);
|
|
794
794
|
},
|
|
795
|
-
onTextSubmit: async (
|
|
796
|
-
|
|
797
|
-
multimodalInputType?: AiAssistanceModel.AiAgent.MultimodalInputType) => {
|
|
795
|
+
onTextSubmit: async (text: string, imageInput?: Host.AidaClient.Part,
|
|
796
|
+
multimodalInputType?: AiAssistanceModel.AiAgent.MultimodalInputType) => {
|
|
798
797
|
const submit = (): void => {
|
|
799
798
|
Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiAssistanceQuerySubmitted);
|
|
800
799
|
void this.#startConversation(text, imageInput, multimodalInputType);
|
|
@@ -14,9 +14,9 @@ import * as SDK from '../../../core/sdk/sdk.js';
|
|
|
14
14
|
import type * as Protocol from '../../../generated/protocol.js';
|
|
15
15
|
import type {
|
|
16
16
|
AiWidget, BottomUpTreeAiWidget, ComputedStyleAiWidget, CoreVitalsAiWidget, DomTreeAiWidget, LighthouseReportAiWidget,
|
|
17
|
-
NetworkRequestGeneralHeadersAiWidget, PerfInsightAiWidget, PerformanceTraceAiWidget,
|
|
18
|
-
SourceFileAiWidget, SourceFilesListAiWidget, StylePropertiesAiWidget,
|
|
19
|
-
TimelineRangeSummaryAiWidget} from '../../../models/ai_assistance/agents/AiAgent.js';
|
|
17
|
+
NetworkRequestGeneralHeadersAiWidget, NetworkRequestsListAiWidget, PerfInsightAiWidget, PerformanceTraceAiWidget,
|
|
18
|
+
SourceCodeAiWidget, SourceFileAiWidget, SourceFilesListAiWidget, StylePropertiesAiWidget,
|
|
19
|
+
TimelineEventSummaryAiWidget, TimelineRangeSummaryAiWidget} from '../../../models/ai_assistance/agents/AiAgent.js';
|
|
20
20
|
import * as AiAssistanceModel from '../../../models/ai_assistance/ai_assistance.js';
|
|
21
21
|
import * as ComputedStyle from '../../../models/computed_style/computed_style.js';
|
|
22
22
|
import * as Formatter from '../../../models/formatter/formatter.js';
|
|
@@ -30,6 +30,7 @@ import * as Buttons from '../../../ui/components/buttons/buttons.js';
|
|
|
30
30
|
import * as Input from '../../../ui/components/input/input.js';
|
|
31
31
|
import type * as MarkdownView from '../../../ui/components/markdown_view/markdown_view.js';
|
|
32
32
|
import type {MarkdownLitRenderer} from '../../../ui/components/markdown_view/MarkdownView.js';
|
|
33
|
+
import * as Snackbars from '../../../ui/components/snackbars/snackbars.js';
|
|
33
34
|
import * as UIHelpers from '../../../ui/helpers/helpers.js';
|
|
34
35
|
import * as UI from '../../../ui/legacy/legacy.js';
|
|
35
36
|
import * as Lit from '../../../ui/lit/lit.js';
|
|
@@ -414,6 +415,14 @@ const UIStringsNotTranslate = {
|
|
|
414
415
|
* @description Title for the character set declaration widget.
|
|
415
416
|
*/
|
|
416
417
|
characterSet: 'Character set declaration',
|
|
418
|
+
/**
|
|
419
|
+
* @description Title for the network requests list widget.
|
|
420
|
+
*/
|
|
421
|
+
networkRequests: 'Network requests',
|
|
422
|
+
/**
|
|
423
|
+
* @description Accessible label for the reveal button in the network requests list widget.
|
|
424
|
+
*/
|
|
425
|
+
revealFirstNetworkRequest: 'Reveal first network request in Network panel',
|
|
417
426
|
/**
|
|
418
427
|
* @description Title for the source files list widget.
|
|
419
428
|
*/
|
|
@@ -1300,7 +1309,12 @@ function renderWidgetResponse(response: WidgetMakerResponse|null): Lit.LitTempla
|
|
|
1300
1309
|
if (response === null) {
|
|
1301
1310
|
return;
|
|
1302
1311
|
}
|
|
1303
|
-
|
|
1312
|
+
Common.Revealer.reveal(response?.revealable).catch((error: Error) => {
|
|
1313
|
+
if (!error.message) {
|
|
1314
|
+
return;
|
|
1315
|
+
}
|
|
1316
|
+
Snackbars.Snackbar.Snackbar.show({message: error.message});
|
|
1317
|
+
});
|
|
1304
1318
|
}
|
|
1305
1319
|
|
|
1306
1320
|
const classes = Lit.Directives.classMap({
|
|
@@ -1466,6 +1480,79 @@ async function makeSourceFilesListWidget(widgetData: SourceFilesListAiWidget): P
|
|
|
1466
1480
|
};
|
|
1467
1481
|
}
|
|
1468
1482
|
|
|
1483
|
+
const expandedNetworkRequestsWidgets = new WeakSet<NetworkRequestsListAiWidget>();
|
|
1484
|
+
|
|
1485
|
+
// A widget with a table of the list of network requests sent to the agent.
|
|
1486
|
+
// Only show 15 requests maximum in collapsed version. The rest of the requests
|
|
1487
|
+
// will be hidden unless the user clicks "Show all".
|
|
1488
|
+
async function makeNetworkRequestsListWidget(widgetData: NetworkRequestsListAiWidget):
|
|
1489
|
+
Promise<WidgetMakerResponse|null> {
|
|
1490
|
+
const requests = widgetData.data.requests;
|
|
1491
|
+
if (requests.length === 0) {
|
|
1492
|
+
return null;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
const isExpanded = expandedNetworkRequestsWidgets.has(widgetData);
|
|
1496
|
+
// We only want just expanded widget to be expanded, if the user closed and reopened the walkthrought, the widget should be collapsed again.
|
|
1497
|
+
// Therefore, after rendering the widget, we remove the widget from the set of expanded widgets so that it is collapsed on next render.
|
|
1498
|
+
if (isExpanded) {
|
|
1499
|
+
expandedNetworkRequestsWidgets.delete(widgetData);
|
|
1500
|
+
}
|
|
1501
|
+
const displayedRequests = isExpanded ? requests : requests.slice(0, 15);
|
|
1502
|
+
|
|
1503
|
+
// The table contains same fields as the ones sent to the agent.
|
|
1504
|
+
// clang-format off
|
|
1505
|
+
const renderedWidget = html`
|
|
1506
|
+
<div class="network-requests-widget">
|
|
1507
|
+
<devtools-data-grid striped inline>
|
|
1508
|
+
<table>
|
|
1509
|
+
<tr>
|
|
1510
|
+
<th id="name" weight="4">${i18n.i18n.lockedString('Name')}</th>
|
|
1511
|
+
<th id="status" weight="1">${i18n.i18n.lockedString('Status')}</th>
|
|
1512
|
+
<th id="size" weight="1">${i18n.i18n.lockedString('Size')}</th>
|
|
1513
|
+
<th id="time" weight="1">${i18n.i18n.lockedString('Time')}</th>
|
|
1514
|
+
</tr>
|
|
1515
|
+
${displayedRequests.map(request => html`
|
|
1516
|
+
<tr>
|
|
1517
|
+
<td>${request.name()}</td>
|
|
1518
|
+
<td>${request.statusCode}</td>
|
|
1519
|
+
<td>${i18n.ByteUtilities.formatBytesToKb(request.transferSize)}</td>
|
|
1520
|
+
<td>${i18n.TimeUtilities.secondsToString(request.duration)}</td>
|
|
1521
|
+
</tr>
|
|
1522
|
+
`)}
|
|
1523
|
+
</table>
|
|
1524
|
+
</devtools-data-grid>
|
|
1525
|
+
${!isExpanded && requests.length > 15 ? html`
|
|
1526
|
+
<div class="show-all-container">
|
|
1527
|
+
<button class="show-all-widget-requests-button text-button"
|
|
1528
|
+
jslog=${VisualLogging.action('show-all-widget-requests-button').track({click: true})}
|
|
1529
|
+
@click=${(e: Event) => {
|
|
1530
|
+
expandedNetworkRequestsWidgets.add(widgetData);
|
|
1531
|
+
const widgetEl = (e.target as HTMLElement).closest('.widget');
|
|
1532
|
+
if (widgetEl) {
|
|
1533
|
+
const widget = UI.Widget.Widget.get(widgetEl) as ChatMessage;
|
|
1534
|
+
if (widget && widget.performUpdate) {
|
|
1535
|
+
void widget.performUpdate();
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
}}>
|
|
1539
|
+
${i18n.i18n.lockedString(`Show all ${requests.length} network requests`)}
|
|
1540
|
+
</button>
|
|
1541
|
+
</div>
|
|
1542
|
+
` : Lit.nothing}
|
|
1543
|
+
</div>
|
|
1544
|
+
`;
|
|
1545
|
+
// clang-format on
|
|
1546
|
+
|
|
1547
|
+
return {
|
|
1548
|
+
renderedWidget,
|
|
1549
|
+
title: lockedString(UIStringsNotTranslate.networkRequests),
|
|
1550
|
+
revealable: requests[0],
|
|
1551
|
+
accessibleRevealLabel: lockedString(UIStringsNotTranslate.revealFirstNetworkRequest),
|
|
1552
|
+
jslogContext: 'network-requests-list-widget',
|
|
1553
|
+
};
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1469
1556
|
function renderNetworkRequestPreview(networkRequest: NonNullable<DomTreeAiWidget['data']['networkRequest']>):
|
|
1470
1557
|
Lit.TemplateResult {
|
|
1471
1558
|
const filename = networkRequest.url.split('/').pop() || networkRequest.url;
|
|
@@ -1583,6 +1670,8 @@ export function getWidgetSignature(widget: AiWidget): string {
|
|
|
1583
1670
|
return `${widget.name}:${widget.data.request.requestId()}`;
|
|
1584
1671
|
case 'SOURCE_CODE':
|
|
1585
1672
|
return `${widget.name}:${widget.data.url}:${widget.data.line ?? ''}:${widget.data.column ?? ''}`;
|
|
1673
|
+
case 'NETWORK_REQUESTS_LIST':
|
|
1674
|
+
return `${widget.name}:${widget.data.requests.map(r => r.requestId()).join(',')}`;
|
|
1586
1675
|
default:
|
|
1587
1676
|
Platform.assertNever(widget, 'Unknown AiWidget name');
|
|
1588
1677
|
}
|
|
@@ -1672,6 +1761,9 @@ async function renderWidgets(
|
|
|
1672
1761
|
case 'SOURCE_FILES_LIST':
|
|
1673
1762
|
response = await makeSourceFilesListWidget(widgetData);
|
|
1674
1763
|
break;
|
|
1764
|
+
case 'NETWORK_REQUESTS_LIST':
|
|
1765
|
+
response = await makeNetworkRequestsListWidget(widgetData);
|
|
1766
|
+
break;
|
|
1675
1767
|
case 'LIGHTHOUSE_REPORT':
|
|
1676
1768
|
response = await makeLighthouseReportWidget(widgetData);
|
|
1677
1769
|
break;
|