chrome-devtools-frontend 1.0.1605219 → 1.0.1606789
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/Images/src/dots-circle.svg +10 -0
- package/front_end/core/host/UserMetrics.ts +0 -1
- package/front_end/core/platform/api/HostRuntime.ts +9 -6
- package/front_end/core/platform/browser/HostRuntime.ts +2 -2
- package/front_end/core/platform/node/HostRuntime.ts +7 -7
- package/front_end/core/protocol_client/InspectorBackend.ts +4 -0
- package/front_end/core/root/ExperimentNames.ts +0 -1
- package/front_end/core/sdk/CrashReportContextModel.ts +28 -0
- package/front_end/core/sdk/sdk.ts +2 -2
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshotWorkerDispatcher.ts +3 -3
- package/front_end/entrypoints/heap_snapshot_worker/heap_snapshot_worker-entrypoint.ts +5 -4
- package/front_end/entrypoints/main/MainImpl.ts +0 -101
- package/front_end/models/ai_assistance/ChangeManager.ts +6 -6
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +112 -5
- package/front_end/models/ai_assistance/agents/AiAgent.ts +9 -25
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +2 -2
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +6 -3
- package/front_end/models/ai_assistance/agents/ConversationSummaryAgent.ts +10 -9
- package/front_end/models/ai_assistance/agents/ExecuteJavascript.ts +313 -0
- package/front_end/models/ai_assistance/agents/FileAgent.ts +15 -1
- package/front_end/models/ai_assistance/agents/NetworkAgent.ts +15 -1
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +19 -8
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +35 -278
- package/front_end/models/ai_assistance/ai_assistance.ts +0 -2
- package/front_end/models/javascript_metadata/NativeFunctions.js +1 -5
- package/front_end/models/web_mcp/WebMCPModel.ts +187 -0
- package/front_end/models/web_mcp/web_mcp.ts +9 -0
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +8 -1
- package/front_end/panels/ai_assistance/ai_assistance.ts +1 -0
- package/front_end/panels/ai_assistance/components/AccessibilityAgentMarkdownRenderer.ts +88 -0
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +149 -49
- package/front_end/panels/ai_assistance/components/ChatView.ts +11 -15
- package/front_end/panels/ai_assistance/components/ExportForAgentsDialog.ts +13 -4
- package/front_end/panels/ai_assistance/components/chatMessage.css +53 -1
- package/front_end/panels/ai_assistance/components/chatView.css +0 -10
- package/front_end/panels/ai_assistance/components/exportForAgentsDialog.css +13 -0
- package/front_end/panels/application/WebMCPView.ts +471 -25
- package/front_end/panels/application/webMCPView.css +53 -2
- package/front_end/panels/elements/ElementsTreeElement.ts +1 -1
- package/front_end/panels/elements/ElementsTreeOutline.ts +87 -0
- package/front_end/panels/elements/StylePropertiesSection.ts +0 -4
- package/front_end/panels/elements/elements.ts +3 -0
- package/front_end/panels/elements/elementsTreeOutline.css +21 -0
- package/front_end/panels/elements/stylePropertiesTreeOutline.css +7 -0
- package/front_end/panels/lighthouse/LighthousePanel.ts +7 -1
- package/front_end/panels/lighthouse/LighthouseProtocolService.ts +25 -2
- package/front_end/panels/profiler/HeapDetachedElementsView.ts +0 -4
- package/front_end/panels/profiler/HeapProfileView.ts +0 -4
- package/front_end/panels/profiler/HeapProfilerPanel.ts +4 -13
- package/front_end/panels/profiler/HeapSnapshotProxy.ts +2 -6
- package/front_end/panels/profiler/HeapSnapshotView.ts +19 -32
- package/front_end/panels/profiler/ProfileHeader.ts +1 -15
- package/front_end/panels/profiler/ProfileTypeRegistry.ts +4 -12
- package/front_end/panels/profiler/ProfileView.ts +1 -6
- package/front_end/panels/profiler/ProfilesPanel.ts +60 -7
- package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +27 -22
- package/front_end/panels/timeline/EventsTimelineTreeView.ts +1 -1
- package/front_end/panels/timeline/ThirdPartyTreeView.ts +2 -2
- package/front_end/panels/timeline/TimelinePanel.ts +11 -153
- package/front_end/panels/timeline/TimelineTreeView.ts +147 -48
- package/front_end/panels/timeline/TimelineUIUtils.ts +2 -1
- package/front_end/panels/timeline/components/CWVMetrics.ts +18 -2
- package/front_end/panels/timeline/timeline-meta.ts +11 -0
- package/front_end/panels/timeline/utils/Helpers.ts +5 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/components/markdown_view/CodeBlock.ts +47 -1
- package/front_end/ui/components/markdown_view/codeBlock.css +8 -0
- package/front_end/ui/legacy/FilterBar.ts +2 -0
- package/front_end/ui/legacy/SplitWidget.ts +33 -27
- package/front_end/ui/legacy/TabbedPane.ts +123 -3
- package/front_end/ui/legacy/Widget.ts +95 -48
- package/front_end/ui/legacy/components/source_frame/JSONView.ts +1 -1
- package/front_end/ui/legacy/components/utils/jsUtils.css +2 -0
- package/front_end/ui/legacy/infobar.css +1 -0
- package/front_end/ui/visual_logging/KnownContextValues.ts +6 -1
- package/package.json +1 -1
- package/front_end/core/sdk/WebMCPModel.ts +0 -104
- package/front_end/models/ai_assistance/ConversationHandler.ts +0 -325
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import * as Host from '../../../core/host/host.js';
|
|
6
6
|
import * as i18n from '../../../core/i18n/i18n.js';
|
|
7
|
-
import * as Platform from '../../../core/platform/platform.js';
|
|
8
7
|
import * as Root from '../../../core/root/root.js';
|
|
9
8
|
import * as SDK from '../../../core/sdk/sdk.js';
|
|
10
9
|
import * as Protocol from '../../../generated/protocol.js';
|
|
@@ -13,24 +12,28 @@ import * as Annotations from '../../annotations/annotations.js';
|
|
|
13
12
|
import * as Emulation from '../../emulation/emulation.js';
|
|
14
13
|
import {ChangeManager} from '../ChangeManager.js';
|
|
15
14
|
import {debugLog} from '../debug.js';
|
|
16
|
-
import {EvaluateAction, formatError, SideEffectError} from '../EvaluateAction.js';
|
|
17
15
|
import {ExtensionScope} from '../ExtensionScope.js';
|
|
18
|
-
import {AI_ASSISTANCE_CSS_CLASS_NAME
|
|
16
|
+
import {AI_ASSISTANCE_CSS_CLASS_NAME} from '../injected.js';
|
|
19
17
|
|
|
20
18
|
import {
|
|
21
|
-
type AgentOptions as BaseAgentOptions,
|
|
22
19
|
AiAgent,
|
|
23
20
|
type ComputedStyleAiWidget,
|
|
24
21
|
type ContextResponse,
|
|
25
22
|
ConversationContext,
|
|
26
23
|
type ConversationSuggestions,
|
|
27
24
|
type FunctionCallHandlerResult,
|
|
28
|
-
type FunctionHandlerOptions,
|
|
29
25
|
type MultimodalInput,
|
|
30
26
|
MultimodalInputType,
|
|
31
27
|
type RequestOptions,
|
|
32
28
|
ResponseType
|
|
33
29
|
} from './AiAgent.js';
|
|
30
|
+
import {
|
|
31
|
+
type CreateExtensionScopeFunction,
|
|
32
|
+
executeJavaScriptFunction,
|
|
33
|
+
type ExecuteJsAgentOptions,
|
|
34
|
+
executeJsCode,
|
|
35
|
+
JavascriptExecutor
|
|
36
|
+
} from './ExecuteJavascript.js';
|
|
34
37
|
|
|
35
38
|
/*
|
|
36
39
|
* Strings that don't need to be translated at this time.
|
|
@@ -69,10 +72,25 @@ First, examine the provided context, then use the functions to gather additional
|
|
|
69
72
|
* Use functions available to you to investigate and fulfill the user request.
|
|
70
73
|
* After applying a fix, please ask the user to confirm if the fix worked or not.
|
|
71
74
|
* 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.
|
|
75
|
+
* 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.
|
|
72
76
|
* **CRITICAL** NEVER write full Python programs - you should only write individual statements that invoke a single function from the provided library.
|
|
73
77
|
* **CRITICAL** NEVER output text before a function call. Always do a function call first.
|
|
74
78
|
* **CRITICAL** When answering questions about positioning or layout, ALWAYS inspect \`position\`, \`display\` and ALL related properties.
|
|
75
|
-
* **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
|
|
79
|
+
* **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.
|
|
80
|
+
|
|
81
|
+
## Response Structure
|
|
82
|
+
|
|
83
|
+
If the user asks a question that requires an investigation of a problem, use this structure:
|
|
84
|
+
- If available, point out the root cause(s) of the problem.
|
|
85
|
+
- Example: "**Root Cause**: The page is slow because of [reason]."
|
|
86
|
+
- Example: "**Root Causes**:"
|
|
87
|
+
- [Reason 1]
|
|
88
|
+
- [Reason 2]
|
|
89
|
+
- if applicable, list actionable solution suggestion(s) in order of impact:
|
|
90
|
+
- Example: "**Suggestion**: [Suggestion 1]
|
|
91
|
+
- Example: "**Suggestions**:"
|
|
92
|
+
- [Suggestion 1]
|
|
93
|
+
- [Suggestion 2]`;
|
|
76
94
|
|
|
77
95
|
const greenDevEmulationEnabled = Greendev.Prototypes.instance().isEnabled('emulationCapabilities');
|
|
78
96
|
if (greenDevEmulationEnabled) {
|
|
@@ -145,64 +163,8 @@ const MULTIMODAL_ENHANCEMENT_PROMPTS: Record<MultimodalInputType, string> = {
|
|
|
145
163
|
[MultimodalInputType.UPLOADED_IMAGE]: promptForUploadedImage + considerationsForMultimodalInputEvaluation,
|
|
146
164
|
};
|
|
147
165
|
|
|
148
|
-
async function executeJsCode(
|
|
149
|
-
functionDeclaration: string,
|
|
150
|
-
{throwOnSideEffect, contextNode}: {throwOnSideEffect: boolean, contextNode: SDK.DOMModel.DOMNode|null}):
|
|
151
|
-
Promise<string> {
|
|
152
|
-
if (!contextNode) {
|
|
153
|
-
throw new Error('Cannot execute JavaScript because of missing context node');
|
|
154
|
-
}
|
|
155
|
-
const target = contextNode.domModel().target();
|
|
156
|
-
|
|
157
|
-
if (!target) {
|
|
158
|
-
throw new Error('Target is not found for executing code');
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const resourceTreeModel = target.model(SDK.ResourceTreeModel.ResourceTreeModel);
|
|
162
|
-
const frameId = contextNode.frameId() ?? resourceTreeModel?.mainFrame?.id;
|
|
163
|
-
|
|
164
|
-
if (!frameId) {
|
|
165
|
-
throw new Error('Main frame is not found for executing code');
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const runtimeModel = target.model(SDK.RuntimeModel.RuntimeModel);
|
|
169
|
-
const pageAgent = target.pageAgent();
|
|
170
|
-
|
|
171
|
-
// This returns previously created world if it exists for the frame.
|
|
172
|
-
const {executionContextId} = await pageAgent.invoke_createIsolatedWorld({frameId, worldName: FREESTYLER_WORLD_NAME});
|
|
173
|
-
const executionContext = runtimeModel?.executionContext(executionContextId);
|
|
174
|
-
if (!executionContext) {
|
|
175
|
-
throw new Error('Execution context is not found for executing code');
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (executionContext.debuggerModel.selectedCallFrame()) {
|
|
179
|
-
return formatError('Cannot evaluate JavaScript because the execution is paused on a breakpoint.');
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const remoteObject = await contextNode.resolveToObject(undefined, executionContextId);
|
|
183
|
-
if (!remoteObject) {
|
|
184
|
-
throw new Error('Cannot execute JavaScript because remote object cannot be resolved');
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return await EvaluateAction.execute(functionDeclaration, [remoteObject], executionContext, {throwOnSideEffect});
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const MAX_OBSERVATION_BYTE_LENGTH = 25_000;
|
|
191
|
-
const OBSERVATION_TIMEOUT = 5_000;
|
|
192
|
-
|
|
193
166
|
export const AI_ASSISTANCE_FILTER_REGEX = `\\.${AI_ASSISTANCE_CSS_CLASS_NAME}-.*&`;
|
|
194
167
|
|
|
195
|
-
type CreateExtensionScopeFunction = (changes: ChangeManager) => {
|
|
196
|
-
install(): Promise<void>, uninstall(): Promise<void>,
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
interface AgentOptions extends BaseAgentOptions {
|
|
200
|
-
changeManager?: ChangeManager;
|
|
201
|
-
|
|
202
|
-
createExtensionScope?: CreateExtensionScopeFunction;
|
|
203
|
-
execJs?: typeof executeJsCode;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
168
|
export class NodeContext extends ConversationContext<SDK.DOMModel.DOMNode> {
|
|
207
169
|
#node: SDK.DOMModel.DOMNode;
|
|
208
170
|
|
|
@@ -310,6 +272,7 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
|
|
|
310
272
|
}
|
|
311
273
|
|
|
312
274
|
#execJs: typeof executeJsCode;
|
|
275
|
+
#javascriptExecutor: JavascriptExecutor;
|
|
313
276
|
|
|
314
277
|
#changes: ChangeManager;
|
|
315
278
|
#createExtensionScope: CreateExtensionScopeFunction;
|
|
@@ -317,7 +280,7 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
|
|
|
317
280
|
#greenDevEmulationAxTree: string|null = null;
|
|
318
281
|
#currentTurnId = 0;
|
|
319
282
|
|
|
320
|
-
constructor(opts:
|
|
283
|
+
constructor(opts: ExecuteJsAgentOptions) {
|
|
321
284
|
super(opts);
|
|
322
285
|
|
|
323
286
|
this.#changes = opts.changeManager || new ChangeManager();
|
|
@@ -326,6 +289,14 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
|
|
|
326
289
|
opts.createExtensionScope ?? ((changes: ChangeManager) => {
|
|
327
290
|
return new ExtensionScope(changes, this.sessionId, this.context?.getItem() ?? null, this.#currentTurnId);
|
|
328
291
|
});
|
|
292
|
+
this.#javascriptExecutor = new JavascriptExecutor(
|
|
293
|
+
{
|
|
294
|
+
executionMode: this.executionMode,
|
|
295
|
+
getContextNode: () => this.#getSelectedNode(),
|
|
296
|
+
createExtensionScope: this.#createExtensionScope.bind(this),
|
|
297
|
+
changes: this.#changes,
|
|
298
|
+
},
|
|
299
|
+
this.#execJs);
|
|
329
300
|
|
|
330
301
|
this.declareFunction<{
|
|
331
302
|
elements: number[],
|
|
@@ -378,91 +349,7 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
|
|
|
378
349
|
},
|
|
379
350
|
});
|
|
380
351
|
|
|
381
|
-
this.declareFunction
|
|
382
|
-
title: string,
|
|
383
|
-
explanation: string,
|
|
384
|
-
code: string,
|
|
385
|
-
}>('executeJavaScript', {
|
|
386
|
-
description:
|
|
387
|
-
`This function allows you to run JavaScript code on the inspected page to access the element styles and page content.
|
|
388
|
-
Call this function to gather additional information or modify the page state. Call this function enough times to investigate the user request.`,
|
|
389
|
-
parameters: {
|
|
390
|
-
type: Host.AidaClient.ParametersTypes.OBJECT,
|
|
391
|
-
description: '',
|
|
392
|
-
nullable: false,
|
|
393
|
-
properties: {
|
|
394
|
-
code: {
|
|
395
|
-
type: Host.AidaClient.ParametersTypes.STRING,
|
|
396
|
-
description:
|
|
397
|
-
`JavaScript code snippet to run on the inspected page. Make sure the code is formatted for readability.
|
|
398
|
-
|
|
399
|
-
# Instructions
|
|
400
|
-
|
|
401
|
-
* 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\`.
|
|
402
|
-
* 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.
|
|
403
|
-
* **CRITICAL** Only get styles that might be relevant to the user request.
|
|
404
|
-
* **CRITICAL** Never assume a selector for the elements unless you verified your knowledge.
|
|
405
|
-
* **CRITICAL** Consider that \`data\` variable from the previous function calls are not available in a new function call.
|
|
406
|
-
|
|
407
|
-
For example, the code to change element styles:
|
|
408
|
-
|
|
409
|
-
\`\`\`
|
|
410
|
-
await setElementStyles($0, {
|
|
411
|
-
color: 'blue',
|
|
412
|
-
});
|
|
413
|
-
\`\`\`
|
|
414
|
-
|
|
415
|
-
For example, the code to get overlapping elements:
|
|
416
|
-
|
|
417
|
-
\`\`\`
|
|
418
|
-
const data = {
|
|
419
|
-
overlappingElements: Array.from(document.querySelectorAll('*'))
|
|
420
|
-
.filter(el => {
|
|
421
|
-
const rect = el.getBoundingClientRect();
|
|
422
|
-
const popupRect = $0.getBoundingClientRect();
|
|
423
|
-
return (
|
|
424
|
-
el !== $0 &&
|
|
425
|
-
rect.left < popupRect.right &&
|
|
426
|
-
rect.right > popupRect.left &&
|
|
427
|
-
rect.top < popupRect.bottom &&
|
|
428
|
-
rect.bottom > popupRect.top
|
|
429
|
-
);
|
|
430
|
-
})
|
|
431
|
-
.map(el => ({
|
|
432
|
-
tagName: el.tagName,
|
|
433
|
-
id: el.id,
|
|
434
|
-
className: el.className,
|
|
435
|
-
zIndex: window.getComputedStyle(el)['z-index']
|
|
436
|
-
}))
|
|
437
|
-
};
|
|
438
|
-
\`\`\`
|
|
439
|
-
`,
|
|
440
|
-
},
|
|
441
|
-
explanation: {
|
|
442
|
-
type: Host.AidaClient.ParametersTypes.STRING,
|
|
443
|
-
description: 'Explain why you want to run this code',
|
|
444
|
-
},
|
|
445
|
-
title: {
|
|
446
|
-
type: Host.AidaClient.ParametersTypes.STRING,
|
|
447
|
-
description: 'Provide a summary of what the code does. For example, "Checking related element styles".',
|
|
448
|
-
},
|
|
449
|
-
},
|
|
450
|
-
required: ['code', 'explanation', 'title']
|
|
451
|
-
},
|
|
452
|
-
displayInfoFromArgs: params => {
|
|
453
|
-
return {
|
|
454
|
-
title: params.title,
|
|
455
|
-
thought: params.explanation,
|
|
456
|
-
action: params.code,
|
|
457
|
-
};
|
|
458
|
-
},
|
|
459
|
-
handler: async (
|
|
460
|
-
params,
|
|
461
|
-
options,
|
|
462
|
-
) => {
|
|
463
|
-
return await this.executeAction(params.code, options);
|
|
464
|
-
},
|
|
465
|
-
});
|
|
352
|
+
this.declareFunction('executeJavaScript', executeJavaScriptFunction(this.#javascriptExecutor));
|
|
466
353
|
|
|
467
354
|
if (Annotations.AnnotationRepository.annotationsEnabled()) {
|
|
468
355
|
this.declareFunction<{
|
|
@@ -528,68 +415,6 @@ const data = {
|
|
|
528
415
|
});
|
|
529
416
|
}
|
|
530
417
|
|
|
531
|
-
async generateObservation(
|
|
532
|
-
action: string,
|
|
533
|
-
{
|
|
534
|
-
throwOnSideEffect,
|
|
535
|
-
}: {
|
|
536
|
-
throwOnSideEffect: boolean,
|
|
537
|
-
},
|
|
538
|
-
): Promise<{
|
|
539
|
-
observation: string,
|
|
540
|
-
sideEffect: boolean,
|
|
541
|
-
canceled: boolean,
|
|
542
|
-
}> {
|
|
543
|
-
const functionDeclaration = `async function ($0) {
|
|
544
|
-
try {
|
|
545
|
-
${action}
|
|
546
|
-
;
|
|
547
|
-
return ((typeof data !== "undefined") ? data : undefined);
|
|
548
|
-
} catch (error) {
|
|
549
|
-
return error;
|
|
550
|
-
}
|
|
551
|
-
}`;
|
|
552
|
-
try {
|
|
553
|
-
const result = await Promise.race([
|
|
554
|
-
this.#execJs(
|
|
555
|
-
functionDeclaration,
|
|
556
|
-
{
|
|
557
|
-
throwOnSideEffect,
|
|
558
|
-
contextNode: this.context?.getItem() || null,
|
|
559
|
-
},
|
|
560
|
-
),
|
|
561
|
-
new Promise<never>((_, reject) => {
|
|
562
|
-
setTimeout(
|
|
563
|
-
() => reject(new Error('Script execution exceeded the maximum allowed time.')), OBSERVATION_TIMEOUT);
|
|
564
|
-
}),
|
|
565
|
-
]);
|
|
566
|
-
const byteCount = Platform.StringUtilities.countWtf8Bytes(result);
|
|
567
|
-
Host.userMetrics.freestylerEvalResponseSize(byteCount);
|
|
568
|
-
if (byteCount > MAX_OBSERVATION_BYTE_LENGTH) {
|
|
569
|
-
throw new Error('Output exceeded the maximum allowed length.');
|
|
570
|
-
}
|
|
571
|
-
return {
|
|
572
|
-
observation: result,
|
|
573
|
-
sideEffect: false,
|
|
574
|
-
canceled: false,
|
|
575
|
-
};
|
|
576
|
-
} catch (error) {
|
|
577
|
-
if (error instanceof SideEffectError) {
|
|
578
|
-
return {
|
|
579
|
-
observation: error.message,
|
|
580
|
-
sideEffect: true,
|
|
581
|
-
canceled: false,
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
return {
|
|
586
|
-
observation: `Error: ${error.message}`,
|
|
587
|
-
sideEffect: false,
|
|
588
|
-
canceled: false,
|
|
589
|
-
};
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
|
|
593
418
|
static async describeElement(element: SDK.DOMModel.DOMNode): Promise<string> {
|
|
594
419
|
let output = `* Element's uid is ${element.backendNodeId()}.
|
|
595
420
|
* Its selector is \`${element.simpleSelector()}\``;
|
|
@@ -742,74 +567,6 @@ const data = {
|
|
|
742
567
|
};
|
|
743
568
|
}
|
|
744
569
|
|
|
745
|
-
async executeAction(action: string, options?: FunctionHandlerOptions): Promise<FunctionCallHandlerResult<unknown>> {
|
|
746
|
-
debugLog(`Action to execute: ${action}`);
|
|
747
|
-
|
|
748
|
-
if (options?.approved === false) {
|
|
749
|
-
return {
|
|
750
|
-
error: 'Error: User denied code execution with side effects.',
|
|
751
|
-
};
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
if (this.executionMode === Root.Runtime.HostConfigFreestylerExecutionMode.NO_SCRIPTS) {
|
|
755
|
-
return {
|
|
756
|
-
error: 'Error: JavaScript execution is currently disabled.',
|
|
757
|
-
};
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
const selectedNode = this.#getSelectedNode();
|
|
761
|
-
if (!selectedNode) {
|
|
762
|
-
return {error: 'Error: no selected node found.'};
|
|
763
|
-
}
|
|
764
|
-
const target = selectedNode.domModel().target();
|
|
765
|
-
if (target.model(SDK.DebuggerModel.DebuggerModel)?.selectedCallFrame()) {
|
|
766
|
-
return {
|
|
767
|
-
error: 'Error: Cannot evaluate JavaScript because the execution is paused on a breakpoint.',
|
|
768
|
-
};
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
const scope = this.#createExtensionScope(this.#changes);
|
|
772
|
-
await scope.install();
|
|
773
|
-
try {
|
|
774
|
-
let throwOnSideEffect = true;
|
|
775
|
-
if (options?.approved) {
|
|
776
|
-
throwOnSideEffect = false;
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
const result = await this.generateObservation(action, {throwOnSideEffect});
|
|
780
|
-
debugLog(`Action result: ${JSON.stringify(result)}`);
|
|
781
|
-
if (result.sideEffect) {
|
|
782
|
-
if (this.executionMode === Root.Runtime.HostConfigFreestylerExecutionMode.SIDE_EFFECT_FREE_SCRIPTS_ONLY) {
|
|
783
|
-
return {
|
|
784
|
-
error: 'Error: JavaScript execution that modifies the page is currently disabled.',
|
|
785
|
-
};
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
if (options?.signal?.aborted) {
|
|
789
|
-
return {
|
|
790
|
-
error: 'Error: evaluation has been cancelled',
|
|
791
|
-
};
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
return {
|
|
795
|
-
requiresApproval: true,
|
|
796
|
-
description: lockedString('This code may modify page content. Continue?'),
|
|
797
|
-
};
|
|
798
|
-
}
|
|
799
|
-
if (result.canceled) {
|
|
800
|
-
return {
|
|
801
|
-
error: result.observation,
|
|
802
|
-
};
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
return {
|
|
806
|
-
result: result.observation,
|
|
807
|
-
};
|
|
808
|
-
} finally {
|
|
809
|
-
await scope.uninstall();
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
|
|
813
570
|
async addElementAnnotation(elementId: string, annotationMessage: string):
|
|
814
571
|
Promise<FunctionCallHandlerResult<unknown>> {
|
|
815
572
|
if (!Annotations.AnnotationRepository.annotationsEnabled()) {
|
|
@@ -19,7 +19,6 @@ import * as AiHistoryStorage from './AiHistoryStorage.js';
|
|
|
19
19
|
import * as AiUtils from './AiUtils.js';
|
|
20
20
|
import * as BuiltInAi from './BuiltInAi.js';
|
|
21
21
|
import * as ChangeManager from './ChangeManager.js';
|
|
22
|
-
import * as ConversationHandler from './ConversationHandler.js';
|
|
23
22
|
import * as FileFormatter from './data_formatters/FileFormatter.js';
|
|
24
23
|
import * as LighthouseFormatter from './data_formatters/LighthouseFormatter.js';
|
|
25
24
|
import * as NetworkRequestFormatter from './data_formatters/NetworkRequestFormatter.js';
|
|
@@ -48,7 +47,6 @@ export {
|
|
|
48
47
|
BuiltInAi,
|
|
49
48
|
ChangeManager,
|
|
50
49
|
ContextSelectionAgent,
|
|
51
|
-
ConversationHandler,
|
|
52
50
|
ConversationSummaryAgent,
|
|
53
51
|
Debug,
|
|
54
52
|
EvaluateAction,
|
|
@@ -7402,11 +7402,7 @@ export const NativeFunctions = [
|
|
|
7402
7402
|
},
|
|
7403
7403
|
{
|
|
7404
7404
|
name: "registerTool",
|
|
7405
|
-
signatures: [["tool"]]
|
|
7406
|
-
},
|
|
7407
|
-
{
|
|
7408
|
-
name: "unregisterTool",
|
|
7409
|
-
signatures: [["name"]]
|
|
7405
|
+
signatures: [["tool","?options"]]
|
|
7410
7406
|
},
|
|
7411
7407
|
{
|
|
7412
7408
|
name: "SnapEvent",
|
|
@@ -0,0 +1,187 @@
|
|
|
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 Common from '../../core/common/common.js';
|
|
6
|
+
import * as SDK from '../../core/sdk/sdk.js';
|
|
7
|
+
import type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';
|
|
8
|
+
import type * as Protocol from '../../generated/protocol.js';
|
|
9
|
+
import * as Bindings from '../bindings/bindings.js';
|
|
10
|
+
import type * as StackTrace from '../stack_trace/stack_trace.js';
|
|
11
|
+
|
|
12
|
+
export const enum Events {
|
|
13
|
+
TOOLS_ADDED = 'ToolsAdded',
|
|
14
|
+
TOOLS_REMOVED = 'ToolsRemoved',
|
|
15
|
+
TOOL_INVOKED = 'ToolInvoked',
|
|
16
|
+
TOOL_RESPONDED = 'ToolResponded',
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface Call {
|
|
20
|
+
invocationId: string;
|
|
21
|
+
tool: Tool;
|
|
22
|
+
input: string;
|
|
23
|
+
result?: {
|
|
24
|
+
status: Protocol.WebMCP.InvocationStatus,
|
|
25
|
+
output?: unknown,
|
|
26
|
+
errorText?: string,
|
|
27
|
+
exception?: Protocol.Runtime.RemoteObject,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class Tool {
|
|
32
|
+
#protocolTool: Readonly<Protocol.WebMCP.Tool>;
|
|
33
|
+
#stackTrace?: Promise<StackTrace.StackTrace.StackTrace>;
|
|
34
|
+
#target: WeakRef<SDK.Target.Target>;
|
|
35
|
+
|
|
36
|
+
constructor(tool: Protocol.WebMCP.Tool, target: SDK.Target.Target) {
|
|
37
|
+
this.#target = new WeakRef(target);
|
|
38
|
+
this.#protocolTool = tool;
|
|
39
|
+
this.#stackTrace = tool.stackTrace &&
|
|
40
|
+
Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().createStackTraceFromProtocolRuntime(
|
|
41
|
+
tool.stackTrace, target);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get stackTrace(): Promise<StackTrace.StackTrace.StackTrace>|undefined {
|
|
45
|
+
return this.#stackTrace;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get name(): string {
|
|
49
|
+
return this.#protocolTool.name;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
get description(): string {
|
|
53
|
+
return this.#protocolTool.description;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
get frame(): SDK.ResourceTreeModel.ResourceTreeFrame|undefined {
|
|
57
|
+
return this.#target.deref()
|
|
58
|
+
?.model(SDK.ResourceTreeModel.ResourceTreeModel)
|
|
59
|
+
?.frameForId(this.#protocolTool.frameId) ??
|
|
60
|
+
undefined;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
get isDeclarative(): boolean {
|
|
64
|
+
return Boolean(this.#protocolTool.backendNodeId);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
get node(): SDK.DOMModel.DeferredDOMNode|undefined {
|
|
68
|
+
const target = this.#target.deref();
|
|
69
|
+
return this.#protocolTool.backendNodeId && target &&
|
|
70
|
+
new SDK.DOMModel.DeferredDOMNode(target, this.#protocolTool.backendNodeId);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export interface EventTypes {
|
|
74
|
+
[Events.TOOLS_ADDED]: readonly Tool[];
|
|
75
|
+
[Events.TOOLS_REMOVED]: readonly Tool[];
|
|
76
|
+
[Events.TOOL_INVOKED]: Call;
|
|
77
|
+
[Events.TOOL_RESPONDED]: Call;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export class WebMCPModel extends SDK.SDKModel.SDKModel<EventTypes> implements ProtocolProxyApi.WebMCPDispatcher {
|
|
81
|
+
readonly #tools = new Map<Protocol.Page.FrameId, Map<string, Tool>>();
|
|
82
|
+
readonly #calls = new Map<string, Call>();
|
|
83
|
+
readonly agent: ProtocolProxyApi.WebMCPApi;
|
|
84
|
+
#enabled = false;
|
|
85
|
+
|
|
86
|
+
constructor(target: SDK.Target.Target) {
|
|
87
|
+
super(target);
|
|
88
|
+
this.agent = target.webMCPAgent();
|
|
89
|
+
target.registerWebMCPDispatcher(this);
|
|
90
|
+
|
|
91
|
+
const runtimeModel = target.model(SDK.RuntimeModel.RuntimeModel);
|
|
92
|
+
if (runtimeModel) {
|
|
93
|
+
runtimeModel.addEventListener(
|
|
94
|
+
SDK.RuntimeModel.Events.ExecutionContextDestroyed, this.#executionContextDestroyed, this);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
void this.enable();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
get tools(): IteratorObject<Tool> {
|
|
101
|
+
return this.#tools.values().flatMap(toolMap => toolMap.values());
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
get toolCalls(): Call[] {
|
|
105
|
+
return [...this.#calls.values()];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
clearCalls(): void {
|
|
109
|
+
this.#calls.clear();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async enable(): Promise<void> {
|
|
113
|
+
if (this.#enabled) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
await this.agent.invoke_enable();
|
|
117
|
+
this.#enabled = true;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
#executionContextDestroyed(event: Common.EventTarget.EventTargetEvent<SDK.RuntimeModel.ExecutionContext>): void {
|
|
121
|
+
const executionContext = event.data;
|
|
122
|
+
if (executionContext.isDefault && executionContext.frameId) {
|
|
123
|
+
const frameTools = this.#tools.get(executionContext.frameId);
|
|
124
|
+
if (frameTools) {
|
|
125
|
+
const toolsToRemove = [...frameTools.values()];
|
|
126
|
+
this.#tools.delete(executionContext.frameId);
|
|
127
|
+
this.dispatchEventToListeners(Events.TOOLS_REMOVED, toolsToRemove);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
toolsRemoved(params: Protocol.WebMCP.ToolsRemovedEvent): void {
|
|
133
|
+
const deletedTools = [];
|
|
134
|
+
for (const protocolTool of params.tools) {
|
|
135
|
+
const tool = this.#tools.get(protocolTool.frameId)?.get(protocolTool.name);
|
|
136
|
+
if (tool) {
|
|
137
|
+
this.#tools.get(protocolTool.frameId)?.delete(protocolTool.name);
|
|
138
|
+
deletedTools.push(tool);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
this.dispatchEventToListeners(Events.TOOLS_REMOVED, deletedTools);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
toolsAdded(params: Protocol.WebMCP.ToolsAddedEvent): void {
|
|
145
|
+
const addedTools = [];
|
|
146
|
+
for (const protocolTool of params.tools) {
|
|
147
|
+
const tool = new Tool(protocolTool, this.target());
|
|
148
|
+
const frameTools = this.#tools.get(protocolTool.frameId) ?? new Map();
|
|
149
|
+
if (!this.#tools.has(protocolTool.frameId)) {
|
|
150
|
+
this.#tools.set(protocolTool.frameId, frameTools);
|
|
151
|
+
}
|
|
152
|
+
frameTools.set(tool.name, tool);
|
|
153
|
+
addedTools.push(tool);
|
|
154
|
+
}
|
|
155
|
+
this.dispatchEventToListeners(Events.TOOLS_ADDED, addedTools);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
toolInvoked(params: Protocol.WebMCP.ToolInvokedEvent): void {
|
|
159
|
+
const tool = this.#tools.get(params.frameId)?.get(params.toolName);
|
|
160
|
+
if (!tool) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const call: Call = {
|
|
164
|
+
invocationId: params.invocationId,
|
|
165
|
+
input: params.input,
|
|
166
|
+
tool,
|
|
167
|
+
};
|
|
168
|
+
this.#calls.set(params.invocationId, call);
|
|
169
|
+
this.dispatchEventToListeners(Events.TOOL_INVOKED, call);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
toolResponded(params: Protocol.WebMCP.ToolRespondedEvent): void {
|
|
173
|
+
const call = this.#calls.get(params.invocationId);
|
|
174
|
+
if (!call) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
call.result = {
|
|
178
|
+
status: params.status,
|
|
179
|
+
output: params.output,
|
|
180
|
+
errorText: params.errorText,
|
|
181
|
+
exception: params.exception,
|
|
182
|
+
};
|
|
183
|
+
this.dispatchEventToListeners(Events.TOOL_RESPONDED, call);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
SDK.SDKModel.SDKModel.register(WebMCPModel, {capabilities: SDK.Target.Capability.WEB_MCP, autostart: true});
|
|
@@ -29,6 +29,7 @@ import * as NetworkPanel from '../network/network.js';
|
|
|
29
29
|
import * as TimelinePanel from '../timeline/timeline.js';
|
|
30
30
|
|
|
31
31
|
import aiAssistancePanelStyles from './aiAssistancePanel.css.js';
|
|
32
|
+
import {AccessibilityAgentMarkdownRenderer} from './components/AccessibilityAgentMarkdownRenderer.js';
|
|
32
33
|
import {
|
|
33
34
|
type AnswerPart,
|
|
34
35
|
ChatMessageEntity,
|
|
@@ -363,6 +364,11 @@ function getMarkdownRenderer(conversation?: AiAssistanceModel.AiConversation.AiC
|
|
|
363
364
|
const resourceTreeModel = domModel?.target().model(SDK.ResourceTreeModel.ResourceTreeModel);
|
|
364
365
|
const mainFrameId = resourceTreeModel?.mainFrame?.id;
|
|
365
366
|
return new StylingAgentMarkdownRenderer(mainFrameId);
|
|
367
|
+
} else if (conversation?.type === AiAssistanceModel.AiHistoryStorage.ConversationType.ACCESSIBILITY) {
|
|
368
|
+
const domModel = SDK.TargetManager.TargetManager.instance().primaryPageTarget()?.model(SDK.DOMModel.DOMModel);
|
|
369
|
+
const resourceTreeModel = domModel?.target().model(SDK.ResourceTreeModel.ResourceTreeModel);
|
|
370
|
+
const mainFrameId = resourceTreeModel?.mainFrame?.id;
|
|
371
|
+
return new AccessibilityAgentMarkdownRenderer(mainFrameId);
|
|
366
372
|
}
|
|
367
373
|
|
|
368
374
|
return new MarkdownRendererWithCodeBlock();
|
|
@@ -1281,7 +1287,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1281
1287
|
return;
|
|
1282
1288
|
}
|
|
1283
1289
|
|
|
1284
|
-
|
|
1290
|
+
const hasAiV2 = Boolean(Root.Runtime.hostConfig.devToolsAiAssistanceV2?.enabled);
|
|
1291
|
+
return this.#changeManager.formatChangesForPatching(this.#conversation.id, /* includeMetadata= */ !hasAiV2);
|
|
1285
1292
|
}
|
|
1286
1293
|
|
|
1287
1294
|
override async performUpdate(): Promise<void> {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
export * from './AiAssistancePanel.js';
|
|
6
6
|
export * from './components/ChatView.js';
|
|
7
|
+
export * from './components/AccessibilityAgentMarkdownRenderer.js';
|
|
7
8
|
export * as ChatInput from './components/ChatInput.js';
|
|
8
9
|
export * from './components/MarkdownRendererWithCodeBlock.js';
|
|
9
10
|
export * from './SelectWorkspaceDialog.js';
|